Add a script to check VINTF compat of target files package. am: e3ba82cff2
am: d14a6110c5
Change-Id: I78b0542099e1e291b39368e89b951b3480b846c4
This commit is contained in:
commit
646b2b6cbc
3 changed files with 287 additions and 16 deletions
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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):
|
||||
|
@ -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 \
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
|
|
@ -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: [
|
||||
|
@ -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: [
|
||||
|
|
232
tools/releasetools/check_target_files_vintf.py
Executable file
232
tools/releasetools/check_target_files_vintf.py
Executable file
|
@ -0,0 +1,232 @@
|
|||
#!/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…
Reference in a new issue