Merge "Add libfdtrack to base_system."
diff --git a/Changes.md b/Changes.md
index 5a0fd23..2720a0f 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,47 @@
 # Build System Changes for Android.mk Writers
 
+## COPY_HEADERS usage now produces warnings {#copy_headers}
+
+We've considered `BUILD_COPY_HEADERS`/`LOCAL_COPY_HEADERS` to be deprecated for
+a long time, and the places where it's been able to be used have shrinked over
+the last several releases. Equivalent functionality is not available in Soong.
+
+See the [build/soong/docs/best_practices.md#headers] for more information about
+how best to handle headers in Android.
+
+## `m4` is not available on `$PATH`
+
+There is a prebuilt of it available in prebuilts/build-tools, and a make
+variable `M4` that contains the path.
+
+Beyond the direct usage, whenever you use bison or flex directly, they call m4
+behind the scene, so you must set the M4 environment variable (and depend upon
+it for incremental build correctness):
+
+```
+$(intermediates)/foo.c: .KATI_IMPLICIT_OUTPUTS := $(intermediates)/foo.h
+$(intermediates)/foo.c: $(LOCAL_PATH)/foo.y $(M4) $(BISON) $(BISON_DATA)
+	M4=$(M4) $(BISON) ...
+```
+
+## Rules executed within limited environment
+
+With `ALLOW_NINJA_ENV=false` (soon to be the default), ninja, and all the
+rules/actions executed within it will only have access to a limited number of
+environment variables. Ninja does not track when environment variables change
+in order to trigger rebuilds, so changing behavior based on arbitrary variables
+is not safe with incremental builds.
+
+Kati and Soong can safely use environment variables, so the expectation is that
+you'd embed any environment variables that you need to use within the command
+line generated by those tools. See the [export section](#export_keyword) below
+for examples.
+
+For a temporary workaround, you can set `ALLOW_NINJA_ENV=true` in your
+environment to restore the previous behavior, or set
+`BUILD_BROKEN_NINJA_USES_ENV_VAR := <var> <var2> ...` in your `BoardConfig.mk`
+to allow specific variables to be passed through until you've fixed the rules.
+
 ## LOCAL_C_INCLUDES outside the source/output trees are an error {#BUILD_BROKEN_OUTSIDE_INCLUDE_DIRS}
 
 Include directories are expected to be within the source tree (or in the output
@@ -31,7 +73,7 @@
 offending line.
 
 
-# `BOARD_HAL_STATIC_LIBRARIES` and `LOCAL_HAL_STATIC_LIBRARIES` are obsolete {#BOARD_HAL_STATIC_LIBRARIES}
+## `BOARD_HAL_STATIC_LIBRARIES` and `LOCAL_HAL_STATIC_LIBRARIES` are obsolete {#BOARD_HAL_STATIC_LIBRARIES}
 
 Define proper HIDL / Stable AIDL HAL instead.
 
@@ -520,6 +562,7 @@
 
 
 [build/soong/Changes.md]: https://android.googlesource.com/platform/build/soong/+/master/Changes.md
+[build/soong/docs/best_practices.md#headers]: https://android.googlesource.com/platform/build/soong/+/master/docs/best_practices.md#headers
 [external/fonttools/Lib/fontTools/Android.bp]: https://android.googlesource.com/platform/external/fonttools/+/master/Lib/fontTools/Android.bp
 [frameworks/base/Android.bp]: https://android.googlesource.com/platform/frameworks/base/+/master/Android.bp
 [frameworks/base/data/fonts/Android.mk]: https://android.googlesource.com/platform/frameworks/base/+/master/data/fonts/Android.mk
diff --git a/Deprecation.md b/Deprecation.md
index 9378e1a..5e26492 100644
--- a/Deprecation.md
+++ b/Deprecation.md
@@ -16,8 +16,11 @@
 | -------------------------------- | --------- |
 | `BUILD_AUX_EXECUTABLE`           | Error     |
 | `BUILD_AUX_STATIC_LIBRARY`       | Error     |
+| `BUILD_COPY_HEADERS`             | Warning   |
+| `BUILD_HOST_EXECUTABLE`          | Warning   |
 | `BUILD_HOST_FUZZ_TEST`           | Error     |
 | `BUILD_HOST_NATIVE_TEST`         | Error     |
+| `BUILD_HOST_SHARED_LIBRARY`      | Warning   |
 | `BUILD_HOST_SHARED_TEST_LIBRARY` | Error     |
 | `BUILD_HOST_STATIC_LIBRARY`      | Warning   |
 | `BUILD_HOST_STATIC_TEST_LIBRARY` | Error     |
diff --git a/common/math.mk b/common/math.mk
index ac3151e..83f2218 100644
--- a/common/math.mk
+++ b/common/math.mk
@@ -33,8 +33,8 @@
 math-expect-error :=
 
 # Run the math tests with:
-#  make -f ${ANDROID_BUILD_TOP}/build/make/core/math.mk RUN_MATH_TESTS=true
-#  $(get_build_var CKATI) -f ${ANDROID_BUILD_TOP}//build/make/core/math.mk RUN_MATH_TESTS=true
+#  make -f ${ANDROID_BUILD_TOP}/build/make/common/math.mk RUN_MATH_TESTS=true
+#  $(get_build_var CKATI) -f ${ANDROID_BUILD_TOP}//build/make/common/math.mk RUN_MATH_TESTS=true
 ifdef RUN_MATH_TESTS
   MATH_TEST_FAILURE :=
   MATH_TEST_ERROR :=
@@ -134,6 +134,10 @@
 $(if $(filter $(1),$(call math_max,$(1),$(2))),true)
 endef
 
+define math_gt
+$(if $(call math_gt_or_eq,$(2),$(1)),,true)
+endef
+
 define math_lt
 $(if $(call math_gt_or_eq,$(1),$(2)),,true)
 endef
@@ -141,6 +145,12 @@
 $(call math-expect-true,(call math_gt_or_eq, 2, 1))
 $(call math-expect-true,(call math_gt_or_eq, 1, 1))
 $(call math-expect-false,(call math_gt_or_eq, 1, 2))
+$(call math-expect-true,(call math_gt, 4, 3))
+$(call math-expect-false,(call math_gt, 5, 5))
+$(call math-expect-false,(call math_gt, 6, 7))
+$(call math-expect-false,(call math_lt, 1, 0))
+$(call math-expect-false,(call math_lt, 8, 8))
+$(call math-expect-true,(call math_lt, 10, 11))
 
 # $1 is the variable name to increment
 define inc_and_print
diff --git a/core/Makefile b/core/Makefile
index c650022..c862e97 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -16,7 +16,28 @@
 define check-product-copy-files
 $(if $(filter-out $(TARGET_COPY_OUT_SYSTEM_OTHER)/%,$(2)), \
   $(if $(filter %.apk, $(2)),$(error \
-     Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!)))
+     Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))) \
+$(if $(filter true,$(BUILD_BROKEN_VINTF_PRODUCT_COPY_FILES)),, \
+  $(if $(filter $(TARGET_COPY_OUT_SYSTEM)/etc/vintf/% \
+                $(TARGET_COPY_OUT_SYSTEM)/manifest.xml \
+                $(TARGET_COPY_OUT_SYSTEM)/compatibility_matrix.xml,$(2)), \
+    $(error VINTF metadata found in PRODUCT_COPY_FILES: $(1), use vintf_fragments instead!)) \
+  $(if $(filter $(TARGET_COPY_OUT_PRODUCT)/etc/vintf/%,$(2)), \
+    $(error VINTF metadata found in PRODUCT_COPY_FILES: $(1), \
+      use PRODUCT_MANIFEST_FILES / DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE / vintf_compatibility_matrix / vintf_fragments instead!)) \
+  $(if $(filter $(TARGET_COPY_OUT_SYSTEM_EXT)/etc/vintf/%,$(2)), \
+    $(error VINTF metadata found in PRODUCT_COPY_FILES: $(1), \
+      use vintf_compatibility_matrix / vintf_fragments instead!)) \
+  $(if $(filter $(TARGET_COPY_OUT_VENDOR)/etc/vintf/% \
+                $(TARGET_COPY_OUT_VENDOR)/manifest.xml \
+                $(TARGET_COPY_OUT_VENDOR)/compatibility_matrix.xml,$(2)), \
+    $(error VINTF metadata found in PRODUCT_COPY_FILES: $(1), \
+      use DEVICE_MANIFEST_FILE / DEVICE_MATRIX_FILE / vintf_compatibility_matrix / vintf_fragments instead!)) \
+  $(if $(filter $(TARGET_COPY_OUT_ODM)/etc/vintf/% \
+                $(TARGET_COPY_OUT_ODM)/etc/manifest%,$(2)), \
+    $(error VINTF metadata found in PRODUCT_COPY_FILES: $(1), \
+      use ODM_MANIFEST_FILES / vintf_fragments instead!)) \
+)
 endef
 # filter out the duplicate <source file>:<dest file> pairs.
 unique_product_copy_files_pairs :=
@@ -1550,6 +1571,8 @@
 $(if $(filter $(2),userdata),\
     $(if $(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "userdata_fs_type=$(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
     $(if $(BOARD_USERDATAIMAGE_PARTITION_SIZE),$(hide) echo "userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE)" >> $(1))
+    $(if $(PRODUCT_FS_CASEFOLD),$(hide) echo "needs_casefold=$(PRODUCT_FS_CASEFOLD)" >> $(1))
+    $(if $(PRODUCT_QUOTA_PROJID),$(hide) echo "needs_projid=$(PRODUCT_QUOTA_PROJID)" >> $(1))
     $(hide) echo "userdata_selinux_fc=$(SELINUX_FC)" >> $(1)
 )
 $(if $(filter $(2),cache),\
@@ -2870,94 +2893,6 @@
       $(ALL_PDK_FUSION_FILES)) \
     $(PDK_FUSION_SYMLINK_STAMP)
 
-# Final Vendor VINTF manifest including fragments. This is not assembled
-# on the device because it depends on everything in a given device
-# image which defines a vintf_fragment.
-ifdef BUILT_VENDOR_MANIFEST
-BUILT_ASSEMBLED_VENDOR_MANIFEST := $(PRODUCT_OUT)/verified_assembled_vendor_manifest.xml
-ifeq (true,$(PRODUCT_ENFORCE_VINTF_MANIFEST))
-ifneq ($(strip $(DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE) $(DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE)),)
-$(BUILT_ASSEMBLED_VENDOR_MANIFEST): PRIVATE_SYSTEM_ASSEMBLE_VINTF_ENV_VARS := VINTF_ENFORCE_NO_UNUSED_HALS=true
-endif # DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE
-endif # PRODUCT_ENFORCE_VINTF_MANIFEST
-$(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(HOST_OUT_EXECUTABLES)/assemble_vintf
-$(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(BUILT_SYSTEM_MATRIX)
-$(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(BUILT_VENDOR_MANIFEST)
-$(BUILT_ASSEMBLED_VENDOR_MANIFEST): $(INTERNAL_VENDORIMAGE_FILES)
-
-$(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_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
-
-ifneq ($(my_board_extracted_kernel),true)
-ifndef INSTALLED_KERNEL_TARGET
-$(warning No INSTALLED_KERNEL_TARGET is defined when PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \
-    is true. Information about the updated kernel cannot be built into OTA update package. \
-    You can fix this by: (1) setting TARGET_NO_KERNEL to false and installing the built kernel \
-    to $(PRODUCT_OUT)/kernel, so that kernel information will be extracted from the built kernel; \
-    or (2) extracting kernel configuration and defining BOARD_KERNEL_CONFIG_FILE and \
-    BOARD_KERNEL_VERSION manually; or (3) unsetting PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \
-    manually.)
-else
-
-# Tools for decompression that is not in PATH.
-# Check $(EXTRACT_KERNEL) for decompression algorithms supported by the script.
-# Algorithms that are in the script but not in this list will be found in PATH.
-my_decompress_tools := \
-    lz4:$(HOST_OUT_EXECUTABLES)/lz4 \
-
-$(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 $(BUILT_KERNEL_VERSION_FILE)
-
-intermediates :=
-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):
-	@echo "Verifying vendor VINTF manifest."
-	PRODUCT_ENFORCE_VINTF_MANIFEST=$(PRODUCT_ENFORCE_VINTF_MANIFEST) \
-	$(PRIVATE_SYSTEM_ASSEMBLE_VINTF_ENV_VARS) \
-	$(HOST_OUT_EXECUTABLES)/assemble_vintf \
-	    $(PRIVATE_FLAGS) \
-	    -c $(BUILT_SYSTEM_MATRIX) \
-	    -i $(BUILT_VENDOR_MANIFEST) \
-	    $$([ -d $(TARGET_OUT_VENDOR)/etc/vintf/manifest ] && \
-	        find $(TARGET_OUT_VENDOR)/etc/vintf/manifest -type f -name "*.xml" | \
-	        sed "s/^/-i /" | tr '\n' ' ') -o $@
-endif # BUILT_VENDOR_MANIFEST
-
 # platform.zip depends on $(INTERNAL_VENDORIMAGE_FILES).
 $(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_VENDORIMAGE_FILES)
 
@@ -3004,9 +2939,6 @@
 
 # We just build this directly to the install location.
 INSTALLED_VENDORIMAGE_TARGET := $(BUILT_VENDORIMAGE_TARGET)
-ifdef BUILT_VENDOR_MANIFEST
-$(INSTALLED_VENDORIMAGE_TARGET): $(BUILT_ASSEMBLED_VENDOR_MANIFEST)
-endif
 $(INSTALLED_VENDORIMAGE_TARGET): \
     $(INTERNAL_USERIMAGES_DEPS) \
     $(INTERNAL_VENDORIMAGE_FILES) \
@@ -3081,52 +3013,6 @@
 endif
 
 # -----------------------------------------------------------------
-# Final Framework VINTF manifest including fragments. This is not assembled
-# on the device because it depends on everything in a given device
-# image which defines a vintf_fragment.
-
-ifdef BUILDING_SYSTEM_IMAGE
-
-ifndef BOARD_USES_PRODUCTIMAGE
-  # If no product image at all, check system manifest directly against device matrix.
-  check_framework_manifest := true
-else ifdef BUILDING_PRODUCT_IMAGE
-  # If device has a product image, only check if the product image is built.
-  check_framework_manifest := true
-endif
-
-# TODO (b/131425279): delete this line once build_mixed script can correctly merge system and
-# product manifests.
-check_framework_manifest := true
-
-ifeq ($(check_framework_manifest),true)
-
-BUILT_ASSEMBLED_FRAMEWORK_MANIFEST := $(PRODUCT_OUT)/verified_assembled_framework_manifest.xml
-$(BUILT_ASSEMBLED_FRAMEWORK_MANIFEST): $(HOST_OUT_EXECUTABLES)/assemble_vintf \
-                                       $(BUILT_VENDOR_MATRIX) \
-                                       $(BUILT_SYSTEM_MANIFEST) \
-                                       $(FULL_SYSTEMIMAGE_DEPS) \
-                                       $(BUILT_PRODUCT_MANIFEST) \
-                                       $(BUILT_PRODUCTIMAGE_TARGET)
-	@echo "Verifying framework VINTF manifest."
-	PRODUCT_ENFORCE_VINTF_MANIFEST=$(PRODUCT_ENFORCE_VINTF_MANIFEST) \
-	$(HOST_OUT_EXECUTABLES)/assemble_vintf \
-	    -o $@ \
-	    -c $(BUILT_VENDOR_MATRIX) \
-	    -i $(BUILT_SYSTEM_MANIFEST) \
-	    $(addprefix -i ,\
-	      $(filter $(TARGET_OUT)/etc/vintf/manifest/%.xml,$(FULL_SYSTEMIMAGE_DEPS)) \
-	      $(BUILT_PRODUCT_MANIFEST) \
-	      $(filter $(TARGET_OUT_PRODUCT)/etc/vintf/manifest/%.xml,$(INTERNAL_PRODUCTIMAGE_FILES)))
-
-droidcore: $(BUILT_ASSEMBLED_FRAMEWORK_MANIFEST)
-
-endif # check_framework_manifest
-check_framework_manifest :=
-
-endif # BUILDING_SYSTEM_IMAGE
-
-# -----------------------------------------------------------------
 # system_ext partition image
 ifdef BUILDING_SYSTEM_EXT_IMAGE
 INTERNAL_SYSTEM_EXTIMAGE_FILES := \
@@ -3636,6 +3522,186 @@
 endif # BOARD_AVB_ENABLE
 
 # -----------------------------------------------------------------
+# Check VINTF of build
+
+ifndef TARGET_BUILD_APPS
+intermediates := $(call intermediates-dir-for,PACKAGING,check_vintf_all)
+check_vintf_all_deps :=
+
+# The build system only writes VINTF metadata to */etc/vintf paths. Legacy paths aren't needed here
+# because they are only used for prebuilt images.
+check_vintf_common_srcs_patterns := \
+  $(TARGET_OUT)/etc/vintf/% \
+  $(TARGET_OUT_VENDOR)/etc/vintf/% \
+  $(TARGET_OUT_ODM)/etc/vintf/% \
+  $(TARGET_OUT_PRODUCT)/etc/vintf/% \
+  $(TARGET_OUT_SYSTEM_EXT)/etc/vintf/% \
+
+check_vintf_common_srcs := $(sort $(filter $(check_vintf_common_srcs_patterns), \
+  $(INTERNAL_SYSTEMIMAGE_FILES) \
+  $(INTERNAL_VENDORIMAGE_FILES) \
+  $(INTERNAL_ODMIMAGE_FILES) \
+  $(INTERNAL_PRODUCTIMAGE_FILES) \
+  $(INTERNAL_SYSTEM_EXTIMAGE_FILES) \
+))
+check_vintf_common_srcs_patterns :=
+
+check_vintf_has_system :=
+check_vintf_has_vendor :=
+
+# -- Check system manifest / matrix including fragments (excluding other framework manifests / matrices, e.g. product);
+check_vintf_system_deps := $(filter $(TARGET_OUT)/etc/vintf/%, $(check_vintf_common_srcs))
+ifneq ($(check_vintf_system_deps),)
+check_vintf_has_system := true
+check_vintf_system_log := $(intermediates)/check_vintf_system_log
+check_vintf_all_deps += $(check_vintf_system_log)
+$(check_vintf_system_log): $(HOST_OUT_EXECUTABLES)/checkvintf $(check_vintf_system_deps)
+	@( $< --check-one --dirmap /system:$(TARGET_OUT) > $@ 2>&1 ) || ( cat $@ && exit 1 )
+check_vintf_system_log :=
+endif # check_vintf_system_deps
+check_vintf_system_deps :=
+
+# -- Check vendor manifest / matrix including fragments (excluding other device manifests / matrices)
+check_vintf_vendor_deps := $(filter $(TARGET_OUT_VENDOR)/etc/vintf/%, $(check_vintf_common_srcs))
+ifneq ($(check_vintf_vendor_deps),)
+check_vintf_has_vendor := true
+check_vintf_vendor_log := $(intermediates)/check_vintf_vendor_log
+check_vintf_all_deps += $(check_vintf_vendor_log)
+$(check_vintf_vendor_log): $(HOST_OUT_EXECUTABLES)/checkvintf $(check_vintf_vendor_deps)
+	@( $< --check-one --dirmap /vendor:$(TARGET_OUT_VENDOR) > $@ 2>&1 ) || ( cat $@ && exit 1 )
+check_vintf_vendor_log :=
+endif # check_vintf_vendor_deps
+check_vintf_vendor_deps :=
+
+# -- Check VINTF compatibility of build.
+# Skip partial builds; only check full builds. Only check if:
+# - PRODUCT_ENFORCE_VINTF_MANIFEST is true
+# - system / vendor VINTF metadata exists
+# - Building product / system_ext / odm images if board has product / system_ext / odm images
+ifeq ($(PRODUCT_ENFORCE_VINTF_MANIFEST),true)
+ifeq ($(check_vintf_has_system),true)
+ifeq ($(check_vintf_has_vendor),true)
+ifeq ($(filter true,$(BUILDING_ODM_IMAGE)),$(filter true,$(BOARD_USES_ODMIMAGE)))
+ifeq ($(filter true,$(BUILDING_PRODUCT_IMAGE)),$(filter true,$(BOARD_USES_PRODUCTIMAGE)))
+ifeq ($(filter true,$(BUILDING_SYSTEM_EXT_IMAGE)),$(filter true,$(BOARD_USES_SYSTEM_EXTIMAGE)))
+
+check_vintf_compatible_log := $(intermediates)/check_vintf_compatible_log
+check_vintf_all_deps += $(check_vintf_compatible_log)
+
+check_vintf_compatible_args :=
+check_vintf_compatible_deps := $(check_vintf_common_srcs)
+
+# -- Kernel version and configurations.
+ifeq ($(PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS),true)
+
+BUILT_KERNEL_CONFIGS_FILE := $(intermediates)/kernel_configs.txt
+BUILT_KERNEL_VERSION_FILE := $(intermediates)/kernel_version.txt
+
+my_board_extracted_kernel :=
+
+# 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_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
+
+ifneq ($(my_board_extracted_kernel),true)
+ifndef INSTALLED_KERNEL_TARGET
+$(warning No INSTALLED_KERNEL_TARGET is defined when PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \
+    is true. Information about the updated kernel cannot be built into OTA update package. \
+    You can fix this by: (1) setting TARGET_NO_KERNEL to false and installing the built kernel \
+    to $(PRODUCT_OUT)/kernel, so that kernel information will be extracted from the built kernel; \
+    or (2) extracting kernel configuration and defining BOARD_KERNEL_CONFIG_FILE and \
+    BOARD_KERNEL_VERSION manually; or (3) unsetting PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS \
+    manually.)
+else
+
+# Tools for decompression that is not in PATH.
+# Check $(EXTRACT_KERNEL) for decompression algorithms supported by the script.
+# Algorithms that are in the script but not in this list will be found in PATH.
+my_decompress_tools := \
+    lz4:$(HOST_OUT_EXECUTABLES)/lz4 \
+
+$(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 $(BUILT_KERNEL_VERSION_FILE)
+
+my_decompress_tools :=
+
+endif # my_board_extracted_kernel
+my_board_extracted_kernel :=
+
+endif # INSTALLED_KERNEL_TARGET
+
+check_vintf_compatible_args += --kernel $$(cat $(BUILT_KERNEL_VERSION_FILE)):$(BUILT_KERNEL_CONFIGS_FILE)
+check_vintf_compatible_deps += $(BUILT_KERNEL_CONFIGS_FILE) $(BUILT_KERNEL_VERSION_FILE)
+
+endif # PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS
+
+check_vintf_compatible_args += \
+  --dirmap /system:$(TARGET_OUT) \
+  --dirmap /vendor:$(TARGET_OUT_VENDOR) \
+  --dirmap /odm:$(TARGET_OUT_ODM) \
+  --dirmap /product:$(TARGET_OUT_PRODUCT) \
+  --dirmap /system_ext:$(TARGET_OUT_SYSTEM_EXT) \
+
+ifdef PRODUCT_SHIPPING_API_LEVEL
+check_vintf_compatible_args += --property ro.product.first_api_level=$(PRODUCT_SHIPPING_API_LEVEL)
+endif # PRODUCT_SHIPPING_API_LEVEL
+
+$(check_vintf_compatible_log): PRIVATE_CHECK_VINTF_ARGS := $(check_vintf_compatible_args)
+$(check_vintf_compatible_log): PRIVATE_CHECK_VINTF_DEPS := $(check_vintf_compatible_deps)
+$(check_vintf_compatible_log): $(HOST_OUT_EXECUTABLES)/checkvintf $(check_vintf_compatible_deps)
+	@echo -n -e 'Deps: \n  ' > $@
+	@sed 's/ /\n  /g' <<< "$(PRIVATE_CHECK_VINTF_DEPS)" >> $@
+	@echo -n -e 'Args: \n  ' >> $@
+	@cat <<< "$(PRIVATE_CHECK_VINTF_ARGS)" >> $@
+	@echo -n -e 'For empty SKU:' >> $@
+	@( $< --check-compat $(PRIVATE_CHECK_VINTF_ARGS) >> $@ 2>&1 ) || ( cat $@ && exit 1 )
+	$(foreach sku,$(ODM_MANIFEST_SKUS), \
+	  echo "For SKU = $(sku):" >> $@; \
+	  ( $< --check-compat $(PRIVATE_CHECK_VINTF_ARGS) \
+	      --property ro.boot.product.hardware.sku=$(sku) >> $@ 2>&1 ) || ( cat $@ && exit 1 ); )
+
+check_vintf_compatible_log :=
+check_vintf_compatible_args :=
+check_vintf_compatible_deps :=
+
+endif # BUILDING_SYSTEM_EXT_IMAGE equals BOARD_USES_SYSTEM_EXTIMAGE
+endif # BUILDING_PRODUCT_IMAGE equals BOARD_USES_PRODUCTIMAGE
+endif # BUILDING_ODM_IMAGE equals BOARD_USES_ODMIMAGE
+endif # check_vintf_has_vendor
+endif # check_vintf_has_system
+endif # PRODUCT_ENFORCE_VINTF_MANIFEST
+
+# Add all logs of VINTF checks to dist builds
+droid_targets: $(check_vintf_all_deps)
+$(call dist-for-goals, droid_targets, $(check_vintf_all_deps))
+
+# Helper alias to check all VINTF of current build.
+.PHONY: check-vintf-all
+check-vintf-all: $(check_vintf_all_deps)
+	$(foreach file,$^,echo "$(file)"; cat "$(file)"; echo;)
+
+check_vintf_has_vendor :=
+check_vintf_has_system :=
+check_vintf_common_srcs :=
+check_vintf_all_deps :=
+intermediates :=
+endif # !TARGET_BUILD_APPS
+
+# -----------------------------------------------------------------
 # Check image sizes <= size of super partition
 
 ifeq (,$(TARGET_BUILD_APPS))
@@ -3764,6 +3830,7 @@
   mkbootfs \
   mkbootimg \
   mke2fs \
+  mke2fs.conf \
   mkf2fsuserimg.sh \
   mksquashfs \
   mksquashfsimage.sh \
@@ -3778,12 +3845,22 @@
   simg2img \
   sload_f2fs \
   tune2fs \
+  unpack_bootimg \
   update_host_simulator \
   validate_target_files \
   verity_signer \
   verity_verifier \
   zipalign \
 
+# Additional tools to unpack and repack the apex file.
+INTERNAL_OTATOOLS_MODULES += \
+  apexer \
+  deapexer \
+  debugfs_static \
+  merge_zips \
+  resize2fs \
+  soong_zip \
+
 ifeq (true,$(PRODUCT_SUPPORTS_VBOOT))
 INTERNAL_OTATOOLS_MODULES += \
   futility \
@@ -3839,7 +3916,7 @@
 	mkdir -p $(dir $@)
 	$(call copy-files-with-structure,$(PRIVATE_OTATOOLS_PACKAGE_FILES),$(HOST_OUT)/,$(PRIVATE_ZIP_ROOT))
 	$(call copy-files-with-structure,$(PRIVATE_OTATOOLS_RELEASETOOLS),build/make/tools/,$(PRIVATE_ZIP_ROOT))
-	cp $(SOONG_ZIP) $(ZIP2ZIP) $(PRIVATE_ZIP_ROOT)/bin/
+	cp $(SOONG_ZIP) $(ZIP2ZIP) $(MERGE_ZIPS) $(PRIVATE_ZIP_ROOT)/bin/
 	$(SOONG_ZIP) -o $@ -C $(PRIVATE_ZIP_ROOT) -D $(PRIVATE_ZIP_ROOT)
 
 .PHONY: otatools-package
diff --git a/core/android_manifest.mk b/core/android_manifest.mk
index 06bea5e..8fab9c6 100644
--- a/core/android_manifest.mk
+++ b/core/android_manifest.mk
@@ -42,19 +42,21 @@
 endif
 
 my_target_sdk_version := $(call module-target-sdk-version)
+my_min_sdk_version := $(call module-min-sdk-version)
 
 ifdef TARGET_BUILD_APPS
   ifndef TARGET_BUILD_APPS_USE_PREBUILT_SDK
     ifeq ($(my_target_sdk_version),$(PLATFORM_VERSION_CODENAME))
       ifdef UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT
         my_target_sdk_version := $(my_target_sdk_version).$$(cat $(API_FINGERPRINT))
+        my_min_sdk_version := $(my_min_sdk_version).$$(cat $(API_FINGERPRINT))
         $(fixed_android_manifest): $(API_FINGERPRINT)
       endif
     endif
   endif
 endif
 
-$(fixed_android_manifest): PRIVATE_MIN_SDK_VERSION := $(call module-min-sdk-version)
+$(fixed_android_manifest): PRIVATE_MIN_SDK_VERSION := $(my_min_sdk_version)
 $(fixed_android_manifest): PRIVATE_TARGET_SDK_VERSION := $(my_target_sdk_version)
 
 my_exported_sdk_libs_file := $(call local-intermediates-dir,COMMON)/exported-sdk-libs
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 6b80a15..cce6ec1 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -800,22 +800,28 @@
 my_required_modules += $(LOCAL_REQUIRED_MODULES_$($(my_prefix)OS))
 endif
 
-###############################################################################
-## When compiling against the VNDK, add the .vendor suffix to required modules.
-###############################################################################
+##########################################################################
+## When compiling against the VNDK, add the .vendor or .product suffix to
+## required modules.
+##########################################################################
 ifneq ($(LOCAL_USE_VNDK),)
-  ####################################################
-  ## Soong modules may be built twice, once for /system
-  ## and once for /vendor. If we're using the VNDK,
-  ## switch all soong libraries over to the /vendor
-  ## variant.
-  ####################################################
+  #####################################################
+  ## Soong modules may be built three times, once for
+  ## /system, once for /vendor and once for /product.
+  ## If we're using the VNDK, switch all soong
+  ## libraries over to the /vendor or /product variant.
+  #####################################################
   ifneq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
     # We don't do this renaming for soong-defined modules since they already
-    # have correct names (with .vendor suffix when necessary) in their
-    # LOCAL_*_LIBRARIES.
-    my_required_modules := $(foreach l,$(my_required_modules),\
-      $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+    # have correct names (with .vendor or .product suffix when necessary) in
+    # their LOCAL_*_LIBRARIES.
+    ifeq ($(LOCAL_USE_VNDK_PRODUCT),true)
+      my_required_modules := $(foreach l,$(my_required_modules),\
+        $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+    else
+      my_required_modules := $(foreach l,$(my_required_modules),\
+        $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+    endif
   endif
 endif
 
diff --git a/core/binary.mk b/core/binary.mk
index cf3cfd5..a62f76c 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -816,7 +816,7 @@
     $(intermediates)/,$(y_yacc_sources:.y=.c))
 ifneq ($(y_yacc_cs),)
 $(y_yacc_cs): $(intermediates)/%.c: \
-    $(TOPDIR)$(LOCAL_PATH)/%.y $(BISON) $(BISON_DATA) \
+    $(TOPDIR)$(LOCAL_PATH)/%.y $(BISON) $(BISON_DATA) $(M4) \
     $(my_additional_dependencies)
 	$(call transform-y-to-c-or-cpp)
 $(call track-src-file-gen,$(y_yacc_sources),$(y_yacc_cs))
@@ -829,7 +829,7 @@
     $(intermediates)/,$(yy_yacc_sources:.yy=$(LOCAL_CPP_EXTENSION)))
 ifneq ($(yy_yacc_cpps),)
 $(yy_yacc_cpps): $(intermediates)/%$(LOCAL_CPP_EXTENSION): \
-    $(TOPDIR)$(LOCAL_PATH)/%.yy $(BISON) $(BISON_DATA) \
+    $(TOPDIR)$(LOCAL_PATH)/%.yy $(BISON) $(BISON_DATA) $(M4) \
     $(my_additional_dependencies)
 	$(call transform-y-to-c-or-cpp)
 $(call track-src-file-gen,$(yy_yacc_sources),$(yy_yacc_cpps))
@@ -845,6 +845,7 @@
 l_lex_cs := $(addprefix \
     $(intermediates)/,$(l_lex_sources:.l=.c))
 ifneq ($(l_lex_cs),)
+$(l_lex_cs): $(LEX) $(M4)
 $(l_lex_cs): $(intermediates)/%.c: \
     $(TOPDIR)$(LOCAL_PATH)/%.l
 	$(transform-l-to-c-or-cpp)
@@ -857,6 +858,7 @@
 ll_lex_cpps := $(addprefix \
     $(intermediates)/,$(ll_lex_sources:.ll=$(LOCAL_CPP_EXTENSION)))
 ifneq ($(ll_lex_cpps),)
+$(ll_lex_cpps): $(LEX) $(M4)
 $(ll_lex_cpps): $(intermediates)/%$(LOCAL_CPP_EXTENSION): \
     $(TOPDIR)$(LOCAL_PATH)/%.ll
 	$(transform-l-to-c-or-cpp)
@@ -1143,22 +1145,35 @@
 ## When compiling against the VNDK, use LL-NDK libraries
 ###########################################################
 ifneq ($(LOCAL_USE_VNDK),)
-  ####################################################
-  ## Soong modules may be built twice, once for /system
-  ## and once for /vendor. If we're using the VNDK,
-  ## switch all soong libraries over to the /vendor
-  ## variant.
-  ####################################################
-  my_whole_static_libraries := $(foreach l,$(my_whole_static_libraries),\
-    $(if $(SPLIT_VENDOR.STATIC_LIBRARIES.$(l)),$(l).vendor,$(l)))
-  my_static_libraries := $(foreach l,$(my_static_libraries),\
-    $(if $(SPLIT_VENDOR.STATIC_LIBRARIES.$(l)),$(l).vendor,$(l)))
-  my_shared_libraries := $(foreach l,$(my_shared_libraries),\
-    $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
-  my_system_shared_libraries := $(foreach l,$(my_system_shared_libraries),\
-    $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
-  my_header_libraries := $(foreach l,$(my_header_libraries),\
-    $(if $(SPLIT_VENDOR.HEADER_LIBRARIES.$(l)),$(l).vendor,$(l)))
+  #####################################################
+  ## Soong modules may be built three times, once for
+  ## /system, once for /vendor and once for /product.
+  ## If we're using the VNDK, switch all soong
+  ## libraries over to the /vendor or /product variant.
+  #####################################################
+  ifeq ($(LOCAL_USE_VNDK_PRODUCT),true)
+    my_whole_static_libraries := $(foreach l,$(my_whole_static_libraries),\
+      $(if $(SPLIT_PRODUCT.STATIC_LIBRARIES.$(l)),$(l).product,$(l)))
+    my_static_libraries := $(foreach l,$(my_static_libraries),\
+      $(if $(SPLIT_PRODUCT.STATIC_LIBRARIES.$(l)),$(l).product,$(l)))
+    my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+      $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+    my_system_shared_libraries := $(foreach l,$(my_system_shared_libraries),\
+      $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+    my_header_libraries := $(foreach l,$(my_header_libraries),\
+      $(if $(SPLIT_PRODUCT.HEADER_LIBRARIES.$(l)),$(l).product,$(l)))
+  else
+    my_whole_static_libraries := $(foreach l,$(my_whole_static_libraries),\
+      $(if $(SPLIT_VENDOR.STATIC_LIBRARIES.$(l)),$(l).vendor,$(l)))
+    my_static_libraries := $(foreach l,$(my_static_libraries),\
+      $(if $(SPLIT_VENDOR.STATIC_LIBRARIES.$(l)),$(l).vendor,$(l)))
+    my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+      $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+    my_system_shared_libraries := $(foreach l,$(my_system_shared_libraries),\
+      $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+    my_header_libraries := $(foreach l,$(my_header_libraries),\
+      $(if $(SPLIT_VENDOR.HEADER_LIBRARIES.$(l)),$(l).vendor,$(l)))
+  endif
 endif
 
 # Platform can use vendor public libraries. If a required shared lib is one of
@@ -1205,6 +1220,7 @@
 my_allowed_types := $(my_allowed_ndk_types)
 else ifdef LOCAL_USE_VNDK
     _name := $(patsubst %.vendor,%,$(LOCAL_MODULE))
+    _name := $(patsubst %.product,%,$(LOCAL_MODULE))
     ifneq ($(filter $(_name),$(VNDK_CORE_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) $(LLNDK_LIBRARIES)),)
         ifeq ($(filter $(_name),$(VNDK_PRIVATE_LIBRARIES)),)
             my_link_type := native:vndk
@@ -1213,6 +1229,12 @@
         endif
         my_warn_types :=
         my_allowed_types := native:vndk native:vndk_private
+    else ifeq ($(LOCAL_USE_VNDK_PRODUCT),true)
+        # Modules installed to /product cannot directly depend on modules marked
+        # with vendor_available: false
+        my_link_type := native:product
+        my_warn_types :=
+        my_allowed_types := native:product native:vndk native:platform_vndk
     else
         # Modules installed to /vendor cannot directly depend on modules marked
         # with vendor_available: false
diff --git a/core/board_config.mk b/core/board_config.mk
index 00ac0be..5d658dc 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -26,6 +26,7 @@
   BOARD_KERNEL_CMDLINE \
   BOARD_KERNEL_BASE \
   BOARD_USES_GENERIC_AUDIO \
+  BOARD_USES_RECOVERY_AS_BOOT \
   BOARD_VENDOR_USE_AKMD \
   BOARD_WPA_SUPPLICANT_DRIVER \
   BOARD_WLAN_DEVICE \
@@ -86,10 +87,11 @@
 
 _build_broken_var_list := \
   BUILD_BROKEN_DUP_RULES \
+  BUILD_BROKEN_OUTSIDE_INCLUDE_DIRS \
   BUILD_BROKEN_PREBUILT_ELF_FILES \
   BUILD_BROKEN_TREBLE_SYSPROP_NEVERALLOW \
   BUILD_BROKEN_USES_NETWORK \
-  BUILD_BROKEN_OUTSIDE_INCLUDE_DIRS \
+  BUILD_BROKEN_VINTF_PRODUCT_COPY_FILES \
 
 _build_broken_var_list += \
   $(foreach m,$(AVAILABLE_BUILD_MODULE_TYPES) \
@@ -98,7 +100,8 @@
     BUILD_BROKEN_USES_$(m))
 
 _board_true_false_vars := $(_build_broken_var_list)
-_board_strip_readonly_list += $(_build_broken_var_list)
+_board_strip_readonly_list += $(_build_broken_var_list) \
+  BUILD_BROKEN_NINJA_USES_ENV_VARS
 
 # Conditional to building on linux, as dex2oat currently does not work on darwin.
 ifeq ($(HOST_OS),linux)
@@ -109,6 +112,7 @@
 # Broken build defaults
 # ###############################################################
 $(foreach v,$(_build_broken_var_list),$(eval $(v) :=))
+BUILD_BROKEN_NINJA_USES_ENV_VARS :=
 
 # Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
 # or under vendor/*/$(TARGET_DEVICE).  Search in both places, but
@@ -618,11 +622,15 @@
 ###########################################
 # Handle BUILD_BROKEN_USES_BUILD_*
 
-$(foreach m,$(DEFAULT_WARNING_BUILD_MODULE_TYPES),\
+$(foreach m,$(filter-out BUILD_COPY_HEADERS,$(DEFAULT_WARNING_BUILD_MODULE_TYPES)),\
   $(if $(filter false,$(BUILD_BROKEN_USES_$(m))),\
     $(KATI_obsolete_var $(m),Please convert to Soong),\
     $(KATI_deprecated_var $(m),Please convert to Soong)))
 
+$(if $(filter false,$(BUILD_BROKEN_USES_BUILD_COPY_HEADERS)),\
+  $(KATI_obsolete_var BUILD_COPY_HEADERS,See $(CHANGES_URL)#copy_headers),\
+  $(KATI_deprecated_var BUILD_COPY_HEADERS,See $(CHANGES_URL)#copy_headers))
+
 $(foreach m,$(DEFAULT_ERROR_BUILD_MODULE_TYPES),\
   $(if $(filter true,$(BUILD_BROKEN_USES_$(m))),\
     $(KATI_deprecated_var $(m),Please convert to Soong),\
diff --git a/core/build_rro_package.mk b/core/build_rro_package.mk
index e5d7685..ae528bd 100644
--- a/core/build_rro_package.mk
+++ b/core/build_rro_package.mk
@@ -32,6 +32,12 @@
   LOCAL_MODULE_PATH := $(partition)/overlay/$(LOCAL_RRO_THEME)
 endif
 
+# Do not remove resources without default values nor dedupe resource
+# configurations with the same value
+LOCAL_AAPT_FLAGS += \
+    --no-resource-deduping \
+    --no-resource-removal
+
 partition :=
 
 include $(BUILD_SYSTEM)/package.mk
diff --git a/core/cc_prebuilt_internal.mk b/core/cc_prebuilt_internal.mk
index 6313019..1d959b5 100644
--- a/core/cc_prebuilt_internal.mk
+++ b/core/cc_prebuilt_internal.mk
@@ -85,6 +85,7 @@
 my_link_type := native:ndk:$(my_ndk_stl_family):$(my_ndk_stl_link_type)
 else ifdef LOCAL_USE_VNDK
     _name := $(patsubst %.vendor,%,$(LOCAL_MODULE))
+    _name := $(patsubst %.product,%,$(LOCAL_MODULE))
     ifneq ($(filter $(_name),$(VNDK_CORE_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) $(LLNDK_LIBRARIES)),)
         ifeq ($(filter $(_name),$(VNDK_PRIVATE_LIBRARIES)),)
             my_link_type := native:vndk
@@ -92,7 +93,11 @@
             my_link_type := native:vndk_private
         endif
     else
-        my_link_type := native:vendor
+        ifeq ($(LOCAL_USE_VNDK_PRODUCT),true)
+            my_link_type := native:product
+        else
+            my_link_type := native:vendor
+        endif
     endif
 else ifneq ($(filter $(TARGET_RECOVERY_OUT)/%,$(LOCAL_MODULE_PATH)),)
 my_link_type := native:recovery
@@ -136,8 +141,13 @@
 
 ifdef my_shared_libraries
 ifdef LOCAL_USE_VNDK
-  my_shared_libraries := $(foreach l,$(my_shared_libraries),\
-    $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+  ifeq ($(LOCAL_USE_VNDK_PRODUCT),true)
+    my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+      $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+  else
+    my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+      $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+  endif
 endif
 $(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)DEPENDENCIES_ON_SHARED_LIBRARIES += \
   $(my_register_name):$(LOCAL_INSTALLED_MODULE):$(subst $(space),$(comma),$(my_shared_libraries))
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 6c3b249..bbc117f 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -29,6 +29,7 @@
 LOCAL_CC:=
 LOCAL_CERTIFICATE:=
 LOCAL_CFLAGS:=
+LOCAL_CHECK_SAME_VNDK_VARIANTS:=
 LOCAL_CHECKED_MODULE:=
 LOCAL_C_INCLUDES:=
 LOCAL_CLANG:=
@@ -184,7 +185,6 @@
 LOCAL_NO_CRT:=
 LOCAL_NO_DEFAULT_COMPILER_FLAGS:=
 LOCAL_NO_FPIE :=
-LOCAL_NO_LIBGCC:=
 LOCAL_NO_LIBCRT_BUILTINS:=
 LOCAL_NO_NOTICE_FILE:=
 LOCAL_NO_PIC:=
@@ -304,6 +304,7 @@
 LOCAL_USE_AAPT2:=
 LOCAL_USE_CLANG_LLD:=
 LOCAL_USE_VNDK:=
+LOCAL_USE_VNDK_PRODUCT:=
 LOCAL_USES_LIBRARIES:=
 LOCAL_VENDOR_MODULE:=
 LOCAL_VINTF_FRAGMENTS:=
diff --git a/core/config.mk b/core/config.mk
index 4cc78b8..c5f54de 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -553,6 +553,7 @@
 BISON := $(prebuilt_build_tools_bin_noasan)/bison
 YACC := $(BISON) -d
 BISON_DATA := $(wildcard $(BISON_PKGDATADIR)/* $(BISON_PKGDATADIR)/*/*)
+M4 :=$= $(prebuilt_build_tools_bin_noasan)/m4
 
 YASM := prebuilts/misc/$(BUILD_OS)-$(HOST_PREBUILT_ARCH)/yasm/yasm
 
@@ -709,19 +710,37 @@
   PRODUCT_USE_VNDK := $(PRODUCT_USE_VNDK_OVERRIDE)
 else ifeq ($(PRODUCT_SHIPPING_API_LEVEL),)
   # No shipping level defined
-else ifeq ($(call math_gt_or_eq,27,$(PRODUCT_SHIPPING_API_LEVEL)),)
+else ifeq ($(call math_gt,$(PRODUCT_SHIPPING_API_LEVEL),27),true)
   PRODUCT_USE_VNDK := $(PRODUCT_FULL_TREBLE)
 endif
 
+# Define PRODUCT_PRODUCT_VNDK_VERSION if PRODUCT_USE_VNDK is true and
+# PRODUCT_SHIPPING_API_LEVEL is greater than 29.
+PRODUCT_USE_PRODUCT_VNDK := false
 ifeq ($(PRODUCT_USE_VNDK),true)
+  ifneq ($(PRODUCT_USE_PRODUCT_VNDK_OVERRIDE),)
+    PRODUCT_USE_PRODUCT_VNDK := $(PRODUCT_USE_PRODUCT_VNDK_OVERRIDE)
+  else ifeq ($(PRODUCT_SHIPPING_API_LEVEL),)
+    # No shipping level defined
+  else ifeq ($(call math_gt,$(PRODUCT_SHIPPING_API_LEVEL),29),true)
+    PRODUCT_USE_PRODUCT_VNDK := true
+  endif
+
   ifndef BOARD_VNDK_VERSION
     BOARD_VNDK_VERSION := current
   endif
+
+  ifeq ($(PRODUCT_USE_PRODUCT_VNDK),true)
+    ifndef PRODUCT_PRODUCT_VNDK_VERSION
+      PRODUCT_PRODUCT_VNDK_VERSION := current
+    endif
+  endif
 endif
 
-$(KATI_obsolete_var PRODUCT_USE_VNDK_OVERRIDE,Use PRODUCT_USE_VNDK instead)
-.KATI_READONLY := \
-    PRODUCT_USE_VNDK
+$(KATI_obsolete_var PRODUCT_USE_VNDK,Use BOARD_VNDK_VERSION instead)
+$(KATI_obsolete_var PRODUCT_USE_VNDK_OVERRIDE,Use BOARD_VNDK_VERSION instead)
+$(KATI_obsolete_var PRODUCT_USE_PRODUCT_VNDK,Use PRODUCT_PRODUCT_VNDK_VERSION instead)
+$(KATI_obsolete_var PRODUCT_USE_PRODUCT_VNDK_OVERRIDE,Use PRODUCT_PRODUCT_VNDK_VERSION instead)
 
 # Set BOARD_SYSTEMSDK_VERSIONS to the latest SystemSDK version starting from P-launching
 # devices if unset.
diff --git a/core/cxx_stl_setup.mk b/core/cxx_stl_setup.mk
index 6571d99..a2abb1a 100644
--- a/core/cxx_stl_setup.mk
+++ b/core/cxx_stl_setup.mk
@@ -76,17 +76,27 @@
         my_ldflags += -nostdlib++
     else
         my_static_libraries += libc++demangle
-        ifeq (arm,$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH))
-            my_static_libraries += libunwind_llvm
-            my_ldflags += -Wl,--exclude-libs,libunwind_llvm.a
-        endif
 
         ifeq ($(my_link_type),static)
             my_static_libraries += libm libc
+            ifeq (arm,$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH))
+                my_static_libraries += libunwind_llvm
+                my_ldflags += -Wl,--exclude-libs,libunwind_llvm.a
+            else
+                my_static_libraries += libgcc_stripped
+                my_ldflags += -Wl,--exclude-libs,libgcc_stripped.a
+            endif
         endif
     endif
 else ifeq ($(my_cxx_stl),ndk)
-    # Using an NDK STL. Handled in binary.mk.
+    # Using an NDK STL. Handled in binary.mk, except for the unwinder.
+    ifeq (arm,$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH))
+        my_static_libraries += libunwind_llvm
+        my_ldflags += -Wl,--exclude-libs,libunwind_llvm.a
+    else
+        my_static_libraries += libgcc_stripped
+        my_ldflags += -Wl,--exclude-libs,libgcc_stripped.a
+    endif
 else ifeq ($(my_cxx_stl),libstdc++)
     $(error $(LOCAL_PATH): $(LOCAL_MODULE): libstdc++ is not supported)
 else ifeq ($(my_cxx_stl),none)
diff --git a/core/definitions.mk b/core/definitions.mk
index 63e609e..fd785b8 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -108,6 +108,9 @@
 # All tests that should be skipped in presubmit check.
 ALL_DISABLED_PRESUBMIT_TESTS :=
 
+# All compatibility suites mentioned in LOCAL_COMPATIBILITY_SUITES
+ALL_COMPATIBILITY_SUITES :=
+
 ###########################################################
 ## Debugging; prints a variable list to stdout
 ###########################################################
@@ -886,7 +889,7 @@
 define transform-l-to-c-or-cpp
 @echo "Lex: $(PRIVATE_MODULE) <= $<"
 @mkdir -p $(dir $@)
-$(hide) $(LEX) -o$@ $<
+M4=$(M4) $(LEX) -o$@ $<
 endef
 
 ###########################################################
@@ -897,7 +900,7 @@
 define transform-y-to-c-or-cpp
 @echo "Yacc: $(PRIVATE_MODULE) <= $<"
 @mkdir -p $(dir $@)
-$(YACC) $(PRIVATE_YACCFLAGS) \
+M4=$(M4) $(YACC) $(PRIVATE_YACCFLAGS) \
   --defines=$(basename $@).h \
   -o $@ $<
 endef
@@ -1717,7 +1720,6 @@
   $(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_COVERAGE_LIB)) \
   $(PRIVATE_TARGET_LIBCRT_BUILTINS) \
   $(PRIVATE_TARGET_LIBATOMIC) \
-  $(PRIVATE_TARGET_LIBGCC) \
   $(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
   $(PRIVATE_LDFLAGS) \
   $(PRIVATE_ALL_SHARED_LIBRARIES) \
@@ -1753,7 +1755,6 @@
   $(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_COVERAGE_LIB)) \
   $(PRIVATE_TARGET_LIBCRT_BUILTINS) \
   $(PRIVATE_TARGET_LIBATOMIC) \
-  $(PRIVATE_TARGET_LIBGCC) \
   $(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
   $(PRIVATE_LDFLAGS) \
   $(PRIVATE_ALL_SHARED_LIBRARIES) \
@@ -1800,7 +1801,6 @@
   $(PRIVATE_TARGET_LIBATOMIC) \
   $(filter %libcompiler_rt.a %libcompiler_rt.hwasan.a,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
   $(PRIVATE_TARGET_LIBCRT_BUILTINS) \
-  $(PRIVATE_TARGET_LIBGCC) \
   -Wl,--end-group \
   $(PRIVATE_TARGET_CRTEND_O)
 endef
@@ -2200,7 +2200,7 @@
 @mkdir -p $(dir $@)
 $(hide) rm -f $(dir $@)classes*.dex $(dir $@)d8_input.jar
 $(hide) $(ZIP2ZIP) -j -i $< -o $(dir $@)d8_input.jar "**/*.class"
-$(hide) $(DX_COMMAND) $(DEX_FLAGS) \
+$(hide) $(D8_WRAPPER) $(DX_COMMAND) $(DEX_FLAGS) \
     --output $(dir $@) \
     $(addprefix --lib ,$(PRIVATE_D8_LIBS)) \
     --min-api $(PRIVATE_MIN_SDK_VERSION) \
@@ -2625,17 +2625,15 @@
 endef
 
 # Define a rule to create a symlink to a file.
-# $(1): full path to source
+# $(1): any dependencies
 # $(2): source (may be relative)
 # $(3): full path to destination
 define symlink-file
 $(eval $(_symlink-file))
 endef
 
-# Order-only dependency because make/ninja will follow the link when checking
-# the timestamp, so the file must exist
 define _symlink-file
-$(3): | $(1)
+$(3): $(1)
 	@echo "Symlink: $$@ -> $(2)"
 	@mkdir -p $(dir $$@)
 	@rm -rf $$@
@@ -2681,7 +2679,7 @@
 define transform-jar-to-dex-r8
 @echo R8: $@
 $(hide) rm -f $(PRIVATE_PROGUARD_DICTIONARY)
-$(hide) $(R8_COMPAT_PROGUARD) $(DEX_FLAGS) \
+$(hide) $(R8_WRAPPER) $(R8_COMPAT_PROGUARD) $(DEX_FLAGS) \
     -injars '$<' \
     --min-api $(PRIVATE_MIN_SDK_VERSION) \
     --no-data-resources \
@@ -2894,6 +2892,7 @@
 #    and use my_compat_dist_$(suite) to define the others.
 define create-suite-dependencies
 $(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
+  $(if $(filter $(suite),$(ALL_COMPATIBILITY_SUITES)),,$(eval ALL_COMPATIBILITY_SUITES += $(suite))) \
   $(eval COMPATIBILITY.$(suite).FILES := \
     $$(COMPATIBILITY.$(suite).FILES) $$(foreach f,$$(my_compat_dist_$(suite)),$$(call word-colon,2,$$(f))) \
       $$(foreach f,$$(my_compat_dist_config_$(suite)),$$(call word-colon,2,$$(f)))) \
diff --git a/core/deprecation.mk b/core/deprecation.mk
index 761a9b6..cc620a3 100644
--- a/core/deprecation.mk
+++ b/core/deprecation.mk
@@ -1,15 +1,12 @@
 # These module types can still be used without warnings or errors.
 AVAILABLE_BUILD_MODULE_TYPES :=$= \
-  BUILD_COPY_HEADERS \
   BUILD_EXECUTABLE \
   BUILD_FUZZ_TEST \
   BUILD_HEADER_LIBRARY \
   BUILD_HOST_DALVIK_JAVA_LIBRARY \
   BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY \
-  BUILD_HOST_EXECUTABLE \
   BUILD_HOST_JAVA_LIBRARY \
   BUILD_HOST_PREBUILT \
-  BUILD_HOST_SHARED_LIBRARY \
   BUILD_JAVA_LIBRARY \
   BUILD_MULTI_PREBUILT \
   BUILD_NATIVE_TEST \
@@ -27,6 +24,9 @@
 # relevant BUILD_BROKEN_USES_BUILD_* variables, then these would move to
 # DEFAULT_ERROR_BUILD_MODULE_TYPES.
 DEFAULT_WARNING_BUILD_MODULE_TYPES :=$= \
+  BUILD_COPY_HEADERS \
+  BUILD_HOST_EXECUTABLE \
+  BUILD_HOST_SHARED_LIBRARY \
   BUILD_HOST_STATIC_LIBRARY \
 
 # These are BUILD_* variables that are errors to reference, but you can set
diff --git a/core/dex_preopt_config.mk b/core/dex_preopt_config.mk
index 0f994c4..5dd5505 100644
--- a/core/dex_preopt_config.mk
+++ b/core/dex_preopt_config.mk
@@ -37,16 +37,6 @@
   endif
 endif
 
-# Default to debug version to help find bugs.
-# Set USE_DEX2OAT_DEBUG to false for only building non-debug versions.
-ifeq ($(USE_DEX2OAT_DEBUG),false)
-DEX2OAT := $(SOONG_HOST_OUT_EXECUTABLES)/dex2oat$(HOST_EXECUTABLE_SUFFIX)
-else
-DEX2OAT := $(SOONG_HOST_OUT_EXECUTABLES)/dex2oatd$(HOST_EXECUTABLE_SUFFIX)
-endif
-
-DEX2OAT_DEPENDENCY += $(DEX2OAT)
-
 # Use the first preloaded-classes file in PRODUCT_COPY_FILES.
 PRELOADED_CLASSES := $(call word-colon,1,$(firstword \
     $(filter %system/etc/preloaded-classes,$(PRODUCT_COPY_FILES))))
@@ -136,16 +126,6 @@
   $(call add_json_str,  Dex2oatImageXmx,                    $(DEX2OAT_IMAGE_XMX))
   $(call add_json_str,  Dex2oatImageXms,                    $(DEX2OAT_IMAGE_XMS))
 
-  $(call add_json_map,  Tools)
-  $(call add_json_str,  Profman,                            $(SOONG_HOST_OUT_EXECUTABLES)/profman)
-  $(call add_json_str,  Dex2oat,                            $(DEX2OAT))
-  $(call add_json_str,  Aapt,                               $(SOONG_HOST_OUT_EXECUTABLES)/aapt)
-  $(call add_json_str,  SoongZip,                           $(SOONG_ZIP))
-  $(call add_json_str,  Zip2zip,                            $(ZIP2ZIP))
-  $(call add_json_str,  ManifestCheck,                      $(SOONG_HOST_OUT_EXECUTABLES)/manifest_check)
-  $(call add_json_str,  ConstructContext,                   $(BUILD_SYSTEM)/construct_context.sh)
-  $(call end_json_map)
-
   $(call json_end)
 
   $(shell mkdir -p $(dir $(DEX_PREOPT_CONFIG)))
@@ -158,11 +138,3 @@
       rm $(DEX_PREOPT_CONFIG).tmp; \
     fi)
 endif
-
-DEXPREOPT_GEN_DEPS := \
-  $(SOONG_HOST_OUT_EXECUTABLES)/profman \
-  $(DEX2OAT) \
-  $(SOONG_HOST_OUT_EXECUTABLES)/aapt \
-  $(SOONG_ZIP) \
-  $(ZIP2ZIP) \
-  $(BUILD_SYSTEM)/construct_context.sh \
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index aa3fd80..0fb2dd2 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -111,9 +111,10 @@
 my_dexpreopt_archs :=
 my_dexpreopt_images :=
 my_dexpreopt_images_deps :=
+my_dexpreopt_image_locations :=
 my_dexpreopt_infix := boot
 ifeq (true, $(DEXPREOPT_USE_APEX_IMAGE))
-  my_dexpreopt_infix := apex
+  my_dexpreopt_infix := jitzygote-boot
 endif
 
 ifdef LOCAL_DEX_PREOPT
@@ -183,6 +184,8 @@
     endif  # TARGET_2ND_ARCH
   endif  # LOCAL_MODULE_CLASS
 
+  my_dexpreopt_image_locations += $(DEXPREOPT_IMAGE_LOCATIONS_$(my_dexpreopt_infix))
+
   my_filtered_optional_uses_libraries := $(filter-out $(INTERNAL_PLATFORM_MISSING_USES_LIBRARIES), \
     $(LOCAL_OPTIONAL_USES_LIBRARIES))
 
@@ -234,7 +237,7 @@
   $(call end_json_map)
   $(call add_json_list, Archs,                          $(my_dexpreopt_archs))
   $(call add_json_list, DexPreoptImages,                $(my_dexpreopt_images))
-  $(call add_json_list, DexPreoptImageLocations,        $(DEXPREOPT_IMAGE_LOCATIONS))
+  $(call add_json_list, DexPreoptImageLocations,        $(my_dexpreopt_image_locations))
   $(call add_json_list, PreoptBootClassPathDexFiles,    $(DEXPREOPT_BOOTCLASSPATH_DEX_FILES))
   $(call add_json_list, PreoptBootClassPathDexLocations,$(DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS))
   $(call add_json_bool, PreoptExtractedApk,             $(my_preopt_for_extracted_apk))
@@ -256,12 +259,16 @@
 
   .KATI_RESTAT: $(my_dexpreopt_script)
   $(my_dexpreopt_script): PRIVATE_MODULE := $(LOCAL_MODULE)
+  $(my_dexpreopt_script): PRIVATE_GLOBAL_SOONG_CONFIG := $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE)
   $(my_dexpreopt_script): PRIVATE_GLOBAL_CONFIG := $(DEX_PREOPT_CONFIG_FOR_MAKE)
   $(my_dexpreopt_script): PRIVATE_MODULE_CONFIG := $(my_dexpreopt_config)
   $(my_dexpreopt_script): $(DEXPREOPT_GEN)
-  $(my_dexpreopt_script): $(my_dexpreopt_config) $(DEX_PREOPT_CONFIG_FOR_MAKE)
+  $(my_dexpreopt_script): $(my_dexpreopt_config) $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE) $(DEX_PREOPT_CONFIG_FOR_MAKE)
 	@echo "$(PRIVATE_MODULE) dexpreopt gen"
-	$(DEXPREOPT_GEN) -global $(PRIVATE_GLOBAL_CONFIG) -module $(PRIVATE_MODULE_CONFIG) \
+	$(DEXPREOPT_GEN) \
+	-global_soong $(PRIVATE_GLOBAL_SOONG_CONFIG) \
+	-global $(PRIVATE_GLOBAL_CONFIG) \
+	-module $(PRIVATE_MODULE_CONFIG) \
 	-dexpreopt_script $@ \
 	-out_dir $(OUT_DIR)
 
diff --git a/core/dynamic_binary.mk b/core/dynamic_binary.mk
index 27ff2c9..48072b3 100644
--- a/core/dynamic_binary.mk
+++ b/core/dynamic_binary.mk
@@ -132,8 +132,8 @@
 	CLANG_BIN=$(LLVM_PREBUILTS_PATH) \
 	CROSS_COMPILE=$(PRIVATE_TOOLS_PREFIX) \
 	XZ=$(XZ) \
-	$(SOONG_STRIP_PATH) -i $< -o $@ -d $@.d $(PRIVATE_STRIP_ARGS)
-  $(call include-depfile,$(strip_output).d)
+	$(SOONG_STRIP_PATH) -i $< -o $@ -d $@.strip.d $(PRIVATE_STRIP_ARGS)
+  $(call include-depfile,$(strip_output).strip.d,$(strip_output))
 else
   # Don't strip the binary, just copy it.  We can't skip this step
   # because a copy of the binary must appear at LOCAL_BUILT_MODULE.
diff --git a/core/executable.mk b/core/executable.mk
index c8d9272..db8dcc6 100644
--- a/core/executable.mk
+++ b/core/executable.mk
@@ -6,6 +6,10 @@
 # LOCAL_MODULE_PATH_32 and LOCAL_MODULE_PATH_64 or LOCAL_MODULE_STEM_32 and
 # LOCAL_MODULE_STEM_64
 
+ifdef LOCAL_IS_HOST_MODULE
+  $(call pretty-error,BUILD_EXECUTABLE is incompatible with LOCAL_IS_HOST_MODULE. Use BUILD_HOST_EXECUTABLE instead.)
+endif
+
 my_skip_this_target :=
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
   ifeq (true,$(LOCAL_FORCE_STATIC_EXECUTABLE))
diff --git a/core/executable_internal.mk b/core/executable_internal.mk
index a9915aa..32e56dd 100644
--- a/core/executable_internal.mk
+++ b/core/executable_internal.mk
@@ -41,11 +41,6 @@
 else
 my_target_libcrt_builtins := $($(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)LIBCRT_BUILTINS)
 endif
-ifeq ($(LOCAL_NO_LIBGCC),true)
-my_target_libgcc :=
-else
-my_target_libgcc := $(call intermediates-dir-for,STATIC_LIBRARIES,libgcc,,,$(LOCAL_2ND_ARCH_VAR_PREFIX))/libgcc.a
-endif
 my_target_libatomic := $(call intermediates-dir-for,STATIC_LIBRARIES,libatomic,,,$(LOCAL_2ND_ARCH_VAR_PREFIX))/libatomic.a
 ifeq ($(LOCAL_NO_CRT),true)
 my_target_crtbegin_dynamic_o :=
@@ -66,7 +61,6 @@
 my_target_crtend_o := $(wildcard $(my_ndk_sysroot_lib)/crtend_android.o)
 endif
 $(linked_module): PRIVATE_TARGET_LIBCRT_BUILTINS := $(my_target_libcrt_builtins)
-$(linked_module): PRIVATE_TARGET_LIBGCC := $(my_target_libgcc)
 $(linked_module): PRIVATE_TARGET_LIBATOMIC := $(my_target_libatomic)
 $(linked_module): PRIVATE_TARGET_CRTBEGIN_DYNAMIC_O := $(my_target_crtbegin_dynamic_o)
 $(linked_module): PRIVATE_TARGET_CRTBEGIN_STATIC_O := $(my_target_crtbegin_static_o)
@@ -74,11 +68,11 @@
 $(linked_module): PRIVATE_POST_LINK_CMD := $(LOCAL_POST_LINK_CMD)
 
 ifeq ($(LOCAL_FORCE_STATIC_EXECUTABLE),true)
-$(linked_module): $(my_target_crtbegin_static_o) $(all_objects) $(all_libraries) $(my_target_crtend_o) $(my_target_libcrt_builtins) $(my_target_libgcc) $(my_target_libatomic) $(CLANG_CXX)
+$(linked_module): $(my_target_crtbegin_static_o) $(all_objects) $(all_libraries) $(my_target_crtend_o) $(my_target_libcrt_builtins) $(my_target_libatomic) $(CLANG_CXX)
 	$(transform-o-to-static-executable)
 	$(PRIVATE_POST_LINK_CMD)
 else
-$(linked_module): $(my_target_crtbegin_dynamic_o) $(all_objects) $(all_libraries) $(my_target_crtend_o) $(my_target_libcrt_builtins) $(my_target_libgcc) $(my_target_libatomic) $(CLANG_CXX)
+$(linked_module): $(my_target_crtbegin_dynamic_o) $(all_objects) $(all_libraries) $(my_target_crtend_o) $(my_target_libcrt_builtins) $(my_target_libatomic) $(CLANG_CXX)
 	$(transform-o-to-executable)
 	$(PRIVATE_POST_LINK_CMD)
 endif
diff --git a/core/host_shared_library.mk b/core/host_shared_library.mk
index 81236d1..c22af97 100644
--- a/core/host_shared_library.mk
+++ b/core/host_shared_library.mk
@@ -37,4 +37,7 @@
 ###########################################################
 ## Copy headers to the install tree
 ###########################################################
-include $(BUILD_COPY_HEADERS)
+ifdef LOCAL_COPY_HEADERS
+$(call pretty-warning,LOCAL_COPY_HEADERS is deprecated. See $(CHANGES_URL)#copy_headers)
+include $(BUILD_SYSTEM)/copy_headers.mk
+endif
diff --git a/core/host_static_library.mk b/core/host_static_library.mk
index 469da29..3dbd144 100644
--- a/core/host_static_library.mk
+++ b/core/host_static_library.mk
@@ -37,4 +37,7 @@
 ###########################################################
 ## Copy headers to the install tree
 ###########################################################
-include $(BUILD_COPY_HEADERS)
+ifdef LOCAL_COPY_HEADERS
+$(call pretty-warning,LOCAL_COPY_HEADERS is deprecated. See $(CHANGES_URL)#copy_headers)
+include $(BUILD_SYSTEM)/copy_headers.mk
+endif
diff --git a/core/install_jni_libs_internal.mk b/core/install_jni_libs_internal.mk
index eac0414..d87513b 100644
--- a/core/install_jni_libs_internal.mk
+++ b/core/install_jni_libs_internal.mk
@@ -49,29 +49,21 @@
   my_shared_library_path := $(call get_non_asan_path,\
       $($(my_2nd_arch_prefix)TARGET_OUT$(partition_tag)_SHARED_LIBRARIES))
   my_installed_library := $(addprefix $(my_shared_library_path)/, $(my_jni_filenames))
-  # Do not use order-only dependency, because we want to rebuild the image if an jni is updated.
-  $(LOCAL_INSTALLED_MODULE) : $(my_installed_library)
 
   ALL_MODULES.$(LOCAL_MODULE).INSTALLED += $(my_installed_library)
 
   # Create symlink in the app specific lib path
   # Skip creating this symlink when running the second part of a target sanitization build.
   ifeq ($(filter address,$(SANITIZE_TARGET)),)
-    ifdef LOCAL_POST_INSTALL_CMD
-      # Add a shell command separator
-      LOCAL_POST_INSTALL_CMD += ;
-    endif
-
     my_symlink_target_dir := $(patsubst $(PRODUCT_OUT)%,%,\
-        $(my_shared_library_path))
-    LOCAL_POST_INSTALL_CMD += \
-        mkdir -p $(my_app_lib_path) \
-        $(foreach lib, $(my_jni_filenames), ;ln -sf $(my_symlink_target_dir)/$(lib) $(my_app_lib_path)/$(lib))
-    $(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := $(LOCAL_POST_INSTALL_CMD)
-  else
-    ifdef LOCAL_POST_INSTALL_CMD
-      $(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := $(LOCAL_POST_INSTALL_CMD)
-    endif
+      $(my_shared_library_path))
+    $(foreach lib,$(my_jni_filenames),\
+      $(call symlink-file, \
+        $(my_shared_library_path)/$(lib), \
+        $(my_symlink_target_dir)/$(lib), \
+        $(my_app_lib_path)/$(lib)) \
+      $(eval $$(LOCAL_INSTALLED_MODULE) : $$(my_app_lib_path)/$$(lib)) \
+      $(eval ALL_MODULES.$$(LOCAL_MODULE).INSTALLED += $$(my_app_lib_path)/$$(lib)))
   endif
 
   # Clear jni_shared_libraries to not embed it into the apk.
@@ -114,11 +106,13 @@
     my_allowed_types := $(my_allowed_ndk_types)
     ifneq (,$(filter true,$(LOCAL_VENDOR_MODULE) $(LOCAL_ODM_MODULE) $(LOCAL_PROPRIETARY_MODULE)))
       my_allowed_types += native:vendor native:vndk native:platform_vndk
+    else ifeq ($(LOCAL_PRODUCT_MODULE),true)
+      my_allowed_types += native:product native:vndk native:platform_vndk
     endif
   else
     my_link_type := app:platform
     my_warn_types := $(my_warn_ndk_types)
-    my_allowed_types := $(my_allowed_ndk_types) native:platform native:vendor native:vndk native:vndk_private native:platform_vndk
+    my_allowed_types := $(my_allowed_ndk_types) native:platform native:product native:vendor native:vndk native:vndk_private native:platform_vndk
   endif
 
   my_link_deps := $(addprefix SHARED_LIBRARIES:,$(LOCAL_JNI_SHARED_LIBRARIES))
diff --git a/core/local_vndk.mk b/core/local_vndk.mk
index 198e361..b1bd3e6 100644
--- a/core/local_vndk.mk
+++ b/core/local_vndk.mk
@@ -1,5 +1,5 @@
 
-#Set LOCAL_USE_VNDK for modules going into vendor or odm partition, except for host modules
+#Set LOCAL_USE_VNDK for modules going into product, vendor or odm partition, except for host modules
 #If LOCAL_SDK_VERSION is set, thats a more restrictive set, so they dont need LOCAL_USE_VNDK
 ifndef LOCAL_IS_HOST_MODULE
 ifndef LOCAL_SDK_VERSION
@@ -8,6 +8,13 @@
     # Note: no need to check LOCAL_MODULE_PATH* since LOCAL_[VENDOR|ODM|OEM]_MODULE is already
     # set correctly before this is included.
   endif
+  ifdef PRODUCT_PRODUCT_VNDK_VERSION
+    # Product modules also use VNDK when PRODUCT_PRODUCT_VNDK_VERSION is defined.
+    ifeq (true,$(LOCAL_PRODUCT_MODULE))
+      LOCAL_USE_VNDK:=true
+      LOCAL_USE_VNDK_PRODUCT:=true
+    endif
+  endif
 endif
 endif
 
@@ -33,6 +40,7 @@
   # If we're not using the VNDK, drop all restrictions
   ifndef BOARD_VNDK_VERSION
     LOCAL_USE_VNDK:=
+    LOCAL_USE_VNDK_PRODUCT:=
   endif
 endif
 
diff --git a/core/main.mk b/core/main.mk
index b51603d..ec1effd 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -444,10 +444,6 @@
 subdir_makefiles_total := $(words init post finish)
 endif
 
-droid_targets: no_vendor_variant_vndk_check
-.PHONY: no_vendor_variant_vndk_check
-no_vendor_variant_vndk_check:
-
 $(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] finishing build rules ...)
 
 # -------------------------------------------------------------------
@@ -1034,7 +1030,7 @@
 # variables being set.
 define auto-included-modules
   $(if $(BOARD_VNDK_VERSION),vndk_package) \
-  $(if $(DEVICE_MANIFEST_FILE),device_manifest.xml) \
+  $(if $(DEVICE_MANIFEST_FILE),vendor_manifest.xml) \
   $(if $(ODM_MANIFEST_FILES),odm_manifest.xml) \
   $(if $(ODM_MANIFEST_SKUS),$(foreach sku, $(ODM_MANIFEST_SKUS),odm_manifest_$(sku).xml)) \
 
@@ -1256,6 +1252,28 @@
     $(CUSTOM_MODULES) \
   )
 
+#
+# Used by the cleanup logic in soong_ui to remove files that should no longer
+# be installed.
+#
+
+# Include all tests, so that we remove them from the test suites / testcase
+# folders when they are removed.
+test_files := $(foreach ts,$(ALL_COMPATIBILITY_SUITES),$(COMPATIBILITY.$(ts).FILES))
+
+$(shell mkdir -p $(PRODUCT_OUT) $(HOST_OUT))
+
+$(file >$(PRODUCT_OUT)/.installable_files$(if $(filter address,$(SANITIZE_TARGET)),_asan), \
+  $(sort $(patsubst $(PRODUCT_OUT)/%,%,$(filter $(PRODUCT_OUT)/%, \
+    $(modules_to_install) $(test_files)))))
+
+$(file >$(HOST_OUT)/.installable_test_files,$(sort \
+  $(patsubst $(HOST_OUT)/%,%,$(filter $(HOST_OUT)/%, \
+    $(test_files)))))
+
+test_files :=
+
+
 # Don't include any GNU General Public License shared objects or static
 # libraries in SDK images.  GPL executables (not static/dynamic libraries)
 # are okay if they don't link against any closed source libraries (directly
@@ -1319,7 +1337,7 @@
 endif
 
 # Build docs as part of checkbuild to catch more breakages.
-module_to_check += $(ALL_DOCS)
+modules_to_check += $(ALL_DOCS)
 
 # for easier debugging
 modules_to_check := $(sort $(modules_to_check))
@@ -1584,7 +1602,7 @@
   endif
 
   ifeq ($(EMMA_INSTRUMENT),true)
-    $(JACOCO_REPORT_CLASSES_ALL) : $(INSTALLED_SYSTEMIMAGE_TARGET)
+    $(JACOCO_REPORT_CLASSES_ALL) : $(modules_to_install)
     $(call dist-for-goals, dist_files, $(JACOCO_REPORT_CLASSES_ALL))
   endif
 
diff --git a/core/product_config.mk b/core/product_config.mk
index afe91d4..1890599 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -344,6 +344,16 @@
 $(KATI_obsolete_var OVERRIDE_PRODUCT_EXTRA_VNDK_VERSIONS \
     ,Use PRODUCT_EXTRA_VNDK_VERSIONS instead)
 
+ifdef OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
+  PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := $(OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE)
+else ifeq ($(PRODUCT_SHIPPING_API_LEVEL),)
+  # No shipping level defined
+else ifeq ($(call math_gt,$(PRODUCT_SHIPPING_API_LEVEL),29),true)
+  PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true
+endif
+
+$(KATI_obsolete_var OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE,Use PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE instead)
+
 define product-overrides-config
 $$(foreach rule,$$(PRODUCT_$(1)_OVERRIDES),\
     $$(if $$(filter 2,$$(words $$(subst :,$$(space),$$(rule)))),,\
diff --git a/core/rbe.mk b/core/rbe.mk
index 231859b..6a92366 100644
--- a/core/rbe.mk
+++ b/core/rbe.mk
@@ -21,12 +21,25 @@
   else
     rbe_dir := $(HOME)/rbe
   endif
-  RBE_WRAPPER := $(rbe_dir)/rewrapper --labels=type=compile,lang=cpp,compiler=clang --env_var_whitelist=PWD
+  RBE_WRAPPER := $(rbe_dir)/rewrapper
+  RBE_CXX := --labels=type=compile,lang=cpp,compiler=clang --env_var_whitelist=PWD
 
   # Append rewrapper to existing *_WRAPPER variables so it's possible to
   # use both ccache and rewrapper.
-  CC_WRAPPER := $(strip $(CC_WRAPPER) $(RBE_WRAPPER))
-  CXX_WRAPPER := $(strip $(CXX_WRAPPER) $(RBE_WRAPPER))
+  CC_WRAPPER := $(strip $(CC_WRAPPER) $(RBE_WRAPPER) $(RBE_CXX))
+  CXX_WRAPPER := $(strip $(CXX_WRAPPER) $(RBE_WRAPPER) $(RBE_CXX))
+
+  ifdef RBE_JAVAC
+    JAVAC_WRAPPER := $(strip $(JAVAC_WRAPPER) $(RBE_WRAPPER) --labels=type=compile,lang=java,compiler=javac,shallow=true)
+  endif
+
+  ifdef RBE_R8
+    R8_WRAPPER := $(strip $(RBE_WRAPPER) --labels=type=compile,compiler=r8,shallow=true)
+  endif
+
+  ifdef RBE_D8
+    D8_WRAPPER := $(strip $(RBE_WRAPPER) --labels=type=compile,compiler=d8,shallow=true)
+  endif
 
   rbe_dir :=
 endif
diff --git a/core/shared_library.mk b/core/shared_library.mk
index 2832c17..ca17151 100644
--- a/core/shared_library.mk
+++ b/core/shared_library.mk
@@ -1,4 +1,7 @@
 $(call record-module-type,SHARED_LIBRARY)
+ifdef LOCAL_IS_HOST_MODULE
+  $(call pretty-error,BUILD_SHARED_LIBRARY is incompatible with LOCAL_IS_HOST_MODULE. Use BUILD_HOST_SHARED_LIBRARY instead.)
+endif
 my_prefix := TARGET_
 include $(BUILD_SYSTEM)/multilib.mk
 
@@ -53,4 +56,7 @@
 ###########################################################
 ## Copy headers to the install tree
 ###########################################################
-include $(BUILD_COPY_HEADERS)
+ifdef LOCAL_COPY_HEADERS
+$(call pretty-warning,LOCAL_COPY_HEADERS is deprecated. See $(CHANGES_URL)#copy_headers)
+include $(BUILD_SYSTEM)/copy_headers.mk
+endif
diff --git a/core/shared_library_internal.mk b/core/shared_library_internal.mk
index 8ec07f8..219772a 100644
--- a/core/shared_library_internal.mk
+++ b/core/shared_library_internal.mk
@@ -39,11 +39,6 @@
 else
 my_target_libcrt_builtins := $($(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)LIBCRT_BUILTINS)
 endif
-ifeq ($(LOCAL_NO_LIBGCC),true)
-my_target_libgcc :=
-else
-my_target_libgcc := $(call intermediates-dir-for,STATIC_LIBRARIES,libgcc,,,$(LOCAL_2ND_ARCH_VAR_PREFIX))/libgcc.a
-endif
 my_target_libatomic := $(call intermediates-dir-for,STATIC_LIBRARIES,libatomic,,,$(LOCAL_2ND_ARCH_VAR_PREFIX))/libatomic.a
 ifeq ($(LOCAL_NO_CRT),true)
 my_target_crtbegin_so_o :=
@@ -60,7 +55,6 @@
 my_target_crtend_so_o := $(wildcard $(my_ndk_sysroot_lib)/crtend_so.o)
 endif
 $(linked_module): PRIVATE_TARGET_LIBCRT_BUILTINS := $(my_target_libcrt_builtins)
-$(linked_module): PRIVATE_TARGET_LIBGCC := $(my_target_libgcc)
 $(linked_module): PRIVATE_TARGET_LIBATOMIC := $(my_target_libatomic)
 $(linked_module): PRIVATE_TARGET_CRTBEGIN_SO_O := $(my_target_crtbegin_so_o)
 $(linked_module): PRIVATE_TARGET_CRTEND_SO_O := $(my_target_crtend_so_o)
@@ -71,7 +65,6 @@
         $(my_target_crtbegin_so_o) \
         $(my_target_crtend_so_o) \
         $(my_target_libcrt_builtins) \
-        $(my_target_libgcc) \
         $(my_target_libatomic) \
         $(LOCAL_ADDITIONAL_DEPENDENCIES) $(CLANG_CXX)
 	$(transform-o-to-shared-lib)
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index 98c646a..0a5ba9d 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -41,6 +41,10 @@
       $(eval $(call copy-one-file,$(full_classes_jar),$(full_classes_header_jar)))
     endif
   endif # TURBINE_ENABLED != false
+
+  javac-check : $(full_classes_jar)
+  javac-check-$(LOCAL_MODULE) : $(full_classes_jar)
+  .PHONY: javac-check-$(LOCAL_MODULE)
 endif
 
 # Run veridex on product, system_ext and vendor modules.
@@ -135,6 +139,9 @@
 my_2nd_arch_prefix :=
 
 PACKAGES := $(PACKAGES) $(LOCAL_MODULE)
+ifndef LOCAL_CERTIFICATE
+  $(call pretty-error,LOCAL_CERTIFICATE must be set for soong_app_prebuilt.mk)
+endif
 ifeq ($(LOCAL_CERTIFICATE),PRESIGNED)
   # The magic string "PRESIGNED" means this package is already checked
   # signed with its release key.
diff --git a/core/soong_cc_prebuilt.mk b/core/soong_cc_prebuilt.mk
index 2d5089d..190a7ed 100644
--- a/core/soong_cc_prebuilt.mk
+++ b/core/soong_cc_prebuilt.mk
@@ -75,8 +75,13 @@
 ifdef LOCAL_USE_VNDK
   ifneq ($(LOCAL_VNDK_DEPEND_ON_CORE_VARIANT),true)
     name_without_suffix := $(patsubst %.vendor,%,$(LOCAL_MODULE))
-    ifneq ($(name_without_suffix),$(LOCAL_MODULE)
+    ifneq ($(name_without_suffix),$(LOCAL_MODULE))
       SPLIT_VENDOR.$(LOCAL_MODULE_CLASS).$(name_without_suffix) := 1
+    else
+      name_without_suffix := $(patsubst %.product,%,$(LOCAL_MODULE))
+      ifneq ($(name_without_suffix),$(LOCAL_MODULE))
+        SPLIT_PRODUCT.$(LOCAL_MODULE_CLASS).$(name_without_suffix) := 1
+      endif
     endif
     name_without_suffix :=
   endif
@@ -104,33 +109,35 @@
   endif
 endif
 
-ifeq ($(LOCAL_VNDK_DEPEND_ON_CORE_VARIANT),true)
-  # Add $(LOCAL_BUILT_MODULE) as a dependency to no_vendor_variant_vndk_check so
-  # that the vendor variant will be built and checked against the core variant.
-  no_vendor_variant_vndk_check: $(LOCAL_BUILT_MODULE)
+my_check_same_vndk_variants :=
+ifeq ($(LOCAL_CHECK_SAME_VNDK_VARIANTS),true)
+  ifeq ($(filter hwaddress address, $(SANITIZE_TARGET)),)
+    my_check_same_vndk_variants := true
+  endif
+endif
 
-  my_core_register_name := $(subst .vendor,,$(my_register_name))
+ifeq ($(my_check_same_vndk_variants),true)
+  same_vndk_variants_stamp := $(intermediates)/same_vndk_variants.timestamp
+
+  my_core_register_name := $(subst .vendor,,$(subst .product,,$(my_register_name)))
   my_core_variant_files := $(call module-target-built-files,$(my_core_register_name))
   my_core_shared_lib := $(sort $(filter %.so,$(my_core_variant_files)))
-  $(LOCAL_BUILT_MODULE): PRIVATE_CORE_VARIANT := $(my_core_shared_lib)
 
-  # The built vendor variant library needs to depend on the built core variant
-  # so that we can perform identity check against the core variant.
-  $(LOCAL_BUILT_MODULE): $(my_core_shared_lib)
+  $(same_vndk_variants_stamp): PRIVATE_CORE_VARIANT := $(my_core_shared_lib)
+  $(same_vndk_variants_stamp): PRIVATE_VENDOR_VARIANT := $(LOCAL_PREBUILT_MODULE_FILE)
+  $(same_vndk_variants_stamp): PRIVATE_TOOLS_PREFIX := $($(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)TOOLS_PREFIX)
+
+  $(same_vndk_variants_stamp): $(my_core_shared_lib) $(LOCAL_PREBUILT_MODULE_FILE)
+		$(call verify-vndk-libs-identical,\
+		    $(PRIVATE_CORE_VARIANT),\
+		    $(PRIVATE_VENDOR_VARIANT),\
+		    $(PRIVATE_TOOLS_PREFIX))
+
+  $(LOCAL_BUILT_MODULE): $(same_vndk_variants_stamp)
 endif
 
-ifeq ($(LOCAL_VNDK_DEPEND_ON_CORE_VARIANT),true)
-$(LOCAL_BUILT_MODULE): PRIVATE_TOOLS_PREFIX := $($(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)TOOLS_PREFIX)
-$(LOCAL_BUILT_MODULE): $(LOCAL_PREBUILT_MODULE_FILE) $(LIBRARY_IDENTITY_CHECK_SCRIPT)
-	$(call verify-vndk-libs-identical,\
-		$(PRIVATE_CORE_VARIANT),\
-		$<,\
-		$(PRIVATE_TOOLS_PREFIX))
-	$(copy-file-to-target)
-else
 $(LOCAL_BUILT_MODULE): $(LOCAL_PREBUILT_MODULE_FILE)
 	$(transform-prebuilt-to-target)
-endif
 ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
 	$(hide) chmod +x $@
 endif
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 7813e30..95ff5ef 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -113,6 +113,7 @@
 $(call add_json_str,  TidyChecks,                        $(WITH_TIDY_CHECKS))
 
 $(call add_json_bool, NativeCoverage,                    $(filter true,$(NATIVE_COVERAGE)))
+$(call add_json_bool, ClangCoverage,                     $(filter true,$(CLANG_COVERAGE)))
 $(call add_json_list, CoveragePaths,                     $(COVERAGE_PATHS))
 $(call add_json_list, CoverageExcludePaths,              $(COVERAGE_EXCLUDE_PATHS))
 
@@ -155,6 +156,9 @@
 
 $(call add_json_bool, UseGoma,                           $(filter-out false,$(USE_GOMA)))
 $(call add_json_bool, UseRBE,                            $(filter-out false,$(USE_RBE)))
+$(call add_json_bool, UseRBEJAVAC,                       $(filter-out false,$(RBE_JAVAC)))
+$(call add_json_bool, UseRBER8,                          $(filter-out false,$(RBE_R8)))
+$(call add_json_bool, UseRBED8,                          $(filter-out false,$(RBE_D8)))
 $(call add_json_bool, Arc,                               $(filter true,$(TARGET_ARC)))
 
 $(call add_json_list, NamespacesToExport,                $(PRODUCT_SOONG_NAMESPACES))
@@ -202,6 +206,8 @@
 
 $(call add_json_bool, InstallExtraFlattenedApexes, $(PRODUCT_INSTALL_EXTRA_FLATTENED_APEXES))
 
+$(call add_json_bool, BoardUsesRecoveryAsBoot, $(BOARD_USES_RECOVERY_AS_BOOT))
+
 $(call json_end)
 
 $(file >$(SOONG_VARIABLES).tmp,$(json_contents))
diff --git a/core/static_library.mk b/core/static_library.mk
index 8002e5c..78908cf 100644
--- a/core/static_library.mk
+++ b/core/static_library.mk
@@ -1,4 +1,7 @@
 $(call record-module-type,STATIC_LIBRARY)
+ifdef LOCAL_IS_HOST_MODULE
+  $(call pretty-error,BUILD_STATIC_LIBRARY is incompatible with LOCAL_IS_HOST_MODULE. Use BUILD_HOST_STATIC_LIBRARY instead)
+endif
 my_prefix := TARGET_
 include $(BUILD_SYSTEM)/multilib.mk
 
@@ -38,4 +41,7 @@
 ###########################################################
 ## Copy headers to the install tree
 ###########################################################
-include $(BUILD_COPY_HEADERS)
+ifdef LOCAL_COPY_HEADERS
+$(call pretty-warning,LOCAL_COPY_HEADERS is deprecated. See $(CHANGES_URL)#copy_headers)
+include $(BUILD_SYSTEM)/copy_headers.mk
+endif
diff --git a/core/tasks/boot_jars_package_check.mk b/core/tasks/boot_jars_package_check.mk
index ba383f5..ceaff54 100644
--- a/core/tasks/boot_jars_package_check.mk
+++ b/core/tasks/boot_jars_package_check.mk
@@ -22,10 +22,23 @@
 
 intermediates := $(call intermediates-dir-for, PACKAGING, boot-jars-package-check,,COMMON)
 stamp := $(intermediates)/stamp
-art_boot_jars := $(addsuffix .com.android.art.release,$(filter $(ART_APEX_JARS), $(PRODUCT_BOOT_JARS)))
-conscrypt_boot_jars := $(addsuffix .com.android.conscrypt,$(filter conscrypt, $(PRODUCT_BOOT_JARS)))
-noncore_boot_jars := $(filter-out $(ART_APEX_JARS) conscrypt, $(PRODUCT_BOOT_JARS))
-built_boot_jars := $(foreach j, $(art_boot_jars) $(conscrypt_boot_jars) $(noncore_boot_jars), \
+
+# The actual names for the updatable jars are <jar_name>.<apex_name> e.g., updatable-media.com.android.media
+updatable_boot_jars := $(foreach pair,$(PRODUCT_UPDATABLE_BOOT_JARS),\
+  $(eval apex := $(call word-colon,1,$(pair)))\
+  $(eval jar := $(call word-colon,2,$(pair)))\
+  $(jar).$(apex)\
+)
+#TODO(jiyong) merge art_boot_jars into updatable_boot_jars
+art_boot_jars := $(addsuffix .com.android.art.release,$(filter $(ART_APEX_JARS),$(PRODUCT_BOOT_JARS)))
+
+platform_boot_jars := $(filter-out \
+  $(ART_APEX_JARS)\
+  $(foreach pair,$(PRODUCT_UPDATABLE_BOOT_JARS),$(call word-colon,2,$(pair))),\
+  $(PRODUCT_BOOT_JARS)\
+)
+
+built_boot_jars := $(foreach j, $(updatable_boot_jars) $(art_boot_jars) $(platform_boot_jars), \
   $(call intermediates-dir-for, JAVA_LIBRARIES, $(j),,COMMON)/classes.jar)
 script := build/make/core/tasks/check_boot_jars/check_boot_jars.py
 whitelist_file := build/make/core/tasks/check_boot_jars/package_whitelist.txt
diff --git a/core/tasks/check_boot_jars/check_boot_jars.py b/core/tasks/check_boot_jars/check_boot_jars.py
index 9d71553..67b73d5 100755
--- a/core/tasks/check_boot_jars/check_boot_jars.py
+++ b/core/tasks/check_boot_jars/check_boot_jars.py
@@ -53,10 +53,9 @@
     if f.endswith('.class'):
       package_name = os.path.dirname(f)
       package_name = package_name.replace('/', '.')
-      # Skip class without a package name
-      if package_name and not whitelist_re.match(package_name):
-        print >> sys.stderr, ('Error: %s contains class file %s, whose package name %s is not '
-                              'in the whitelist %s of packages allowed on the bootclasspath.'
+      if not package_name or not whitelist_re.match(package_name):
+        print >> sys.stderr, ('Error: %s contains class file %s, whose package name %s is empty or'
+                              ' not in the whitelist %s of packages allowed on the bootclasspath.'
                               % (jar, f, package_name, whitelist_path))
         return False
   return True
diff --git a/core/tasks/check_boot_jars/package_whitelist.txt b/core/tasks/check_boot_jars/package_whitelist.txt
index 8d9878f..d4f600a 100644
--- a/core/tasks/check_boot_jars/package_whitelist.txt
+++ b/core/tasks/check_boot_jars/package_whitelist.txt
@@ -69,6 +69,8 @@
 javax\.xml\.transform\.stream
 javax\.xml\.validation
 javax\.xml\.xpath
+jdk\.internal\.util
+jdk\.internal\.vm\.annotation
 jdk\.net
 org\.w3c\.dom
 org\.w3c\.dom\.ls
diff --git a/core/tasks/tools/package-modules.mk b/core/tasks/tools/package-modules.mk
index d7b3010..55a08f5 100644
--- a/core/tasks/tools/package-modules.mk
+++ b/core/tasks/tools/package-modules.mk
@@ -5,6 +5,11 @@
 #   my_modules: a list of module names
 #   my_package_name: the name of the output zip file.
 #   my_copy_pairs: a list of extra files to install (in src:dest format)
+# Optional input variables:
+#   my_modules_strict: what happens when a module from my_modules does not exist
+#     "true": error out when a module is missing
+#     "false": print a warning when a module is missing
+#     "": defaults to false currently
 # Output variables:
 #   my_package_zip: the path to the output zip file.
 #
@@ -15,6 +20,7 @@
 my_built_modules := $(foreach p,$(my_copy_pairs),$(call word-colon,1,$(p)))
 my_copy_pairs := $(foreach p,$(my_copy_pairs),$(call word-colon,1,$(p)):$(my_staging_dir)/$(call word-colon,2,$(p)))
 my_pickup_files :=
+my_missing_error :=
 
 # Iterate over the modules and include their direct dependencies stated in the
 # LOCAL_REQUIRED_MODULES.
@@ -26,10 +32,17 @@
   $(eval my_modules_and_deps += $(_explicitly_required))\
 )
 
-# Ignore unknown installed files on partial builds
-my_missing_files :=
-ifneq ($(ALLOW_MISSING_DEPENDENCIES),true)
+ifneq ($(filter-out true false,$(my_modules_strict)),)
+  $(shell $(call echo-error,$(my_makefile),$(my_package_name): Invalid value for 'my_module_strict' = '$(my_modules_strict)'. Valid values: 'true', 'false', ''))
+  $(error done)
+endif
+
 my_missing_files = $(shell $(call echo-warning,$(my_makefile),$(my_package_name): Unknown installed file for module '$(1)'))
+ifeq ($(ALLOW_MISSING_DEPENDENCIES),true)
+  # Ignore unknown installed files on partial builds
+  my_missing_files =
+else ifeq ($(my_modules_strict),true)
+  my_missing_files = $(shell $(call echo-error,$(my_makefile),$(my_package_name): Unknown installed file for module '$(1)'))$(eval my_missing_error := true)
 endif
 
 # Iterate over modules' built files and installed files;
@@ -63,6 +76,10 @@
       $(eval my_copy_pairs += $(bui):$(my_staging_dir)/$(my_copy_dest)))\
   ))
 
+ifneq ($(my_missing_error),)
+  $(error done)
+endif
+
 my_package_zip := $(my_staging_dir)/$(my_package_name).zip
 $(my_package_zip): PRIVATE_COPY_PAIRS := $(my_copy_pairs)
 $(my_package_zip): PRIVATE_PICKUP_FILES := $(my_pickup_files)
@@ -84,4 +101,6 @@
 my_copy_pairs :=
 my_pickup_files :=
 my_missing_files :=
+my_missing_error :=
 my_modules_and_deps :=
+my_modules_strict :=
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 8095212..5d445e0 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -250,7 +250,7 @@
     #  It must be of the form "YYYY-MM-DD" on production devices.
     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
-      PLATFORM_SECURITY_PATCH := 2019-12-05
+      PLATFORM_SECURITY_PATCH := 2020-01-01
 endif
 .KATI_READONLY := PLATFORM_SECURITY_PATCH
 
diff --git a/envsetup.sh b/envsetup.sh
index a44cd50..389fbb7 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -1342,7 +1342,7 @@
         refreshmod || return 1
     fi
 
-    python -c "import json; print '\n'.join(sorted(json.load(open('$ANDROID_PRODUCT_OUT/module-info.json')).keys()))"
+    python -c "import json; print('\n'.join(sorted(json.load(open('$ANDROID_PRODUCT_OUT/module-info.json')).keys())))"
 }
 
 # Get the path of a specific module in the android tree, as cached in module-info.json. If any build change
@@ -1368,7 +1368,7 @@
 module_info = json.load(open('$ANDROID_PRODUCT_OUT/module-info.json'))
 if module not in module_info:
     exit(1)
-print module_info[module]['path'][0]" 2>/dev/null)
+print(module_info[module]['path'][0])" 2>/dev/null)
 
     if [ -z "$relpath" ]; then
         echo "Could not find module '$1' (try 'refreshmod' if there have been build changes?)." >&2
diff --git a/target/board/Android.mk b/target/board/Android.mk
index c8705c3..2c7d2da 100644
--- a/target/board/Android.mk
+++ b/target/board/Android.mk
@@ -34,7 +34,7 @@
 ifdef DEVICE_MANIFEST_FILE
 # $(DEVICE_MANIFEST_FILE) can be a list of files
 include $(CLEAR_VARS)
-LOCAL_MODULE        := device_manifest.xml
+LOCAL_MODULE        := vendor_manifest.xml
 LOCAL_MODULE_STEM   := manifest.xml
 LOCAL_MODULE_CLASS  := ETC
 LOCAL_MODULE_PATH   := $(TARGET_OUT_VENDOR)/etc/vintf
@@ -50,7 +50,6 @@
 
 LOCAL_PREBUILT_MODULE_FILE := $(GEN)
 include $(BUILD_PREBUILT)
-BUILT_VENDOR_MANIFEST := $(LOCAL_BUILT_MODULE)
 endif
 
 # ODM manifest
diff --git a/target/board/mainline_arm64/BoardConfig.mk b/target/board/mainline_arm64/BoardConfig.mk
index c53da9e..a09960f 100644
--- a/target/board/mainline_arm64/BoardConfig.mk
+++ b/target/board/mainline_arm64/BoardConfig.mk
@@ -40,8 +40,3 @@
 BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
-
-# Mainline devices support apex
-# TODO: move this to BoardConfigMainlineCommon. Currently, GSI wants flattened
-#       apexes, but emulator wants .apex files, preventing this.
-TARGET_FLATTEN_APEX := false
diff --git a/target/board/mainline_x86/BoardConfig.mk b/target/board/mainline_x86/BoardConfig.mk
index a20d17c..4dda058 100644
--- a/target/board/mainline_x86/BoardConfig.mk
+++ b/target/board/mainline_x86/BoardConfig.mk
@@ -29,7 +29,3 @@
 BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
-
-# Mainline devices support apex
-# TODO: move this to product makefile and use updatable_apex.mk
-TARGET_FLATTEN_APEX := false
diff --git a/target/board/mainline_x86_arm/BoardConfig.mk b/target/board/mainline_x86_arm/BoardConfig.mk
index 6b282c2..d775a77 100644
--- a/target/board/mainline_x86_arm/BoardConfig.mk
+++ b/target/board/mainline_x86_arm/BoardConfig.mk
@@ -34,7 +34,3 @@
 BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
-
-# Mainline devices support apex
-# TODO: move this to product makefile and use updatable_apex.mk
-TARGET_FLATTEN_APEX := false
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 39a9101..20fd189 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -97,6 +97,7 @@
     idmap2 \
     idmap2d \
     ime \
+    ims-common \
     incident \
     incidentd \
     incident_helper \
@@ -251,6 +252,7 @@
     task_profiles.json \
     tc \
     telecom \
+    telephony-common \
     tombstoned \
     traced \
     traced_probes \
@@ -269,10 +271,6 @@
     wifi-service \
     wm \
 
-# TODO(b/146549048) remove this
-PRODUCT_PACKAGES += \
-    boringssl_self_test
-
 # VINTF data for system image
 PRODUCT_PACKAGES += \
     system_manifest.xml \
@@ -326,7 +324,7 @@
     telephony-common \
     voip-common \
     ims-common \
-    framework-sdkext \
+    framework-sdkextensions \
     ike \
     updatable-media \
     framework-tethering
@@ -335,9 +333,7 @@
     com.android.conscrypt:conscrypt \
     com.android.ipsec:ike \
     com.android.media:updatable-media \
-    com.android.sdkext:framework-sdkext \
-    com.android.telephony:telephony-common \
-    com.android.telephony:ims-common \
+    com.android.sdkext:framework-sdkextensions \
     com.android.tethering:framework-tethering
 
 PRODUCT_COPY_FILES += \
diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk
index c49aab7..9ed2ef1 100644
--- a/target/product/base_vendor.mk
+++ b/target/product/base_vendor.mk
@@ -72,7 +72,7 @@
 
 # VINTF data for vendor image
 PRODUCT_PACKAGES += \
-    device_compatibility_matrix.xml \
+    vendor_compatibility_matrix.xml \
 
 # Packages to update the recovery partition, which will be installed on
 # /vendor. TODO(b/141648565): Don't install these unless they're needed.
diff --git a/target/product/emulated_storage.mk b/target/product/emulated_storage.mk
new file mode 100644
index 0000000..89de192
--- /dev/null
+++ b/target/product/emulated_storage.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2020 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.
+#
+
+PRODUCT_QUOTA_PROJID := 1
+PRODUCT_PRODUCT_PROPERTIES += ro.emulated_storage.projid=1
+
+PRODUCT_FS_CASEFOLD := 1
+PRODUCT_PRODUCT_PROPERTIES += ro.emulated_storage.casefold=1
diff --git a/target/product/gsi/Android.mk b/target/product/gsi/Android.mk
index 424cf05..4f2027f 100644
--- a/target/product/gsi/Android.mk
+++ b/target/product/gsi/Android.mk
@@ -51,7 +51,7 @@
 ifeq (REL,$(PLATFORM_VERSION_CODENAME))
 _vndk_check_failure_message += "       Changing the VNDK library list is not allowed in API locked branches."
 else
-_vndk_check_failure_message += "       Run update-vndk-list.sh to update $(LATEST_VNDK_LIB_LIST)"
+_vndk_check_failure_message += "       Run \`update-vndk-list.sh\` to update $(LATEST_VNDK_LIB_LIST)"
 endif
 
 $(check-vndk-list-timestamp): $(INTERNAL_VNDK_LIB_LIST) $(LATEST_VNDK_LIB_LIST) $(HOST_OUT_EXECUTABLES)/update-vndk-list.sh
@@ -93,8 +93,8 @@
 	@chmod a+x $@
 
 #####################################################################
-# Check that all ABI reference dumps have corresponding NDK/VNDK
-# libraries.
+# Check that all ABI reference dumps have corresponding
+# NDK/VNDK/PLATFORM libraries.
 
 # $(1): The directory containing ABI dumps.
 # Return a list of ABI dump paths ending with .so.lsdump.
@@ -104,25 +104,42 @@
     $(call find-files-in-subdirs,$(1),"*.so.lsdump" -and -type f,.)))
 endef
 
+# $(1): A list of tags.
+# $(2): A list of tag:path.
+# Return the file names of the ABI dumps that match the tags.
+define filter-abi-dump-paths
+$(eval tag_patterns := $(foreach tag,$(1),$(tag):%))
+$(notdir $(patsubst $(tag_patterns),%,$(filter $(tag_patterns),$(2))))
+endef
+
 VNDK_ABI_DUMP_DIR := prebuilts/abi-dumps/vndk/$(PLATFORM_VNDK_VERSION)
 NDK_ABI_DUMP_DIR := prebuilts/abi-dumps/ndk/$(PLATFORM_VNDK_VERSION)
+PLATFORM_ABI_DUMP_DIR := prebuilts/abi-dumps/platform/$(PLATFORM_VNDK_VERSION)
 VNDK_ABI_DUMPS := $(call find-abi-dump-paths,$(VNDK_ABI_DUMP_DIR))
 NDK_ABI_DUMPS := $(call find-abi-dump-paths,$(NDK_ABI_DUMP_DIR))
+PLATFORM_ABI_DUMPS := $(call find-abi-dump-paths,$(PLATFORM_ABI_DUMP_DIR))
 
-$(check-vndk-abi-dump-list-timestamp): $(VNDK_ABI_DUMPS) $(NDK_ABI_DUMPS)
+$(check-vndk-abi-dump-list-timestamp): PRIVATE_LSDUMP_PATHS := $(LSDUMP_PATHS)
+$(check-vndk-abi-dump-list-timestamp):
 	$(eval added_vndk_abi_dumps := $(strip $(sort $(filter-out \
-	  $(addsuffix .so.lsdump,$(filter-out $(NDK_MIGRATED_LIBS) $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) $(VNDK_CORE_LIBRARIES))), \
+	  $(call filter-abi-dump-paths,LLNDK VNDK-SP VNDK-core,$(PRIVATE_LSDUMP_PATHS)), \
 	  $(notdir $(VNDK_ABI_DUMPS))))))
 	$(if $(added_vndk_abi_dumps), \
-	  echo -e "Found ABI reference dumps for non-VNDK libraries. Run \`find \$${ANDROID_BUILD_TOP}/$(VNDK_ABI_DUMP_DIR) '(' -name $(subst $(space), -or -name ,$(added_vndk_abi_dumps)) ')' -delete\` to delete the dumps.")
+	  echo -e "Found unexpected ABI reference dump files under $(VNDK_ABI_DUMP_DIR). It is caused by mismatch between Android.bp and the dump files. Run \`find \$${ANDROID_BUILD_TOP}/$(VNDK_ABI_DUMP_DIR) '(' -name $(subst $(space), -or -name ,$(added_vndk_abi_dumps)) ')' -delete\` to delete the dump files.")
 
 	$(eval added_ndk_abi_dumps := $(strip $(sort $(filter-out \
-	  $(addsuffix .so.lsdump,$(NDK_MIGRATED_LIBS)), \
+	  $(call filter-abi-dump-paths,NDK,$(PRIVATE_LSDUMP_PATHS)), \
 	  $(notdir $(NDK_ABI_DUMPS))))))
 	$(if $(added_ndk_abi_dumps), \
-	  echo -e "Found ABI reference dumps for non-NDK libraries. Run \`find \$${ANDROID_BUILD_TOP}/$(NDK_ABI_DUMP_DIR) '(' -name $(subst $(space), -or -name ,$(added_ndk_abi_dumps)) ')' -delete\` to delete the dumps.")
+	  echo -e "Found unexpected ABI reference dump files under $(NDK_ABI_DUMP_DIR). It is caused by mismatch between Android.bp and the dump files. Run \`find \$${ANDROID_BUILD_TOP}/$(NDK_ABI_DUMP_DIR) '(' -name $(subst $(space), -or -name ,$(added_ndk_abi_dumps)) ')' -delete\` to delete the dump files.")
 
-	$(if $(added_vndk_abi_dumps)$(added_ndk_abi_dumps),exit 1)
+	$(eval added_platform_abi_dumps := $(strip $(sort $(filter-out \
+	  $(call filter-abi-dump-paths,PLATFORM,$(PRIVATE_LSDUMP_PATHS)), \
+	  $(notdir $(PLATFORM_ABI_DUMPS))))))
+	$(if $(added_platform_abi_dumps), \
+	  echo -e "Found unexpected ABI reference dump files under $(PLATFORM_ABI_DUMP_DIR). It is caused by mismatch between Android.bp and the dump files. Run \`find \$${ANDROID_BUILD_TOP}/$(PLATFORM_ABI_DUMP_DIR) '(' -name $(subst $(space), -or -name ,$(added_platform_abi_dumps)) ')' -delete\` to delete the dump files.")
+
+	$(if $(added_vndk_abi_dumps)$(added_ndk_abi_dumps)$(added_platform_abi_dumps),exit 1)
 	$(hide) mkdir -p $(dir $@)
 	$(hide) touch $@
 
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index c50177f..b015c83 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -128,6 +128,7 @@
 VNDK-core: android.hardware.health@1.0.so
 VNDK-core: android.hardware.health@2.0.so
 VNDK-core: android.hardware.health@2.1.so
+VNDK-core: android.hardware.identity@1.0.so
 VNDK-core: android.hardware.input.classifier@1.0.so
 VNDK-core: android.hardware.input.common@1.0.so
 VNDK-core: android.hardware.ir@1.0.so
@@ -149,6 +150,7 @@
 VNDK-core: android.hardware.nfc@1.1.so
 VNDK-core: android.hardware.nfc@1.2.so
 VNDK-core: android.hardware.oemlock@1.0.so
+VNDK-core: android.hardware.power-V1-ndk_platform.so
 VNDK-core: android.hardware.power.stats@1.0.so
 VNDK-core: android.hardware.power@1.0.so
 VNDK-core: android.hardware.power@1.1.so
@@ -167,6 +169,7 @@
 VNDK-core: android.hardware.radio@1.5.so
 VNDK-core: android.hardware.secure_element@1.0.so
 VNDK-core: android.hardware.secure_element@1.1.so
+VNDK-core: android.hardware.secure_element@1.2.so
 VNDK-core: android.hardware.sensors@1.0.so
 VNDK-core: android.hardware.sensors@2.0.so
 VNDK-core: android.hardware.soundtrigger@2.0-core.so
@@ -186,6 +189,7 @@
 VNDK-core: android.hardware.usb@1.0.so
 VNDK-core: android.hardware.usb@1.1.so
 VNDK-core: android.hardware.usb@1.2.so
+VNDK-core: android.hardware.vibrator-V1-ndk_platform.so
 VNDK-core: android.hardware.vibrator@1.0.so
 VNDK-core: android.hardware.vibrator@1.1.so
 VNDK-core: android.hardware.vibrator@1.2.so
@@ -232,8 +236,6 @@
 VNDK-core: libhardware_legacy.so
 VNDK-core: libhidlallocatorutils.so
 VNDK-core: libjpeg.so
-VNDK-core: libkeymaster_messages.so
-VNDK-core: libkeymaster_portable.so
 VNDK-core: libldacBT_abr.so
 VNDK-core: libldacBT_enc.so
 VNDK-core: liblz4.so
@@ -249,12 +251,8 @@
 VNDK-core: libpng.so
 VNDK-core: libpower.so
 VNDK-core: libprocinfo.so
-VNDK-core: libprotobuf-cpp-full-3.9.1.so
-VNDK-core: libprotobuf-cpp-lite-3.9.1.so
-VNDK-core: libpuresoftkeymasterdevice.so
 VNDK-core: libradio_metadata.so
 VNDK-core: libselinux.so
-VNDK-core: libsoftkeymasterdevice.so
 VNDK-core: libspeexresampler.so
 VNDK-core: libsqlite.so
 VNDK-core: libssl.so
@@ -273,7 +271,6 @@
 VNDK-core: libxml2.so
 VNDK-core: libyuv.so
 VNDK-core: libziparchive.so
-VNDK-core: vintf-vibrator-V1-ndk_platform.so
 VNDK-private: libbacktrace.so
 VNDK-private: libbinderthreadstate.so
 VNDK-private: libblas.so
diff --git a/target/product/mainline_system.mk b/target/product/mainline_system.mk
index c880971..ccbc907 100644
--- a/target/product/mainline_system.mk
+++ b/target/product/mainline_system.mk
@@ -24,9 +24,6 @@
 # Enable updating of APEXes
 $(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
 
-# Mainline devices support userspace reboot
-$(call inherit-product, $(SRC_TARGET_DIR)/product/userspace_reboot.mk)
-
 # Shared java libs
 PRODUCT_PACKAGES += \
     com.android.nfc_extras \
diff --git a/target/product/mainline_system_x86_64.mk b/target/product/mainline_system_x86_64.mk
index 1b1a42f..473ff72 100644
--- a/target/product/mainline_system_x86_64.mk
+++ b/target/product/mainline_system_x86_64.mk
@@ -24,9 +24,6 @@
 # Enable mainline checking
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
 
-# Enable nonflat APEX
-$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
-
 PRODUCT_BUILD_CACHE_IMAGE := false
 PRODUCT_BUILD_ODM_IMAGE := false
 PRODUCT_BUILD_PRODUCT_IMAGE  := false
diff --git a/target/product/sdk_phone_x86.mk b/target/product/sdk_phone_x86.mk
index 4f7602d..9df26a9 100644
--- a/target/product/sdk_phone_x86.mk
+++ b/target/product/sdk_phone_x86.mk
@@ -15,7 +15,6 @@
 #
 QEMU_USE_SYSTEM_EXT_PARTITIONS := true
 PRODUCT_USE_DYNAMIC_PARTITIONS := true
-BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS += --flags 2
 
 #
 # All components inherited here go to system image
diff --git a/target/product/virtual_ab_ota.mk b/target/product/virtual_ab_ota.mk
index c00b0ed..5c398b4 100644
--- a/target/product/virtual_ab_ota.mk
+++ b/target/product/virtual_ab_ota.mk
@@ -17,3 +17,5 @@
 PRODUCT_VIRTUAL_AB_OTA := true
 
 PRODUCT_PRODUCT_PROPERTIES += ro.virtual_ab.enabled=true
+
+PRODUCT_PACKAGES += e2fsck_ramdisk
diff --git a/tools/check_identical_lib.sh b/tools/check_identical_lib.sh
index 01007c0..c3aa41a 100755
--- a/tools/check_identical_lib.sh
+++ b/tools/check_identical_lib.sh
@@ -5,11 +5,13 @@
 CORE="${2}"
 VENDOR="${3}"
 
-stripped_core="${CORE}.vndk_lib_check.stripped"
-stripped_vendor="${VENDOR}.vndk_lib_check.stripped"
+TMPDIR="$(mktemp -d ${CORE}.vndk_lib_check.XXXXXXXX)"
+stripped_core="${TMPDIR}/core"
+stripped_vendor="${TMPDIR}/vendor"
 
 function cleanup() {
-  rm -f ${stripped_core} ${stripped_vendor}
+  rm -f "${stripped_core}" "${stripped_vendor}"
+  rmdir "${TMPDIR}"
 }
 trap cleanup EXIT
 
diff --git a/tools/releasetools/apex_utils.py b/tools/releasetools/apex_utils.py
index ee3c463..cf10386 100644
--- a/tools/releasetools/apex_utils.py
+++ b/tools/releasetools/apex_utils.py
@@ -18,6 +18,7 @@
 import os.path
 import re
 import shlex
+import shutil
 import zipfile
 
 import common
@@ -41,6 +42,136 @@
     Exception.__init__(self, message)
 
 
+class ApexApkSigner(object):
+  """Class to sign the apk files in a apex payload image and repack the apex"""
+
+  def __init__(self, apex_path, key_passwords, codename_to_api_level_map):
+    self.apex_path = apex_path
+    self.key_passwords = key_passwords
+    self.codename_to_api_level_map = codename_to_api_level_map
+
+  def ProcessApexFile(self, apk_keys, payload_key, payload_public_key):
+    """Scans and signs the apk files and repack the apex
+
+    Args:
+      apk_keys: A dict that holds the signing keys for apk files.
+      payload_key: The path to the apex payload signing key.
+      payload_public_key: The path to the public key corresponding to the
+       payload signing key.
+
+    Returns:
+      The repacked apex file containing the signed apk files.
+    """
+    list_cmd = ['deapexer', 'list', self.apex_path]
+    entries_names = common.RunAndCheckOutput(list_cmd).split()
+    apk_entries = [name for name in entries_names if name.endswith('.apk')]
+
+    # No need to sign and repack, return the original apex path.
+    if not apk_entries:
+      logger.info('No apk file to sign in %s', self.apex_path)
+      return self.apex_path
+
+    for entry in apk_entries:
+      apk_name = os.path.basename(entry)
+      if apk_name not in apk_keys:
+        raise ApexSigningError('Failed to find signing keys for apk file {} in'
+                               ' apex {}.  Use "-e <apkname>=" to specify a key'
+                               .format(entry, self.apex_path))
+      if not any(dirname in entry for dirname in ['app/', 'priv-app/',
+                                                  'overlay/']):
+        logger.warning('Apk path does not contain the intended directory name:'
+                       ' %s', entry)
+
+    payload_dir, has_signed_apk = self.ExtractApexPayloadAndSignApks(
+        apk_entries, apk_keys)
+    if not has_signed_apk:
+      logger.info('No apk file has been signed in %s', self.apex_path)
+      return self.apex_path
+
+    return self.RepackApexPayload(payload_dir, payload_key, payload_public_key)
+
+  def ExtractApexPayloadAndSignApks(self, apk_entries, apk_keys):
+    """Extracts the payload image and signs the containing apk files."""
+    payload_dir = common.MakeTempDir()
+    extract_cmd = ['deapexer', 'extract', self.apex_path, payload_dir]
+    common.RunAndCheckOutput(extract_cmd)
+
+    has_signed_apk = False
+    for entry in apk_entries:
+      apk_path = os.path.join(payload_dir, entry)
+      assert os.path.exists(self.apex_path)
+
+      key_name = apk_keys.get(os.path.basename(entry))
+      if key_name in common.SPECIAL_CERT_STRINGS:
+        logger.info('Not signing: %s due to special cert string', apk_path)
+        continue
+
+      logger.info('Signing apk file %s in apex %s', apk_path, self.apex_path)
+      # Rename the unsigned apk and overwrite the original apk path with the
+      # signed apk file.
+      unsigned_apk = common.MakeTempFile()
+      os.rename(apk_path, unsigned_apk)
+      common.SignFile(unsigned_apk, apk_path, key_name, self.key_passwords,
+                      codename_to_api_level_map=self.codename_to_api_level_map)
+      has_signed_apk = True
+    return payload_dir, has_signed_apk
+
+  def RepackApexPayload(self, payload_dir, payload_key, payload_public_key):
+    """Rebuilds the apex file with the updated payload directory."""
+    apex_dir = common.MakeTempDir()
+    # Extract the apex file and reuse its meta files as repack parameters.
+    common.UnzipToDir(self.apex_path, apex_dir)
+
+    android_jar_path = common.OPTIONS.android_jar_path
+    if not android_jar_path:
+      android_jar_path = os.path.join(os.environ.get('ANDROID_BUILD_TOP', ''),
+                                      'prebuilts', 'sdk', 'current', 'public',
+                                      'android.jar')
+      logger.warning('android_jar_path not found in options, falling back to'
+                     ' use %s', android_jar_path)
+
+    arguments_dict = {
+        'manifest': os.path.join(apex_dir, 'apex_manifest.pb'),
+        'build_info': os.path.join(apex_dir, 'apex_build_info.pb'),
+        'android_jar_path': android_jar_path,
+        'key': payload_key,
+        'pubkey': payload_public_key,
+    }
+    for filename in arguments_dict.values():
+      assert os.path.exists(filename), 'file {} not found'.format(filename)
+
+    # The repack process will add back these files later in the payload image.
+    for name in ['apex_manifest.pb', 'apex_manifest.json', 'lost+found']:
+      path = os.path.join(payload_dir, name)
+      if os.path.isfile(path):
+        os.remove(path)
+      elif os.path.isdir(path):
+        shutil.rmtree(path)
+
+    repacked_apex = common.MakeTempFile(suffix='.apex')
+    repack_cmd = ['apexer', '--force', '--include_build_info',
+                  '--do_not_check_keyname', '--apexer_tool_path',
+                  os.getenv('PATH')]
+    for key, val in arguments_dict.items():
+      repack_cmd.append('--' + key)
+      repack_cmd.append(val)
+    # optional arguments for apex repacking
+    manifest_json = os.path.join(apex_dir, 'apex_manifest.json')
+    if os.path.exists(manifest_json):
+      repack_cmd.append('--manifest_json')
+      repack_cmd.append(manifest_json)
+    assets_dir = os.path.join(apex_dir, 'assets')
+    if os.path.isdir(assets_dir):
+      repack_cmd.append('--assets_dir')
+      repack_cmd.append(assets_dir)
+
+    repack_cmd.append(payload_dir)
+    repack_cmd.append(repacked_apex)
+    common.RunAndCheckOutput(repack_cmd)
+
+    return repacked_apex
+
+
 def SignApexPayload(avbtool, payload_file, payload_key_path, payload_key_name,
                     algorithm, salt, no_hashtree, signing_args=None):
   """Signs a given payload_file with the payload key."""
@@ -155,7 +286,8 @@
 
 
 def SignApex(avbtool, apex_data, payload_key, container_key, container_pw,
-             codename_to_api_level_map, no_hashtree, signing_args=None):
+             apk_keys, codename_to_api_level_map,
+             no_hashtree, signing_args=None):
   """Signs the current APEX with the given payload/container keys.
 
   Args:
@@ -163,6 +295,7 @@
     payload_key: The path to payload signing key (w/ extension).
     container_key: The path to container signing key (w/o extension).
     container_pw: The matching password of the container_key, or None.
+    apk_keys: A dict that holds the signing keys for apk files.
     codename_to_api_level_map: A dict that maps from codename to API level.
     no_hashtree: Don't include hashtree in the signed APEX.
     signing_args: Additional args to be passed to the payload signer.
@@ -177,7 +310,15 @@
   APEX_PAYLOAD_IMAGE = 'apex_payload.img'
   APEX_PUBKEY = 'apex_pubkey'
 
-  # 1a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
+  # 1. Extract the apex payload image and sign the containing apk files. Repack
+  # the apex file after signing.
+  payload_public_key = common.ExtractAvbPublicKey(avbtool, payload_key)
+  apk_signer = ApexApkSigner(apex_file, container_pw,
+                             codename_to_api_level_map)
+  apex_file = apk_signer.ProcessApexFile(apk_keys, payload_key,
+                                         payload_public_key)
+
+  # 2a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
   # payload_key.
   payload_dir = common.MakeTempDir(prefix='apex-payload-')
   with zipfile.ZipFile(apex_file) as apex_fd:
@@ -195,8 +336,7 @@
       no_hashtree,
       signing_args)
 
-  # 1b. Update the embedded payload public key.
-  payload_public_key = common.ExtractAvbPublicKey(avbtool, payload_key)
+  # 2b. Update the embedded payload public key.
 
   common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
   if APEX_PUBKEY in zip_items:
@@ -206,11 +346,11 @@
   common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY)
   common.ZipClose(apex_zip)
 
-  # 2. Align the files at page boundary (same as in apexer).
+  # 3. Align the files at page boundary (same as in apexer).
   aligned_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')
   common.RunAndCheckOutput(['zipalign', '-f', '4096', apex_file, aligned_apex])
 
-  # 3. Sign the APEX container with container_key.
+  # 4. Sign the APEX container with container_key.
   signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')
 
   # Specify the 4K alignment when calling SignApk.
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 1e7d387..e424b6f 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -248,6 +248,8 @@
   build_command = []
   fs_type = prop_dict.get("fs_type", "")
   run_e2fsck = False
+  needs_projid = prop_dict.get("needs_projid", 0)
+  needs_casefold = prop_dict.get("needs_casefold", 0)
 
   if fs_type.startswith("ext"):
     build_command = [prop_dict["ext_mkuserimg"]]
@@ -287,7 +289,10 @@
         build_command.extend(["-S", prop_dict["hash_seed"]])
     if "ext4_share_dup_blocks" in prop_dict:
       build_command.append("-c")
-    build_command.extend(["--inode_size", "256"])
+    if (needs_projid):
+      build_command.extend(["--inode_size", "512"])
+    else:
+      build_command.extend(["--inode_size", "256"])
     if "selinux_fc" in prop_dict:
       build_command.append(prop_dict["selinux_fc"])
   elif fs_type.startswith("squash"):
@@ -328,6 +333,10 @@
     if "timestamp" in prop_dict:
       build_command.extend(["-T", str(prop_dict["timestamp"])])
     build_command.extend(["-L", prop_dict["mount_point"]])
+    if (needs_projid):
+      build_command.append("--prjquota")
+    if (needs_casefold):
+      build_command.append("--casefold")
   else:
     raise BuildImageError(
         "Error: unknown filesystem type: {}".format(fs_type))
@@ -598,6 +607,8 @@
     copy_prop("flash_logical_block_size", "flash_logical_block_size")
     copy_prop("flash_erase_block_size", "flash_erase_block_size")
     copy_prop("userdata_selinux_fc", "selinux_fc")
+    copy_prop("needs_casefold", "needs_casefold")
+    copy_prop("needs_projid", "needs_projid")
   elif mount_point == "cache":
     copy_prop("cache_fs_type", "fs_type")
     copy_prop("cache_size", "partition_size")
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index a556f53..f41df37 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -45,6 +45,7 @@
     '/vendor': ('VENDOR', 'SYSTEM/vendor'),
     '/product': ('PRODUCT', 'SYSTEM/product'),
     '/odm': ('ODM', 'VENDOR/odm', 'SYSTEM/vendor/odm'),
+    '/system_ext': ('SYSTEM_EXT', 'SYSTEM/system_ext'),
 }
 
 UNZIP_PATTERN = ['META/*', '*/build.prop']
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 556d25a..2e235ee 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -62,13 +62,14 @@
           'Warning: releasetools script should be invoked as hermetic Python '
           'executable -- build and run `{}` directly.'.format(script_name[:-3]),
           file=sys.stderr)
-    self.search_path = os.path.realpath(os.path.join(exec_path, '..'))
+    self.search_path = os.path.realpath(os.path.join(os.path.dirname(exec_path), '..'))
 
     self.signapk_path = "framework/signapk.jar"  # Relative to search_path
     self.signapk_shared_library_path = "lib64"   # Relative to search_path
     self.extra_signapk_args = []
     self.java_path = "java"  # Use the one on the path by default.
     self.java_args = ["-Xmx2048m"]  # The default JVM args.
+    self.android_jar_path = None
     self.public_key_suffix = ".x509.pem"
     self.private_key_suffix = ".pk8"
     # use otatools built boot_signer by default
@@ -823,6 +824,12 @@
     merged_dict[key] = (
         "%s %s" %
         (framework_dict.get(key, ""), vendor_dict.get(key, ""))).strip()
+
+  # Pick virtual ab related flags from vendor dict, if defined.
+  if "virtual_ab" in vendor_dict.keys():
+     merged_dict["virtual_ab"] = vendor_dict["virtual_ab"]
+  if "virtual_ab_retrofit" in vendor_dict.keys():
+     merged_dict["virtual_ab_retrofit"] = vendor_dict["virtual_ab_retrofit"]
   return merged_dict
 
 
@@ -1817,7 +1824,7 @@
         argv, "hvp:s:x:" + extra_opts,
         ["help", "verbose", "path=", "signapk_path=",
          "signapk_shared_library_path=", "extra_signapk_args=",
-         "java_path=", "java_args=", "public_key_suffix=",
+         "java_path=", "java_args=", "android_jar_path=", "public_key_suffix=",
          "private_key_suffix=", "boot_signer_path=", "boot_signer_args=",
          "verity_signer_path=", "verity_signer_args=", "device_specific=",
          "extra=", "logfile=", "aftl_server=", "aftl_key_path=",
@@ -1846,6 +1853,8 @@
       OPTIONS.java_path = a
     elif o in ("--java_args",):
       OPTIONS.java_args = shlex.split(a)
+    elif o in ("--android_jar_path",):
+      OPTIONS.android_jar_path = a
     elif o in ("--public_key_suffix",):
       OPTIONS.public_key_suffix = a
     elif o in ("--private_key_suffix",):
diff --git a/tools/releasetools/sign_apex.py b/tools/releasetools/sign_apex.py
index 4c0850c..b0128dc 100755
--- a/tools/releasetools/sign_apex.py
+++ b/tools/releasetools/sign_apex.py
@@ -31,6 +31,10 @@
   --payload_extra_args <args>
       Optional flag that specifies any extra args to be passed to payload signer
       (e.g. --payload_extra_args="--signing_helper_with_files /path/to/helper").
+
+  -e  (--extra_apks)  <name,name,...=key>
+      Add extra APK name/key pairs. This is useful to sign the apk files in the
+      apex payload image.
 """
 
 import logging
@@ -43,8 +47,8 @@
 logger = logging.getLogger(__name__)
 
 
-def SignApexFile(avbtool, apex_file, payload_key, container_key,
-                 no_hashtree, signing_args=None):
+def SignApexFile(avbtool, apex_file, payload_key, container_key, no_hashtree,
+                 apk_keys=None, signing_args=None):
   """Signs the given apex file."""
   with open(apex_file, 'rb') as input_fp:
     apex_data = input_fp.read()
@@ -57,6 +61,7 @@
       container_pw=None,
       codename_to_api_level_map=None,
       no_hashtree=no_hashtree,
+      apk_keys=apk_keys,
       signing_args=signing_args)
 
 
@@ -77,18 +82,26 @@
       options['payload_key'] = a
     elif o == '--payload_extra_args':
       options['payload_extra_args'] = a
+    elif o in ("-e", "--extra_apks"):
+      names, key = a.split("=")
+      names = names.split(",")
+      for n in names:
+        if 'extra_apks' not in options:
+          options['extra_apks'] = {}
+        options['extra_apks'].update({n: key})
     else:
       return False
     return True
 
   args = common.ParseOptions(
       argv, __doc__,
-      extra_opts='',
+      extra_opts='e:',
       extra_long_opts=[
           'avbtool=',
           'container_key=',
           'payload_extra_args=',
           'payload_key=',
+          'extra_apks=',
       ],
       extra_option_handler=option_handler)
 
@@ -105,6 +118,7 @@
       options['payload_key'],
       options['container_key'],
       no_hashtree=False,
+      apk_keys=options.get('extra_apks', {}),
       signing_args=options.get('payload_extra_args'))
   shutil.copyfile(signed_apex, args[1])
   logger.info("done.")
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 35b11c1..cce771c 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -103,6 +103,9 @@
       Specify any additional args that are needed to AVB-sign the image
       (e.g. "--signing_helper /path/to/helper"). The args will be appended to
       the existing ones in info dict.
+
+  --android_jar_path <path>
+      Path to the android.jar to repack the apex file.
 """
 
 from __future__ import print_function
@@ -151,6 +154,7 @@
 OPTIONS.avb_keys = {}
 OPTIONS.avb_algorithms = {}
 OPTIONS.avb_extra_args = {}
+OPTIONS.android_jar_path = None
 
 
 AVB_FOOTER_ARGS_BY_PARTITION = {
@@ -492,6 +496,7 @@
             payload_key,
             container_key,
             key_passwords[container_key],
+            apk_keys,
             codename_to_api_level_map,
             no_hashtree=True,
             signing_args=OPTIONS.avb_extra_args.get('apex'))
@@ -552,8 +557,13 @@
 
     # Ask add_img_to_target_files to rebuild the recovery patch if needed.
     elif filename in ("SYSTEM/recovery-from-boot.p",
+                      "VENDOR/recovery-from-boot.p",
+
                       "SYSTEM/etc/recovery.img",
-                      "SYSTEM/bin/install-recovery.sh"):
+                      "VENDOR/etc/recovery.img",
+
+                      "SYSTEM/bin/install-recovery.sh",
+                      "VENDOR/bin/install-recovery.sh"):
       OPTIONS.rebuild_recovery = True
 
     # Don't copy OTA certs if we're replacing them.
@@ -1242,6 +1252,8 @@
   apex_keys_info = ReadApexKeysInfo(input_zip)
   apex_keys = GetApexKeys(apex_keys_info, apk_keys)
 
+  # TODO(xunchang) check for the apks inside the apex files, and abort early if
+  # the keys are not available.
   CheckApkAndApexKeysAvailable(
       input_zip,
       set(apk_keys.keys()) | set(apex_keys.keys()),
diff --git a/tools/releasetools/test_apex_utils.py b/tools/releasetools/test_apex_utils.py
index 5d4cc77..cc28f3f 100644
--- a/tools/releasetools/test_apex_utils.py
+++ b/tools/releasetools/test_apex_utils.py
@@ -16,6 +16,7 @@
 
 import os
 import os.path
+import zipfile
 
 import apex_utils
 import common
@@ -32,6 +33,8 @@
     # The default payload signing key.
     self.payload_key = os.path.join(self.testdata_dir, 'testkey.key')
 
+    common.OPTIONS.search_path = test_utils.get_search_path()
+
   @staticmethod
   def _GetTestPayload():
     payload_file = common.MakeTempFile(prefix='apex-', suffix='.img')
@@ -126,3 +129,50 @@
         payload_file,
         os.path.join(self.testdata_dir, 'testkey_with_passwd.key'),
         no_hashtree=True)
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_ApexApkSigner_noApkPresent(self):
+    apex_path = os.path.join(self.testdata_dir, 'foo.apex')
+    signer = apex_utils.ApexApkSigner(apex_path, None, None)
+    processed_apex = signer.ProcessApexFile({}, self.payload_key,
+                                            None)
+    self.assertEqual(apex_path, processed_apex)
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_ApexApkSigner_apkKeyNotPresent(self):
+    apex_path = os.path.join(self.testdata_dir, 'has_apk.apex')
+    signer = apex_utils.ApexApkSigner(apex_path, None, None)
+    self.assertRaises(apex_utils.ApexSigningError, signer.ProcessApexFile, {},
+                      self.payload_key, None)
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_ApexApkSigner_signApk(self):
+    apex_path = os.path.join(self.testdata_dir, 'has_apk.apex')
+    signer = apex_utils.ApexApkSigner(apex_path, None, None)
+    apk_keys = {'wifi-service-resources.apk': os.path.join(
+        self.testdata_dir, 'testkey')}
+
+    self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
+    payload_pubkey = common.ExtractAvbPublicKey('avbtool',
+                                                self.payload_key)
+    signer.ProcessApexFile(apk_keys, self.payload_key, payload_pubkey)
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_ApexApkSigner_noAssetDir(self):
+    apex_path = os.path.join(self.testdata_dir, 'has_apk.apex')
+    no_asset = common.MakeTempFile(suffix='.apex')
+    with zipfile.ZipFile(no_asset, 'w') as output_zip:
+      with zipfile.ZipFile(apex_path, 'r') as input_zip:
+        name_list = input_zip.namelist()
+        for name in name_list:
+          if not name.startswith('assets'):
+            output_zip.writestr(name, input_zip.read(name))
+
+    signer = apex_utils.ApexApkSigner(no_asset, None, None)
+    apk_keys = {'wifi-service-resources.apk': os.path.join(
+        self.testdata_dir, 'testkey')}
+
+    self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
+    payload_pubkey = common.ExtractAvbPublicKey('avbtool',
+                                                self.payload_key)
+    signer.ProcessApexFile(apk_keys, self.payload_key, payload_pubkey)
diff --git a/tools/releasetools/test_sign_apex.py b/tools/releasetools/test_sign_apex.py
index 79d1de4..82f5938 100644
--- a/tools/releasetools/test_sign_apex.py
+++ b/tools/releasetools/test_sign_apex.py
@@ -41,3 +41,19 @@
         container_key,
         False)
     self.assertTrue(os.path.exists(signed_foo_apex))
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_SignApexWithApk(self):
+    test_apex = os.path.join(self.testdata_dir, 'has_apk.apex')
+    payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
+    container_key = os.path.join(self.testdata_dir, 'testkey')
+    apk_keys = {'wifi-service-resources.apk': os.path.join(
+        self.testdata_dir, 'testkey')}
+    signed_test_apex = sign_apex.SignApexFile(
+        'avbtool',
+        test_apex,
+        payload_key,
+        container_key,
+        False,
+        apk_keys)
+    self.assertTrue(os.path.exists(signed_test_apex))
diff --git a/tools/releasetools/testdata/has_apk.apex b/tools/releasetools/testdata/has_apk.apex
new file mode 100644
index 0000000..12bbdf9
--- /dev/null
+++ b/tools/releasetools/testdata/has_apk.apex
Binary files differ
diff --git a/tools/warn/android_project_list.py b/tools/warn/android_project_list.py
index 1e9e276..4726fa2 100644
--- a/tools/warn/android_project_list.py
+++ b/tools/warn/android_project_list.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,161 +16,160 @@
 """Define a project list to sort warnings by project directory path."""
 
 
-def project_name_and_pattern(name, pattern):
-  return [name, '(^|.*/)' + pattern + '/.*: warning:']
-
-
-def simple_project_pattern(pattern):
-  return project_name_and_pattern(pattern, pattern)
+def create_pattern(name, pattern=None):
+  if pattern is not None:
+    return [name, '(^|.*/)' + pattern + '/.*: warning:']
+  return [name, '(^|.*/)' + name + '/.*: warning:']
 
 
 # A list of [project_name, file_path_pattern].
 # project_name should not contain comma, to be used in CSV output.
 project_list = [
-    simple_project_pattern('art'),
-    simple_project_pattern('bionic'),
-    simple_project_pattern('bootable'),
-    simple_project_pattern('build'),
-    simple_project_pattern('cts'),
-    simple_project_pattern('dalvik'),
-    simple_project_pattern('developers'),
-    simple_project_pattern('development'),
-    simple_project_pattern('device'),
-    simple_project_pattern('doc'),
+    create_pattern('art'),
+    create_pattern('bionic'),
+    create_pattern('bootable'),
+    create_pattern('build'),
+    create_pattern('cts'),
+    create_pattern('dalvik'),
+    create_pattern('developers'),
+    create_pattern('development'),
+    create_pattern('device'),
+    create_pattern('doc'),
     # match external/google* before external/
-    project_name_and_pattern('external/google', 'external/google.*'),
-    project_name_and_pattern('external/non-google', 'external'),
-    simple_project_pattern('frameworks/av/camera'),
-    simple_project_pattern('frameworks/av/cmds'),
-    simple_project_pattern('frameworks/av/drm'),
-    simple_project_pattern('frameworks/av/include'),
-    simple_project_pattern('frameworks/av/media/img_utils'),
-    simple_project_pattern('frameworks/av/media/libcpustats'),
-    simple_project_pattern('frameworks/av/media/libeffects'),
-    simple_project_pattern('frameworks/av/media/libmediaplayerservice'),
-    simple_project_pattern('frameworks/av/media/libmedia'),
-    simple_project_pattern('frameworks/av/media/libstagefright'),
-    simple_project_pattern('frameworks/av/media/mtp'),
-    simple_project_pattern('frameworks/av/media/ndk'),
-    simple_project_pattern('frameworks/av/media/utils'),
-    project_name_and_pattern('frameworks/av/media/Other',
-                             'frameworks/av/media'),
-    simple_project_pattern('frameworks/av/radio'),
-    simple_project_pattern('frameworks/av/services'),
-    simple_project_pattern('frameworks/av/soundtrigger'),
-    project_name_and_pattern('frameworks/av/Other', 'frameworks/av'),
-    simple_project_pattern('frameworks/base/cmds'),
-    simple_project_pattern('frameworks/base/core'),
-    simple_project_pattern('frameworks/base/drm'),
-    simple_project_pattern('frameworks/base/media'),
-    simple_project_pattern('frameworks/base/libs'),
-    simple_project_pattern('frameworks/base/native'),
-    simple_project_pattern('frameworks/base/packages'),
-    simple_project_pattern('frameworks/base/rs'),
-    simple_project_pattern('frameworks/base/services'),
-    simple_project_pattern('frameworks/base/tests'),
-    simple_project_pattern('frameworks/base/tools'),
-    project_name_and_pattern('frameworks/base/Other', 'frameworks/base'),
-    simple_project_pattern('frameworks/compile/libbcc'),
-    simple_project_pattern('frameworks/compile/mclinker'),
-    simple_project_pattern('frameworks/compile/slang'),
-    project_name_and_pattern('frameworks/compile/Other', 'frameworks/compile'),
-    simple_project_pattern('frameworks/minikin'),
-    simple_project_pattern('frameworks/ml'),
-    simple_project_pattern('frameworks/native/cmds'),
-    simple_project_pattern('frameworks/native/include'),
-    simple_project_pattern('frameworks/native/libs'),
-    simple_project_pattern('frameworks/native/opengl'),
-    simple_project_pattern('frameworks/native/services'),
-    simple_project_pattern('frameworks/native/vulkan'),
-    project_name_and_pattern('frameworks/native/Other', 'frameworks/native'),
-    simple_project_pattern('frameworks/opt'),
-    simple_project_pattern('frameworks/rs'),
-    simple_project_pattern('frameworks/webview'),
-    simple_project_pattern('frameworks/wilhelm'),
-    project_name_and_pattern('frameworks/Other', 'frameworks'),
-    simple_project_pattern('hardware/akm'),
-    simple_project_pattern('hardware/broadcom'),
-    simple_project_pattern('hardware/google'),
-    simple_project_pattern('hardware/intel'),
-    simple_project_pattern('hardware/interfaces'),
-    simple_project_pattern('hardware/libhardware'),
-    simple_project_pattern('hardware/libhardware_legacy'),
-    simple_project_pattern('hardware/qcom'),
-    simple_project_pattern('hardware/ril'),
-    project_name_and_pattern('hardware/Other', 'hardware'),
-    simple_project_pattern('kernel'),
-    simple_project_pattern('libcore'),
-    simple_project_pattern('libnativehelper'),
-    simple_project_pattern('ndk'),
+    create_pattern('external/google', 'external/google.*'),
+    create_pattern('external/non-google', 'external'),
+    create_pattern('frameworks/av/camera'),
+    create_pattern('frameworks/av/cmds'),
+    create_pattern('frameworks/av/drm'),
+    create_pattern('frameworks/av/include'),
+    create_pattern('frameworks/av/media/img_utils'),
+    create_pattern('frameworks/av/media/libcpustats'),
+    create_pattern('frameworks/av/media/libeffects'),
+    create_pattern('frameworks/av/media/libmediaplayerservice'),
+    create_pattern('frameworks/av/media/libmedia'),
+    create_pattern('frameworks/av/media/libstagefright'),
+    create_pattern('frameworks/av/media/mtp'),
+    create_pattern('frameworks/av/media/ndk'),
+    create_pattern('frameworks/av/media/utils'),
+    create_pattern('frameworks/av/media/Other', 'frameworks/av/media'),
+    create_pattern('frameworks/av/radio'),
+    create_pattern('frameworks/av/services'),
+    create_pattern('frameworks/av/soundtrigger'),
+    create_pattern('frameworks/av/Other', 'frameworks/av'),
+    create_pattern('frameworks/base/cmds'),
+    create_pattern('frameworks/base/core'),
+    create_pattern('frameworks/base/drm'),
+    create_pattern('frameworks/base/media'),
+    create_pattern('frameworks/base/libs'),
+    create_pattern('frameworks/base/native'),
+    create_pattern('frameworks/base/packages'),
+    create_pattern('frameworks/base/rs'),
+    create_pattern('frameworks/base/services'),
+    create_pattern('frameworks/base/tests'),
+    create_pattern('frameworks/base/tools'),
+    create_pattern('frameworks/base/Other', 'frameworks/base'),
+    create_pattern('frameworks/compile/libbcc'),
+    create_pattern('frameworks/compile/mclinker'),
+    create_pattern('frameworks/compile/slang'),
+    create_pattern('frameworks/compile/Other', 'frameworks/compile'),
+    create_pattern('frameworks/minikin'),
+    create_pattern('frameworks/ml'),
+    create_pattern('frameworks/native/cmds'),
+    create_pattern('frameworks/native/include'),
+    create_pattern('frameworks/native/libs'),
+    create_pattern('frameworks/native/opengl'),
+    create_pattern('frameworks/native/services'),
+    create_pattern('frameworks/native/vulkan'),
+    create_pattern('frameworks/native/Other', 'frameworks/native'),
+    create_pattern('frameworks/opt'),
+    create_pattern('frameworks/rs'),
+    create_pattern('frameworks/webview'),
+    create_pattern('frameworks/wilhelm'),
+    create_pattern('frameworks/Other', 'frameworks'),
+    create_pattern('hardware/akm'),
+    create_pattern('hardware/broadcom'),
+    create_pattern('hardware/google'),
+    create_pattern('hardware/intel'),
+    create_pattern('hardware/interfaces'),
+    create_pattern('hardware/libhardware'),
+    create_pattern('hardware/libhardware_legacy'),
+    create_pattern('hardware/qcom'),
+    create_pattern('hardware/ril'),
+    create_pattern('hardware/Other', 'hardware'),
+    create_pattern('kernel'),
+    create_pattern('libcore'),
+    create_pattern('libnativehelper'),
+    create_pattern('ndk'),
     # match vendor/unbungled_google/packages before other packages
-    simple_project_pattern('unbundled_google'),
-    simple_project_pattern('packages'),
-    simple_project_pattern('pdk'),
-    simple_project_pattern('prebuilts'),
-    simple_project_pattern('system/bt'),
-    simple_project_pattern('system/connectivity'),
-    simple_project_pattern('system/core/adb'),
-    simple_project_pattern('system/core/base'),
-    simple_project_pattern('system/core/debuggerd'),
-    simple_project_pattern('system/core/fastboot'),
-    simple_project_pattern('system/core/fingerprintd'),
-    simple_project_pattern('system/core/fs_mgr'),
-    simple_project_pattern('system/core/gatekeeperd'),
-    simple_project_pattern('system/core/healthd'),
-    simple_project_pattern('system/core/include'),
-    simple_project_pattern('system/core/init'),
-    simple_project_pattern('system/core/libbacktrace'),
-    simple_project_pattern('system/core/liblog'),
-    simple_project_pattern('system/core/libpixelflinger'),
-    simple_project_pattern('system/core/libprocessgroup'),
-    simple_project_pattern('system/core/libsysutils'),
-    simple_project_pattern('system/core/logcat'),
-    simple_project_pattern('system/core/logd'),
-    simple_project_pattern('system/core/run-as'),
-    simple_project_pattern('system/core/sdcard'),
-    simple_project_pattern('system/core/toolbox'),
-    project_name_and_pattern('system/core/Other', 'system/core'),
-    simple_project_pattern('system/extras/ANRdaemon'),
-    simple_project_pattern('system/extras/cpustats'),
-    simple_project_pattern('system/extras/crypto-perf'),
-    simple_project_pattern('system/extras/ext4_utils'),
-    simple_project_pattern('system/extras/f2fs_utils'),
-    simple_project_pattern('system/extras/iotop'),
-    simple_project_pattern('system/extras/libfec'),
-    simple_project_pattern('system/extras/memory_replay'),
-    simple_project_pattern('system/extras/mmap-perf'),
-    simple_project_pattern('system/extras/multinetwork'),
-    simple_project_pattern('system/extras/procrank'),
-    simple_project_pattern('system/extras/runconuid'),
-    simple_project_pattern('system/extras/showmap'),
-    simple_project_pattern('system/extras/simpleperf'),
-    simple_project_pattern('system/extras/su'),
-    simple_project_pattern('system/extras/tests'),
-    simple_project_pattern('system/extras/verity'),
-    project_name_and_pattern('system/extras/Other', 'system/extras'),
-    simple_project_pattern('system/gatekeeper'),
-    simple_project_pattern('system/keymaster'),
-    simple_project_pattern('system/libhidl'),
-    simple_project_pattern('system/libhwbinder'),
-    simple_project_pattern('system/media'),
-    simple_project_pattern('system/netd'),
-    simple_project_pattern('system/nvram'),
-    simple_project_pattern('system/security'),
-    simple_project_pattern('system/sepolicy'),
-    simple_project_pattern('system/tools'),
-    simple_project_pattern('system/update_engine'),
-    simple_project_pattern('system/vold'),
-    project_name_and_pattern('system/Other', 'system'),
-    simple_project_pattern('toolchain'),
-    simple_project_pattern('test'),
-    simple_project_pattern('tools'),
+    create_pattern('unbundled_google'),
+    create_pattern('packages'),
+    create_pattern('pdk'),
+    create_pattern('prebuilts'),
+    create_pattern('system/bt'),
+    create_pattern('system/connectivity'),
+    create_pattern('system/core/adb'),
+    create_pattern('system/core/base'),
+    create_pattern('system/core/debuggerd'),
+    create_pattern('system/core/fastboot'),
+    create_pattern('system/core/fingerprintd'),
+    create_pattern('system/core/fs_mgr'),
+    create_pattern('system/core/gatekeeperd'),
+    create_pattern('system/core/healthd'),
+    create_pattern('system/core/include'),
+    create_pattern('system/core/init'),
+    create_pattern('system/core/libbacktrace'),
+    create_pattern('system/core/liblog'),
+    create_pattern('system/core/libpixelflinger'),
+    create_pattern('system/core/libprocessgroup'),
+    create_pattern('system/core/libsysutils'),
+    create_pattern('system/core/logcat'),
+    create_pattern('system/core/logd'),
+    create_pattern('system/core/run-as'),
+    create_pattern('system/core/sdcard'),
+    create_pattern('system/core/toolbox'),
+    create_pattern('system/core/Other', 'system/core'),
+    create_pattern('system/extras/ANRdaemon'),
+    create_pattern('system/extras/cpustats'),
+    create_pattern('system/extras/crypto-perf'),
+    create_pattern('system/extras/ext4_utils'),
+    create_pattern('system/extras/f2fs_utils'),
+    create_pattern('system/extras/iotop'),
+    create_pattern('system/extras/libfec'),
+    create_pattern('system/extras/memory_replay'),
+    create_pattern('system/extras/mmap-perf'),
+    create_pattern('system/extras/multinetwork'),
+    create_pattern('system/extras/perfprofd'),
+    create_pattern('system/extras/procrank'),
+    create_pattern('system/extras/runconuid'),
+    create_pattern('system/extras/showmap'),
+    create_pattern('system/extras/simpleperf'),
+    create_pattern('system/extras/su'),
+    create_pattern('system/extras/tests'),
+    create_pattern('system/extras/verity'),
+    create_pattern('system/extras/Other', 'system/extras'),
+    create_pattern('system/gatekeeper'),
+    create_pattern('system/keymaster'),
+    create_pattern('system/libhidl'),
+    create_pattern('system/libhwbinder'),
+    create_pattern('system/media'),
+    create_pattern('system/netd'),
+    create_pattern('system/nvram'),
+    create_pattern('system/security'),
+    create_pattern('system/sepolicy'),
+    create_pattern('system/tools'),
+    create_pattern('system/update_engine'),
+    create_pattern('system/vold'),
+    create_pattern('system/Other', 'system'),
+    create_pattern('toolchain'),
+    create_pattern('test'),
+    create_pattern('tools'),
     # match vendor/google* before vendor/
-    project_name_and_pattern('vendor/google', 'vendor/google.*'),
-    project_name_and_pattern('vendor/non-google', 'vendor'),
+    create_pattern('vendor/google', 'vendor/google.*'),
+    create_pattern('vendor/non-google', 'vendor'),
     # keep out/obj and other patterns at the end.
-    ['out/obj',
-     '.*/(gen|obj[^/]*)/(include|EXECUTABLES|SHARED_LIBRARIES|'
-     'STATIC_LIBRARIES|NATIVE_TESTS)/.*: warning:'],
+    [
+        'out/obj', '.*/(gen|obj[^/]*)/(include|EXECUTABLES|SHARED_LIBRARIES|'
+        'STATIC_LIBRARIES|NATIVE_TESTS)/.*: warning:'
+    ],
     ['other', '.*']  # all other unrecognized patterns
 ]
diff --git a/tools/warn/cpp_warn_patterns.py b/tools/warn/cpp_warn_patterns.py
index 8ae0a3c..65ce73a 100644
--- a/tools/warn/cpp_warn_patterns.py
+++ b/tools/warn/cpp_warn_patterns.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,563 +15,471 @@
 
 """Warning patterns for C/C++ compiler, but not clang-tidy."""
 
-from severity import Severity
+import re
 
-patterns = [
+# pylint:disable=relative-beyond-top-level
+# pylint:disable=g-importing-member
+from .severity import Severity
+
+
+def cpp_warn(severity, description, pattern_list):
+  return {
+      'category': 'C/C++',
+      'severity': severity,
+      'description': description,
+      'patterns': pattern_list
+  }
+
+
+def fixmenow(description, pattern_list):
+  return cpp_warn(Severity.FIXMENOW, description, pattern_list)
+
+
+def high(description, pattern_list):
+  return cpp_warn(Severity.HIGH, description, pattern_list)
+
+
+def medium(description, pattern_list):
+  return cpp_warn(Severity.MEDIUM, description, pattern_list)
+
+
+def low(description, pattern_list):
+  return cpp_warn(Severity.LOW, description, pattern_list)
+
+
+def skip(description, pattern_list):
+  return cpp_warn(Severity.SKIP, description, pattern_list)
+
+
+def harmless(description, pattern_list):
+  return cpp_warn(Severity.HARMLESS, description, pattern_list)
+
+
+warn_patterns = [
     # pylint:disable=line-too-long,g-inconsistent-quotes
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wimplicit-function-declaration',
-     'description': 'Implicit function declaration',
-     'patterns': [r".*: warning: implicit declaration of function .+",
-                  r".*: warning: implicitly declaring library function"]},
-    {'category': 'C/C++', 'severity': Severity.SKIP,
-     'description': 'skip, conflicting types for ...',
-     'patterns': [r".*: warning: conflicting types for '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': '-Wtype-limits',
-     'description': 'Expression always evaluates to true or false',
-     'patterns': [r".*: warning: comparison is always .+ due to limited range of data type",
-                  r".*: warning: comparison of unsigned .*expression .+ is always true",
-                  r".*: warning: comparison of unsigned .*expression .+ is always false"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH,
-     'description': 'Use transient memory for control value',
-     'patterns': [r".*: warning: .+Using such transient memory for the control value is .*dangerous."]},
-    {'category': 'C/C++', 'severity': Severity.HIGH,
-     'description': 'Return address of stack memory',
-     'patterns': [r".*: warning: Address of stack memory .+ returned to caller",
-                  r".*: warning: Address of stack memory .+ will be a dangling reference"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': 'infinite-recursion',
-     'description': 'Infinite recursion',
-     'patterns': [r".*: warning: all paths through this function will call itself"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH,
-     'description': 'Potential buffer overflow',
-     'patterns': [r".*: warning: Size argument is greater than .+ the destination buffer",
-                  r".*: warning: Potential buffer overflow.",
-                  r".*: warning: String copy function overflows destination buffer"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Incompatible pointer types',
-     'patterns': [r".*: warning: assignment from incompatible pointer type",
-                  r".*: warning: return from incompatible pointer type",
-                  r".*: warning: passing argument [0-9]+ of '.*' from incompatible pointer type",
-                  r".*: warning: initialization from incompatible pointer type"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': '-fno-builtin',
-     'description': 'Incompatible declaration of built in function',
-     'patterns': [r".*: warning: incompatible implicit declaration of built-in function .+"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': '-Wincompatible-library-redeclaration',
-     'description': 'Incompatible redeclaration of library function',
-     'patterns': [r".*: warning: incompatible redeclaration of library function .+"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH,
-     'description': 'Null passed as non-null argument',
-     'patterns': [r".*: warning: Null passed to a callee that requires a non-null"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wunused-parameter',
-     'description': 'Unused parameter',
-     'patterns': [r".*: warning: unused parameter '.*'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wunused',
-     'description': 'Unused function, variable, label, comparison, etc.',
-     'patterns': [r".*: warning: '.+' defined but not used",
-                  r".*: warning: unused function '.+'",
-                  r".*: warning: unused label '.+'",
-                  r".*: warning: relational comparison result unused",
-                  r".*: warning: lambda capture .* is not used",
-                  r".*: warning: private field '.+' is not used",
-                  r".*: warning: unused variable '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wunused-value',
-     'description': 'Statement with no effect or result unused',
-     'patterns': [r".*: warning: statement with no effect",
-                  r".*: warning: expression result unused"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wunused-result',
-     'description': 'Ignoreing return value of function',
-     'patterns': [r".*: warning: ignoring return value of function .+Wunused-result"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wmissing-field-initializers',
-     'description': 'Missing initializer',
-     'patterns': [r".*: warning: missing initializer"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wdelete-non-virtual-dtor',
-     'description': 'Need virtual destructor',
-     'patterns': [r".*: warning: delete called .* has virtual functions but non-virtual destructor"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip, near initialization for ...',
-     'patterns': [r".*: warning: \(near initialization for '.+'\)"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wdate-time',
-     'description': 'Expansion of data or time macro',
-     'patterns': [r".*: warning: expansion of date or time macro is not reproducible"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wexpansion-to-defined',
-     'description': 'Macro expansion has undefined behavior',
-     'patterns': [r".*: warning: macro expansion .* has undefined behavior"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wformat',
-     'description': 'Format string does not match arguments',
-     'patterns': [r".*: warning: format '.+' expects type '.+', but argument [0-9]+ has type '.+'",
-                  r".*: warning: more '%' conversions than data arguments",
-                  r".*: warning: data argument not used by format string",
-                  r".*: warning: incomplete format specifier",
-                  r".*: warning: unknown conversion type .* in format",
-                  r".*: warning: format .+ expects .+ but argument .+Wformat=",
-                  r".*: warning: field precision should have .+ but argument has .+Wformat",
-                  r".*: warning: format specifies type .+ but the argument has .*type .+Wformat"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wformat-extra-args',
-     'description': 'Too many arguments for format string',
-     'patterns': [r".*: warning: too many arguments for format"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Too many arguments in call',
-     'patterns': [r".*: warning: too many arguments in call to "]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wformat-invalid-specifier',
-     'description': 'Invalid format specifier',
-     'patterns': [r".*: warning: invalid .+ specifier '.+'.+format-invalid-specifier"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wsign-compare',
-     'description': 'Comparison between signed and unsigned',
-     'patterns': [r".*: warning: comparison between signed and unsigned",
-                  r".*: warning: comparison of promoted \~unsigned with unsigned",
-                  r".*: warning: signed and unsigned type in conditional expression"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Comparison between enum and non-enum',
-     'patterns': [r".*: warning: enumeral and non-enumeral type in conditional expression"]},
-    {'category': 'libpng', 'severity': Severity.MEDIUM,
-     'description': 'libpng: zero area',
-     'patterns': [r".*libpng warning: Ignoring attempt to set cHRM RGB triangle with zero area"]},
-    {'category': 'aapt', 'severity': Severity.MEDIUM,
-     'description': 'aapt: no comment for public symbol',
-     'patterns': [r".*: warning: No comment for public symbol .+"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wmissing-braces',
-     'description': 'Missing braces around initializer',
-     'patterns': [r".*: warning: missing braces around initializer.*"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS,
-     'description': 'No newline at end of file',
-     'patterns': [r".*: warning: no newline at end of file"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS,
-     'description': 'Missing space after macro name',
-     'patterns': [r".*: warning: missing whitespace after the macro name"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wcast-align',
-     'description': 'Cast increases required alignment',
-     'patterns': [r".*: warning: cast from .* to .* increases required alignment .*"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wcast-qual',
-     'description': 'Qualifier discarded',
-     'patterns': [r".*: warning: passing argument [0-9]+ of '.+' discards qualifiers from pointer target type",
-                  r".*: warning: assignment discards qualifiers from pointer target type",
-                  r".*: warning: passing .+ to parameter of type .+ discards qualifiers",
-                  r".*: warning: assigning to .+ from .+ discards qualifiers",
-                  r".*: warning: initializing .+ discards qualifiers .+types-discards-qualifiers",
-                  r".*: warning: return discards qualifiers from pointer target type"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wunknown-attributes',
-     'description': 'Unknown attribute',
-     'patterns': [r".*: warning: unknown attribute '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wignored-attributes',
-     'description': 'Attribute ignored',
-     'patterns': [r".*: warning: '_*packed_*' attribute ignored",
-                  r".*: warning: attribute declaration must precede definition .+ignored-attributes"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wvisibility',
-     'description': 'Visibility problem',
-     'patterns': [r".*: warning: declaration of '.+' will not be visible outside of this function"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wattributes',
-     'description': 'Visibility mismatch',
-     'patterns': [r".*: warning: '.+' declared with greater visibility than the type of its field '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Shift count greater than width of type',
-     'patterns': [r".*: warning: (left|right) shift count >= width of type"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wextern-initializer',
-     'description': 'extern &lt;foo&gt; is initialized',
-     'patterns': [r".*: warning: '.+' initialized and declared 'extern'",
-                  r".*: warning: 'extern' variable has an initializer"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wold-style-declaration',
-     'description': 'Old style declaration',
-     'patterns': [r".*: warning: 'static' is not at beginning of declaration"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wreturn-type',
-     'description': 'Missing return value',
-     'patterns': [r".*: warning: control reaches end of non-void function"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wimplicit-int',
-     'description': 'Implicit int type',
-     'patterns': [r".*: warning: type specifier missing, defaults to 'int'",
-                  r".*: warning: type defaults to 'int' in declaration of '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wmain-return-type',
-     'description': 'Main function should return int',
-     'patterns': [r".*: warning: return type of 'main' is not 'int'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wuninitialized',
-     'description': 'Variable may be used uninitialized',
-     'patterns': [r".*: warning: '.+' may be used uninitialized in this function"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': '-Wuninitialized',
-     'description': 'Variable is used uninitialized',
-     'patterns': [r".*: warning: '.+' is used uninitialized in this function",
-                  r".*: warning: variable '.+' is uninitialized when used here"]},
-    {'category': 'ld', 'severity': Severity.MEDIUM, 'option': '-fshort-enums',
-     'description': 'ld: possible enum size mismatch',
-     'patterns': [r".*: warning: .* uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wpointer-sign',
-     'description': 'Pointer targets differ in signedness',
-     'patterns': [r".*: warning: pointer targets in initialization differ in signedness",
-                  r".*: warning: pointer targets in assignment differ in signedness",
-                  r".*: warning: pointer targets in return differ in signedness",
-                  r".*: warning: pointer targets in passing argument [0-9]+ of '.+' differ in signedness"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wstrict-overflow',
-     'description': 'Assuming overflow does not occur',
-     'patterns': [r".*: warning: assuming signed overflow does not occur when assuming that .* is always (true|false)"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wempty-body',
-     'description': 'Suggest adding braces around empty body',
-     'patterns': [r".*: warning: suggest braces around empty body in an 'if' statement",
-                  r".*: warning: empty body in an if-statement",
-                  r".*: warning: suggest braces around empty body in an 'else' statement",
-                  r".*: warning: empty body in an else-statement"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wparentheses',
-     'description': 'Suggest adding parentheses',
-     'patterns': [r".*: warning: suggest explicit braces to avoid ambiguous 'else'",
-                  r".*: warning: suggest parentheses around arithmetic in operand of '.+'",
-                  r".*: warning: suggest parentheses around comparison in operand of '.+'",
-                  r".*: warning: logical not is only applied to the left hand side of this comparison",
-                  r".*: warning: using the result of an assignment as a condition without parentheses",
-                  r".*: warning: .+ has lower precedence than .+ be evaluated first .+Wparentheses",
-                  r".*: warning: suggest parentheses around '.+?' .+ '.+?'",
-                  r".*: warning: suggest parentheses around assignment used as truth value"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Static variable used in non-static inline function',
-     'patterns': [r".*: warning: '.+' is static but used in inline function '.+' which is not static"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wimplicit int',
-     'description': 'No type or storage class (will default to int)',
-     'patterns': [r".*: warning: data definition has no type or storage class"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip, parameter name (without types) in function declaration',
-     'patterns': [r".*: warning: parameter names \(without types\) in function declaration"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wstrict-aliasing',
-     'description': 'Dereferencing &lt;foo&gt; breaks strict aliasing rules',
-     'patterns': [r".*: warning: dereferencing .* break strict-aliasing rules"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wpointer-to-int-cast',
-     'description': 'Cast from pointer to integer of different size',
-     'patterns': [r".*: warning: cast from pointer to integer of different size",
-                  r".*: warning: initialization makes pointer from integer without a cast"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wint-to-pointer-cast',
-     'description': 'Cast to pointer from integer of different size',
-     'patterns': [r".*: warning: cast to pointer from integer of different size"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Macro redefined',
-     'patterns': [r".*: warning: '.+' macro redefined"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip, ... location of the previous definition',
-     'patterns': [r".*: warning: this is the location of the previous definition"]},
-    {'category': 'ld', 'severity': Severity.MEDIUM,
-     'description': 'ld: type and size of dynamic symbol are not defined',
-     'patterns': [r".*: warning: type and size of dynamic symbol `.+' are not defined"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Pointer from integer without cast',
-     'patterns': [r".*: warning: assignment makes pointer from integer without a cast"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Pointer from integer without cast',
-     'patterns': [r".*: warning: passing argument [0-9]+ of '.+' makes pointer from integer without a cast"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Integer from pointer without cast',
-     'patterns': [r".*: warning: assignment makes integer from pointer without a cast"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Integer from pointer without cast',
-     'patterns': [r".*: warning: passing argument [0-9]+ of '.+' makes integer from pointer without a cast"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Integer from pointer without cast',
-     'patterns': [r".*: warning: return makes integer from pointer without a cast"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wunknown-pragmas',
-     'description': 'Ignoring pragma',
-     'patterns': [r".*: warning: ignoring #pragma .+"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-W#pragma-messages',
-     'description': 'Pragma warning messages',
-     'patterns': [r".*: warning: .+W#pragma-messages"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wclobbered',
-     'description': 'Variable might be clobbered by longjmp or vfork',
-     'patterns': [r".*: warning: variable '.+' might be clobbered by 'longjmp' or 'vfork'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wclobbered',
-     'description': 'Argument might be clobbered by longjmp or vfork',
-     'patterns': [r".*: warning: argument '.+' might be clobbered by 'longjmp' or 'vfork'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wredundant-decls',
-     'description': 'Redundant declaration',
-     'patterns': [r".*: warning: redundant redeclaration of '.+'"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip, previous declaration ... was here',
-     'patterns': [r".*: warning: previous declaration of '.+' was here"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': '-Wswitch-enum',
-     'description': 'Enum value not handled in switch',
-     'patterns': [r".*: warning: .*enumeration value.* not handled in switch.+Wswitch"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wuser-defined-warnings',
-     'description': 'User defined warnings',
-     'patterns': [r".*: warning: .* \[-Wuser-defined-warnings\]$"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Taking address of temporary',
-     'patterns': [r".*: warning: taking address of temporary"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Taking address of packed member',
-     'patterns': [r".*: warning: taking address of packed member"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Possible broken line continuation',
-     'patterns': [r".*: warning: backslash and newline separated by space"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wundefined-var-template',
-     'description': 'Undefined variable template',
-     'patterns': [r".*: warning: instantiation of variable .* no definition is available"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wundefined-inline',
-     'description': 'Inline function is not defined',
-     'patterns': [r".*: warning: inline function '.*' is not defined"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Excess elements in initializer',
-     'patterns': [r".*: warning: excess elements in .+ initializer"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Decimal constant is unsigned only in ISO C90',
-     'patterns': [r".*: warning: this decimal constant is unsigned only in ISO C90"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wmain',
-     'description': 'main is usually a function',
-     'patterns': [r".*: warning: 'main' is usually a function"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Typedef ignored',
-     'patterns': [r".*: warning: 'typedef' was ignored in this declaration"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': '-Waddress',
-     'description': 'Address always evaluates to true',
-     'patterns': [r".*: warning: the address of '.+' will always evaluate as 'true'"]},
-    {'category': 'C/C++', 'severity': Severity.FIXMENOW,
-     'description': 'Freeing a non-heap object',
-     'patterns': [r".*: warning: attempt to free a non-heap object '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wchar-subscripts',
-     'description': 'Array subscript has type char',
-     'patterns': [r".*: warning: array subscript .+ type 'char'.+Wchar-subscripts"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Constant too large for type',
-     'patterns': [r".*: warning: integer constant is too large for '.+' type"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Woverflow',
-     'description': 'Constant too large for type, truncated',
-     'patterns': [r".*: warning: large integer implicitly truncated to unsigned type"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Winteger-overflow',
-     'description': 'Overflow in expression',
-     'patterns': [r".*: warning: overflow in expression; .*Winteger-overflow"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Woverflow',
-     'description': 'Overflow in implicit constant conversion',
-     'patterns': [r".*: warning: overflow in implicit constant conversion"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Declaration does not declare anything',
-     'patterns': [r".*: warning: declaration 'class .+' does not declare anything"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wreorder',
-     'description': 'Initialization order will be different',
-     'patterns': [r".*: warning: '.+' will be initialized after",
-                  r".*: warning: field .+ will be initialized after .+Wreorder"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip,   ....',
-     'patterns': [r".*: warning:   '.+'"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip,   base ...',
-     'patterns': [r".*: warning:   base '.+'"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip,   when initialized here',
-     'patterns': [r".*: warning:   when initialized here"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wmissing-parameter-type',
-     'description': 'Parameter type not specified',
-     'patterns': [r".*: warning: type of '.+' defaults to 'int'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wmissing-declarations',
-     'description': 'Missing declarations',
-     'patterns': [r".*: warning: declaration does not declare anything"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wmissing-noreturn',
-     'description': 'Missing noreturn',
-     'patterns': [r".*: warning: function '.*' could be declared with attribute 'noreturn'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'User warning',
-     'patterns': [r".*: warning: #warning "".+"""]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wvexing-parse',
-     'description': 'Vexing parsing problem',
-     'patterns': [r".*: warning: empty parentheses interpreted as a function declaration"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wextra',
-     'description': 'Dereferencing void*',
-     'patterns': [r".*: warning: dereferencing 'void \*' pointer"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Comparison of pointer and integer',
-     'patterns': [r".*: warning: ordered comparison of pointer with integer zero",
-                  r".*: warning: .*comparison between pointer and integer"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Use of error-prone unary operator',
-     'patterns': [r".*: warning: use of unary operator that may be intended as compound assignment"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wwrite-strings',
-     'description': 'Conversion of string constant to non-const char*',
-     'patterns': [r".*: warning: deprecated conversion from string constant to '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wstrict-prototypes',
-     'description': 'Function declaration isn''t a prototype',
-     'patterns': [r".*: warning: function declaration isn't a prototype"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wignored-qualifiers',
-     'description': 'Type qualifiers ignored on function return value',
-     'patterns': [r".*: warning: type qualifiers ignored on function return type",
-                  r".*: warning: .+ type qualifier .+ has no effect .+Wignored-qualifiers"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': '&lt;foo&gt; declared inside parameter list, scope limited to this definition',
-     'patterns': [r".*: warning: '.+' declared inside parameter list"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip, its scope is only this ...',
-     'patterns': [r".*: warning: its scope is only this definition or declaration, which is probably not what you want"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wcomment',
-     'description': 'Line continuation inside comment',
-     'patterns': [r".*: warning: multi-line comment"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wcomment',
-     'description': 'Comment inside comment',
-     'patterns': [r".*: warning: '.+' within block comment .*-Wcomment"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wdeprecated-declarations',
-     'description': 'Deprecated declarations',
-     'patterns': [r".*: warning: .+ is deprecated.+deprecated-declarations"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wdeprecated-register',
-     'description': 'Deprecated register',
-     'patterns': [r".*: warning: 'register' storage class specifier is deprecated"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wpointer-sign',
-     'description': 'Converts between pointers to integer types with different sign',
-     'patterns': [r".*: warning: .+ converts between pointers to integer types with different sign"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS,
-     'description': 'Extra tokens after #endif',
-     'patterns': [r".*: warning: extra tokens at end of #endif directive"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wenum-compare',
-     'description': 'Comparison between different enums',
-     'patterns': [r".*: warning: comparison between '.+' and '.+'.+Wenum-compare",
-                  r".*: warning: comparison of .* enumeration types .*-Wenum-compare-switch"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wconversion',
-     'description': 'Conversion may change value',
-     'patterns': [r".*: warning: converting negative value '.+' to '.+'",
-                  r".*: warning: conversion to '.+' .+ may (alter|change)"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wconversion-null',
-     'description': 'Converting to non-pointer type from NULL',
-     'patterns': [r".*: warning: converting to non-pointer type '.+' from NULL"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wsign-conversion',
-     'description': 'Implicit sign conversion',
-     'patterns': [r".*: warning: implicit conversion changes signedness"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wnull-conversion',
-     'description': 'Converting NULL to non-pointer type',
-     'patterns': [r".*: warning: implicit conversion of NULL constant to '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wnon-literal-null-conversion',
-     'description': 'Zero used as null pointer',
-     'patterns': [r".*: warning: expression .* zero treated as a null pointer constant"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Implicit conversion changes value or loses precision',
-     'patterns': [r".*: warning: implicit conversion .* changes value from .* to .*-conversion",
-                  r".*: warning: implicit conversion loses integer precision:"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Passing NULL as non-pointer argument',
-     'patterns': [r".*: warning: passing NULL to non-pointer argument [0-9]+ of '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wctor-dtor-privacy',
-     'description': 'Class seems unusable because of private ctor/dtor',
-     'patterns': [r".*: warning: all member functions in class '.+' are private"]},
+    medium('Implicit function declaration',
+           [r".*: warning: implicit declaration of function .+",
+            r".*: warning: implicitly declaring library function"]),
+    skip('skip, conflicting types for ...',
+         [r".*: warning: conflicting types for '.+'"]),
+    high('Expression always evaluates to true or false',
+         [r".*: warning: comparison is always .+ due to limited range of data type",
+          r".*: warning: comparison of unsigned .*expression .+ is always true",
+          r".*: warning: comparison of unsigned .*expression .+ is always false"]),
+    high('Use transient memory for control value',
+         [r".*: warning: .+Using such transient memory for the control value is .*dangerous."]),
+    high('Return address of stack memory',
+         [r".*: warning: Address of stack memory .+ returned to caller",
+          r".*: warning: Address of stack memory .+ will be a dangling reference"]),
+    high('Infinite recursion',
+         [r".*: warning: all paths through this function will call itself"]),
+    high('Potential buffer overflow',
+         [r".*: warning: Size argument is greater than .+ the destination buffer",
+          r".*: warning: Potential buffer overflow.",
+          r".*: warning: String copy function overflows destination buffer"]),
+    medium('Incompatible pointer types',
+           [r".*: warning: assignment from incompatible pointer type",
+            r".*: warning: return from incompatible pointer type",
+            r".*: warning: passing argument [0-9]+ of '.*' from incompatible pointer type",
+            r".*: warning: initialization from incompatible pointer type"]),
+    high('Incompatible declaration of built in function',
+         [r".*: warning: incompatible implicit declaration of built-in function .+"]),
+    high('Incompatible redeclaration of library function',
+         [r".*: warning: incompatible redeclaration of library function .+"]),
+    high('Null passed as non-null argument',
+         [r".*: warning: Null passed to a callee that requires a non-null"]),
+    medium('Unused parameter',
+           [r".*: warning: unused parameter '.*'"]),
+    medium('Unused function, variable, label, comparison, etc.',
+           [r".*: warning: '.+' defined but not used",
+            r".*: warning: unused function '.+'",
+            r".*: warning: unused label '.+'",
+            r".*: warning: relational comparison result unused",
+            r".*: warning: lambda capture .* is not used",
+            r".*: warning: private field '.+' is not used",
+            r".*: warning: unused variable '.+'"]),
+    medium('Statement with no effect or result unused',
+           [r".*: warning: statement with no effect",
+            r".*: warning: expression result unused"]),
+    medium('Ignoreing return value of function',
+           [r".*: warning: ignoring return value of function .+Wunused-result"]),
+    medium('Missing initializer',
+           [r".*: warning: missing initializer"]),
+    medium('Need virtual destructor',
+           [r".*: warning: delete called .* has virtual functions but non-virtual destructor"]),
+    skip('skip, near initialization for ...',
+         [r".*: warning: \(near initialization for '.+'\)"]),
+    medium('Expansion of data or time macro',
+           [r".*: warning: expansion of date or time macro is not reproducible"]),
+    medium('Macro expansion has undefined behavior',
+           [r".*: warning: macro expansion .* has undefined behavior"]),
+    medium('Format string does not match arguments',
+           [r".*: warning: format '.+' expects type '.+', but argument [0-9]+ has type '.+'",
+            r".*: warning: more '%' conversions than data arguments",
+            r".*: warning: data argument not used by format string",
+            r".*: warning: incomplete format specifier",
+            r".*: warning: unknown conversion type .* in format",
+            r".*: warning: format .+ expects .+ but argument .+Wformat=",
+            r".*: warning: field precision should have .+ but argument has .+Wformat",
+            r".*: warning: format specifies type .+ but the argument has .*type .+Wformat"]),
+    medium('Too many arguments for format string',
+           [r".*: warning: too many arguments for format"]),
+    medium('Too many arguments in call',
+           [r".*: warning: too many arguments in call to "]),
+    medium('Invalid format specifier',
+           [r".*: warning: invalid .+ specifier '.+'.+format-invalid-specifier"]),
+    medium('Comparison between signed and unsigned',
+           [r".*: warning: comparison between signed and unsigned",
+            r".*: warning: comparison of promoted \~unsigned with unsigned",
+            r".*: warning: signed and unsigned type in conditional expression"]),
+    medium('Comparison between enum and non-enum',
+           [r".*: warning: enumeral and non-enumeral type in conditional expression"]),
+    medium('libpng: zero area',
+           [r".*libpng warning: Ignoring attempt to set cHRM RGB triangle with zero area"]),
+    medium('Missing braces around initializer',
+           [r".*: warning: missing braces around initializer.*"]),
+    harmless('No newline at end of file',
+             [r".*: warning: no newline at end of file"]),
+    harmless('Missing space after macro name',
+             [r".*: warning: missing whitespace after the macro name"]),
+    low('Cast increases required alignment',
+        [r".*: warning: cast from .* to .* increases required alignment .*"]),
+    medium('Qualifier discarded',
+           [r".*: warning: passing argument [0-9]+ of '.+' discards qualifiers from pointer target type",
+            r".*: warning: assignment discards qualifiers from pointer target type",
+            r".*: warning: passing .+ to parameter of type .+ discards qualifiers",
+            r".*: warning: assigning to .+ from .+ discards qualifiers",
+            r".*: warning: initializing .+ discards qualifiers .+types-discards-qualifiers",
+            r".*: warning: return discards qualifiers from pointer target type"]),
+    medium('Unknown attribute',
+           [r".*: warning: unknown attribute '.+'"]),
+    medium('Attribute ignored',
+           [r".*: warning: '_*packed_*' attribute ignored",
+            r".*: warning: attribute declaration must precede definition .+ignored-attributes"]),
+    medium('Visibility problem',
+           [r".*: warning: declaration of '.+' will not be visible outside of this function"]),
+    medium('Visibility mismatch',
+           [r".*: warning: '.+' declared with greater visibility than the type of its field '.+'"]),
+    medium('Shift count greater than width of type',
+           [r".*: warning: (left|right) shift count >= width of type"]),
+    medium('extern &lt;foo&gt; is initialized',
+           [r".*: warning: '.+' initialized and declared 'extern'",
+            r".*: warning: 'extern' variable has an initializer"]),
+    medium('Old style declaration',
+           [r".*: warning: 'static' is not at beginning of declaration"]),
+    medium('Missing return value',
+           [r".*: warning: control reaches end of non-void function"]),
+    medium('Implicit int type',
+           [r".*: warning: type specifier missing, defaults to 'int'",
+            r".*: warning: type defaults to 'int' in declaration of '.+'"]),
+    medium('Main function should return int',
+           [r".*: warning: return type of 'main' is not 'int'"]),
+    medium('Variable may be used uninitialized',
+           [r".*: warning: '.+' may be used uninitialized in this function"]),
+    high('Variable is used uninitialized',
+         [r".*: warning: '.+' is used uninitialized in this function",
+          r".*: warning: variable '.+' is uninitialized when used here"]),
+    medium('ld: possible enum size mismatch',
+           [r".*: warning: .* uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail"]),
+    medium('Pointer targets differ in signedness',
+           [r".*: warning: pointer targets in initialization differ in signedness",
+            r".*: warning: pointer targets in assignment differ in signedness",
+            r".*: warning: pointer targets in return differ in signedness",
+            r".*: warning: pointer targets in passing argument [0-9]+ of '.+' differ in signedness"]),
+    medium('Assuming overflow does not occur',
+           [r".*: warning: assuming signed overflow does not occur when assuming that .* is always (true|false)"]),
+    medium('Suggest adding braces around empty body',
+           [r".*: warning: suggest braces around empty body in an 'if' statement",
+            r".*: warning: empty body in an if-statement",
+            r".*: warning: suggest braces around empty body in an 'else' statement",
+            r".*: warning: empty body in an else-statement"]),
+    medium('Suggest adding parentheses',
+           [r".*: warning: suggest explicit braces to avoid ambiguous 'else'",
+            r".*: warning: suggest parentheses around arithmetic in operand of '.+'",
+            r".*: warning: suggest parentheses around comparison in operand of '.+'",
+            r".*: warning: logical not is only applied to the left hand side of this comparison",
+            r".*: warning: using the result of an assignment as a condition without parentheses",
+            r".*: warning: .+ has lower precedence than .+ be evaluated first .+Wparentheses",
+            r".*: warning: suggest parentheses around '.+?' .+ '.+?'",
+            r".*: warning: suggest parentheses around assignment used as truth value"]),
+    medium('Static variable used in non-static inline function',
+           [r".*: warning: '.+' is static but used in inline function '.+' which is not static"]),
+    medium('No type or storage class (will default to int)',
+           [r".*: warning: data definition has no type or storage class"]),
+    skip('skip, parameter name (without types) in function declaration',
+         [r".*: warning: parameter names \(without types\) in function declaration"]),
+    medium('Dereferencing &lt;foo&gt; breaks strict aliasing rules',
+           [r".*: warning: dereferencing .* break strict-aliasing rules"]),
+    medium('Cast from pointer to integer of different size',
+           [r".*: warning: cast from pointer to integer of different size",
+            r".*: warning: initialization makes pointer from integer without a cast"]),
+    medium('Cast to pointer from integer of different size',
+           [r".*: warning: cast to pointer from integer of different size"]),
+    medium('Macro redefined',
+           [r".*: warning: '.+' macro redefined"]),
+    skip('skip, ... location of the previous definition',
+         [r".*: warning: this is the location of the previous definition"]),
+    medium('ld: type and size of dynamic symbol are not defined',
+           [r".*: warning: type and size of dynamic symbol `.+' are not defined"]),
+    medium('Pointer from integer without cast',
+           [r".*: warning: assignment makes pointer from integer without a cast"]),
+    medium('Pointer from integer without cast',
+           [r".*: warning: passing argument [0-9]+ of '.+' makes pointer from integer without a cast"]),
+    medium('Integer from pointer without cast',
+           [r".*: warning: assignment makes integer from pointer without a cast"]),
+    medium('Integer from pointer without cast',
+           [r".*: warning: passing argument [0-9]+ of '.+' makes integer from pointer without a cast"]),
+    medium('Integer from pointer without cast',
+           [r".*: warning: return makes integer from pointer without a cast"]),
+    medium('Ignoring pragma',
+           [r".*: warning: ignoring #pragma .+"]),
+    medium('Pragma warning messages',
+           [r".*: warning: .+W#pragma-messages"]),
+    medium('Variable might be clobbered by longjmp or vfork',
+           [r".*: warning: variable '.+' might be clobbered by 'longjmp' or 'vfork'"]),
+    medium('Argument might be clobbered by longjmp or vfork',
+           [r".*: warning: argument '.+' might be clobbered by 'longjmp' or 'vfork'"]),
+    medium('Redundant declaration',
+           [r".*: warning: redundant redeclaration of '.+'"]),
+    skip('skip, previous declaration ... was here',
+         [r".*: warning: previous declaration of '.+' was here"]),
+    high('Enum value not handled in switch',
+         [r".*: warning: .*enumeration value.* not handled in switch.+Wswitch"]),
+    medium('User defined warnings',
+           [r".*: warning: .* \[-Wuser-defined-warnings\]$"]),
+    medium('Taking address of temporary',
+           [r".*: warning: taking address of temporary"]),
+    medium('Taking address of packed member',
+           [r".*: warning: taking address of packed member"]),
+    medium('Possible broken line continuation',
+           [r".*: warning: backslash and newline separated by space"]),
+    medium('Undefined variable template',
+           [r".*: warning: instantiation of variable .* no definition is available"]),
+    medium('Inline function is not defined',
+           [r".*: warning: inline function '.*' is not defined"]),
+    medium('Excess elements in initializer',
+           [r".*: warning: excess elements in .+ initializer"]),
+    medium('Decimal constant is unsigned only in ISO C90',
+           [r".*: warning: this decimal constant is unsigned only in ISO C90"]),
+    medium('main is usually a function',
+           [r".*: warning: 'main' is usually a function"]),
+    medium('Typedef ignored',
+           [r".*: warning: 'typedef' was ignored in this declaration"]),
+    high('Address always evaluates to true',
+         [r".*: warning: the address of '.+' will always evaluate as 'true'"]),
+    fixmenow('Freeing a non-heap object',
+             [r".*: warning: attempt to free a non-heap object '.+'"]),
+    medium('Array subscript has type char',
+           [r".*: warning: array subscript .+ type 'char'.+Wchar-subscripts"]),
+    medium('Constant too large for type',
+           [r".*: warning: integer constant is too large for '.+' type"]),
+    medium('Constant too large for type, truncated',
+           [r".*: warning: large integer implicitly truncated to unsigned type"]),
+    medium('Overflow in expression',
+           [r".*: warning: overflow in expression; .*Winteger-overflow"]),
+    medium('Overflow in implicit constant conversion',
+           [r".*: warning: overflow in implicit constant conversion"]),
+    medium('Declaration does not declare anything',
+           [r".*: warning: declaration 'class .+' does not declare anything"]),
+    medium('Initialization order will be different',
+           [r".*: warning: '.+' will be initialized after",
+            r".*: warning: field .+ will be initialized after .+Wreorder"]),
+    skip('skip,   ....',
+         [r".*: warning:   '.+'"]),
+    skip('skip,   base ...',
+         [r".*: warning:   base '.+'"]),
+    skip('skip,   when initialized here',
+         [r".*: warning:   when initialized here"]),
+    medium('Parameter type not specified',
+           [r".*: warning: type of '.+' defaults to 'int'"]),
+    medium('Missing declarations',
+           [r".*: warning: declaration does not declare anything"]),
+    medium('Missing noreturn',
+           [r".*: warning: function '.*' could be declared with attribute 'noreturn'"]),
+    medium('User warning',
+           [r".*: warning: #warning "".+"""]),
+    medium('Vexing parsing problem',
+           [r".*: warning: empty parentheses interpreted as a function declaration"]),
+    medium('Dereferencing void*',
+           [r".*: warning: dereferencing 'void \*' pointer"]),
+    medium('Comparison of pointer and integer',
+           [r".*: warning: ordered comparison of pointer with integer zero",
+            r".*: warning: .*comparison between pointer and integer"]),
+    medium('Use of error-prone unary operator',
+           [r".*: warning: use of unary operator that may be intended as compound assignment"]),
+    medium('Conversion of string constant to non-const char*',
+           [r".*: warning: deprecated conversion from string constant to '.+'"]),
+    medium('Function declaration isn''t a prototype',
+           [r".*: warning: function declaration isn't a prototype"]),
+    medium('Type qualifiers ignored on function return value',
+           [r".*: warning: type qualifiers ignored on function return type",
+            r".*: warning: .+ type qualifier .+ has no effect .+Wignored-qualifiers"]),
+    medium('&lt;foo&gt; declared inside parameter list, scope limited to this definition',
+           [r".*: warning: '.+' declared inside parameter list"]),
+    skip('skip, its scope is only this ...',
+         [r".*: warning: its scope is only this definition or declaration, which is probably not what you want"]),
+    low('Line continuation inside comment',
+        [r".*: warning: multi-line comment"]),
+    low('Comment inside comment',
+        [r".*: warning: '.+' within block comment .*-Wcomment"]),
+    low('Deprecated declarations',
+        [r".*: warning: .+ is deprecated.+deprecated-declarations"]),
+    low('Deprecated register',
+        [r".*: warning: 'register' storage class specifier is deprecated"]),
+    low('Converts between pointers to integer types with different sign',
+        [r".*: warning: .+ converts between pointers to integer types with different sign"]),
+    harmless('Extra tokens after #endif',
+             [r".*: warning: extra tokens at end of #endif directive"]),
+    medium('Comparison between different enums',
+           [r".*: warning: comparison between '.+' and '.+'.+Wenum-compare",
+            r".*: warning: comparison of .* enumeration types .*-Wenum-compare-switch"]),
+    medium('Conversion may change value',
+           [r".*: warning: converting negative value '.+' to '.+'",
+            r".*: warning: conversion to '.+' .+ may (alter|change)"]),
+    medium('Converting to non-pointer type from NULL',
+           [r".*: warning: converting to non-pointer type '.+' from NULL"]),
+    medium('Implicit sign conversion',
+           [r".*: warning: implicit conversion changes signedness"]),
+    medium('Converting NULL to non-pointer type',
+           [r".*: warning: implicit conversion of NULL constant to '.+'"]),
+    medium('Zero used as null pointer',
+           [r".*: warning: expression .* zero treated as a null pointer constant"]),
+    medium('Compare pointer to null character',
+           [r".*: warning: comparing a pointer to a null character constant"]),
+    medium('Implicit conversion changes value or loses precision',
+           [r".*: warning: implicit conversion .* changes value from .* to .*-conversion",
+            r".*: warning: implicit conversion loses integer precision:"]),
+    medium('Passing NULL as non-pointer argument',
+           [r".*: warning: passing NULL to non-pointer argument [0-9]+ of '.+'"]),
+    medium('Class seems unusable because of private ctor/dtor',
+           [r".*: warning: all member functions in class '.+' are private"]),
     # skip this next one, because it only points out some RefBase-based classes
     # where having a private destructor is perfectly fine
-    {'category': 'C/C++', 'severity': Severity.SKIP, 'option': '-Wctor-dtor-privacy',
-     'description': 'Class seems unusable because of private ctor/dtor',
-     'patterns': [r".*: warning: 'class .+' only defines a private destructor and has no friends"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wctor-dtor-privacy',
-     'description': 'Class seems unusable because of private ctor/dtor',
-     'patterns': [r".*: warning: 'class .+' only defines private constructors and has no friends"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wgnu-static-float-init',
-     'description': 'In-class initializer for static const float/double',
-     'patterns': [r".*: warning: in-class initializer for static data member of .+const (float|double)"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wpointer-arith',
-     'description': 'void* used in arithmetic',
-     'patterns': [r".*: warning: pointer of type 'void \*' used in (arithmetic|subtraction)",
-                  r".*: warning: arithmetic on .+ to void is a GNU extension.*Wpointer-arith",
-                  r".*: warning: wrong type argument to increment"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wsign-promo',
-     'description': 'Overload resolution chose to promote from unsigned or enum to signed type',
-     'patterns': [r".*: warning: passing '.+' chooses '.+' over '.+'.*Wsign-promo"]},
-    {'category': 'cont.', 'severity': Severity.SKIP,
-     'description': 'skip,   in call to ...',
-     'patterns': [r".*: warning:   in call to '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.HIGH, 'option': '-Wextra',
-     'description': 'Base should be explicitly initialized in copy constructor',
-     'patterns': [r".*: warning: base class '.+' should be explicitly initialized in the copy constructor"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Return value from void function',
-     'patterns': [r".*: warning: 'return' with a value, in function returning void"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': 'multichar',
-     'description': 'Multi-character character constant',
-     'patterns': [r".*: warning: multi-character character constant"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': 'writable-strings',
-     'description': 'Conversion from string literal to char*',
-     'patterns': [r".*: warning: .+ does not allow conversion from string literal to 'char \*'"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wextra-semi',
-     'description': 'Extra \';\'',
-     'patterns': [r".*: warning: extra ';' .+extra-semi"]},
-    {'category': 'C/C++', 'severity': Severity.LOW,
-     'description': 'Useless specifier',
-     'patterns': [r".*: warning: useless storage class specifier in empty declaration"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wduplicate-decl-specifier',
-     'description': 'Duplicate declaration specifier',
-     'patterns': [r".*: warning: duplicate '.+' declaration specifier"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': 'tautological-compare',
-     'description': 'Comparison of self is always false',
-     'patterns': [r".*: self-comparison always evaluates to false"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': 'constant-logical-operand',
-     'description': 'Logical op with constant operand',
-     'patterns': [r".*: use of logical '.+' with constant operand"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': 'literal-suffix',
-     'description': 'Needs a space between literal and string macro',
-     'patterns': [r".*: warning: invalid suffix on literal.+ requires a space .+Wliteral-suffix"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '#warnings',
-     'description': 'Warnings from #warning',
-     'patterns': [r".*: warning: .+-W#warnings"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': 'absolute-value',
-     'description': 'Using float/int absolute value function with int/float argument',
-     'patterns': [r".*: warning: using .+ absolute value function .+ when argument is .+ type .+Wabsolute-value",
-                  r".*: warning: absolute value function '.+' given .+ which may cause truncation .+Wabsolute-value"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Wc++11-extensions',
-     'description': 'Using C++11 extensions',
-     'patterns': [r".*: warning: 'auto' type specifier is a C\+\+11 extension"]},
-    {'category': 'C/C++', 'severity': Severity.LOW,
-     'description': 'Refers to implicitly defined namespace',
-     'patterns': [r".*: warning: using directive refers to implicitly-defined namespace .+"]},
-    {'category': 'C/C++', 'severity': Severity.LOW, 'option': '-Winvalid-pp-token',
-     'description': 'Invalid pp token',
-     'patterns': [r".*: warning: missing .+Winvalid-pp-token"]},
-    {'category': 'link', 'severity': Severity.LOW,
-     'description': 'need glibc to link',
-     'patterns': [r".*: warning: .* requires at runtime .* glibc .* for linking"]},
-
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Operator new returns NULL',
-     'patterns': [r".*: warning: 'operator new' must not return NULL unless it is declared 'throw\(\)' .+"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wnull-arithmetic',
-     'description': 'NULL used in arithmetic',
-     'patterns': [r".*: warning: NULL used in arithmetic",
-                  r".*: warning: comparison between NULL and non-pointer"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': 'header-guard',
-     'description': 'Misspelled header guard',
-     'patterns': [r".*: warning: '.+' is used as a header guard .+ followed by .+ different macro"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': 'empty-body',
-     'description': 'Empty loop body',
-     'patterns': [r".*: warning: .+ loop has empty body"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': 'enum-conversion',
-     'description': 'Implicit conversion from enumeration type',
-     'patterns': [r".*: warning: implicit conversion from enumeration type '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': 'switch',
-     'description': 'case value not in enumerated type',
-     'patterns': [r".*: warning: case value not in enumerated type '.+'"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Use of deprecated method',
-     'patterns': [r".*: warning: '.+' is deprecated .+"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Use of garbage or uninitialized value',
-     'patterns': [r".*: warning: .+ uninitialized .+\[-Wsometimes-uninitialized\]"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wsizeof-array-argument',
-     'description': 'Sizeof on array argument',
-     'patterns': [r".*: warning: sizeof on array function parameter will return"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wsizeof-pointer-memacces',
-     'description': 'Bad argument size of memory access functions',
-     'patterns': [r".*: warning: .+\[-Wsizeof-pointer-memaccess\]"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Return value not checked',
-     'patterns': [r".*: warning: The return value from .+ is not checked"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Possible heap pollution',
-     'patterns': [r".*: warning: .*Possible heap pollution from .+ type .+"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wfor-loop-analysis',
-     'description': 'Variable used in loop condition not modified in loop body',
-     'patterns': [r".*: warning: variable '.+' used in loop condition.*Wfor-loop-analysis"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM,
-     'description': 'Closing a previously closed file',
-     'patterns': [r".*: warning: Closing a previously closed file"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wunnamed-type-template-args',
-     'description': 'Unnamed template type argument',
-     'patterns': [r".*: warning: template argument.+Wunnamed-type-template-args"]},
-    {'category': 'C/C++', 'severity': Severity.MEDIUM, 'option': '-Wimplicit-fallthrough',
-     'description': 'Unannotated fall-through between switch labels',
-     'patterns': [r".*: warning: unannotated fall-through between switch labels.+Wimplicit-fallthrough"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS,
-     'description': 'Discarded qualifier from pointer target type',
-     'patterns': [r".*: warning: .+ discards '.+' qualifier from pointer target type"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS,
-     'description': 'Use snprintf instead of sprintf',
-     'patterns': [r".*: warning: .*sprintf is often misused; please use snprintf"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS,
-     'description': 'Unsupported optimizaton flag',
-     'patterns': [r".*: warning: optimization flag '.+' is not supported"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS,
-     'description': 'Extra or missing parentheses',
-     'patterns': [r".*: warning: equality comparison with extraneous parentheses",
-                  r".*: warning: .+ within .+Wlogical-op-parentheses"]},
-    {'category': 'C/C++', 'severity': Severity.HARMLESS, 'option': 'mismatched-tags',
-     'description': 'Mismatched class vs struct tags',
-     'patterns': [r".*: warning: '.+' defined as a .+ here but previously declared as a .+mismatched-tags",
-                  r".*: warning: .+ was previously declared as a .+mismatched-tags"]},
+    skip('Class seems unusable because of private ctor/dtor',
+         [r".*: warning: 'class .+' only defines a private destructor and has no friends"]),
+    medium('Class seems unusable because of private ctor/dtor',
+           [r".*: warning: 'class .+' only defines private constructors and has no friends"]),
+    medium('In-class initializer for static const float/double',
+           [r".*: warning: in-class initializer for static data member of .+const (float|double)"]),
+    medium('void* used in arithmetic',
+           [r".*: warning: pointer of type 'void \*' used in (arithmetic|subtraction)",
+            r".*: warning: arithmetic on .+ to void is a GNU extension.*Wpointer-arith",
+            r".*: warning: wrong type argument to increment"]),
+    medium('Overload resolution chose to promote from unsigned or enum to signed type',
+           [r".*: warning: passing '.+' chooses '.+' over '.+'.*Wsign-promo"]),
+    skip('skip,   in call to ...',
+         [r".*: warning:   in call to '.+'"]),
+    high('Base should be explicitly initialized in copy constructor',
+         [r".*: warning: base class '.+' should be explicitly initialized in the copy constructor"]),
+    medium('Return value from void function',
+           [r".*: warning: 'return' with a value, in function returning void"]),
+    medium('Multi-character character constant',
+           [r".*: warning: multi-character character constant"]),
+    medium('Conversion from string literal to char*',
+           [r".*: warning: .+ does not allow conversion from string literal to 'char \*'"]),
+    low('Extra \';\'',
+        [r".*: warning: extra ';' .+extra-semi"]),
+    low('Useless specifier',
+        [r".*: warning: useless storage class specifier in empty declaration"]),
+    low('Duplicate declaration specifier',
+        [r".*: warning: duplicate '.+' declaration specifier"]),
+    low('Comparison of self is always false',
+        [r".*: self-comparison always evaluates to false"]),
+    low('Logical op with constant operand',
+        [r".*: use of logical '.+' with constant operand"]),
+    low('Needs a space between literal and string macro',
+        [r".*: warning: invalid suffix on literal.+ requires a space .+Wliteral-suffix"]),
+    low('Warnings from #warning',
+        [r".*: warning: .+-W#warnings"]),
+    low('Using float/int absolute value function with int/float argument',
+        [r".*: warning: using .+ absolute value function .+ when argument is .+ type .+Wabsolute-value",
+         r".*: warning: absolute value function '.+' given .+ which may cause truncation .+Wabsolute-value"]),
+    low('Using C++11 extensions',
+        [r".*: warning: 'auto' type specifier is a C\+\+11 extension"]),
+    low('Refers to implicitly defined namespace',
+        [r".*: warning: using directive refers to implicitly-defined namespace .+"]),
+    low('Invalid pp token',
+        [r".*: warning: missing .+Winvalid-pp-token"]),
+    low('need glibc to link',
+        [r".*: warning: .* requires at runtime .* glibc .* for linking"]),
+    medium('Operator new returns NULL',
+           [r".*: warning: 'operator new' must not return NULL unless it is declared 'throw\(\)' .+"]),
+    medium('NULL used in arithmetic',
+           [r".*: warning: NULL used in arithmetic",
+            r".*: warning: comparison between NULL and non-pointer"]),
+    medium('Misspelled header guard',
+           [r".*: warning: '.+' is used as a header guard .+ followed by .+ different macro"]),
+    medium('Empty loop body',
+           [r".*: warning: .+ loop has empty body"]),
+    medium('Implicit conversion from enumeration type',
+           [r".*: warning: implicit conversion from enumeration type '.+'"]),
+    medium('case value not in enumerated type',
+           [r".*: warning: case value not in enumerated type '.+'"]),
+    medium('Use of deprecated method',
+           [r".*: warning: '.+' is deprecated .+"]),
+    medium('Use of garbage or uninitialized value',
+           [r".*: warning: .+ uninitialized .+\[-Wsometimes-uninitialized\]"]),
+    medium('Sizeof on array argument',
+           [r".*: warning: sizeof on array function parameter will return"]),
+    medium('Bad argument size of memory access functions',
+           [r".*: warning: .+\[-Wsizeof-pointer-memaccess\]"]),
+    medium('Return value not checked',
+           [r".*: warning: The return value from .+ is not checked"]),
+    medium('Possible heap pollution',
+           [r".*: warning: .*Possible heap pollution from .+ type .+"]),
+    medium('Variable used in loop condition not modified in loop body',
+           [r".*: warning: variable '.+' used in loop condition.*Wfor-loop-analysis"]),
+    medium('Closing a previously closed file',
+           [r".*: warning: Closing a previously closed file"]),
+    medium('Unnamed template type argument',
+           [r".*: warning: template argument.+Wunnamed-type-template-args"]),
+    medium('Unannotated fall-through between switch labels',
+           [r".*: warning: unannotated fall-through between switch labels.+Wimplicit-fallthrough"]),
+    medium('Invalid partial specialization',
+           [r".*: warning: class template partial specialization.+Winvalid-partial-specialization"]),
+    medium('Overlapping compatisons',
+           [r".*: warning: overlapping comparisons.+Wtautological-overlap-compare"]),
+    medium('int in bool context',
+           [r".*: warning: converting.+to a boolean.+Wint-in-bool-context"]),
+    medium('bitwise conditional parentheses',
+           [r".*: warning: operator.+has lower precedence.+Wbitwise-conditional-parentheses"]),
+    medium('sizeof array div',
+           [r".*: warning: .+number of elements in.+array.+Wsizeof-array-div"]),
+    medium('bool operation',
+           [r".*: warning: .+boolean.+always.+Wbool-operation"]),
+    medium('Undefined bool conversion',
+           [r".*: warning: .+may be.+always.+true.+Wundefined-bool-conversion"]),
+    medium('Typedef requires a name',
+           [r".*: warning: typedef requires a name.+Wmissing-declaration"]),
+    medium('Unknown escape sequence',
+           [r".*: warning: unknown escape sequence.+Wunknown-escape-sequence"]),
+    medium('Unicode whitespace',
+           [r".*: warning: treating Unicode.+as whitespace.+Wunicode-whitespace"]),
+    medium('Unused local typedef',
+           [r".*: warning: unused typedef.+Wunused-local-typedef"]),
+    medium('varargs warnings',
+           [r".*: warning: .*argument to 'va_start'.+\[-Wvarargs\]"]),
+    harmless('Discarded qualifier from pointer target type',
+             [r".*: warning: .+ discards '.+' qualifier from pointer target type"]),
+    harmless('Use snprintf instead of sprintf',
+             [r".*: warning: .*sprintf is often misused; please use snprintf"]),
+    harmless('Unsupported optimizaton flag',
+             [r".*: warning: optimization flag '.+' is not supported"]),
+    harmless('Extra or missing parentheses',
+             [r".*: warning: equality comparison with extraneous parentheses",
+              r".*: warning: .+ within .+Wlogical-op-parentheses"]),
+    harmless('Mismatched class vs struct tags',
+             [r".*: warning: '.+' defined as a .+ here but previously declared as a .+mismatched-tags",
+              r".*: warning: .+ was previously declared as a .+mismatched-tags"]),
 ]
+
+
+def compile_patterns(patterns):
+  """Precompiling every pattern speeds up parsing by about 30x."""
+  for i in patterns:
+    i['compiled_patterns'] = []
+    for pat in i['patterns']:
+      i['compiled_patterns'].append(re.compile(pat))
+
+
+compile_patterns(warn_patterns)
diff --git a/tools/warn/java_warn_patterns.py b/tools/warn/java_warn_patterns.py
index 696ce9a..96510b4 100644
--- a/tools/warn/java_warn_patterns.py
+++ b/tools/warn/java_warn_patterns.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,10 @@
 
 """Warning patterns for Java compiler tools."""
 
-from severity import Severity
+# pylint:disable=relative-beyond-top-level
+from .cpp_warn_patterns import compile_patterns
+# pylint:disable=g-importing-member
+from .severity import Severity
 
 
 def java_warn(severity, description, pattern_list):
@@ -35,15 +38,20 @@
   return java_warn(Severity.MEDIUM, description, pattern_list)
 
 
+def java_medium_type(name):
+  return java_medium(name, [r'.*\.java:.*: warning: .+ \[' + name + r'\]$'])
+
+
 def java_low(description, pattern_list):
   return java_warn(Severity.LOW, description, pattern_list)
 
 
-patterns = [
+warn_patterns = [
     # pylint:disable=line-too-long,g-inconsistent-quotes
     # Warnings from Javac
-    java_medium('Use of deprecated member',
-                [r'.*: warning: \[deprecation\] .+']),
+    java_medium('Use of deprecated',
+                [r'.*: warning: \[deprecation\] .+',
+                 r'.*: warning: \[removal\] .+ has been deprecated and marked for removal$']),
     java_medium('Unchecked conversion',
                 [r'.*: warning: \[unchecked\] .+']),
     # Warnings generated by Error Prone
@@ -89,6 +97,8 @@
              [r".*: warning: \[MultipleTopLevelClasses\] .+"]),
     java_low('Avoid having multiple unary operators acting on the same variable in a method call',
              [r".*: warning: \[MultipleUnaryOperatorsInMethodCall\] .+"]),
+    java_low('OnNameExpected naming style',
+             [r".*\.java:.*: warning: .+ \[OnNameExpected\]$"]),
     java_low('Package names should match the directory they are declared in',
              [r".*: warning: \[PackageLocation\] .+"]),
     java_low('Non-standard parameter comment; prefer `/* paramName= */ arg`',
@@ -125,6 +135,8 @@
              [r".*: warning: \[UseBinds\] .+"]),
     java_low('Wildcard imports, static or otherwise, should not be used',
              [r".*: warning: \[WildcardImport\] .+"]),
+    java_medium('AcronymName',
+                [r".*\.java:.*: warning: .+ \[AcronymName\]$"]),
     java_medium('Method reference is ambiguous',
                 [r".*: warning: \[AmbiguousMethodReference\] .+"]),
     java_medium('This method passes a pair of parameters through to String.format, but the enclosing method wasn\'t annotated @FormatMethod. Doing so gives compile-time rather than run-time protection against malformed format strings.',
@@ -265,6 +277,8 @@
                 [r".*: warning: \[InstanceOfAndCastMatchWrongType\] .+"]),
     java_medium('Expression of type int may overflow before being assigned to a long',
                 [r".*: warning: \[IntLongMath\] .+"]),
+    java_medium('IntentBuilderName',
+                [r".*\.java:.*: warning: .+ \[IntentBuilderName\]$"]),
     java_medium('This @param tag doesn\'t refer to a parameter of the method.',
                 [r".*: warning: \[InvalidParam\] .+"]),
     java_medium('This tag is invalid.',
@@ -319,6 +333,8 @@
                 [r".*: warning: \[NonCanonicalStaticMemberImport\] .+"]),
     java_medium('equals method doesn\'t override Object.equals',
                 [r".*: warning: \[NonOverridingEquals\] .+"]),
+    java_medium('Not closeable',
+                [r".*\.java:.*: warning: .+ \[NotCloseable\]$"]),
     java_medium('Constructors should not be annotated with @Nullable since they cannot return null',
                 [r".*: warning: \[NullableConstructor\] .+"]),
     java_medium('Dereference of possibly-null value',
@@ -369,6 +385,8 @@
                 [r".*: warning: \[RequiredModifiers\] .+"]),
     java_medium('Void methods should not have a @return tag.',
                 [r".*: warning: \[ReturnFromVoid\] .+"]),
+    java_medium('SAM-compatible parameters should be last',
+                [r".*\.java:.*: warning: .+ \[SamShouldBeLast\]$"]),
     java_medium(u'Prefer the short-circuiting boolean operators \u0026\u0026 and || to \u0026 and |.',
                 [r".*: warning: \[ShortCircuitBoolean\] .+"]),
     java_medium('Writes to static fields should not be guarded by instance locks',
@@ -431,6 +449,10 @@
                 [r".*: warning: \[UnusedException\] .+"]),
     java_medium('Java assert is used in test. For testing purposes Assert.* matchers should be used.',
                 [r".*: warning: \[UseCorrectAssertInTests\] .+"]),
+    java_medium('UserHandle',
+                [r".*\.java:.*: warning: .+ \[UserHandle\]$"]),
+    java_medium('UserHandleName',
+                [r".*\.java:.*: warning: .+ \[UserHandleName\]$"]),
     java_medium('Non-constant variable missing @Var annotation',
                 [r".*: warning: \[Var\] .+"]),
     java_medium('variableName and type with the same name would refer to the static field instead of the class',
@@ -439,6 +461,13 @@
                 [r".*: warning: \[WaitNotInLoop\] .+"]),
     java_medium('A wakelock acquired with a timeout may be released by the system before calling `release`, even after checking `isHeld()`. If so, it will throw a RuntimeException. Please wrap in a try/catch block.',
                 [r".*: warning: \[WakelockReleasedDangerously\] .+"]),
+    java_medium_type('CallbackName'),
+    java_medium_type('ExecutorRegistration'),
+    java_medium_type('ListenerLast'),
+    java_medium_type('MissingBuildMethod'),
+    java_medium_type('NoByteOrShort'),
+    java_medium_type('SetterReturnsThis'),
+    java_medium_type('UseIcu'),
     java_high('AndroidInjection.inject() should always be invoked before calling super.lifecycleMethod()',
               [r".*: warning: \[AndroidInjectionBeforeSuper\] .+"]),
     java_high('Use of class, field, or method that is not compatible with legacy Android devices',
@@ -449,6 +478,8 @@
               [r".*: warning: \[ArrayFillIncompatibleType\] .+"]),
     java_high('hashcode method on array does not hash array contents',
               [r".*: warning: \[ArrayHashCode\] .+"]),
+    java_high('ArrayReturn',
+              [r".*\.java:.*: warning: .+ \[ArrayReturn\]$"]),
     java_high('Calling toString on an array does not provide useful information',
               [r".*: warning: \[ArrayToString\] .+"]),
     java_high('Arrays.asList does not autobox primitive arrays, as one might expect.',
@@ -500,7 +531,7 @@
     java_high('Thread created but not started',
               [r".*: warning: \[DeadThread\] .+"]),
     java_high('Deprecated item is not annotated with @Deprecated',
-              [r".*: warning: \[DepAnn\] .+"]),
+              [r".*\.java:.*: warning: \[.*\] .+ is not annotated with @Deprecated$"]),
     java_high('Division by integer literal zero',
               [r".*: warning: \[DivZero\] .+"]),
     java_high('This method should not be called.',
@@ -721,4 +752,11 @@
               [r".*: warning: \[UnusedCollectionModifiedInPlace\] .+"]),
     java_high('`var` should not be used as a type name.',
               [r".*: warning: \[VarTypeName\] .+"]),
+    # Other javac tool warnings
+    java_medium('addNdkApiCoverage failed to getPackage',
+                [r".*: warning: addNdkApiCoverage failed to getPackage"]),
+    java_medium('Supported version from annotation processor',
+                [r".*: warning: Supported source version .+ from annotation processor"]),
 ]
+
+compile_patterns(warn_patterns)
diff --git a/tools/warn/make_warn_patterns.py b/tools/warn/make_warn_patterns.py
index ac3c508..327fce4 100644
--- a/tools/warn/make_warn_patterns.py
+++ b/tools/warn/make_warn_patterns.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,9 +15,12 @@
 
 """Warning patterns for build make tools."""
 
-from severity import Severity
+# pylint:disable=relative-beyond-top-level
+from .cpp_warn_patterns import compile_patterns
+# pylint:disable=g-importing-member
+from .severity import Severity
 
-patterns = [
+warn_patterns = [
     # pylint:disable=line-too-long,g-inconsistent-quotes
     {'category': 'make', 'severity': Severity.MEDIUM,
      'description': 'make: overriding commands/ignoring old commands',
@@ -51,3 +54,6 @@
      'description': 'make: please convert to soong',
      'patterns': [r".*: warning: .* has been deprecated. Please convert to Soong."]},
 ]
+
+
+compile_patterns(warn_patterns)
diff --git a/tools/warn/other_warn_patterns.py b/tools/warn/other_warn_patterns.py
index 45d14dc..19a4e38 100644
--- a/tools/warn/other_warn_patterns.py
+++ b/tools/warn/other_warn_patterns.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,10 @@
 
 """Warning patterns from other tools."""
 
-from severity import Severity
+# pylint:disable=relative-beyond-top-level
+from .cpp_warn_patterns import compile_patterns
+# pylint:disable=g-importing-member
+from .severity import Severity
 
 
 def warn(name, severity, description, pattern_list):
@@ -39,9 +42,19 @@
   return warn('asm', Severity.MEDIUM, description, pattern_list)
 
 
-patterns = [
+def kotlin(description, pattern_list):
+  return warn('Kotlin', Severity.MEDIUM, description, pattern_list)
+
+
+def yacc(description, pattern_list):
+  return warn('yacc', Severity.MEDIUM, description, pattern_list)
+
+
+warn_patterns = [
     # pylint:disable=line-too-long,g-inconsistent-quotes
     # aapt warnings
+    aapt('No comment for public symbol',
+         [r".*: warning: No comment for public symbol .+"]),
     aapt('No default translation',
          [r".*: warning: string '.+' has no default translation in .*"]),
     aapt('Missing default or required localization',
@@ -90,22 +103,30 @@
      'patterns': [r".*: warning: .* generate guard with empty availability: obsoleted ="]},
     # Protoc warnings
     {'category': 'Protoc', 'severity': Severity.MEDIUM,
-     'description': 'Proto: Enum name colision after strip',
+     'description': 'Proto: Enum name collision after strip',
      'patterns': [r".*: warning: Enum .* has the same name .* ignore case and strip"]},
     {'category': 'Protoc', 'severity': Severity.MEDIUM,
      'description': 'Proto: Import not used',
      'patterns': [r".*: warning: Import .*/.*\.proto but not used.$"]},
     # Kotlin warnings
-    {'category': 'Kotlin', 'severity': Severity.MEDIUM,
-     'description': 'Kotlin: never used parameter or variable',
-     'patterns': [r".*: warning: (parameter|variable) '.*' is never used$"]},
-    {'category': 'Kotlin', 'severity': Severity.MEDIUM,
-     'description': 'Kotlin: Deprecated in Java',
-     'patterns': [r".*: warning: '.*' is deprecated. Deprecated in Java"]},
-    {'category': 'Kotlin', 'severity': Severity.MEDIUM,
-     'description': 'Kotlin: library has Kotlin runtime',
-     'patterns': [r".*: warning: library has Kotlin runtime bundled into it",
-                  r".*: warning: some JAR files .* have the Kotlin Runtime library"]},
+    kotlin('never used parameter or variable',
+           [r".*\.kt:.*: warning: (parameter|variable) '.*' is never used$",
+            r".*\.kt:.*: warning: (parameter|variable) '.*' is never used, could be renamed to _$"]),
+    kotlin('unchecked cast',
+           [r".*\.kt:.*: warning: unchecked cast: .* to .*$"]),
+    kotlin('Deprecated in Java',
+           [r".*\.kt:.*: warning: '.*' is deprecated. Deprecated in Java"]),
+    kotlin('library has Kotlin runtime',
+           [r".*: warning: library has Kotlin runtime bundled into it",
+            r".*: warning: some JAR files .* have the Kotlin Runtime library"]),
+    # Yacc warnings
+    yacc('deprecate directive',
+         [r".*\.yy?:.*: warning: deprecated directive: "]),
+    yacc('shift/reduce conflicts',
+         [r".*\.yy?: warning: .+ shift/reduce conflicts "]),
+    {'category': 'yacc', 'severity': Severity.SKIP,
+     'description': 'yacc: fix-its can be applied',
+     'patterns': [r".*\.yy?: warning: fix-its can be applied."]},
     # Rust warnings
     {'category': 'Rust', 'severity': Severity.HIGH,
      'description': 'Rust: Does not derive Copy',
@@ -124,7 +145,10 @@
      'description': 'skip, In file included from ...',
      'patterns': [r".*: warning: In file included from .+,"]},
     # catch-all for warnings this script doesn't know about yet
-    {'category': 'C/C++', 'severity': Severity.UNKNOWN,
+    {'category': 'C/C++', 'severity': Severity.UNMATCHED,
      'description': 'Unclassified/unrecognized warnings',
      'patterns': [r".*: warning: .+"]},
 ]
+
+
+compile_patterns(warn_patterns)
diff --git a/tools/warn/severity.py b/tools/warn/severity.py
index bb23f2c..b1c38e4 100644
--- a/tools/warn/severity.py
+++ b/tools/warn/severity.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,35 +13,45 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Severity levels and attributes."""
+"""Clang_Tidy_Warn Severity class definition.
+
+This file stores definition for class Severity that is used in warn_patterns.
+"""
 
 
-class Severity(object):
-  """Severity levels and attributes."""
-  # numbered by dump order
-  FIXMENOW = 0
-  HIGH = 1
-  MEDIUM = 2
-  LOW = 3
-  ANALYZER = 4
-  TIDY = 5
-  HARMLESS = 6
-  UNKNOWN = 7
-  SKIP = 8
-  range = range(SKIP + 1)
-  attributes = [
-      # pylint:disable=bad-whitespace
-      ['fuchsia',   'FixNow',    'Critical warnings, fix me now'],
-      ['red',       'High',      'High severity warnings'],
-      ['orange',    'Medium',    'Medium severity warnings'],
-      ['yellow',    'Low',       'Low severity warnings'],
-      ['hotpink',   'Analyzer',  'Clang-Analyzer warnings'],
-      ['peachpuff', 'Tidy',      'Clang-Tidy warnings'],
-      ['limegreen', 'Harmless',  'Harmless warnings'],
-      ['lightblue', 'Unknown',   'Unknown warnings'],
-      ['grey',      'Unhandled', 'Unhandled warnings']
+# pylint:disable=old-style-class
+class Severity:
+  """Class of Severity levels where each level is a SeverityInfo."""
+
+  class SeverityInfo:
+
+    def __init__(self, value, color, column_header, header):
+      self.value = value
+      self.color = color
+      self.column_header = column_header
+      self.header = header
+
+  # SEVERITY_UNKNOWN should never occur since every warn_pattern listed has
+  # a specified severity. It exists for protobuf, the other values must
+  # map to non-zero values (since 0 is reserved for a default UNKNOWN), but
+  # logic in clang_tidy_warn.py assumes severity level values are consecutive
+  # ints starting with 0.
+  SEVERITY_UNKNOWN = SeverityInfo(0, 'blueviolet', 'Errors of unknown severity',
+                                  'Unknown severity (should not occur)')
+  FIXMENOW = SeverityInfo(1, 'fuschia', 'FixNow',
+                          'Critical warnings, fix me now')
+  HIGH = SeverityInfo(2, 'red', 'High', 'High severity warnings')
+  MEDIUM = SeverityInfo(3, 'orange', 'Medium', 'Medium severity warnings')
+  LOW = SeverityInfo(4, 'yellow', 'Low', 'Low severity warnings')
+  ANALYZER = SeverityInfo(5, 'hotpink', 'Analyzer', 'Clang-Analyzer warnings')
+  TIDY = SeverityInfo(6, 'peachpuff', 'Tidy', 'Clang-Tidy warnings')
+  HARMLESS = SeverityInfo(7, 'limegreen', 'Harmless', 'Harmless warnings')
+  UNMATCHED = SeverityInfo(8, 'lightblue', 'Unmatched', 'Unmatched warnings')
+  SKIP = SeverityInfo(9, 'grey', 'Unhandled', 'Unhandled warnings')
+
+  levels = [
+      SEVERITY_UNKNOWN, FIXMENOW, HIGH, MEDIUM, LOW, ANALYZER, TIDY, HARMLESS,
+      UNMATCHED, SKIP
   ]
-  colors = [a[0] for a in attributes]
-  column_headers = [a[1] for a in attributes]
-  headers = [a[2] for a in attributes]
-
+  # HTML relies on ordering by value. Sort here to ensure that this is proper
+  levels = sorted(levels, key=lambda severity: severity.value)
diff --git a/tools/warn/tidy_warn_patterns.py b/tools/warn/tidy_warn_patterns.py
index a26b388..2c5ab79 100644
--- a/tools/warn/tidy_warn_patterns.py
+++ b/tools/warn/tidy_warn_patterns.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,10 @@
 
 """Warning patterns for clang-tidy."""
 
-from severity import Severity
+# pylint:disable=relative-beyond-top-level
+from .cpp_warn_patterns import compile_patterns
+# pylint:disable=g-importing-member
+from .severity import Severity
 
 
 def tidy_warn_pattern(description, pattern):
@@ -35,13 +38,13 @@
   return tidy_warn_pattern(description, description + r'-.+')
 
 
-def analyzer_high(description, pattern_list):
+def analyzer_high(description, patterns):
   # Important clang analyzer warnings to be fixed ASAP.
   return {
       'category': 'C/C++',
       'severity': Severity.HIGH,
       'description': description,
-      'patterns': pattern_list
+      'patterns': patterns
   }
 
 
@@ -53,12 +56,12 @@
   return analyzer_high(check, [r'.*: .+\[' + check + r'.+\]$'])
 
 
-def analyzer_warn(description, pattern_list):
+def analyzer_warn(description, patterns):
   return {
       'category': 'C/C++',
       'severity': Severity.ANALYZER,
       'description': description,
-      'patterns': pattern_list
+      'patterns': patterns
   }
 
 
@@ -70,7 +73,7 @@
   return analyzer_warn(check, [r'.*: .+\[' + check + r'.+\]$'])
 
 
-patterns = [
+warn_patterns = [
     # pylint:disable=line-too-long,g-inconsistent-quotes
     group_tidy_warn_pattern('android'),
     simple_tidy_warn_pattern('abseil-string-find-startswith'),
@@ -136,6 +139,13 @@
     simple_tidy_warn_pattern('portability-simd-intrinsics'),
     group_tidy_warn_pattern('performance'),
     group_tidy_warn_pattern('readability'),
+    simple_tidy_warn_pattern('abseil-string-find-startwith'),
+    simple_tidy_warn_pattern('abseil-faster-strsplit-delimiter'),
+    simple_tidy_warn_pattern('abseil-no-namespace'),
+    simple_tidy_warn_pattern('abseil-no-internal-dependencies'),
+    group_tidy_warn_pattern('abseil'),
+    simple_tidy_warn_pattern('portability-simd-intrinsics'),
+    group_tidy_warn_pattern('portability'),
 
     # warnings from clang-tidy's clang-analyzer checks
     analyzer_high('clang-analyzer-core, null pointer',
@@ -189,5 +199,8 @@
     analyzer_high_check('clang-analyzer-cplusplus.NewDeleteLeaks'),
     analyzer_high_check('clang-analyzer-cplusplus.NewDelete'),
     analyzer_group_check('clang-analyzer-unix'),
-    analyzer_group_check('clang-analyzer'),  # catch al
+    analyzer_group_check('clang-analyzer'),  # catch all
 ]
+
+
+compile_patterns(warn_patterns)
diff --git a/tools/warn/warn.py b/tools/warn/warn.py
index 252f073..bdfd489 100755
--- a/tools/warn/warn.py
+++ b/tools/warn/warn.py
@@ -19,6 +19,7 @@
 import multiprocessing
 
 # pylint:disable=relative-beyond-top-level
+# pylint:disable=g-importing-member
 from .warn_common import common_main
 
 
diff --git a/tools/warn/warn_common.py b/tools/warn/warn_common.py
index de4b805..0c9d9ef 100755
--- a/tools/warn/warn_common.py
+++ b/tools/warn/warn_common.py
@@ -1,4 +1,4 @@
-#
+# python3
 # Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,18 +24,13 @@
 #
 # To parse and keep warning message in the input file:
 #   severity:                classification of message severity
-#   severity.range           [0, 1, ... last_severity_level]
-#   severity.colors          for header background
-#   severity.column_headers  for the warning count table
-#   severity.headers         for warning message tables
 #   warn_patterns:
 #   warn_patterns[w]['category']     tool that issued the warning, not used now
 #   warn_patterns[w]['description']  table heading
 #   warn_patterns[w]['members']      matched warnings from input
-#   warn_patterns[w]['option']       compiler flag to control the warning
 #   warn_patterns[w]['patterns']     regular expressions to match warnings
 #   warn_patterns[w]['projects'][p]  number of warnings of pattern w in p
-#   warn_patterns[w]['severity']     severity level
+#   warn_patterns[w]['severity']     severity tuple
 #   project_list[p][0]               project name
 #   project_list[p][1]               regular expression to match a project path
 #   project_patterns[p]              re.compile(project_list[p][1])
@@ -48,7 +43,7 @@
 #   platform_version
 #   target_product
 #   target_variant
-#   compile_patterns, parse_input_file
+#   parse_input_file
 #
 # To emit html page of warning messages:
 #   flags: --byproject, --url, --separator
@@ -68,13 +63,12 @@
 #   Some data are copied from Python to JavaScript, to generate HTML elements.
 #   FlagURL                args.url
 #   FlagSeparator          args.separator
-#   SeverityColors:        severity.colors
-#   SeverityHeaders:       severity.headers
-#   SeverityColumnHeaders: severity.column_headers
+#   SeverityColors:        list of colors for all severity levels
+#   SeverityHeaders:       list of headers for all severity levels
+#   SeverityColumnHeaders: list of column_headers for all severity levels
 #   ProjectNames:          project_names, or project_list[*][0]
 #   WarnPatternsSeverity:     warn_patterns[*]['severity']
 #   WarnPatternsDescription:  warn_patterns[*]['description']
-#   WarnPatternsOption:       warn_patterns[*]['option']
 #   WarningMessages:          warning_messages
 #   Warnings:                 warning_records
 #   StatsHeader:           warning count table header row
@@ -103,6 +97,7 @@
 from . import make_warn_patterns
 from . import other_warn_patterns
 from . import tidy_warn_patterns
+# pylint:disable=g-importing-member
 from .android_project_list import project_list
 from .severity import Severity
 
@@ -132,11 +127,11 @@
                     help='Path to build.log file')
 args = parser.parse_args()
 
-warn_patterns = make_warn_patterns.patterns
-warn_patterns.extend(cpp_warn_patterns.patterns)
-warn_patterns.extend(java_warn_patterns.patterns)
-warn_patterns.extend(tidy_warn_patterns.patterns)
-warn_patterns.extend(other_warn_patterns.patterns)
+warn_patterns = make_warn_patterns.warn_patterns
+warn_patterns.extend(cpp_warn_patterns.warn_patterns)
+warn_patterns.extend(java_warn_patterns.warn_patterns)
+warn_patterns.extend(tidy_warn_patterns.warn_patterns)
+warn_patterns.extend(other_warn_patterns.warn_patterns)
 
 project_patterns = []
 project_names = []
@@ -151,8 +146,6 @@
   project_patterns = [re.compile(p[1]) for p in project_list]
   for w in warn_patterns:
     w['members'] = []
-    if 'option' not in w:
-      w['option'] = ''
     # Each warning pattern has a 'projects' dictionary, that
     # maps a project name to number of warnings in that project.
     w['projects'] = {}
@@ -206,22 +199,30 @@
 """
 
 
+def make_writer(output_stream):
+
+  def writer(text):
+    return output_stream.write(text + '\n')
+
+  return writer
+
+
 def html_big(param):
   return '<font size="+2">' + param + '</font>'
 
 
-def dump_html_prologue(title):
-  print('<html>\n<head>')
-  print('<title>' + title + '</title>')
-  print(html_head_scripts)
-  emit_stats_by_project()
-  print('</head>\n<body>')
-  print(html_big(title))
-  print('<p>')
+def dump_html_prologue(title, writer):
+  writer('<html>\n<head>')
+  writer('<title>' + title + '</title>')
+  writer(html_head_scripts)
+  emit_stats_by_project(writer)
+  writer('</head>\n<body>')
+  writer(html_big(title))
+  writer('<p>')
 
 
-def dump_html_epilogue():
-  print('</body>\n</head>\n</html>')
+def dump_html_epilogue(writer):
+  writer('</body>\n</head>\n</html>')
 
 
 def sort_warnings():
@@ -229,31 +230,37 @@
     i['members'] = sorted(set(i['members']))
 
 
-def emit_stats_by_project():
+def emit_stats_by_project(writer):
   """Dump a google chart table of warnings per project and severity."""
   # warnings[p][s] is number of warnings in project p of severity s.
   # pylint:disable=g-complex-comprehension
-  warnings = {p: {s: 0 for s in Severity.range} for p in project_names}
+  warnings = {p: {s.value: 0 for s in Severity.levels} for p in project_names}
   for i in warn_patterns:
-    s = i['severity']
+    # pytype: disable=attribute-error
+    s = i['severity'].value
+    # pytype: enable=attribute-error
     for p in i['projects']:
       warnings[p][s] += i['projects'][p]
 
   # total_by_project[p] is number of warnings in project p.
-  total_by_project = {p: sum(warnings[p][s] for s in Severity.range)
-                      for p in project_names}
+  total_by_project = {
+      p: sum(warnings[p][s.value] for s in Severity.levels)
+      for p in project_names
+  }
 
   # total_by_severity[s] is number of warnings of severity s.
-  total_by_severity = {s: sum(warnings[p][s] for p in project_names)
-                       for s in Severity.range}
+  total_by_severity = {
+      s.value: sum(warnings[p][s.value] for p in project_names)
+      for s in Severity.levels
+  }
 
   # emit table header
   stats_header = ['Project']
-  for s in Severity.range:
-    if total_by_severity[s]:
-      stats_header.append("<span style='background-color:{}'>{}</span>".
-                          format(Severity.colors[s],
-                                 Severity.column_headers[s]))
+  for s in Severity.levels:
+    if total_by_severity[s.value]:
+      stats_header.append(
+          '<span style=\'background-color:{}\'>{}</span>'.format(
+              s.color, s.column_header))
   stats_header.append('TOTAL')
 
   # emit a row of warning counts per project, skip no-warning projects
@@ -262,9 +269,9 @@
   for p in project_names:
     if total_by_project[p]:
       one_row = [p]
-      for s in Severity.range:
-        if total_by_severity[s]:
-          one_row.append(warnings[p][s])
+      for s in Severity.levels:
+        if total_by_severity[s.value]:
+          one_row.append(warnings[p][s.value])
       one_row.append(total_by_project[p])
       stats_rows.append(one_row)
       total_all_projects += total_by_project[p]
@@ -272,40 +279,40 @@
   # emit a row of warning counts per severity
   total_all_severities = 0
   one_row = ['<b>TOTAL</b>']
-  for s in Severity.range:
-    if total_by_severity[s]:
-      one_row.append(total_by_severity[s])
-      total_all_severities += total_by_severity[s]
+  for s in Severity.levels:
+    if total_by_severity[s.value]:
+      one_row.append(total_by_severity[s.value])
+      total_all_severities += total_by_severity[s.value]
   one_row.append(total_all_projects)
   stats_rows.append(one_row)
-  print('<script>')
-  emit_const_string_array('StatsHeader', stats_header)
-  emit_const_object_array('StatsRows', stats_rows)
-  print(draw_table_javascript)
-  print('</script>')
+  writer('<script>')
+  emit_const_string_array('StatsHeader', stats_header, writer)
+  emit_const_object_array('StatsRows', stats_rows, writer)
+  writer(draw_table_javascript)
+  writer('</script>')
 
 
-def dump_stats():
+def dump_stats(writer):
   """Dump some stats about total number of warnings and such."""
   known = 0
   skipped = 0
   unknown = 0
   sort_warnings()
   for i in warn_patterns:
-    if i['severity'] == Severity.UNKNOWN:
+    if i['severity'] == Severity.UNMATCHED:
       unknown += len(i['members'])
     elif i['severity'] == Severity.SKIP:
       skipped += len(i['members'])
     else:
       known += len(i['members'])
-  print('Number of classified warnings: <b>' + str(known) + '</b><br>')
-  print('Number of skipped warnings: <b>' + str(skipped) + '</b><br>')
-  print('Number of unclassified warnings: <b>' + str(unknown) + '</b><br>')
+  writer('Number of classified warnings: <b>' + str(known) + '</b><br>')
+  writer('Number of skipped warnings: <b>' + str(skipped) + '</b><br>')
+  writer('Number of unclassified warnings: <b>' + str(unknown) + '</b><br>')
   total = unknown + known + skipped
   extra_msg = ''
   if total < 1000:
     extra_msg = ' (low count may indicate incremental build)'
-  print('Total number of warnings: <b>' + str(total) + '</b>' + extra_msg)
+  writer('Total number of warnings: <b>' + str(total) + '</b>' + extra_msg)
 
 
 # New base table of warnings, [severity, warn_id, project, warning_message]
@@ -318,15 +325,15 @@
 # (3) New, group by project + severity,
 #     id for each warning pattern
 #     sort by project, severity, warn_id, warning_message
-def emit_buttons():
-  print('<button class="button" onclick="expandCollapse(1);">'
-        'Expand all warnings</button>\n'
-        '<button class="button" onclick="expandCollapse(0);">'
-        'Collapse all warnings</button>\n'
-        '<button class="button" onclick="groupBySeverity();">'
-        'Group warnings by severity</button>\n'
-        '<button class="button" onclick="groupByProject();">'
-        'Group warnings by project</button><br>')
+def emit_buttons(writer):
+  writer('<button class="button" onclick="expandCollapse(1);">'
+         'Expand all warnings</button>\n'
+         '<button class="button" onclick="expandCollapse(0);">'
+         'Collapse all warnings</button>\n'
+         '<button class="button" onclick="groupBySeverity();">'
+         'Group warnings by severity</button>\n'
+         '<button class="button" onclick="groupByProject();">'
+         'Group warnings by project</button><br>')
 
 
 def all_patterns(category):
@@ -337,35 +344,32 @@
   return patterns
 
 
-def dump_fixed():
+def dump_fixed(writer):
   """Show which warnings no longer occur."""
   anchor = 'fixed_warnings'
   mark = anchor + '_mark'
-  print('\n<br><p style="background-color:lightblue"><b>'
-        '<button id="' + mark + '" '
-        'class="bt" onclick="expand(\'' + anchor + '\');">'
-        '&#x2295</button> Fixed warnings. '
-        'No more occurrences. Please consider turning these into '
-        'errors if possible, before they are reintroduced in to the build'
-        ':</b></p>')
-  print('<blockquote>')
+  writer('\n<br><p style="background-color:lightblue"><b>'
+         '<button id="' + mark + '" '
+         'class="bt" onclick="expand(\'' + anchor + '\');">'
+         '&#x2295</button> Fixed warnings. '
+         'No more occurrences. Please consider turning these into '
+         'errors if possible, before they are reintroduced in to the build'
+         ':</b></p>')
+  writer('<blockquote>')
   fixed_patterns = []
   for i in warn_patterns:
     if not i['members']:
-      fixed_patterns.append(i['description'] + ' (' +
-                            all_patterns(i) + ')')
-    if i['option']:
-      fixed_patterns.append(' ' + i['option'])
+      fixed_patterns.append(i['description'] + ' (' + all_patterns(i) + ')')
   fixed_patterns = sorted(fixed_patterns)
-  print('<div id="' + anchor + '" style="display:none;"><table>')
+  writer('<div id="' + anchor + '" style="display:none;"><table>')
   cur_row_class = 0
   for text in fixed_patterns:
     cur_row_class = 1 - cur_row_class
     # remove last '\n'
     t = text[:-1] if text[-1] == '\n' else text
-    print('<tr><td class="c' + str(cur_row_class) + '">' + t + '</td></tr>')
-  print('</table></div>')
-  print('</blockquote>')
+    writer('<tr><td class="c' + str(cur_row_class) + '">' + t + '</td></tr>')
+  writer('</table></div>')
+  writer('</blockquote>')
 
 
 def find_project_index(line):
@@ -380,6 +384,7 @@
   for i in range(len(warn_patterns)):
     w = warn_patterns[i]
     for cpat in w['compiled_patterns']:
+      # pytype: disable=attribute-error
       if cpat.match(line):
         p = find_project_index(line)
         results.append([line, i, p])
@@ -389,6 +394,7 @@
         # probably caused by 'make -j' mixing the output from
         # 2 or more concurrent compiles
         pass
+      # pytype: enable=attribute-error
 
 
 def classify_warnings(lines):
@@ -404,7 +410,6 @@
 
 def parallel_classify_warnings(warning_lines, parallel_process):
   """Classify all warning lines with num_cpu parallel processes."""
-  compile_patterns()
   num_cpu = args.processes
   if num_cpu > 1:
     groups = [[] for x in range(num_cpu)]
@@ -431,14 +436,6 @@
         pattern['projects'][pname] = 1
 
 
-def compile_patterns():
-  """Precompiling every pattern speeds up parsing by about 30x."""
-  for i in warn_patterns:
-    i['compiled_patterns'] = []
-    for pat in i['patterns']:
-      i['compiled_patterns'].append(re.compile(pat))
-
-
 def find_warn_py_and_android_root(path):
   """Set and return android_root path if it is found."""
   global android_root
@@ -475,7 +472,9 @@
           return
   # Do not use common prefix of a small number of paths.
   if count > 10:
+    # pytype: disable=wrong-arg-types
     root_path = os.path.commonprefix(warning_lines)
+    # pytype: enable=wrong-arg-types
     if len(root_path) > 2 and root_path[len(root_path) - 1] == '/':
       android_root = root_path[:-1]
 
@@ -548,6 +547,7 @@
       prev_warning = 'unknown_source_file: ' + prev_warning
       warning_lines.add(normalize_warning_line(prev_warning))
       prev_warning = ''
+
     if warning_pattern.match(line):
       if warning_without_file.match(line):
         # save this line and combine it with the next line
@@ -555,6 +555,7 @@
       else:
         warning_lines.add(normalize_warning_line(line))
       continue
+
     if line_counter < 100:
       # save a little bit of time by only doing this for the first few lines
       line_counter += 1
@@ -575,7 +576,9 @@
 
 # Return s with escaped backslash and quotation characters.
 def escape_string(s):
+  # pytype: disable=attribute-error
   return s.replace('\\', '\\\\').replace('"', '\\"')
+  # pytype: enable=attribute-error
 
 
 # Return s without trailing '\n' and escape the quotation characters.
@@ -586,22 +589,22 @@
   return escape_string(s)
 
 
-def emit_warning_array(name):
-  print('var warning_{} = ['.format(name))
+def emit_warning_array(name, writer):
+  writer('var warning_{} = ['.format(name))
   for i in range(len(warn_patterns)):
-    print('{},'.format(warn_patterns[i][name]))
-  print('];')
+    writer('{},'.format(warn_patterns[i][name]))
+  writer('];')
 
 
-def emit_warning_arrays():
-  emit_warning_array('severity')
-  print('var warning_description = [')
+def emit_warning_arrays(writer):
+  emit_warning_array('severity', writer)
+  writer('var warning_description = [')
   for i in range(len(warn_patterns)):
     if warn_patterns[i]['members']:
-      print('"{}",'.format(escape_string(warn_patterns[i]['description'])))
+      writer('"{}",'.format(escape_string(warn_patterns[i]['description'])))
     else:
-      print('"",')  # no such warning
-  print('];')
+      writer('"",')  # no such warning
+  writer('];')
 
 
 scripts_for_warning_groups = """
@@ -707,7 +710,8 @@
     var result = "";
     var groups = groupWarningsBySeverity();
     for (s=0; s<SeverityColors.length; s++) {
-      result += createWarningSection(SeverityHeaders[s], SeverityColors[s], groups[s]);
+      result += createWarningSection(SeverityHeaders[s], SeverityColors[s],
+                                     groups[s]);
     }
     return result;
   }
@@ -734,61 +738,67 @@
 
 
 # Emit a JavaScript const string
-def emit_const_string(name, value):
-  print('const ' + name + ' = "' + escape_string(value) + '";')
+def emit_const_string(name, value, writer):
+  writer('const ' + name + ' = "' + escape_string(value) + '";')
 
 
 # Emit a JavaScript const integer array.
-def emit_const_int_array(name, array):
-  print('const ' + name + ' = [')
+def emit_const_int_array(name, array, writer):
+  writer('const ' + name + ' = [')
   for n in array:
-    print(str(n) + ',')
-  print('];')
+    writer(str(n) + ',')
+  writer('];')
 
 
 # Emit a JavaScript const string array.
-def emit_const_string_array(name, array):
-  print('const ' + name + ' = [')
+def emit_const_string_array(name, array, writer):
+  writer('const ' + name + ' = [')
   for s in array:
-    print('"' + strip_escape_string(s) + '",')
-  print('];')
+    writer('"' + strip_escape_string(s) + '",')
+  writer('];')
 
 
 # Emit a JavaScript const string array for HTML.
-def emit_const_html_string_array(name, array):
-  print('const ' + name + ' = [')
+def emit_const_html_string_array(name, array, writer):
+  writer('const ' + name + ' = [')
   for s in array:
     # Not using html.escape yet, to work for both python 2 and 3,
     # until all users switch to python 3.
     # pylint:disable=deprecated-method
-    print('"' + cgi.escape(strip_escape_string(s)) + '",')
-  print('];')
+    writer('"' + cgi.escape(strip_escape_string(s)) + '",')
+  writer('];')
 
 
 # Emit a JavaScript const object array.
-def emit_const_object_array(name, array):
-  print('const ' + name + ' = [')
+def emit_const_object_array(name, array, writer):
+  writer('const ' + name + ' = [')
   for x in array:
-    print(str(x) + ',')
-  print('];')
+    writer(str(x) + ',')
+  writer('];')
 
 
-def emit_js_data():
+def emit_js_data(writer):
   """Dump dynamic HTML page's static JavaScript data."""
-  emit_const_string('FlagURL', args.url if args.url else '')
-  emit_const_string('FlagSeparator', args.separator if args.separator else '')
-  emit_const_string_array('SeverityColors', Severity.colors)
-  emit_const_string_array('SeverityHeaders', Severity.headers)
-  emit_const_string_array('SeverityColumnHeaders', Severity.column_headers)
-  emit_const_string_array('ProjectNames', project_names)
+  emit_const_string('FlagURL',
+                    args.url if args.url else '', writer)
+  emit_const_string('FlagSeparator',
+                    args.separator if args.separator else '', writer)
+  emit_const_string_array('SeverityColors',
+                          [s.color for s in Severity.levels], writer)
+  emit_const_string_array('SeverityHeaders',
+                          [s.header for s in Severity.levels], writer)
+  emit_const_string_array('SeverityColumnHeaders',
+                          [s.column_header for s in Severity.levels], writer)
+  emit_const_string_array('ProjectNames', project_names, writer)
+  # pytype: disable=attribute-error
   emit_const_int_array('WarnPatternsSeverity',
-                       [w['severity'] for w in warn_patterns])
+                       [w['severity'].value for w in warn_patterns], writer)
+  # pytype: enable=attribute-error
   emit_const_html_string_array('WarnPatternsDescription',
-                               [w['description'] for w in warn_patterns])
-  emit_const_html_string_array('WarnPatternsOption',
-                               [w['option'] for w in warn_patterns])
-  emit_const_html_string_array('WarningMessages', warning_messages)
-  emit_const_object_array('Warnings', warning_records)
+                               [w['description'] for w in warn_patterns],
+                               writer)
+  emit_const_html_string_array('WarningMessages', warning_messages, writer)
+  emit_const_object_array('Warnings', warning_records, writer)
 
 draw_table_javascript = """
 google.charts.load('current', {'packages':['table']});
@@ -805,31 +815,33 @@
       data.setProperty(i, j, 'style', 'border:1px solid black;');
     }
   }
-  var table = new google.visualization.Table(document.getElementById('stats_table'));
+  var table = new google.visualization.Table(
+      document.getElementById('stats_table'));
   table.draw(data, {allowHtml: true, alternatingRowStyle: true});
 }
 """
 
 
-def dump_html():
-  """Dump the html output to stdout."""
+def dump_html(output_stream):
+  """Dump the html output to output_stream."""
+  writer = make_writer(output_stream)
   dump_html_prologue('Warnings for ' + platform_version + ' - ' +
-                     target_product + ' - ' + target_variant)
-  dump_stats()
-  print('<br><div id="stats_table"></div><br>')
-  print('\n<script>')
-  emit_js_data()
-  print(scripts_for_warning_groups)
-  print('</script>')
-  emit_buttons()
+                     target_product + ' - ' + target_variant, writer)
+  dump_stats(writer)
+  writer('<br><div id="stats_table"></div><br>')
+  writer('\n<script>')
+  emit_js_data(writer)
+  writer(scripts_for_warning_groups)
+  writer('</script>')
+  emit_buttons(writer)
   # Warning messages are grouped by severities or project names.
-  print('<br><div id="warning_groups"></div>')
+  writer('<br><div id="warning_groups"></div>')
   if args.byproject:
-    print('<script>groupByProject();</script>')
+    writer('<script>groupByProject();</script>')
   else:
-    print('<script>groupBySeverity();</script>')
-  dump_fixed()
-  dump_html_epilogue()
+    writer('<script>groupBySeverity();</script>')
+  dump_fixed(writer)
+  dump_html_epilogue(writer)
 
 
 ##### Functions to count warnings and dump csv file. #########################
@@ -851,7 +863,9 @@
       warning = kind + ': ' + description_for_csv(i)
       writer.writerow([n, '', warning])
       # print number of warnings for each project, ordered by project name.
+      # pytype: disable=attribute-error
       projects = sorted(i['projects'].keys())
+      # pytype: enable=attribute-error
       for p in projects:
         writer.writerow([i['projects'][p], p, warning])
   writer.writerow([total, '', kind + ' warnings'])
@@ -864,8 +878,9 @@
   """Dump number of warnings in csv format to stdout."""
   sort_warnings()
   total = 0
-  for s in Severity.range:
-    total += count_severity(writer, s, Severity.column_headers[s])
+  for s in Severity.levels:
+    if s != Severity.SEVERITY_UNKNOWN:
+      total += count_severity(writer, s, s.column_header)
   writer.writerow([total, '', 'All warnings'])
 
 
@@ -885,4 +900,4 @@
   if args.gencsv:
     dump_csv(csv.writer(sys.stdout, lineterminator='\n'))
   else:
-    dump_html()
+    dump_html(sys.stdout)