1#!/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"""This script merges two partial target files packages. 18 19One input package contains framework files, and the other contains vendor files. 20 21This script produces a complete, merged target files package: 22 - This package can be used to generate a flashable IMG package. 23 See --output-img. 24 - This package can be used to generate an OTA package. See --output-ota. 25 - The merged package is checked for compatibility between the two inputs. 26 27Usage: merge_target_files [args] 28 29 --framework-target-files framework-target-files-zip-archive 30 The input target files package containing framework bits. This is a zip 31 archive. 32 33 --framework-item-list framework-item-list-file 34 The optional path to a newline-separated config file that replaces the 35 contents of DEFAULT_FRAMEWORK_ITEM_LIST if provided. 36 37 --framework-misc-info-keys framework-misc-info-keys-file 38 The optional path to a newline-separated config file that replaces the 39 contents of DEFAULT_FRAMEWORK_MISC_INFO_KEYS if provided. 40 41 --vendor-target-files vendor-target-files-zip-archive 42 The input target files package containing vendor bits. This is a zip 43 archive. 44 45 --vendor-item-list vendor-item-list-file 46 The optional path to a newline-separated config file that replaces the 47 contents of DEFAULT_VENDOR_ITEM_LIST if provided. 48 49 --output-target-files output-target-files-package 50 If provided, the output merged target files package. Also a zip archive. 51 52 --output-dir output-directory 53 If provided, the destination directory for saving merged files. Requires 54 the --output-item-list flag. 55 Can be provided alongside --output-target-files, or by itself. 56 57 --output-item-list output-item-list-file. 58 The optional path to a newline-separated config file that specifies the 59 file patterns to copy into the --output-dir. Required if providing 60 the --output-dir flag. 61 62 --output-ota output-ota-package 63 The output ota package. This is a zip archive. Use of this flag may 64 require passing the --path common flag; see common.py. 65 66 --output-img output-img-package 67 The output img package, suitable for use with 'fastboot update'. Use of 68 this flag may require passing the --path common flag; see common.py. 69 70 --output-super-empty output-super-empty-image 71 If provided, creates a super_empty.img file from the merged target 72 files package and saves it at this path. 73 74 --rebuild_recovery 75 Deprecated; does nothing. 76 77 --allow-duplicate-apkapex-keys 78 If provided, duplicate APK/APEX keys are ignored and the value from the 79 framework is used. 80 81 --keep-tmp 82 Keep tempoary files for debugging purposes. 83""" 84 85from __future__ import print_function 86 87import fnmatch 88import json 89import logging 90import os 91import re 92import shutil 93import subprocess 94import sys 95import zipfile 96from xml.etree import ElementTree 97 98import add_img_to_target_files 99import apex_utils 100import build_image 101import build_super_image 102import check_target_files_vintf 103import common 104import img_from_target_files 105import find_shareduid_violation 106import ota_from_target_files 107import sparse_img 108import verity_utils 109 110from common import AddCareMapForAbOta, ExternalError, PARTITIONS_WITH_CARE_MAP 111 112logger = logging.getLogger(__name__) 113 114OPTIONS = common.OPTIONS 115# Always turn on verbose logging. 116OPTIONS.verbose = True 117OPTIONS.framework_target_files = None 118OPTIONS.framework_item_list = None 119OPTIONS.framework_misc_info_keys = None 120OPTIONS.vendor_target_files = None 121OPTIONS.vendor_item_list = None 122OPTIONS.output_target_files = None 123OPTIONS.output_dir = None 124OPTIONS.output_item_list = None 125OPTIONS.output_ota = None 126OPTIONS.output_img = None 127OPTIONS.output_super_empty = None 128# TODO(b/132730255): Remove this option. 129OPTIONS.rebuild_recovery = False 130# TODO(b/150582573): Remove this option. 131OPTIONS.allow_duplicate_apkapex_keys = False 132OPTIONS.keep_tmp = False 133 134# In an item list (framework or vendor), we may see entries that select whole 135# partitions. Such an entry might look like this 'SYSTEM/*' (e.g., for the 136# system partition). The following regex matches this and extracts the 137# partition name. 138 139PARTITION_ITEM_PATTERN = re.compile(r'^([A-Z_]+)/\*$') 140 141# In apexkeys.txt or apkcerts.txt, we will find partition tags on each entry in 142# the file. We use these partition tags to filter the entries in those files 143# from the two different target files packages to produce a merged apexkeys.txt 144# or apkcerts.txt file. A partition tag (e.g., for the product partition) looks 145# like this: 'partition="product"'. We use the group syntax grab the value of 146# the tag. We use non-greedy matching in case there are other fields on the 147# same line. 148 149PARTITION_TAG_PATTERN = re.compile(r'partition="(.*?)"') 150 151# The sorting algorithm for apexkeys.txt and apkcerts.txt does not include the 152# ".apex" or ".apk" suffix, so we use the following pattern to extract a key. 153 154MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"') 155 156# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial 157# framework target files package as is, meaning these items will land in the 158# output target files package exactly as they appear in the input partial 159# framework target files package. 160 161DEFAULT_FRAMEWORK_ITEM_LIST = ( 162 'META/apkcerts.txt', 163 'META/filesystem_config.txt', 164 'META/root_filesystem_config.txt', 165 'META/update_engine_config.txt', 166 'PRODUCT/*', 167 'ROOT/*', 168 'SYSTEM/*', 169) 170 171# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the 172# framework instance of META/misc_info.txt. The remaining keys should come 173# from the vendor instance. 174 175DEFAULT_FRAMEWORK_MISC_INFO_KEYS = ( 176 'avb_system_hashtree_enable', 177 'avb_system_add_hashtree_footer_args', 178 'avb_system_key_path', 179 'avb_system_algorithm', 180 'avb_system_rollback_index_location', 181 'avb_product_hashtree_enable', 182 'avb_product_add_hashtree_footer_args', 183 'avb_system_ext_hashtree_enable', 184 'avb_system_ext_add_hashtree_footer_args', 185 'system_root_image', 186 'root_dir', 187 'ab_update', 188 'default_system_dev_certificate', 189 'system_size', 190 'building_system_image', 191 'building_system_ext_image', 192 'building_product_image', 193) 194 195# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial 196# vendor target files package as is, meaning these items will land in the output 197# target files package exactly as they appear in the input partial vendor target 198# files package. 199 200DEFAULT_VENDOR_ITEM_LIST = ( 201 'META/boot_filesystem_config.txt', 202 'META/otakeys.txt', 203 'META/releasetools.py', 204 'META/vendor_filesystem_config.txt', 205 'BOOT/*', 206 'DATA/*', 207 'ODM/*', 208 'OTA/android-info.txt', 209 'PREBUILT_IMAGES/*', 210 'RADIO/*', 211 'VENDOR/*', 212) 213 214# The merge config lists should not attempt to extract items from both 215# builds for any of the following partitions. The partitions in 216# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either 217# framework or vendor, but not both). 218 219SINGLE_BUILD_PARTITIONS = ( 220 'BOOT/', 221 'DATA/', 222 'ODM/', 223 'PRODUCT/', 224 'SYSTEM_EXT/', 225 'RADIO/', 226 'RECOVERY/', 227 'ROOT/', 228 'SYSTEM/', 229 'SYSTEM_OTHER/', 230 'VENDOR/', 231 'VENDOR_DLKM/', 232 'ODM_DLKM/', 233) 234 235 236def write_sorted_data(data, path): 237 """Writes the sorted contents of either a list or dict to file. 238 239 This function sorts the contents of the list or dict and then writes the 240 resulting sorted contents to a file specified by path. 241 242 Args: 243 data: The list or dict to sort and write. 244 path: Path to the file to write the sorted values to. The file at path will 245 be overridden if it exists. 246 """ 247 with open(path, 'w') as output: 248 for entry in sorted(data): 249 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance( 250 data, dict) else '{}\n'.format(entry) 251 output.write(out_str) 252 253 254def extract_items(target_files, target_files_temp_dir, extract_item_list): 255 """Extracts items from target files to temporary directory. 256 257 This function extracts from the specified target files zip archive into the 258 specified temporary directory, the items specified in the extract item list. 259 260 Args: 261 target_files: The target files zip archive from which to extract items. 262 target_files_temp_dir: The temporary directory where the extracted items 263 will land. 264 extract_item_list: A list of items to extract. 265 """ 266 267 logger.info('extracting from %s', target_files) 268 269 # Filter the extract_item_list to remove any items that do not exist in the 270 # zip file. Otherwise, the extraction step will fail. 271 272 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile: 273 target_files_namelist = target_files_zipfile.namelist() 274 275 filtered_extract_item_list = [] 276 for pattern in extract_item_list: 277 matching_namelist = fnmatch.filter(target_files_namelist, pattern) 278 if not matching_namelist: 279 logger.warning('no match for %s', pattern) 280 else: 281 filtered_extract_item_list.append(pattern) 282 283 # Extract from target_files into target_files_temp_dir the 284 # filtered_extract_item_list. 285 286 common.UnzipToDir(target_files, target_files_temp_dir, 287 filtered_extract_item_list) 288 289 290def copy_items(from_dir, to_dir, patterns): 291 """Similar to extract_items() except uses an input dir instead of zip.""" 292 file_paths = [] 293 for dirpath, _, filenames in os.walk(from_dir): 294 file_paths.extend( 295 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir) 296 for filename in filenames) 297 298 filtered_file_paths = set() 299 for pattern in patterns: 300 filtered_file_paths.update(fnmatch.filter(file_paths, pattern)) 301 302 for file_path in filtered_file_paths: 303 original_file_path = os.path.join(from_dir, file_path) 304 copied_file_path = os.path.join(to_dir, file_path) 305 copied_file_dir = os.path.dirname(copied_file_path) 306 if not os.path.exists(copied_file_dir): 307 os.makedirs(copied_file_dir) 308 if os.path.islink(original_file_path): 309 os.symlink(os.readlink(original_file_path), copied_file_path) 310 else: 311 shutil.copyfile(original_file_path, copied_file_path) 312 313 314def validate_config_lists(framework_item_list, framework_misc_info_keys, 315 vendor_item_list): 316 """Performs validations on the merge config lists. 317 318 Args: 319 framework_item_list: The list of items to extract from the partial framework 320 target files package as is. 321 framework_misc_info_keys: A list of keys to obtain from the framework 322 instance of META/misc_info.txt. The remaining keys should come from the 323 vendor instance. 324 vendor_item_list: The list of items to extract from the partial vendor 325 target files package as is. 326 327 Returns: 328 False if a validation fails, otherwise true. 329 """ 330 has_error = False 331 332 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST) 333 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST) 334 335 combined_item_set = set(framework_item_list) 336 combined_item_set.update(vendor_item_list) 337 338 # Check that the merge config lists are not missing any item specified 339 # by the default config lists. 340 difference = default_combined_item_set.difference(combined_item_set) 341 if difference: 342 logger.error('Missing merge config items: %s', list(difference)) 343 logger.error('Please ensure missing items are in either the ' 344 'framework-item-list or vendor-item-list files provided to ' 345 'this script.') 346 has_error = True 347 348 # Check that partitions only come from one input. 349 for partition in SINGLE_BUILD_PARTITIONS: 350 image_path = 'IMAGES/{}.img'.format(partition.lower().replace('/', '')) 351 in_framework = ( 352 any(item.startswith(partition) for item in framework_item_list) or 353 image_path in framework_item_list) 354 in_vendor = ( 355 any(item.startswith(partition) for item in vendor_item_list) or 356 image_path in vendor_item_list) 357 if in_framework and in_vendor: 358 logger.error( 359 'Cannot extract items from %s for both the framework and vendor' 360 ' builds. Please ensure only one merge config item list' 361 ' includes %s.', partition, partition) 362 has_error = True 363 364 if ('dynamic_partition_list' 365 in framework_misc_info_keys) or ('super_partition_groups' 366 in framework_misc_info_keys): 367 logger.error('Dynamic partition misc info keys should come from ' 368 'the vendor instance of META/misc_info.txt.') 369 has_error = True 370 371 return not has_error 372 373 374def process_ab_partitions_txt(framework_target_files_temp_dir, 375 vendor_target_files_temp_dir, 376 output_target_files_temp_dir): 377 """Performs special processing for META/ab_partitions.txt. 378 379 This function merges the contents of the META/ab_partitions.txt files from the 380 framework directory and the vendor directory, placing the merged result in the 381 output directory. The precondition in that the files are already extracted. 382 The post condition is that the output META/ab_partitions.txt contains the 383 merged content. The format for each ab_partitions.txt is one partition name 384 per line. The output file contains the union of the partition names. 385 386 Args: 387 framework_target_files_temp_dir: The name of a directory containing the 388 special items extracted from the framework target files package. 389 vendor_target_files_temp_dir: The name of a directory containing the special 390 items extracted from the vendor target files package. 391 output_target_files_temp_dir: The name of a directory that will be used to 392 create the output target files package after all the special cases are 393 processed. 394 """ 395 396 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir, 397 'META', 'ab_partitions.txt') 398 399 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META', 400 'ab_partitions.txt') 401 402 with open(framework_ab_partitions_txt) as f: 403 framework_ab_partitions = f.read().splitlines() 404 405 with open(vendor_ab_partitions_txt) as f: 406 vendor_ab_partitions = f.read().splitlines() 407 408 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions) 409 410 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META', 411 'ab_partitions.txt') 412 413 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt) 414 415 416def process_misc_info_txt(framework_target_files_temp_dir, 417 vendor_target_files_temp_dir, 418 output_target_files_temp_dir, 419 framework_misc_info_keys): 420 """Performs special processing for META/misc_info.txt. 421 422 This function merges the contents of the META/misc_info.txt files from the 423 framework directory and the vendor directory, placing the merged result in the 424 output directory. The precondition in that the files are already extracted. 425 The post condition is that the output META/misc_info.txt contains the merged 426 content. 427 428 Args: 429 framework_target_files_temp_dir: The name of a directory containing the 430 special items extracted from the framework target files package. 431 vendor_target_files_temp_dir: The name of a directory containing the special 432 items extracted from the vendor target files package. 433 output_target_files_temp_dir: The name of a directory that will be used to 434 create the output target files package after all the special cases are 435 processed. 436 framework_misc_info_keys: A list of keys to obtain from the framework 437 instance of META/misc_info.txt. The remaining keys should come from the 438 vendor instance. 439 """ 440 441 misc_info_path = ['META', 'misc_info.txt'] 442 framework_dict = common.LoadDictionaryFromFile( 443 os.path.join(framework_target_files_temp_dir, *misc_info_path)) 444 445 # We take most of the misc info from the vendor target files. 446 447 merged_dict = common.LoadDictionaryFromFile( 448 os.path.join(vendor_target_files_temp_dir, *misc_info_path)) 449 450 # Replace certain values in merged_dict with values from 451 # framework_dict. 452 453 for key in framework_misc_info_keys: 454 merged_dict[key] = framework_dict[key] 455 456 # Merge misc info keys used for Dynamic Partitions. 457 if (merged_dict.get('use_dynamic_partitions') 458 == 'true') and (framework_dict.get('use_dynamic_partitions') == 'true'): 459 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts( 460 framework_dict=framework_dict, vendor_dict=merged_dict) 461 merged_dict.update(merged_dynamic_partitions_dict) 462 # Ensure that add_img_to_target_files rebuilds super split images for 463 # devices that retrofit dynamic partitions. This flag may have been set to 464 # false in the partial builds to prevent duplicate building of super.img. 465 merged_dict['build_super_partition'] = 'true' 466 467 # If AVB is enabled then ensure that we build vbmeta.img. 468 # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to 469 # skip building an incomplete vbmeta.img. 470 if merged_dict.get('avb_enable') == 'true': 471 merged_dict['avb_building_vbmeta_image'] = 'true' 472 473 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin 474 # depending on which dictionary the key came from. 475 # Only the file basename is required because all selinux_fc properties are 476 # replaced with the full path to the file under META/ when misc_info.txt is 477 # loaded from target files for repacking. See common.py LoadInfoDict(). 478 for key in merged_dict: 479 if key.endswith('_selinux_fc'): 480 merged_dict[key] = 'vendor_file_contexts.bin' 481 for key in framework_dict: 482 if key.endswith('_selinux_fc'): 483 merged_dict[key] = 'framework_file_contexts.bin' 484 485 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META', 486 'misc_info.txt') 487 write_sorted_data(data=merged_dict, path=output_misc_info_txt) 488 489 490def process_dynamic_partitions_info_txt(framework_target_files_dir, 491 vendor_target_files_dir, 492 output_target_files_dir): 493 """Performs special processing for META/dynamic_partitions_info.txt. 494 495 This function merges the contents of the META/dynamic_partitions_info.txt 496 files from the framework directory and the vendor directory, placing the 497 merged result in the output directory. 498 499 This function does nothing if META/dynamic_partitions_info.txt from the vendor 500 directory does not exist. 501 502 Args: 503 framework_target_files_dir: The name of a directory containing the special 504 items extracted from the framework target files package. 505 vendor_target_files_dir: The name of a directory containing the special 506 items extracted from the vendor target files package. 507 output_target_files_dir: The name of a directory that will be used to create 508 the output target files package after all the special cases are processed. 509 """ 510 511 if not os.path.exists( 512 os.path.join(vendor_target_files_dir, 'META', 513 'dynamic_partitions_info.txt')): 514 return 515 516 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt'] 517 518 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile( 519 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path)) 520 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile( 521 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path)) 522 523 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts( 524 framework_dict=framework_dynamic_partitions_dict, 525 vendor_dict=vendor_dynamic_partitions_dict) 526 527 output_dynamic_partitions_info_txt = os.path.join( 528 output_target_files_dir, 'META', 'dynamic_partitions_info.txt') 529 write_sorted_data( 530 data=merged_dynamic_partitions_dict, 531 path=output_dynamic_partitions_info_txt) 532 533 534def item_list_to_partition_set(item_list): 535 """Converts a target files item list to a partition set. 536 537 The item list contains items that might look like 'SYSTEM/*' or 'VENDOR/*' or 538 'OTA/android-info.txt'. Items that end in '/*' are assumed to match entire 539 directories where 'SYSTEM' or 'VENDOR' is a directory name that identifies the 540 contents of a partition of the same name. Other items in the list, such as the 541 'OTA' example contain metadata. This function iterates such a list, returning 542 a set that contains the partition entries. 543 544 Args: 545 item_list: A list of items in a target files package. 546 547 Returns: 548 A set of partitions extracted from the list of items. 549 """ 550 551 partition_set = set() 552 553 for item in item_list: 554 match = PARTITION_ITEM_PATTERN.search(item.strip()) 555 partition_tag = match.group(1).lower() if match else None 556 557 if partition_tag: 558 partition_set.add(partition_tag) 559 560 return partition_set 561 562 563def process_apex_keys_apk_certs_common(framework_target_files_dir, 564 vendor_target_files_dir, 565 output_target_files_dir, 566 framework_partition_set, 567 vendor_partition_set, file_name): 568 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt. 569 570 This function merges the contents of the META/apexkeys.txt or 571 META/apkcerts.txt files from the framework directory and the vendor directory, 572 placing the merged result in the output directory. The precondition in that 573 the files are already extracted. The post condition is that the output 574 META/apexkeys.txt or META/apkcerts.txt contains the merged content. 575 576 Args: 577 framework_target_files_dir: The name of a directory containing the special 578 items extracted from the framework target files package. 579 vendor_target_files_dir: The name of a directory containing the special 580 items extracted from the vendor target files package. 581 output_target_files_dir: The name of a directory that will be used to create 582 the output target files package after all the special cases are processed. 583 framework_partition_set: Partitions that are considered framework 584 partitions. Used to filter apexkeys.txt and apkcerts.txt. 585 vendor_partition_set: Partitions that are considered vendor partitions. Used 586 to filter apexkeys.txt and apkcerts.txt. 587 file_name: The name of the file to merge. One of apkcerts.txt or 588 apexkeys.txt. 589 """ 590 591 def read_helper(d): 592 temp = {} 593 file_path = os.path.join(d, 'META', file_name) 594 with open(file_path) as f: 595 for line in f: 596 if line.strip(): 597 name = line.split()[0] 598 match = MODULE_KEY_PATTERN.search(name) 599 temp[match.group(1)] = line.strip() 600 return temp 601 602 framework_dict = read_helper(framework_target_files_dir) 603 vendor_dict = read_helper(vendor_target_files_dir) 604 merged_dict = {} 605 606 def filter_into_merged_dict(item_dict, partition_set): 607 for key, value in item_dict.items(): 608 match = PARTITION_TAG_PATTERN.search(value) 609 610 if match is None: 611 raise ValueError('Entry missing partition tag: %s' % value) 612 613 partition_tag = match.group(1) 614 615 if partition_tag in partition_set: 616 if key in merged_dict: 617 if OPTIONS.allow_duplicate_apkapex_keys: 618 # TODO(b/150582573) Always raise on duplicates. 619 logger.warning('Duplicate key %s' % key) 620 continue 621 else: 622 raise ValueError('Duplicate key %s' % key) 623 624 merged_dict[key] = value 625 626 filter_into_merged_dict(framework_dict, framework_partition_set) 627 filter_into_merged_dict(vendor_dict, vendor_partition_set) 628 629 output_file = os.path.join(output_target_files_dir, 'META', file_name) 630 631 # The following code is similar to write_sorted_data, but different enough 632 # that we couldn't use that function. We need the output to be sorted by the 633 # basename of the apex/apk (without the ".apex" or ".apk" suffix). This 634 # allows the sort to be consistent with the framework/vendor input data and 635 # eases comparison of input data with merged data. 636 with open(output_file, 'w') as output: 637 for key in sorted(merged_dict.keys()): 638 out_str = merged_dict[key] + '\n' 639 output.write(out_str) 640 641 642def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir, 643 output_target_files_dir): 644 """Creates named copies of each build's file_contexts.bin in output META/.""" 645 framework_fc_path = os.path.join(framework_target_files_dir, 'META', 646 'framework_file_contexts.bin') 647 if not os.path.exists(framework_fc_path): 648 framework_fc_path = os.path.join(framework_target_files_dir, 'META', 649 'file_contexts.bin') 650 if not os.path.exists(framework_fc_path): 651 raise ValueError('Missing framework file_contexts.bin.') 652 shutil.copyfile( 653 framework_fc_path, 654 os.path.join(output_target_files_dir, 'META', 655 'framework_file_contexts.bin')) 656 657 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META', 658 'vendor_file_contexts.bin') 659 if not os.path.exists(vendor_fc_path): 660 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META', 661 'file_contexts.bin') 662 if not os.path.exists(vendor_fc_path): 663 raise ValueError('Missing vendor file_contexts.bin.') 664 shutil.copyfile( 665 vendor_fc_path, 666 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin')) 667 668 669def compile_split_sepolicy(product_out, partition_map, output_policy): 670 """Uses secilc to compile a split sepolicy file. 671 672 Depends on various */etc/selinux/* and */etc/vintf/* files within partitions. 673 674 Args: 675 product_out: PRODUCT_OUT directory, containing partition directories. 676 partition_map: A map of partition name -> relative path within product_out. 677 output_policy: The name of the output policy created by secilc. 678 679 Returns: 680 A command list that can be executed to create the compiled sepolicy. 681 """ 682 683 def get_file(partition, path): 684 if partition not in partition_map: 685 logger.warning('Cannot load SEPolicy files for missing partition %s', 686 partition) 687 return None 688 return os.path.join(product_out, partition_map[partition], path) 689 690 # Load the kernel sepolicy version from the FCM. This is normally provided 691 # directly to selinux.cpp as a build flag, but is also available in this file. 692 fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml') 693 if not fcm_file or not os.path.exists(fcm_file): 694 raise ExternalError('Missing required file for loading sepolicy: %s', fcm) 695 kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find( 696 'sepolicy/kernel-sepolicy-version').text 697 698 # Load the vendor's plat sepolicy version. This is the version used for 699 # locating sepolicy mapping files. 700 vendor_plat_version_file = get_file('vendor', 701 'etc/selinux/plat_sepolicy_vers.txt') 702 if not vendor_plat_version_file or not os.path.exists( 703 vendor_plat_version_file): 704 raise ExternalError('Missing required sepolicy file %s', 705 vendor_plat_version_file) 706 with open(vendor_plat_version_file) as f: 707 vendor_plat_version = f.read().strip() 708 709 # Use the same flags and arguments as selinux.cpp OpenSplitPolicy(). 710 cmd = ['secilc', '-m', '-M', 'true', '-G', '-N'] 711 cmd.extend(['-c', kernel_sepolicy_version]) 712 cmd.extend(['-o', output_policy]) 713 cmd.extend(['-f', '/dev/null']) 714 715 required_policy_files = ( 716 ('system', 'etc/selinux/plat_sepolicy.cil'), 717 ('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version), 718 ('vendor', 'etc/selinux/vendor_sepolicy.cil'), 719 ('vendor', 'etc/selinux/plat_pub_versioned.cil'), 720 ) 721 for policy in (map(lambda partition_and_path: get_file(*partition_and_path), 722 required_policy_files)): 723 if not policy or not os.path.exists(policy): 724 raise ExternalError('Missing required sepolicy file %s', policy) 725 cmd.append(policy) 726 727 optional_policy_files = ( 728 ('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version), 729 ('system_ext', 'etc/selinux/system_ext_sepolicy.cil'), 730 ('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version), 731 ('product', 'etc/selinux/product_sepolicy.cil'), 732 ('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version), 733 ('odm', 'etc/selinux/odm_sepolicy.cil'), 734 ) 735 for policy in (map(lambda partition_and_path: get_file(*partition_and_path), 736 optional_policy_files)): 737 if policy and os.path.exists(policy): 738 cmd.append(policy) 739 740 return cmd 741 742 743def validate_merged_apex_info(output_target_files_dir, partitions): 744 """Validates the APEX files in the merged target files directory. 745 746 Checks the APEX files in all possible preinstalled APEX directories. 747 Depends on the <partition>/apex/* APEX files within partitions. 748 749 Args: 750 output_target_files_dir: Output directory containing merged partition directories. 751 partitions: A list of all the partitions in the output directory. 752 753 Raises: 754 RuntimeError: if apex_utils fails to parse any APEX file. 755 ExternalError: if the same APEX package is provided by multiple partitions. 756 """ 757 apex_packages = set() 758 759 apex_partitions = ('system', 'system_ext', 'product', 'vendor') 760 for partition in filter(lambda p: p in apex_partitions, partitions): 761 apex_info = apex_utils.GetApexInfoFromTargetFiles( 762 output_target_files_dir, partition, compressed_only=False) 763 partition_apex_packages = set([info.package_name for info in apex_info]) 764 duplicates = apex_packages.intersection(partition_apex_packages) 765 if duplicates: 766 raise ExternalError( 767 'Duplicate APEX packages found in multiple partitions: %s' % 768 ' '.join(duplicates)) 769 apex_packages.update(partition_apex_packages) 770 771 772def generate_care_map(partitions, output_target_files_dir): 773 """Generates a merged META/care_map.pb file in the output target files dir. 774 775 Depends on the info dict from META/misc_info.txt, as well as built images 776 within IMAGES/. 777 778 Args: 779 partitions: A list of partitions to potentially include in the care map. 780 output_target_files_dir: The name of a directory that will be used to create 781 the output target files package after all the special cases are processed. 782 """ 783 OPTIONS.info_dict = common.LoadInfoDict(output_target_files_dir) 784 partition_image_map = {} 785 for partition in partitions: 786 image_path = os.path.join(output_target_files_dir, 'IMAGES', 787 '{}.img'.format(partition)) 788 if os.path.exists(image_path): 789 partition_image_map[partition] = image_path 790 # Regenerated images should have their image_size property already set. 791 image_size_prop = '{}_image_size'.format(partition) 792 if image_size_prop not in OPTIONS.info_dict: 793 # Images copied directly from input target files packages will need 794 # their image sizes calculated. 795 partition_size = sparse_img.GetImagePartitionSize(image_path) 796 image_props = build_image.ImagePropFromGlobalDict( 797 OPTIONS.info_dict, partition) 798 verity_image_builder = verity_utils.CreateVerityImageBuilder( 799 image_props) 800 image_size = verity_image_builder.CalculateMaxImageSize(partition_size) 801 OPTIONS.info_dict[image_size_prop] = image_size 802 803 AddCareMapForAbOta( 804 os.path.join(output_target_files_dir, 'META', 'care_map.pb'), 805 PARTITIONS_WITH_CARE_MAP, partition_image_map) 806 807 808def process_special_cases(framework_target_files_temp_dir, 809 vendor_target_files_temp_dir, 810 output_target_files_temp_dir, 811 framework_misc_info_keys, framework_partition_set, 812 vendor_partition_set): 813 """Performs special-case processing for certain target files items. 814 815 Certain files in the output target files package require special-case 816 processing. This function performs all that special-case processing. 817 818 Args: 819 framework_target_files_temp_dir: The name of a directory containing the 820 special items extracted from the framework target files package. 821 vendor_target_files_temp_dir: The name of a directory containing the special 822 items extracted from the vendor target files package. 823 output_target_files_temp_dir: The name of a directory that will be used to 824 create the output target files package after all the special cases are 825 processed. 826 framework_misc_info_keys: A list of keys to obtain from the framework 827 instance of META/misc_info.txt. The remaining keys should come from the 828 vendor instance. 829 framework_partition_set: Partitions that are considered framework 830 partitions. Used to filter apexkeys.txt and apkcerts.txt. 831 vendor_partition_set: Partitions that are considered vendor partitions. Used 832 to filter apexkeys.txt and apkcerts.txt. 833 """ 834 835 if 'ab_update' in framework_misc_info_keys: 836 process_ab_partitions_txt( 837 framework_target_files_temp_dir=framework_target_files_temp_dir, 838 vendor_target_files_temp_dir=vendor_target_files_temp_dir, 839 output_target_files_temp_dir=output_target_files_temp_dir) 840 841 copy_file_contexts( 842 framework_target_files_dir=framework_target_files_temp_dir, 843 vendor_target_files_dir=vendor_target_files_temp_dir, 844 output_target_files_dir=output_target_files_temp_dir) 845 846 process_misc_info_txt( 847 framework_target_files_temp_dir=framework_target_files_temp_dir, 848 vendor_target_files_temp_dir=vendor_target_files_temp_dir, 849 output_target_files_temp_dir=output_target_files_temp_dir, 850 framework_misc_info_keys=framework_misc_info_keys) 851 852 process_dynamic_partitions_info_txt( 853 framework_target_files_dir=framework_target_files_temp_dir, 854 vendor_target_files_dir=vendor_target_files_temp_dir, 855 output_target_files_dir=output_target_files_temp_dir) 856 857 process_apex_keys_apk_certs_common( 858 framework_target_files_dir=framework_target_files_temp_dir, 859 vendor_target_files_dir=vendor_target_files_temp_dir, 860 output_target_files_dir=output_target_files_temp_dir, 861 framework_partition_set=framework_partition_set, 862 vendor_partition_set=vendor_partition_set, 863 file_name='apkcerts.txt') 864 865 process_apex_keys_apk_certs_common( 866 framework_target_files_dir=framework_target_files_temp_dir, 867 vendor_target_files_dir=vendor_target_files_temp_dir, 868 output_target_files_dir=output_target_files_temp_dir, 869 framework_partition_set=framework_partition_set, 870 vendor_partition_set=vendor_partition_set, 871 file_name='apexkeys.txt') 872 873 874def create_merged_package(temp_dir, framework_target_files, framework_item_list, 875 vendor_target_files, vendor_item_list, 876 framework_misc_info_keys, rebuild_recovery): 877 """Merges two target files packages into one target files structure. 878 879 Args: 880 temp_dir: The name of a directory we use when we extract items from the 881 input target files packages, and also a scratch directory that we use for 882 temporary files. 883 framework_target_files: The name of the zip archive containing the framework 884 partial target files package. 885 framework_item_list: The list of items to extract from the partial framework 886 target files package as is, meaning these items will land in the output 887 target files package exactly as they appear in the input partial framework 888 target files package. 889 vendor_target_files: The name of the zip archive containing the vendor 890 partial target files package. 891 vendor_item_list: The list of items to extract from the partial vendor 892 target files package as is, meaning these items will land in the output 893 target files package exactly as they appear in the input partial vendor 894 target files package. 895 framework_misc_info_keys: A list of keys to obtain from the framework 896 instance of META/misc_info.txt. The remaining keys should come from the 897 vendor instance. 898 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B 899 devices and write it to the system image. 900 901 Returns: 902 Path to merged package under temp directory. 903 """ 904 # Extract "as is" items from the input framework and vendor partial target 905 # files packages directly into the output temporary directory, since these items 906 # do not need special case processing. 907 908 output_target_files_temp_dir = os.path.join(temp_dir, 'output') 909 extract_items( 910 target_files=framework_target_files, 911 target_files_temp_dir=output_target_files_temp_dir, 912 extract_item_list=framework_item_list) 913 extract_items( 914 target_files=vendor_target_files, 915 target_files_temp_dir=output_target_files_temp_dir, 916 extract_item_list=vendor_item_list) 917 918 # Perform special case processing on META/* items. 919 # After this function completes successfully, all the files we need to create 920 # the output target files package are in place. 921 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework') 922 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor') 923 extract_items( 924 target_files=framework_target_files, 925 target_files_temp_dir=framework_target_files_temp_dir, 926 extract_item_list=('META/*',)) 927 extract_items( 928 target_files=vendor_target_files, 929 target_files_temp_dir=vendor_target_files_temp_dir, 930 extract_item_list=('META/*',)) 931 process_special_cases( 932 framework_target_files_temp_dir=framework_target_files_temp_dir, 933 vendor_target_files_temp_dir=vendor_target_files_temp_dir, 934 output_target_files_temp_dir=output_target_files_temp_dir, 935 framework_misc_info_keys=framework_misc_info_keys, 936 framework_partition_set=item_list_to_partition_set(framework_item_list), 937 vendor_partition_set=item_list_to_partition_set(vendor_item_list)) 938 939 return output_target_files_temp_dir 940 941 942def generate_images(target_files_dir, rebuild_recovery): 943 """Generate images from target files. 944 945 This function takes merged output temporary directory and create images 946 from it. 947 948 Args: 949 target_files_dir: Path to merged temp directory. 950 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B 951 devices and write it to the system image. 952 """ 953 954 # Regenerate IMAGES in the target directory. 955 956 add_img_args = [ 957 '--verbose', 958 '--add_missing', 959 ] 960 # TODO(b/132730255): Remove this if statement. 961 if rebuild_recovery: 962 add_img_args.append('--rebuild_recovery') 963 add_img_args.append(target_files_dir) 964 965 add_img_to_target_files.main(add_img_args) 966 967 968def generate_super_empty_image(target_dir, output_super_empty): 969 """Generates super_empty image from target package. 970 971 Args: 972 target_dir: Path to the target file package which contains misc_info.txt for 973 detailed information for super image. 974 output_super_empty: If provided, copies a super_empty.img file from the 975 target files package to this path. 976 """ 977 # Create super_empty.img using the merged misc_info.txt. 978 979 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt') 980 981 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get( 982 'use_dynamic_partitions') 983 984 if use_dynamic_partitions != 'true' and output_super_empty: 985 raise ValueError( 986 'Building super_empty.img requires use_dynamic_partitions=true.') 987 elif use_dynamic_partitions == 'true': 988 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img') 989 build_super_image_args = [ 990 misc_info_txt, 991 super_empty_img, 992 ] 993 build_super_image.main(build_super_image_args) 994 995 # Copy super_empty.img to the user-provided output_super_empty location. 996 if output_super_empty: 997 shutil.copyfile(super_empty_img, output_super_empty) 998 999 1000def create_target_files_archive(output_file, source_dir, temp_dir): 1001 """Creates archive from target package. 1002 1003 Args: 1004 output_file: The name of the zip archive target files package. 1005 source_dir: The target directory contains package to be archived. 1006 temp_dir: Path to temporary directory for any intermediate files. 1007 """ 1008 output_target_files_list = os.path.join(temp_dir, 'output.list') 1009 output_zip = os.path.abspath(output_file) 1010 output_target_files_meta_dir = os.path.join(source_dir, 'META') 1011 1012 def files_from_path(target_path, extra_args=None): 1013 """Gets files under the given path and return a sorted list.""" 1014 find_command = ['find', target_path] + (extra_args or []) 1015 find_process = common.Run( 1016 find_command, stdout=subprocess.PIPE, verbose=False) 1017 return common.RunAndCheckOutput(['sort'], 1018 stdin=find_process.stdout, 1019 verbose=False) 1020 1021 meta_content = files_from_path(output_target_files_meta_dir) 1022 other_content = files_from_path( 1023 source_dir, 1024 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print']) 1025 1026 with open(output_target_files_list, 'w') as f: 1027 f.write(meta_content) 1028 f.write(other_content) 1029 1030 command = [ 1031 'soong_zip', 1032 '-d', 1033 '-o', 1034 output_zip, 1035 '-C', 1036 source_dir, 1037 '-r', 1038 output_target_files_list, 1039 ] 1040 1041 logger.info('creating %s', output_file) 1042 common.RunAndCheckOutput(command, verbose=True) 1043 logger.info('finished creating %s', output_file) 1044 1045 return output_zip 1046 1047 1048def merge_target_files(temp_dir, framework_target_files, framework_item_list, 1049 framework_misc_info_keys, vendor_target_files, 1050 vendor_item_list, output_target_files, output_dir, 1051 output_item_list, output_ota, output_img, 1052 output_super_empty, rebuild_recovery): 1053 """Merges two target files packages together. 1054 1055 This function takes framework and vendor target files packages as input, 1056 performs various file extractions, special case processing, and finally 1057 creates a merged zip archive as output. 1058 1059 Args: 1060 temp_dir: The name of a directory we use when we extract items from the 1061 input target files packages, and also a scratch directory that we use for 1062 temporary files. 1063 framework_target_files: The name of the zip archive containing the framework 1064 partial target files package. 1065 framework_item_list: The list of items to extract from the partial framework 1066 target files package as is, meaning these items will land in the output 1067 target files package exactly as they appear in the input partial framework 1068 target files package. 1069 framework_misc_info_keys: A list of keys to obtain from the framework 1070 instance of META/misc_info.txt. The remaining keys should come from the 1071 vendor instance. 1072 vendor_target_files: The name of the zip archive containing the vendor 1073 partial target files package. 1074 vendor_item_list: The list of items to extract from the partial vendor 1075 target files package as is, meaning these items will land in the output 1076 target files package exactly as they appear in the input partial vendor 1077 target files package. 1078 output_target_files: The name of the output zip archive target files package 1079 created by merging framework and vendor. 1080 output_dir: The destination directory for saving merged files. 1081 output_item_list: The list of items to copy into the output_dir. 1082 output_ota: The name of the output zip archive ota package. 1083 output_img: The name of the output zip archive img package. 1084 output_super_empty: If provided, creates a super_empty.img file from the 1085 merged target files package and saves it at this path. 1086 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B 1087 devices and write it to the system image. 1088 """ 1089 1090 logger.info('starting: merge framework %s and vendor %s into output %s', 1091 framework_target_files, vendor_target_files, output_target_files) 1092 1093 output_target_files_temp_dir = create_merged_package( 1094 temp_dir, framework_target_files, framework_item_list, 1095 vendor_target_files, vendor_item_list, framework_misc_info_keys, 1096 rebuild_recovery) 1097 1098 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir): 1099 raise RuntimeError('Incompatible VINTF metadata') 1100 1101 partition_map = common.PartitionMapFromTargetFiles( 1102 output_target_files_temp_dir) 1103 1104 # Generate and check for cross-partition violations of sharedUserId 1105 # values in APKs. This requires the input target-files packages to contain 1106 # *.apk files. 1107 shareduid_violation_modules = os.path.join( 1108 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json') 1109 with open(shareduid_violation_modules, 'w') as f: 1110 violation = find_shareduid_violation.FindShareduidViolation( 1111 output_target_files_temp_dir, partition_map) 1112 1113 # Write the output to a file to enable debugging. 1114 f.write(violation) 1115 1116 # Check for violations across the input builds' partition groups. 1117 framework_partitions = item_list_to_partition_set(framework_item_list) 1118 vendor_partitions = item_list_to_partition_set(vendor_item_list) 1119 shareduid_errors = common.SharedUidPartitionViolations( 1120 json.loads(violation), [framework_partitions, vendor_partitions]) 1121 if shareduid_errors: 1122 for error in shareduid_errors: 1123 logger.error(error) 1124 raise ValueError('sharedUserId APK error. See %s' % 1125 shareduid_violation_modules) 1126 1127 # host_init_verifier and secilc check only the following partitions: 1128 filtered_partitions = { 1129 partition: path 1130 for partition, path in partition_map.items() 1131 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm'] 1132 } 1133 1134 # Run host_init_verifier on the combined init rc files. 1135 common.RunHostInitVerifier( 1136 product_out=output_target_files_temp_dir, 1137 partition_map=filtered_partitions) 1138 1139 # Check that the split sepolicy from the multiple builds can compile. 1140 split_sepolicy_cmd = compile_split_sepolicy( 1141 product_out=output_target_files_temp_dir, 1142 partition_map=filtered_partitions, 1143 output_policy=os.path.join(output_target_files_temp_dir, 1144 'META/combined.policy')) 1145 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd)) 1146 common.RunAndCheckOutput(split_sepolicy_cmd) 1147 # TODO(b/178864050): Run tests on the combined.policy file. 1148 1149 # Run validation checks on the pre-installed APEX files. 1150 validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys()) 1151 1152 generate_images(output_target_files_temp_dir, rebuild_recovery) 1153 1154 generate_super_empty_image(output_target_files_temp_dir, output_super_empty) 1155 1156 # Finally, create the output target files zip archive and/or copy the 1157 # output items to the output target files directory. 1158 1159 if output_dir: 1160 copy_items(output_target_files_temp_dir, output_dir, output_item_list) 1161 1162 if not output_target_files: 1163 return 1164 1165 # Create the merged META/care_map.bp 1166 generate_care_map(partition_map.keys(), output_target_files_temp_dir) 1167 1168 output_zip = create_target_files_archive(output_target_files, 1169 output_target_files_temp_dir, 1170 temp_dir) 1171 1172 # Create the IMG package from the merged target files package. 1173 if output_img: 1174 img_from_target_files.main([output_zip, output_img]) 1175 1176 # Create the OTA package from the merged target files package. 1177 1178 if output_ota: 1179 ota_from_target_files.main([output_zip, output_ota]) 1180 1181 1182def call_func_with_temp_dir(func, keep_tmp): 1183 """Manages the creation and cleanup of the temporary directory. 1184 1185 This function calls the given function after first creating a temporary 1186 directory. It also cleans up the temporary directory. 1187 1188 Args: 1189 func: The function to call. Should accept one parameter, the path to the 1190 temporary directory. 1191 keep_tmp: Keep the temporary directory after processing is complete. 1192 """ 1193 1194 # Create a temporary directory. This will serve as the parent of directories 1195 # we use when we extract items from the input target files packages, and also 1196 # a scratch directory that we use for temporary files. 1197 1198 temp_dir = common.MakeTempDir(prefix='merge_target_files_') 1199 1200 try: 1201 func(temp_dir) 1202 finally: 1203 if keep_tmp: 1204 logger.info('keeping %s', temp_dir) 1205 else: 1206 common.Cleanup() 1207 1208 1209def main(): 1210 """The main function. 1211 1212 Process command line arguments, then call merge_target_files to 1213 perform the heavy lifting. 1214 """ 1215 1216 common.InitLogging() 1217 1218 def option_handler(o, a): 1219 if o == '--system-target-files': 1220 logger.warning( 1221 '--system-target-files has been renamed to --framework-target-files') 1222 OPTIONS.framework_target_files = a 1223 elif o == '--framework-target-files': 1224 OPTIONS.framework_target_files = a 1225 elif o == '--system-item-list': 1226 logger.warning( 1227 '--system-item-list has been renamed to --framework-item-list') 1228 OPTIONS.framework_item_list = a 1229 elif o == '--framework-item-list': 1230 OPTIONS.framework_item_list = a 1231 elif o == '--system-misc-info-keys': 1232 logger.warning('--system-misc-info-keys has been renamed to ' 1233 '--framework-misc-info-keys') 1234 OPTIONS.framework_misc_info_keys = a 1235 elif o == '--framework-misc-info-keys': 1236 OPTIONS.framework_misc_info_keys = a 1237 elif o == '--other-target-files': 1238 logger.warning( 1239 '--other-target-files has been renamed to --vendor-target-files') 1240 OPTIONS.vendor_target_files = a 1241 elif o == '--vendor-target-files': 1242 OPTIONS.vendor_target_files = a 1243 elif o == '--other-item-list': 1244 logger.warning('--other-item-list has been renamed to --vendor-item-list') 1245 OPTIONS.vendor_item_list = a 1246 elif o == '--vendor-item-list': 1247 OPTIONS.vendor_item_list = a 1248 elif o == '--output-target-files': 1249 OPTIONS.output_target_files = a 1250 elif o == '--output-dir': 1251 OPTIONS.output_dir = a 1252 elif o == '--output-item-list': 1253 OPTIONS.output_item_list = a 1254 elif o == '--output-ota': 1255 OPTIONS.output_ota = a 1256 elif o == '--output-img': 1257 OPTIONS.output_img = a 1258 elif o == '--output-super-empty': 1259 OPTIONS.output_super_empty = a 1260 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn 1261 OPTIONS.rebuild_recovery = True 1262 elif o == '--allow-duplicate-apkapex-keys': 1263 OPTIONS.allow_duplicate_apkapex_keys = True 1264 elif o == '--keep-tmp': 1265 OPTIONS.keep_tmp = True 1266 else: 1267 return False 1268 return True 1269 1270 args = common.ParseOptions( 1271 sys.argv[1:], 1272 __doc__, 1273 extra_long_opts=[ 1274 'system-target-files=', 1275 'framework-target-files=', 1276 'system-item-list=', 1277 'framework-item-list=', 1278 'system-misc-info-keys=', 1279 'framework-misc-info-keys=', 1280 'other-target-files=', 1281 'vendor-target-files=', 1282 'other-item-list=', 1283 'vendor-item-list=', 1284 'output-target-files=', 1285 'output-dir=', 1286 'output-item-list=', 1287 'output-ota=', 1288 'output-img=', 1289 'output-super-empty=', 1290 'rebuild_recovery', 1291 'allow-duplicate-apkapex-keys', 1292 'keep-tmp', 1293 ], 1294 extra_option_handler=option_handler) 1295 1296 # pylint: disable=too-many-boolean-expressions 1297 if (args or OPTIONS.framework_target_files is None or 1298 OPTIONS.vendor_target_files is None or 1299 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or 1300 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)): 1301 common.Usage(__doc__) 1302 sys.exit(1) 1303 1304 if OPTIONS.framework_item_list: 1305 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list) 1306 else: 1307 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST 1308 1309 if OPTIONS.framework_misc_info_keys: 1310 framework_misc_info_keys = common.LoadListFromFile( 1311 OPTIONS.framework_misc_info_keys) 1312 else: 1313 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS 1314 1315 if OPTIONS.vendor_item_list: 1316 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list) 1317 else: 1318 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST 1319 1320 if OPTIONS.output_item_list: 1321 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list) 1322 else: 1323 output_item_list = None 1324 1325 if not validate_config_lists( 1326 framework_item_list=framework_item_list, 1327 framework_misc_info_keys=framework_misc_info_keys, 1328 vendor_item_list=vendor_item_list): 1329 sys.exit(1) 1330 1331 call_func_with_temp_dir( 1332 lambda temp_dir: merge_target_files( 1333 temp_dir=temp_dir, 1334 framework_target_files=OPTIONS.framework_target_files, 1335 framework_item_list=framework_item_list, 1336 framework_misc_info_keys=framework_misc_info_keys, 1337 vendor_target_files=OPTIONS.vendor_target_files, 1338 vendor_item_list=vendor_item_list, 1339 output_target_files=OPTIONS.output_target_files, 1340 output_dir=OPTIONS.output_dir, 1341 output_item_list=output_item_list, 1342 output_ota=OPTIONS.output_ota, 1343 output_img=OPTIONS.output_img, 1344 output_super_empty=OPTIONS.output_super_empty, 1345 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp) 1346 1347 1348if __name__ == '__main__': 1349 main() 1350