Loading core/Makefile +34 −16 Original line number Diff line number Diff line Loading @@ -2699,12 +2699,19 @@ $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS := # -- Kernel version and configurations. ifeq ($(PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS),true) intermediates := $(call intermediates-dir-for,ETC,$(notdir $(BUILT_ASSEMBLED_VENDOR_MANIFEST))) BUILT_KERNEL_CONFIGS_FILE := $(intermediates)/kernel_configs.txt BUILT_KERNEL_VERSION_FILE := $(intermediates)/kernel_version.txt # BOARD_KERNEL_CONFIG_FILE and BOARD_KERNEL_VERSION can be used to override the values extracted # from INSTALLED_KERNEL_TARGET. ifdef BOARD_KERNEL_CONFIG_FILE ifdef BOARD_KERNEL_VERSION $(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(BOARD_KERNEL_CONFIG_FILE) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS += --kernel $(BOARD_KERNEL_VERSION):$(BOARD_KERNEL_CONFIG_FILE) $(BUILT_KERNEL_CONFIGS_FILE): $(BOARD_KERNEL_CONFIG_FILE) cp $< $@ $(BUILT_KERNEL_VERSION_FILE): echo $(BOARD_KERNEL_VERSION) > $@ my_board_extracted_kernel := true endif # BOARD_KERNEL_VERSION endif # BOARD_KERNEL_CONFIG_FILE Loading @@ -2719,7 +2726,6 @@ $(warning No INSTALLED_KERNEL_TARGET is defined when PRODUCT_OTA_ENFORCE_VINTF_K BOARD_KERNEL_VERSION manually; or (3) unsetting PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \ manually.) else intermediates := $(call intermediates-dir-for,ETC,$(notdir $(BUILT_ASSEMBLED_VENDOR_MANIFEST))) # Tools for decompression that is not in PATH. # Check $(EXTRACT_KERNEL) for decompression algorithms supported by the script. Loading @@ -2727,29 +2733,25 @@ intermediates := $(call intermediates-dir-for,ETC,$(notdir $(BUILT_ASSEMBLED_VEN my_decompress_tools := \ lz4:$(HOST_OUT_EXECUTABLES)/lz4 \ my_kernel_configs := $(intermediates)/kernel_configs.txt my_kernel_version := $(intermediates)/kernel_version.txt $(my_kernel_configs): .KATI_IMPLICIT_OUTPUTS := $(my_kernel_version) $(my_kernel_configs): PRIVATE_KERNEL_VERSION_FILE := $(my_kernel_version) $(my_kernel_configs): PRIVATE_DECOMPRESS_TOOLS := $(my_decompress_tools) $(my_kernel_configs): $(foreach pair,$(my_decompress_tools),$(call word-colon,2,$(pair))) $(my_kernel_configs): $(EXTRACT_KERNEL) $(INSTALLED_KERNEL_TARGET) $(BUILT_KERNEL_CONFIGS_FILE): .KATI_IMPLICIT_OUTPUTS := $(BUILT_KERNEL_VERSION_FILE) $(BUILT_KERNEL_CONFIGS_FILE): PRIVATE_DECOMPRESS_TOOLS := $(my_decompress_tools) $(BUILT_KERNEL_CONFIGS_FILE): $(foreach pair,$(my_decompress_tools),$(call word-colon,2,$(pair))) $(BUILT_KERNEL_CONFIGS_FILE): $(EXTRACT_KERNEL) $(INSTALLED_KERNEL_TARGET) $< --tools $(PRIVATE_DECOMPRESS_TOOLS) --input $(INSTALLED_KERNEL_TARGET) \ --output-configs $@ \ --output-version $(PRIVATE_KERNEL_VERSION_FILE) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(my_kernel_configs) $(my_kernel_version) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS += --kernel $$(cat $(my_kernel_version)):$(my_kernel_configs) --output-version $(BUILT_KERNEL_VERSION_FILE) intermediates := my_kernel_configs := my_kernel_version := my_decompress_tools := endif # my_board_extracted_kernel my_board_extracted_kernel := endif # INSTALLED_KERNEL_TARGET $(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(BUILT_KERNEL_CONFIGS_FILE) $(BUILT_KERNEL_VERSION_FILE) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS += --kernel $$(cat $(BUILT_KERNEL_VERSION_FILE)):$(BUILT_KERNEL_CONFIGS_FILE) endif # PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS $(BUILT_ASSEMBLED_VENDOR_MANIFEST): Loading Loading @@ -3615,6 +3617,7 @@ INTERNAL_OTATOOLS_MODULES := \ care_map_generator \ check_ota_package_signature \ check_target_files_signatures \ check_target_files_vintf \ checkvintf \ delta_generator \ e2fsck \ Loading Loading @@ -3847,6 +3850,13 @@ endif # BOARD_AVB_DTBO_KEY_PATH endif # BOARD_AVB_ENABLE endif # BOARD_PREBUILT_DTBOIMAGE $(call dump-dynamic-partitions-info,$@) @# VINTF checks ifeq ($(PRODUCT_ENFORCE_VINTF_MANIFEST),true) $(hide) echo "vintf_enforce=true" >> $@ endif ifdef ODM_MANIFEST_SKUS $(hide) echo "vintf_odm_manifest_skus=$(ODM_MANIFEST_SKUS)" >> $@ endif .PHONY: misc_info misc_info: $(INSTALLED_MISC_INFO_TARGET) Loading Loading @@ -4006,6 +4016,8 @@ $(BUILT_TARGET_FILES_PACKAGE): \ $(BUILT_ASSEMBLED_VENDOR_MANIFEST) \ $(BUILT_SYSTEM_MATRIX) \ $(BUILT_VENDOR_MATRIX) \ $(BUILT_KERNEL_CONFIGS_FILE) \ $(BUILT_KERNEL_VERSION_FILE) \ | $(ACP) @echo "Package target files: $@" $(call create-system-vendor-symlink) Loading Loading @@ -4254,6 +4266,12 @@ endif ifdef BUILT_VENDOR_MATRIX $(hide) cp $(BUILT_VENDOR_MATRIX) $(zip_root)/META/vendor_matrix.xml endif ifdef BUILT_KERNEL_CONFIGS_FILE $(hide) cp $(BUILT_KERNEL_CONFIGS_FILE) $(zip_root)/META/kernel_configs.txt endif ifdef BUILT_KERNEL_VERSION_FILE $(hide) cp $(BUILT_KERNEL_VERSION_FILE) $(zip_root)/META/kernel_version.txt endif ifneq ($(BOARD_SUPER_PARTITION_GROUPS),) $(hide) echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" > $(zip_root)/META/dynamic_partitions_info.txt @# Remove 'vendor' from the group partition list if the image is not available. This should only Loading tools/releasetools/Android.bp +21 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,19 @@ python_defaults { ], } python_defaults { name: "releasetools_check_target_files_vintf_defaults", srcs: [ "check_target_files_vintf.py", ], libs: [ "releasetools_common", ], required: [ "checkvintf", ], } python_defaults { name: "releasetools_ota_from_target_files_defaults", srcs: [ Loading Loading @@ -265,6 +278,14 @@ python_binary_host { ], } python_binary_host { name: "check_target_files_vintf", defaults: [ "releasetools_binary_defaults", "releasetools_check_target_files_vintf_defaults" ], } python_binary_host { name: "img_from_target_files", defaults: [ Loading tools/releasetools/check_target_files_vintf.py 0 → 100755 +232 −0 Original line number Diff line number Diff line #!/usr/bin/env python # # Copyright (C) 2019 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Check VINTF compatibility from a target files package. Usage: check_target_files_vintf target_files target_files can be a ZIP file or an extracted target files directory. """ import logging import subprocess import sys import os import zipfile import common logger = logging.getLogger(__name__) OPTIONS = common.OPTIONS # Keys are paths that VINTF searches. Must keep in sync with libvintf's search # paths (VintfObject.cpp). # These paths are stored in different directories in target files package, so # we have to search for the correct path and tell checkvintf to remap them. DIR_SEARCH_PATHS = { '/system': ('SYSTEM',), '/vendor': ('VENDOR', 'SYSTEM/vendor'), '/product': ('PRODUCT', 'SYSTEM/product'), '/odm': ('ODM', 'VENDOR/odm'), } UNZIP_PATTERN = ['META/*', '*/build.prop'] def GetDirmap(input_tmp): dirmap = {} for device_path, target_files_rel_paths in DIR_SEARCH_PATHS.items(): for target_files_rel_path in target_files_rel_paths: target_files_path = os.path.join(input_tmp, target_files_rel_path) if os.path.isdir(target_files_path): dirmap[device_path] = target_files_path break if device_path not in dirmap: raise ValueError("Can't determine path for device path " + device_path + ". Searched the following:" + ("\n".join(target_files_rel_paths))) return dirmap def GetArgsForSkus(info_dict): skus = info_dict.get('vintf_odm_manifest_skus', '').strip().split() if not skus: logger.info("ODM_MANIFEST_SKUS is not defined. Check once without SKUs.") skus = [''] return [['--property', 'ro.boot.product.hardware.sku=' + sku] for sku in skus] def GetArgsForShippingApiLevel(info_dict): shipping_api_level = info_dict['vendor.build.prop'].get( 'ro.product.first_api_level') if not shipping_api_level: logger.warning('Cannot determine ro.product.first_api_level') return [] return ['--property', 'ro.product.first_api_level=' + shipping_api_level] def GetArgsForKernel(input_tmp): version_path = os.path.join(input_tmp, 'META/kernel_version.txt') config_path = os.path.join(input_tmp, 'META/kernel_configs.txt') if not os.path.isfile(version_path) or not os.path.isfile(config_path): logger.info('Skipping kernel config checks because ' + 'PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS is not set') return [] with open(version_path) as f: version = f.read().strip() return ['--kernel', '{}:{}'.format(version, config_path)] def CheckVintfFromExtractedTargetFiles(input_tmp, info_dict=None): """ Checks VINTF metadata of an extracted target files directory. Args: inp: path to the directory that contains the extracted target files archive. info_dict: The build-time info dict. If None, it will be loaded from inp. Returns: True if VINTF check is skipped or compatible, False if incompatible. Raise a RuntimeError if any error occurs. """ if info_dict is None: info_dict = common.LoadInfoDict(input_tmp) if info_dict.get('vintf_enforce') != 'true': logger.warning('PRODUCT_ENFORCE_VINTF_MANIFEST is not set, skipping checks') return True dirmap = GetDirmap(input_tmp) args_for_skus = GetArgsForSkus(info_dict) shipping_api_level_args = GetArgsForShippingApiLevel(info_dict) kernel_args = GetArgsForKernel(input_tmp) common_command = [ 'checkvintf', '--check-compat', ] for device_path, real_path in dirmap.items(): common_command += ['--dirmap', '{}:{}'.format(device_path, real_path)] common_command += kernel_args common_command += shipping_api_level_args success = True for sku_args in args_for_skus: command = common_command + sku_args proc = common.Run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() if proc.returncode == 0: logger.info("Command `%s` returns 'compatible'", ' '.join(command)) elif out.strip() == "INCOMPATIBLE": logger.info("Command `%s` returns 'incompatible'", ' '.join(command)) success = False else: raise common.ExternalError( "Failed to run command '{}' (exit code {}):\nstdout:{}\nstderr:{}" .format(' '.join(command), proc.returncode, out, err)) logger.info("stdout: %s", out) logger.info("stderr: %s", err) return success def GetVintfFileList(): """ Returns a list of VINTF metadata files that should be read from a target files package before executing checkvintf. """ def PathToPatterns(path): if path[-1] == '/': path += '*' for device_path, target_files_rel_paths in DIR_SEARCH_PATHS.items(): if path.startswith(device_path): suffix = path[len(device_path):] return [rel_path + suffix for rel_path in target_files_rel_paths] raise RuntimeError('Unrecognized path from checkvintf --dump-file-list: ' + path) out = common.RunAndCheckOutput(['checkvintf', '--dump-file-list']) paths = out.strip().split('\n') paths = sum((PathToPatterns(path) for path in paths if path), []) return paths def CheckVintfFromTargetFiles(inp, info_dict=None): """ Checks VINTF metadata of a target files zip. Args: inp: path to the target files archive. info_dict: The build-time info dict. If None, it will be loaded from inp. Returns: True if VINTF check is skipped or compatible, False if incompatible. Raise a RuntimeError if any error occurs. """ input_tmp = common.UnzipTemp(inp, GetVintfFileList() + UNZIP_PATTERN) return CheckVintfFromExtractedTargetFiles(input_tmp, info_dict) def CheckVintf(inp, info_dict=None): """ Checks VINTF metadata of a target files zip or extracted target files directory. Args: inp: path to the (possibly extracted) target files archive. info_dict: The build-time info dict. If None, it will be loaded from inp. Returns: True if VINTF check is skipped or compatible, False if incompatible. Raise a RuntimeError if any error occurs. """ if os.path.isdir(inp): logger.info('Checking VINTF compatibility extracted target files...') return CheckVintfFromExtractedTargetFiles(inp, info_dict) if zipfile.is_zipfile(inp): logger.info('Checking VINTF compatibility target files...') return CheckVintfFromTargetFiles(inp, info_dict) raise ValueError('{} is not a valid directory or zip file'.format(inp)) def main(argv): args = common.ParseOptions(argv, __doc__) if len(args) != 1: common.Usage(__doc__) sys.exit(1) common.InitLogging() if not CheckVintf(args[0]): sys.exit(1) if __name__ == '__main__': try: common.CloseInheritedPipes() main(sys.argv[1:]) except common.ExternalError: logger.exception('\n ERROR:\n') sys.exit(1) finally: common.Cleanup() Loading
core/Makefile +34 −16 Original line number Diff line number Diff line Loading @@ -2699,12 +2699,19 @@ $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS := # -- Kernel version and configurations. ifeq ($(PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS),true) intermediates := $(call intermediates-dir-for,ETC,$(notdir $(BUILT_ASSEMBLED_VENDOR_MANIFEST))) BUILT_KERNEL_CONFIGS_FILE := $(intermediates)/kernel_configs.txt BUILT_KERNEL_VERSION_FILE := $(intermediates)/kernel_version.txt # BOARD_KERNEL_CONFIG_FILE and BOARD_KERNEL_VERSION can be used to override the values extracted # from INSTALLED_KERNEL_TARGET. ifdef BOARD_KERNEL_CONFIG_FILE ifdef BOARD_KERNEL_VERSION $(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(BOARD_KERNEL_CONFIG_FILE) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS += --kernel $(BOARD_KERNEL_VERSION):$(BOARD_KERNEL_CONFIG_FILE) $(BUILT_KERNEL_CONFIGS_FILE): $(BOARD_KERNEL_CONFIG_FILE) cp $< $@ $(BUILT_KERNEL_VERSION_FILE): echo $(BOARD_KERNEL_VERSION) > $@ my_board_extracted_kernel := true endif # BOARD_KERNEL_VERSION endif # BOARD_KERNEL_CONFIG_FILE Loading @@ -2719,7 +2726,6 @@ $(warning No INSTALLED_KERNEL_TARGET is defined when PRODUCT_OTA_ENFORCE_VINTF_K BOARD_KERNEL_VERSION manually; or (3) unsetting PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \ manually.) else intermediates := $(call intermediates-dir-for,ETC,$(notdir $(BUILT_ASSEMBLED_VENDOR_MANIFEST))) # Tools for decompression that is not in PATH. # Check $(EXTRACT_KERNEL) for decompression algorithms supported by the script. Loading @@ -2727,29 +2733,25 @@ intermediates := $(call intermediates-dir-for,ETC,$(notdir $(BUILT_ASSEMBLED_VEN my_decompress_tools := \ lz4:$(HOST_OUT_EXECUTABLES)/lz4 \ my_kernel_configs := $(intermediates)/kernel_configs.txt my_kernel_version := $(intermediates)/kernel_version.txt $(my_kernel_configs): .KATI_IMPLICIT_OUTPUTS := $(my_kernel_version) $(my_kernel_configs): PRIVATE_KERNEL_VERSION_FILE := $(my_kernel_version) $(my_kernel_configs): PRIVATE_DECOMPRESS_TOOLS := $(my_decompress_tools) $(my_kernel_configs): $(foreach pair,$(my_decompress_tools),$(call word-colon,2,$(pair))) $(my_kernel_configs): $(EXTRACT_KERNEL) $(INSTALLED_KERNEL_TARGET) $(BUILT_KERNEL_CONFIGS_FILE): .KATI_IMPLICIT_OUTPUTS := $(BUILT_KERNEL_VERSION_FILE) $(BUILT_KERNEL_CONFIGS_FILE): PRIVATE_DECOMPRESS_TOOLS := $(my_decompress_tools) $(BUILT_KERNEL_CONFIGS_FILE): $(foreach pair,$(my_decompress_tools),$(call word-colon,2,$(pair))) $(BUILT_KERNEL_CONFIGS_FILE): $(EXTRACT_KERNEL) $(INSTALLED_KERNEL_TARGET) $< --tools $(PRIVATE_DECOMPRESS_TOOLS) --input $(INSTALLED_KERNEL_TARGET) \ --output-configs $@ \ --output-version $(PRIVATE_KERNEL_VERSION_FILE) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(my_kernel_configs) $(my_kernel_version) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS += --kernel $$(cat $(my_kernel_version)):$(my_kernel_configs) --output-version $(BUILT_KERNEL_VERSION_FILE) intermediates := my_kernel_configs := my_kernel_version := my_decompress_tools := endif # my_board_extracted_kernel my_board_extracted_kernel := endif # INSTALLED_KERNEL_TARGET $(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(BUILT_KERNEL_CONFIGS_FILE) $(BUILT_KERNEL_VERSION_FILE) $(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_FLAGS += --kernel $$(cat $(BUILT_KERNEL_VERSION_FILE)):$(BUILT_KERNEL_CONFIGS_FILE) endif # PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS $(BUILT_ASSEMBLED_VENDOR_MANIFEST): Loading Loading @@ -3615,6 +3617,7 @@ INTERNAL_OTATOOLS_MODULES := \ care_map_generator \ check_ota_package_signature \ check_target_files_signatures \ check_target_files_vintf \ checkvintf \ delta_generator \ e2fsck \ Loading Loading @@ -3847,6 +3850,13 @@ endif # BOARD_AVB_DTBO_KEY_PATH endif # BOARD_AVB_ENABLE endif # BOARD_PREBUILT_DTBOIMAGE $(call dump-dynamic-partitions-info,$@) @# VINTF checks ifeq ($(PRODUCT_ENFORCE_VINTF_MANIFEST),true) $(hide) echo "vintf_enforce=true" >> $@ endif ifdef ODM_MANIFEST_SKUS $(hide) echo "vintf_odm_manifest_skus=$(ODM_MANIFEST_SKUS)" >> $@ endif .PHONY: misc_info misc_info: $(INSTALLED_MISC_INFO_TARGET) Loading Loading @@ -4006,6 +4016,8 @@ $(BUILT_TARGET_FILES_PACKAGE): \ $(BUILT_ASSEMBLED_VENDOR_MANIFEST) \ $(BUILT_SYSTEM_MATRIX) \ $(BUILT_VENDOR_MATRIX) \ $(BUILT_KERNEL_CONFIGS_FILE) \ $(BUILT_KERNEL_VERSION_FILE) \ | $(ACP) @echo "Package target files: $@" $(call create-system-vendor-symlink) Loading Loading @@ -4254,6 +4266,12 @@ endif ifdef BUILT_VENDOR_MATRIX $(hide) cp $(BUILT_VENDOR_MATRIX) $(zip_root)/META/vendor_matrix.xml endif ifdef BUILT_KERNEL_CONFIGS_FILE $(hide) cp $(BUILT_KERNEL_CONFIGS_FILE) $(zip_root)/META/kernel_configs.txt endif ifdef BUILT_KERNEL_VERSION_FILE $(hide) cp $(BUILT_KERNEL_VERSION_FILE) $(zip_root)/META/kernel_version.txt endif ifneq ($(BOARD_SUPER_PARTITION_GROUPS),) $(hide) echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" > $(zip_root)/META/dynamic_partitions_info.txt @# Remove 'vendor' from the group partition list if the image is not available. This should only Loading
tools/releasetools/Android.bp +21 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,19 @@ python_defaults { ], } python_defaults { name: "releasetools_check_target_files_vintf_defaults", srcs: [ "check_target_files_vintf.py", ], libs: [ "releasetools_common", ], required: [ "checkvintf", ], } python_defaults { name: "releasetools_ota_from_target_files_defaults", srcs: [ Loading Loading @@ -265,6 +278,14 @@ python_binary_host { ], } python_binary_host { name: "check_target_files_vintf", defaults: [ "releasetools_binary_defaults", "releasetools_check_target_files_vintf_defaults" ], } python_binary_host { name: "img_from_target_files", defaults: [ Loading
tools/releasetools/check_target_files_vintf.py 0 → 100755 +232 −0 Original line number Diff line number Diff line #!/usr/bin/env python # # Copyright (C) 2019 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Check VINTF compatibility from a target files package. Usage: check_target_files_vintf target_files target_files can be a ZIP file or an extracted target files directory. """ import logging import subprocess import sys import os import zipfile import common logger = logging.getLogger(__name__) OPTIONS = common.OPTIONS # Keys are paths that VINTF searches. Must keep in sync with libvintf's search # paths (VintfObject.cpp). # These paths are stored in different directories in target files package, so # we have to search for the correct path and tell checkvintf to remap them. DIR_SEARCH_PATHS = { '/system': ('SYSTEM',), '/vendor': ('VENDOR', 'SYSTEM/vendor'), '/product': ('PRODUCT', 'SYSTEM/product'), '/odm': ('ODM', 'VENDOR/odm'), } UNZIP_PATTERN = ['META/*', '*/build.prop'] def GetDirmap(input_tmp): dirmap = {} for device_path, target_files_rel_paths in DIR_SEARCH_PATHS.items(): for target_files_rel_path in target_files_rel_paths: target_files_path = os.path.join(input_tmp, target_files_rel_path) if os.path.isdir(target_files_path): dirmap[device_path] = target_files_path break if device_path not in dirmap: raise ValueError("Can't determine path for device path " + device_path + ". Searched the following:" + ("\n".join(target_files_rel_paths))) return dirmap def GetArgsForSkus(info_dict): skus = info_dict.get('vintf_odm_manifest_skus', '').strip().split() if not skus: logger.info("ODM_MANIFEST_SKUS is not defined. Check once without SKUs.") skus = [''] return [['--property', 'ro.boot.product.hardware.sku=' + sku] for sku in skus] def GetArgsForShippingApiLevel(info_dict): shipping_api_level = info_dict['vendor.build.prop'].get( 'ro.product.first_api_level') if not shipping_api_level: logger.warning('Cannot determine ro.product.first_api_level') return [] return ['--property', 'ro.product.first_api_level=' + shipping_api_level] def GetArgsForKernel(input_tmp): version_path = os.path.join(input_tmp, 'META/kernel_version.txt') config_path = os.path.join(input_tmp, 'META/kernel_configs.txt') if not os.path.isfile(version_path) or not os.path.isfile(config_path): logger.info('Skipping kernel config checks because ' + 'PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS is not set') return [] with open(version_path) as f: version = f.read().strip() return ['--kernel', '{}:{}'.format(version, config_path)] def CheckVintfFromExtractedTargetFiles(input_tmp, info_dict=None): """ Checks VINTF metadata of an extracted target files directory. Args: inp: path to the directory that contains the extracted target files archive. info_dict: The build-time info dict. If None, it will be loaded from inp. Returns: True if VINTF check is skipped or compatible, False if incompatible. Raise a RuntimeError if any error occurs. """ if info_dict is None: info_dict = common.LoadInfoDict(input_tmp) if info_dict.get('vintf_enforce') != 'true': logger.warning('PRODUCT_ENFORCE_VINTF_MANIFEST is not set, skipping checks') return True dirmap = GetDirmap(input_tmp) args_for_skus = GetArgsForSkus(info_dict) shipping_api_level_args = GetArgsForShippingApiLevel(info_dict) kernel_args = GetArgsForKernel(input_tmp) common_command = [ 'checkvintf', '--check-compat', ] for device_path, real_path in dirmap.items(): common_command += ['--dirmap', '{}:{}'.format(device_path, real_path)] common_command += kernel_args common_command += shipping_api_level_args success = True for sku_args in args_for_skus: command = common_command + sku_args proc = common.Run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() if proc.returncode == 0: logger.info("Command `%s` returns 'compatible'", ' '.join(command)) elif out.strip() == "INCOMPATIBLE": logger.info("Command `%s` returns 'incompatible'", ' '.join(command)) success = False else: raise common.ExternalError( "Failed to run command '{}' (exit code {}):\nstdout:{}\nstderr:{}" .format(' '.join(command), proc.returncode, out, err)) logger.info("stdout: %s", out) logger.info("stderr: %s", err) return success def GetVintfFileList(): """ Returns a list of VINTF metadata files that should be read from a target files package before executing checkvintf. """ def PathToPatterns(path): if path[-1] == '/': path += '*' for device_path, target_files_rel_paths in DIR_SEARCH_PATHS.items(): if path.startswith(device_path): suffix = path[len(device_path):] return [rel_path + suffix for rel_path in target_files_rel_paths] raise RuntimeError('Unrecognized path from checkvintf --dump-file-list: ' + path) out = common.RunAndCheckOutput(['checkvintf', '--dump-file-list']) paths = out.strip().split('\n') paths = sum((PathToPatterns(path) for path in paths if path), []) return paths def CheckVintfFromTargetFiles(inp, info_dict=None): """ Checks VINTF metadata of a target files zip. Args: inp: path to the target files archive. info_dict: The build-time info dict. If None, it will be loaded from inp. Returns: True if VINTF check is skipped or compatible, False if incompatible. Raise a RuntimeError if any error occurs. """ input_tmp = common.UnzipTemp(inp, GetVintfFileList() + UNZIP_PATTERN) return CheckVintfFromExtractedTargetFiles(input_tmp, info_dict) def CheckVintf(inp, info_dict=None): """ Checks VINTF metadata of a target files zip or extracted target files directory. Args: inp: path to the (possibly extracted) target files archive. info_dict: The build-time info dict. If None, it will be loaded from inp. Returns: True if VINTF check is skipped or compatible, False if incompatible. Raise a RuntimeError if any error occurs. """ if os.path.isdir(inp): logger.info('Checking VINTF compatibility extracted target files...') return CheckVintfFromExtractedTargetFiles(inp, info_dict) if zipfile.is_zipfile(inp): logger.info('Checking VINTF compatibility target files...') return CheckVintfFromTargetFiles(inp, info_dict) raise ValueError('{} is not a valid directory or zip file'.format(inp)) def main(argv): args = common.ParseOptions(argv, __doc__) if len(args) != 1: common.Usage(__doc__) sys.exit(1) common.InitLogging() if not CheckVintf(args[0]): sys.exit(1) if __name__ == '__main__': try: common.CloseInheritedPipes() main(sys.argv[1:]) except common.ExternalError: logger.exception('\n ERROR:\n') sys.exit(1) finally: common.Cleanup()