aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2019-08-28 17:20:52 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-08-28 17:20:52 -0700
commitd14a6110c50402a760d797e709293a79dc11a052 (patch)
treedbd815d7c9a7e466488d7ef94cabbc4f041e86e9
parenta9fef4a0c7e696e7c3beed6e3dba3e1dec4f112b (diff)
parente3ba82cff24a2bf44c39230cf1f6d934c3f4c644 (diff)
downloadplatform_build-d14a6110c50402a760d797e709293a79dc11a052.tar.gz
platform_build-d14a6110c50402a760d797e709293a79dc11a052.tar.bz2
platform_build-d14a6110c50402a760d797e709293a79dc11a052.zip
Add a script to check VINTF compat of target files package.
am: e3ba82cff2 Change-Id: Iccf4b7afa93749f441f48a3270f3d4beac8a0f06
-rw-r--r--core/Makefile50
-rw-r--r--tools/releasetools/Android.bp21
-rwxr-xr-xtools/releasetools/check_target_files_vintf.py232
3 files changed, 287 insertions, 16 deletions
diff --git a/core/Makefile b/core/Makefile
index 9ae356bd26..ceaf6c7a52 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -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
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index 69205b1883..fdc4393ec4 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -76,6 +76,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: [
"edify_generator.py",
@@ -266,6 +279,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: [
"releasetools_binary_defaults",
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
new file mode 100755
index 0000000000..543147c981
--- /dev/null
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -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()