blob: 77c774a9660c55c1810c386447f251d8997994b0 [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
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 Norman2c99c5b2019-03-07 13:01:48 -0800129# default_system_misc_info_keys is a list of keys to obtain from the system instance of
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800130# META/misc_info.txt. The remaining keys from the other instance.
131
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.
188
189 target_files_temp_dir: The temporary directory where the extracted items
190 will land.
191
192 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800193 """
194
195 logger.info('extracting from %s', target_files)
196
197 # Filter the extract_item_list to remove any items that do not exist in the
198 # zip file. Otherwise, the extraction step will fail.
199
200 with zipfile.ZipFile(
201 target_files,
202 'r',
203 allowZip64=True) as target_files_zipfile:
204 target_files_namelist = target_files_zipfile.namelist()
205
206 filtered_extract_item_list = []
207 for pattern in extract_item_list:
208 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
209 if not matching_namelist:
210 logger.warning('no match for %s', pattern)
211 else:
212 filtered_extract_item_list.append(pattern)
213
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800214 # Extract from target_files into target_files_temp_dir the
215 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800216
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800217 common.UnzipToDir(
218 target_files,
219 target_files_temp_dir,
220 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800221
222
Daniel Normanfdb38812019-04-15 09:47:24 -0700223def copy_items(from_dir, to_dir, patterns):
224 """Similar to extract_items() except uses an input dir instead of zip."""
225 file_paths = []
226 for dirpath, _, filenames in os.walk(from_dir):
227 file_paths.extend(os.path.relpath(path=os.path.join(dirpath, filename),
228 start=from_dir) for filename in filenames)
229
230 filtered_file_paths = set()
231 for pattern in patterns:
232 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
233
234 for file_path in filtered_file_paths:
235 original_file_path = os.path.join(from_dir, file_path)
236 copied_file_path = os.path.join(to_dir, file_path)
237 copied_file_dir = os.path.dirname(copied_file_path)
238 if not os.path.exists(copied_file_dir):
239 os.makedirs(copied_file_dir)
240 if os.path.islink(original_file_path):
241 os.symlink(os.readlink(original_file_path), copied_file_path)
242 else:
243 shutil.copyfile(original_file_path, copied_file_path)
244
245
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800246def read_config_list(config_file_path):
247 """Reads a config file into a list of strings.
248
249 Expects the file to be newline-separated.
250
251 Args:
252 config_file_path: The path to the config file to open and read.
253 """
254 with open(config_file_path) as config_file:
255 return config_file.read().splitlines()
256
257
Daniel Norman19b9fe92019-03-19 14:48:02 -0700258def validate_config_lists(
259 system_item_list,
260 system_misc_info_keys,
261 other_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700262 """Performs validations on the merge config lists.
263
264 Args:
265 system_item_list: The list of items to extract from the partial
266 system target files package as is.
267
Daniel Norman19b9fe92019-03-19 14:48:02 -0700268 system_misc_info_keys: A list of keys to obtain from the system instance
269 of META/misc_info.txt. The remaining keys from the other instance.
270
Daniel Normane5964522019-03-19 10:32:03 -0700271 other_item_list: The list of items to extract from the partial
272 other target files package as is.
273
274 Returns:
275 False if a validation fails, otherwise true.
276 """
277 default_combined_item_set = set(default_system_item_list)
278 default_combined_item_set.update(default_other_item_list)
279
280 combined_item_set = set(system_item_list)
281 combined_item_set.update(other_item_list)
282
283 # Check that the merge config lists are not missing any item specified
284 # by the default config lists.
285 difference = default_combined_item_set.difference(combined_item_set)
286 if difference:
287 logger.error('Missing merge config items: %s' % list(difference))
288 logger.error('Please ensure missing items are in either the '
289 'system-item-list or other-item-list files provided to '
290 'this script.')
291 return False
292
Daniel Norman19b9fe92019-03-19 14:48:02 -0700293 if ('dynamic_partition_list' in system_misc_info_keys) or (
294 'super_partition_groups' in system_misc_info_keys):
295 logger.error('Dynamic partition misc info keys should come from '
296 'the other instance of META/misc_info.txt.')
297 return False
298
Daniel Normane5964522019-03-19 10:32:03 -0700299 return True
300
301
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800302def process_ab_partitions_txt(
303 system_target_files_temp_dir,
304 other_target_files_temp_dir,
305 output_target_files_temp_dir):
306 """Perform special processing for META/ab_partitions.txt
307
308 This function merges the contents of the META/ab_partitions.txt files from
309 the system directory and the other directory, placing the merged result in
310 the output directory. The precondition in that the files are already
311 extracted. The post condition is that the output META/ab_partitions.txt
312 contains the merged content. The format for each ab_partitions.txt a one
313 partition name per line. The output file contains the union of the parition
314 names.
315
316 Args:
317 system_target_files_temp_dir: The name of a directory containing the
318 special items extracted from the system target files package.
319
320 other_target_files_temp_dir: The name of a directory containing the
321 special items extracted from the other target files package.
322
323 output_target_files_temp_dir: The name of a directory that will be used
324 to create the output target files package after all the special cases
325 are processed.
326 """
327
328 system_ab_partitions_txt = os.path.join(
329 system_target_files_temp_dir, 'META', 'ab_partitions.txt')
330
331 other_ab_partitions_txt = os.path.join(
332 other_target_files_temp_dir, 'META', 'ab_partitions.txt')
333
334 with open(system_ab_partitions_txt) as f:
335 system_ab_partitions = f.read().splitlines()
336
337 with open(other_ab_partitions_txt) as f:
338 other_ab_partitions = f.read().splitlines()
339
340 output_ab_partitions = set(system_ab_partitions + other_ab_partitions)
341
342 output_ab_partitions_txt = os.path.join(
343 output_target_files_temp_dir, 'META', 'ab_partitions.txt')
344
345 with open(output_ab_partitions_txt, 'w') as output:
346 for partition in sorted(output_ab_partitions):
347 output.write('%s\n' % partition)
348
349
Bill Peckham364c1cc2019-03-29 18:27:23 -0700350def append_recovery_to_filesystem_config(output_target_files_temp_dir):
351 """Perform special processing for META/filesystem_config.txt
352
353 This function appends recovery information to META/filesystem_config.txt
354 so that recovery patch regeneration will succeed.
355
356 Args:
357 output_target_files_temp_dir: The name of a directory that will be used
358 to create the output target files package after all the special cases
359 are processed. We find filesystem_config.txt here.
360 """
361
362 filesystem_config_txt = os.path.join(
363 output_target_files_temp_dir,
364 'META',
365 'filesystem_config.txt')
366
367 with open(filesystem_config_txt, 'a') as f:
368 # TODO(bpeckham) this data is hard coded. It should be generated
369 # programmatically.
370 f.write(
371 'system/bin/install-recovery.sh 0 0 750 '
372 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
373 f.write(
374 'system/recovery-from-boot.p 0 0 644 '
375 'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
376 f.write(
377 'system/etc/recovery.img 0 0 440 '
378 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
379
380
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800381def process_misc_info_txt(
382 system_target_files_temp_dir,
383 other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800384 output_target_files_temp_dir,
385 system_misc_info_keys):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800386 """Perform special processing for META/misc_info.txt
387
388 This function merges the contents of the META/misc_info.txt files from the
389 system directory and the other directory, placing the merged result in the
390 output directory. The precondition in that the files are already extracted.
391 The post condition is that the output META/misc_info.txt contains the merged
392 content.
393
394 Args:
395 system_target_files_temp_dir: The name of a directory containing the
396 special items extracted from the system target files package.
397
398 other_target_files_temp_dir: The name of a directory containing the
399 special items extracted from the other target files package.
400
401 output_target_files_temp_dir: The name of a directory that will be used
402 to create the output target files package after all the special cases
403 are processed.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800404
405 system_misc_info_keys: A list of keys to obtain from the system instance
406 of META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800407 """
408
409 def read_helper(d):
410 misc_info_txt = os.path.join(d, 'META', 'misc_info.txt')
411 with open(misc_info_txt) as f:
412 return list(f.read().splitlines())
413
414 system_info_dict = common.LoadDictionaryFromLines(
415 read_helper(system_target_files_temp_dir))
416
417 # We take most of the misc info from the other target files.
418
419 merged_info_dict = common.LoadDictionaryFromLines(
420 read_helper(other_target_files_temp_dir))
421
422 # Replace certain values in merged_info_dict with values from
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800423 # system_info_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800424
425 for key in system_misc_info_keys:
426 merged_info_dict[key] = system_info_dict[key]
427
Daniel Norman19b9fe92019-03-19 14:48:02 -0700428 # Merge misc info keys used for Dynamic Partitions.
429 if (merged_info_dict.get('use_dynamic_partitions') == 'true') and (
430 system_info_dict.get('use_dynamic_partitions') == 'true'):
431 merged_info_dict['dynamic_partition_list'] = '%s %s' % (
432 system_info_dict.get('dynamic_partition_list', ''),
433 merged_info_dict.get('dynamic_partition_list', ''))
434 # Partition groups and group sizes are defined by the other (non-system)
435 # misc info file because these values may vary for each board that uses
436 # a shared system image.
437 for partition_group in merged_info_dict['super_partition_groups'].split(' '):
438 if ('super_%s_group_size' % partition_group) not in merged_info_dict:
Daniel Normanf0318252019-04-15 11:34:56 -0700439 raise ValueError(
Daniel Norman19b9fe92019-03-19 14:48:02 -0700440 'Other META/misc_info.txt does not contain required key '
441 'super_%s_group_size.' % partition_group)
442 key = 'super_%s_partition_list' % partition_group
443 merged_info_dict[key] = '%s %s' % (
444 system_info_dict.get(key, ''),
445 merged_info_dict.get(key, ''))
446
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800447 output_misc_info_txt = os.path.join(
448 output_target_files_temp_dir,
449 'META', 'misc_info.txt')
450
451 sorted_keys = sorted(merged_info_dict.keys())
452
453 with open(output_misc_info_txt, 'w') as output:
454 for key in sorted_keys:
455 output.write('{}={}\n'.format(key, merged_info_dict[key]))
456
457
458def process_file_contexts_bin(temp_dir, output_target_files_temp_dir):
459 """Perform special processing for META/file_contexts.bin.
460
461 This function combines plat_file_contexts and vendor_file_contexts, which are
462 expected to already be extracted in temp_dir, to produce a merged
463 file_contexts.bin that will land in temp_dir at META/file_contexts.bin.
464
465 Args:
466 temp_dir: The name of a scratch directory that this function can use for
467 intermediate files generated during processing.
468
469 output_target_files_temp_dir: The name of the working directory that must
470 already contain plat_file_contexts and vendor_file_contexts (in the
471 appropriate sub directories), and to which META/file_contexts.bin will be
472 written.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800473 """
474
475 # To create a merged file_contexts.bin file, we use the system and vendor
476 # file contexts files as input, the m4 tool to combine them, the sorting tool
477 # to sort, and finally the sefcontext_compile tool to generate the final
478 # output. We currently omit a checkfc step since the files had been checked
479 # as part of the build.
480
481 # The m4 step concatenates the two input files contexts files. Since m4
482 # writes to stdout, we receive that into an array of bytes, and then write it
483 # to a file.
484
485 # Collect the file contexts that we're going to combine from SYSTEM, VENDOR,
486 # PRODUCT, and ODM. We require SYSTEM and VENDOR, but others are optional.
487
488 file_contexts_list = []
489
490 for partition in ['SYSTEM', 'VENDOR', 'PRODUCT', 'ODM']:
491 prefix = 'plat' if partition == 'SYSTEM' else partition.lower()
492
493 file_contexts = os.path.join(
494 output_target_files_temp_dir,
495 partition, 'etc', 'selinux', prefix + '_file_contexts')
496
497 mandatory = partition in ['SYSTEM', 'VENDOR']
498
499 if mandatory or os.path.isfile(file_contexts):
500 file_contexts_list.append(file_contexts)
501 else:
502 logger.warning('file not found: %s', file_contexts)
503
504 command = ['m4', '--fatal-warnings', '-s'] + file_contexts_list
505
506 merged_content = common.RunAndCheckOutput(command, verbose=False)
507
508 merged_file_contexts_txt = os.path.join(temp_dir, 'merged_file_contexts.txt')
509
510 with open(merged_file_contexts_txt, 'wb') as f:
511 f.write(merged_content)
512
513 # The sort step sorts the concatenated file.
514
515 sorted_file_contexts_txt = os.path.join(temp_dir, 'sorted_file_contexts.txt')
516 command = ['fc_sort', merged_file_contexts_txt, sorted_file_contexts_txt]
Bill Peckham889b0c62019-02-21 18:53:37 -0800517 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800518
519 # Finally, the compile step creates the final META/file_contexts.bin.
520
521 file_contexts_bin = os.path.join(
522 output_target_files_temp_dir,
523 'META', 'file_contexts.bin')
524
525 command = [
526 'sefcontext_compile',
527 '-o', file_contexts_bin,
528 sorted_file_contexts_txt,
529 ]
530
Bill Peckham889b0c62019-02-21 18:53:37 -0800531 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800532
533
534def process_special_cases(
535 temp_dir,
536 system_target_files_temp_dir,
537 other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800538 output_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700539 system_misc_info_keys,
540 rebuild_recovery
541):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800542 """Perform special-case processing for certain target files items.
543
544 Certain files in the output target files package require special-case
545 processing. This function performs all that special-case processing.
546
547 Args:
548 temp_dir: The name of a scratch directory that this function can use for
549 intermediate files generated during processing.
550
551 system_target_files_temp_dir: The name of a directory containing the
552 special items extracted from the system target files package.
553
554 other_target_files_temp_dir: The name of a directory containing the
555 special items extracted from the other target files package.
556
557 output_target_files_temp_dir: The name of a directory that will be used
558 to create the output target files package after all the special cases
559 are processed.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800560
561 system_misc_info_keys: A list of keys to obtain from the system instance
562 of META/misc_info.txt. The remaining keys from the other instance.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700563
564 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
565 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800566 """
567
Bill Peckham364c1cc2019-03-29 18:27:23 -0700568 if 'ab_update' in system_misc_info_keys:
569 process_ab_partitions_txt(
570 system_target_files_temp_dir=system_target_files_temp_dir,
571 other_target_files_temp_dir=other_target_files_temp_dir,
572 output_target_files_temp_dir=output_target_files_temp_dir)
573
574 if rebuild_recovery:
575 append_recovery_to_filesystem_config(
576 output_target_files_temp_dir=output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800577
578 process_misc_info_txt(
579 system_target_files_temp_dir=system_target_files_temp_dir,
580 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800581 output_target_files_temp_dir=output_target_files_temp_dir,
582 system_misc_info_keys=system_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800583
Bill Peckham889b0c62019-02-21 18:53:37 -0800584 process_file_contexts_bin(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800585 temp_dir=temp_dir,
586 output_target_files_temp_dir=output_target_files_temp_dir)
587
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800588
589def merge_target_files(
590 temp_dir,
591 system_target_files,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800592 system_item_list,
593 system_misc_info_keys,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800594 other_target_files,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800595 other_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700596 output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -0700597 output_dir,
598 output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -0700599 output_ota,
Daniel Normanf0318252019-04-15 11:34:56 -0700600 output_super_empty,
Daniel Normana4911da2019-03-15 14:36:21 -0700601 rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800602 """Merge two target files packages together.
603
604 This function takes system and other target files packages as input, performs
605 various file extractions, special case processing, and finally creates a
606 merged zip archive as output.
607
608 Args:
609 temp_dir: The name of a directory we use when we extract items from the
610 input target files packages, and also a scratch directory that we use for
611 temporary files.
612
613 system_target_files: The name of the zip archive containing the system
614 partial target files package.
615
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800616 system_item_list: The list of items to extract from the partial system
617 target files package as is, meaning these items will land in the output
618 target files package exactly as they appear in the input partial system
619 target files package.
620
621 system_misc_info_keys: The list of keys to obtain from the system instance
622 of META/misc_info.txt. The remaining keys from the other instance.
623
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800624 other_target_files: The name of the zip archive containing the other
625 partial target files package.
626
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800627 other_item_list: The list of items to extract from the partial other
628 target files package as is, meaning these items will land in the output
629 target files package exactly as they appear in the input partial other
630 target files package.
631
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800632 output_target_files: The name of the output zip archive target files
633 package created by merging system and other.
Daniel Normana4911da2019-03-15 14:36:21 -0700634
Daniel Norman3b64ce12019-04-16 16:11:35 -0700635 output_ota: The name of the output zip archive ota package.
636
Daniel Normanf0318252019-04-15 11:34:56 -0700637 output_super_empty: If provided, creates a super_empty.img file from the
638 merged target files package and saves it at this path.
639
Daniel Normana4911da2019-03-15 14:36:21 -0700640 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
641 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800642 """
643
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800644 logger.info(
645 'starting: merge system %s and other %s into output %s',
646 system_target_files,
647 other_target_files,
648 output_target_files)
649
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800650 # Create directory names that we'll use when we extract files from system,
651 # and other, and for zipping the final output.
652
653 system_target_files_temp_dir = os.path.join(temp_dir, 'system')
654 other_target_files_temp_dir = os.path.join(temp_dir, 'other')
655 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
656
657 # Extract "as is" items from the input system partial target files package.
658 # We extract them directly into the output temporary directory since the
659 # items do not need special case processing.
660
Bill Peckham889b0c62019-02-21 18:53:37 -0800661 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800662 target_files=system_target_files,
663 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800664 extract_item_list=system_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800665
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800666 # Extract "as is" items from the input other partial target files package. We
667 # extract them directly into the output temporary directory since the items
668 # do not need special case processing.
669
Bill Peckham889b0c62019-02-21 18:53:37 -0800670 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800671 target_files=other_target_files,
672 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800673 extract_item_list=other_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800674
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800675 # Extract "special" items from the input system partial target files package.
676 # We extract these items to different directory since they require special
677 # processing before they will end up in the output directory.
678
Bill Peckham889b0c62019-02-21 18:53:37 -0800679 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800680 target_files=system_target_files,
681 target_files_temp_dir=system_target_files_temp_dir,
682 extract_item_list=system_extract_special_item_list)
683
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800684 # Extract "special" items from the input other partial target files package.
685 # We extract these items to different directory since they require special
686 # processing before they will end up in the output directory.
687
Bill Peckham889b0c62019-02-21 18:53:37 -0800688 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800689 target_files=other_target_files,
690 target_files_temp_dir=other_target_files_temp_dir,
691 extract_item_list=other_extract_special_item_list)
692
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800693 # Now that the temporary directories contain all the extracted files, perform
694 # special case processing on any items that need it. After this function
695 # completes successfully, all the files we need to create the output target
696 # files package are in place.
697
Bill Peckham889b0c62019-02-21 18:53:37 -0800698 process_special_cases(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800699 temp_dir=temp_dir,
700 system_target_files_temp_dir=system_target_files_temp_dir,
701 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800702 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700703 system_misc_info_keys=system_misc_info_keys,
704 rebuild_recovery=rebuild_recovery)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800705
Daniel Normanf0318252019-04-15 11:34:56 -0700706 # Create super_empty.img using the merged misc_info.txt.
707
708 if output_super_empty:
709 misc_info_txt = os.path.join(output_target_files_temp_dir,
710 'META', 'misc_info.txt')
711 def read_helper():
712 with open(misc_info_txt) as f:
713 return list(f.read().splitlines())
714
715 misc_info_dict = common.LoadDictionaryFromLines(read_helper())
716 if misc_info_dict.get('use_dynamic_partitions') != 'true':
717 raise ValueError(
718 'Building super_empty.img requires use_dynamic_partitions=true.')
719
720 build_super_image_args = [
721 '--verbose',
722 misc_info_txt,
723 output_super_empty,
724 ]
725 build_super_image.main(build_super_image_args)
726
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800727 # Regenerate IMAGES in the temporary directory.
728
Daniel Normana4911da2019-03-15 14:36:21 -0700729 add_img_args = ['--verbose']
730 if rebuild_recovery:
731 add_img_args.append('--rebuild_recovery')
732 add_img_args.append(output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800733
734 add_img_to_target_files.main(add_img_args)
735
Daniel Normanfdb38812019-04-15 09:47:24 -0700736 # Finally, create the output target files zip archive and/or copy the
737 # output items to the output target files directory.
738
739 if output_dir:
740 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
741
742 if not output_target_files:
743 return
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800744
745 output_zip = os.path.abspath(output_target_files)
746 output_target_files_list = os.path.join(temp_dir, 'output.list')
747 output_target_files_meta_dir = os.path.join(
748 output_target_files_temp_dir, 'META')
749
750 command = [
751 'find',
752 output_target_files_meta_dir,
753 ]
754 # TODO(bpeckham): sort this to be more like build.
755 meta_content = common.RunAndCheckOutput(command, verbose=False)
756 command = [
757 'find',
758 output_target_files_temp_dir,
759 '-path',
760 output_target_files_meta_dir,
761 '-prune',
762 '-o',
763 '-print'
764 ]
765 # TODO(bpeckham): sort this to be more like build.
766 other_content = common.RunAndCheckOutput(command, verbose=False)
767
768 with open(output_target_files_list, 'wb') as f:
769 f.write(meta_content)
770 f.write(other_content)
771
772 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800773 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800774 '-d',
775 '-o', output_zip,
776 '-C', output_target_files_temp_dir,
777 '-l', output_target_files_list,
778 ]
779 logger.info('creating %s', output_target_files)
Bill Peckham889b0c62019-02-21 18:53:37 -0800780 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800781
Daniel Norman3b64ce12019-04-16 16:11:35 -0700782 # Create the OTA package from the merged target files package.
783
784 if output_ota:
785 ota_from_target_files_args = [
786 output_zip,
787 output_ota,
788 ]
789 ota_from_target_files.main(ota_from_target_files_args)
790
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800791
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800792def call_func_with_temp_dir(func, keep_tmp):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800793 """Manage the creation and cleanup of the temporary directory.
794
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800795 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800796 directory. It also cleans up the temporary directory.
797
798 Args:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800799 func: The function to call. Should accept one parameter, the path to
800 the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800801
802 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800803 """
804
805 # Create a temporary directory. This will serve as the parent of directories
806 # we use when we extract items from the input target files packages, and also
807 # a scratch directory that we use for temporary files.
808
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800809 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
810
811 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800812 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800813 except:
814 raise
815 finally:
816 if keep_tmp:
817 logger.info('keeping %s', temp_dir)
818 else:
819 common.Cleanup()
820
821
822def main():
823 """The main function.
824
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800825 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800826 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800827 """
828
829 common.InitLogging()
830
Bill Peckhamf753e152019-02-19 18:02:46 -0800831 def option_handler(o, a):
832 if o == '--system-target-files':
833 OPTIONS.system_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800834 elif o == '--system-item-list':
835 OPTIONS.system_item_list = a
836 elif o == '--system-misc-info-keys':
837 OPTIONS.system_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800838 elif o == '--other-target-files':
839 OPTIONS.other_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800840 elif o == '--other-item-list':
841 OPTIONS.other_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800842 elif o == '--output-target-files':
843 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -0700844 elif o == '--output-dir':
845 OPTIONS.output_dir = a
846 elif o == '--output-item-list':
847 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -0700848 elif o == '--output-ota':
849 OPTIONS.output_ota = a
Daniel Normanf0318252019-04-15 11:34:56 -0700850 elif o == '--output-super-empty':
851 OPTIONS.output_super_empty = a
Daniel Normana4911da2019-03-15 14:36:21 -0700852 elif o == '--rebuild_recovery':
853 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -0700854 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -0800855 OPTIONS.keep_tmp = True
856 else:
857 return False
858 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800859
Bill Peckhamf753e152019-02-19 18:02:46 -0800860 args = common.ParseOptions(
861 sys.argv[1:], __doc__,
862 extra_long_opts=[
863 'system-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800864 'system-item-list=',
865 'system-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800866 'other-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800867 'other-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800868 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -0700869 'output-dir=',
870 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -0700871 'output-ota=',
Daniel Normanf0318252019-04-15 11:34:56 -0700872 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -0700873 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -0700874 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -0800875 ],
876 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800877
Bill Peckham889b0c62019-02-21 18:53:37 -0800878 if (len(args) != 0 or
Bill Peckhamf753e152019-02-19 18:02:46 -0800879 OPTIONS.system_target_files is None or
Daniel Normanfdb38812019-04-15 09:47:24 -0700880 OPTIONS.other_target_files is None or (
881 OPTIONS.output_target_files is None and
882 OPTIONS.output_dir is None) or (
883 OPTIONS.output_dir is not None and
884 OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -0800885 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -0800886 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800887
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800888 if OPTIONS.system_item_list:
889 system_item_list = read_config_list(OPTIONS.system_item_list)
890 else:
891 system_item_list = default_system_item_list
892
893 if OPTIONS.system_misc_info_keys:
894 system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys)
895 else:
896 system_misc_info_keys = default_system_misc_info_keys
897
898 if OPTIONS.other_item_list:
899 other_item_list = read_config_list(OPTIONS.other_item_list)
900 else:
901 other_item_list = default_other_item_list
902
Daniel Normanfdb38812019-04-15 09:47:24 -0700903 if OPTIONS.output_item_list:
904 output_item_list = read_config_list(OPTIONS.output_item_list)
905 else:
906 output_item_list = None
907
Daniel Normane5964522019-03-19 10:32:03 -0700908 if not validate_config_lists(
909 system_item_list=system_item_list,
Daniel Norman19b9fe92019-03-19 14:48:02 -0700910 system_misc_info_keys=system_misc_info_keys,
Daniel Normane5964522019-03-19 10:32:03 -0700911 other_item_list=other_item_list):
912 sys.exit(1)
913
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800914 call_func_with_temp_dir(
915 lambda temp_dir: merge_target_files(
916 temp_dir=temp_dir,
917 system_target_files=OPTIONS.system_target_files,
918 system_item_list=system_item_list,
919 system_misc_info_keys=system_misc_info_keys,
920 other_target_files=OPTIONS.other_target_files,
921 other_item_list=other_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700922 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -0700923 output_dir=OPTIONS.output_dir,
924 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -0700925 output_ota=OPTIONS.output_ota,
Daniel Normanf0318252019-04-15 11:34:56 -0700926 output_super_empty=OPTIONS.output_super_empty,
Daniel Normana4911da2019-03-15 14:36:21 -0700927 rebuild_recovery=OPTIONS.rebuild_recovery),
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800928 OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800929
930
931if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -0800932 main()