Merge "Auto-generate dexpreopt boot image module"
diff --git a/Changes.md b/Changes.md
index 61e6bb6..3109e9b 100644
--- a/Changes.md
+++ b/Changes.md
@@ -87,16 +87,16 @@
 
 `BUILD_BROKEN_DUP_SYSPROP := true`
 
-## ELF prebuilts in PRODUCT_COPY_FILES
+## ELF prebuilts in `PRODUCT_COPY_FILES` {#BUILD_BROKEN_ELF_PREBUILT_PRODUCT_COPY_FILES}
 
-ELF prebuilts in PRODUCT_COPY_FILES that are installed into these paths are an
+ELF prebuilts in `PRODUCT_COPY_FILES` that are installed into these paths are an
 error:
 
 * `<partition>/bin/*`
 * `<partition>/lib/*`
 * `<partition>/lib64/*`
 
-Define prebuilt modules and add them to PRODUCT_PACKAGES instead.
+Define prebuilt modules and add them to `PRODUCT_PACKAGES` instead.
 To temporarily relax this check and restore the behavior prior to this change,
 set `BUILD_BROKEN_ELF_PREBUILT_PRODUCT_COPY_FILES := true` in `BoardConfig.mk`.
 
diff --git a/core/Makefile b/core/Makefile
index 5aad799..584a144 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -383,9 +383,9 @@
   $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,RECOVERY,$(TARGET_RECOVERY_ROOT_OUT),,modules.load.recovery,,$(dir))) \
   $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,VENDOR_RAMDISK,$(TARGET_VENDOR_RAMDISK_OUT),,modules.load,$(VENDOR_RAMDISK_STRIPPED_MODULE_STAGING_DIR),$(dir))) \
   $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-vendor-ramdisk-recovery-load,$(dir))) \
-  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,VENDOR,$(TARGET_OUT_VENDOR),vendor,modules.load,$(VENDOR_STRIPPED_MODULE_STAGING_DIR),$(dir))) \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,VENDOR,$(if $(filter true,$(BOARD_USES_VENDOR_DLKMIMAGE)),$(TARGET_OUT_VENDOR_DLKM),$(TARGET_OUT_VENDOR)),vendor,modules.load,$(VENDOR_STRIPPED_MODULE_STAGING_DIR),$(dir))) \
   $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-vendor-charger-load,$(dir))) \
-  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,ODM,$(TARGET_OUT_ODM),odm,modules.load,,$(dir))) \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,ODM,$(if $(filter true,$(BOARD_USES_ODM_DLKMIMAGE)),$(TARGET_OUT_ODM_DLKM),$(TARGET_OUT_ODM)),odm,modules.load,,$(dir))) \
   $(if $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)),\
     $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-recovery-as-boot-load,$(dir))),\
     $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,GENERIC_RAMDISK,$(TARGET_RAMDISK_OUT),,modules.load,,$(dir)))))
@@ -476,7 +476,7 @@
 SOONG_CONV_DATA := $(call intermediates-dir-for,PACKAGING,soong_conversion)/soong_conv_data
 $(SOONG_CONV_DATA):
 	@rm -f $@
-	@$(foreach s,$(SOONG_CONV),echo "$(s),$(SOONG_CONV.$(s).TYPE),$(sort $(SOONG_CONV.$(s).PROBLEMS)),$(sort $(filter-out $(SOONG_ALREADY_CONV),$(SOONG_CONV.$(s).DEPS)))" >>$@;)
+	@$(foreach s,$(SOONG_CONV),echo "$(s),$(SOONG_CONV.$(s).TYPE),$(sort $(SOONG_CONV.$(s).PROBLEMS)),$(sort $(filter-out $(SOONG_ALREADY_CONV),$(SOONG_CONV.$(s).DEPS))),$(sort $(SOONG_CONV.$(s).MAKEFILES)),$(sort $(SOONG_CONV.$(s).INSTALLED))" >>$@;)
 
 SOONG_TO_CONVERT_SCRIPT := build/make/tools/soong_to_convert.py
 SOONG_TO_CONVERT := $(PRODUCT_OUT)/soong_to_convert.txt
@@ -485,6 +485,19 @@
 	$(hide) $(SOONG_TO_CONVERT_SCRIPT) $< >$@
 $(call dist-for-goals,droidcore,$(SOONG_TO_CONVERT))
 
+MK2BP_CATALOG_SCRIPT := build/make/tools/mk2bp_catalog.py
+MK2BP_REMAINING_HTML := $(PRODUCT_OUT)/mk2bp_remaining.html
+$(MK2BP_REMAINING_HTML): PRIVATE_CODE_SEARCH_BASE_URL := "https://cs.android.com/android/platform/superproject/+/master:"
+$(MK2BP_REMAINING_HTML): $(SOONG_CONV_DATA) $(MK2BP_CATALOG_SCRIPT)
+	@rm -f $@
+	$(hide) $(MK2BP_CATALOG_SCRIPT) \
+		--device=$(TARGET_DEVICE) \
+		--title="Remaining Android.mk files for $(TARGET_DEVICE)-$(TARGET_BUILD_VARIANT)" \
+		--codesearch=$(PRIVATE_CODE_SEARCH_BASE_URL) \
+		--out_dir="$(OUT_DIR)" \
+		> $@
+$(call dist-for-goals,droidcore,$(MK2BP_REMAINING_HTML))
+
 # -----------------------------------------------------------------
 # Modules use -Wno-error, or added default -Wall -Werror
 WALL_WERROR := $(PRODUCT_OUT)/wall_werror.txt
@@ -889,8 +902,10 @@
 .PHONY: notice_files
 
 # Create the rule to combine the files into text and html/xml forms
-# $(1) - xml_excluded_system_product_odm|xml_excluded_vendor_product_odm
-#        xml_product|xml_odm|xml_system_ext|xml_system|html
+# $(1) - xml_excluded_system_product_odm_vendor_dlkm_odm_dlkm|
+#        xml_excluded_vendor_product_odm_vendor_dlkm_odm_dlkm|
+#        xml_product|xml_odm|xml_system_ext|xml_system|xml_vendor_dlkm|
+#        xml_odm_dlkm|html
 # $(2) - Plain text output file
 # $(3) - HTML/XML output file
 # $(4) - File title
@@ -916,13 +931,15 @@
 $(2): .KATI_IMPLICIT_OUTPUTS := $(3)
 $(2): $(6) $(BUILD_SYSTEM)/Makefile build/make/tools/generate-notice-files.py
 	build/make/tools/generate-notice-files.py --text-output $(2) $(foreach xdir, $(7), -e $(xdir) )\
-	    $(if $(filter $(1),xml_excluded_vendor_product_odm),-e vendor -e product -e system_ext -e odm --xml-output, \
-	      $(if $(filter $(1),xml_excluded_system_product_odm),-e system -e product -e system_ext -e odm --xml-output, \
+	    $(if $(filter $(1),xml_excluded_vendor_product_odm_vendor_dlkm_odm_dlkm),-e vendor -e product -e system_ext -e odm -e vendor_dlkm -e odm_dlkm --xml-output, \
+	      $(if $(filter $(1),xml_excluded_system_product_odm_vendor_dlkm_odm_dlkm),-e system -e product -e system_ext -e odm -e vendor_dlkm -e odm_dlkm --xml-output, \
 	        $(if $(filter $(1),xml_product),-i product --xml-output, \
 	          $(if $(filter $(1),xml_system_ext),-i system_ext --xml-output, \
 	            $(if $(filter $(1),xml_system),-i system --xml-output, \
 	              $(if $(filter $(1),xml_odm),-i odm --xml-output, \
-	                --html-output)))))) $(3) \
+	                $(if $(filter $(1),xml_vendor_dlkm),-i vendor_dlkm --xml-output, \
+	                  $(if $(filter $(1),xml_odm_dlkm),-i odm_dlkm --xml-output, \
+	                    --html-output)))))))) $(3) \
 	    -t $$(PRIVATE_MESSAGE) -s $$(PRIVATE_DIR)/src
 notice_files: $(2) $(3)
 endef
@@ -986,6 +1003,16 @@
 target_odm_notice_file_xml_gz := $(TARGET_OUT_INTERMEDIATES)/NOTICE_ODM.xml.gz
 installed_odm_notice_xml_gz := $(TARGET_OUT_ODM)/etc/NOTICE.xml.gz
 
+target_vendor_dlkm_notice_file_txt := $(TARGET_OUT_INTERMEDIATES)/NOTICE_VENDOR_DLKM.txt
+target_vendor_dlkm_notice_file_xml := $(TARGET_OUT_INTERMEDIATES)/NOTICE_VENDOR_DLKM.xml
+target_vendor_dlkm_notice_file_xml_gz := $(TARGET_OUT_INTERMEDIATES)/NOTICE_VENDOR_DLKM.xml.gz
+installed_vendor_dlkm_notice_xml_gz := $(TARGET_OUT_VENDOR_DLKM)/etc/NOTICE.xml.gz
+
+target_odm_dlkm_notice_file_txt := $(TARGET_OUT_INTERMEDIATES)/NOTICE_ODM_DLKM.txt
+target_odm_dlkm_notice_file_xml := $(TARGET_OUT_INTERMEDIATES)/NOTICE_ODM_DLKM.xml
+target_odm_dlkm_notice_file_xml_gz := $(TARGET_OUT_INTERMEDIATES)/NOTICE_ODM_DLKM.xml.gz
+installed_odm_dlkm_notice_xml_gz := $(TARGET_OUT_ODM_DLKM)/etc/NOTICE.xml.gz
+
 # Notice files are copied to TARGET_OUT_NOTICE_FILES as a side-effect of their module
 # being built. A notice xml file must depend on all modules that could potentially
 # install a license file relevant to it.
@@ -996,17 +1023,21 @@
 license_modules := $(filter-out $(TARGET_OUT_FAKE)/%,$(license_modules))
 # testcases are not relevant to the system image.
 license_modules := $(filter-out $(TARGET_OUT_TESTCASES)/%,$(license_modules))
-# filesystem images: system, vendor, product, system_ext, and odm
+# filesystem images: system, vendor, product, system_ext, odm, vendor_dlkm, and odm_dlkm
 license_modules_system := $(filter $(TARGET_OUT)/%,$(license_modules))
 license_modules_vendor := $(filter $(TARGET_OUT_VENDOR)/%,$(license_modules))
 license_modules_product := $(filter $(TARGET_OUT_PRODUCT)/%,$(license_modules))
 license_modules_system_ext := $(filter $(TARGET_OUT_SYSTEM_EXT)/%,$(license_modules))
 license_modules_odm := $(filter $(TARGET_OUT_ODM)/%,$(license_modules))
+license_modules_vendor_dlkm := $(filter $(TARGET_OUT_VENDOR_DLKM)/%,$(license_modules))
+license_modules_odm_dlkm := $(filter $(TARGET_OUT_ODM_DLKM)/%,$(license_modules))
 license_modules_agg := $(license_modules_system) \
                        $(license_modules_vendor) \
                        $(license_modules_product) \
                        $(license_modules_system_ext) \
-                       $(license_modules_odm)
+                       $(license_modules_odm) \
+                       $(license_modules_vendor_dlkm) \
+                       $(license_modules_odm_dlkm)
 # targets used for debug symbols only and do not get copied to the device
 license_modules_symbols_only := $(filter $(PRODUCT_OUT)/apex/%,$(license_modules))
 
@@ -1041,8 +1072,8 @@
 # update its notice file, so include those notices in the system partition instead
 ifdef BOARD_PREBUILT_VENDORIMAGE
 license_modules_system += $(license_modules_rehomed)
-system_xml_directories := xml_excluded_vendor_product_odm
-system_notice_file_message := "Notices for files contained in all filesystem images except vendor/system_ext/product/odm in this directory:"
+system_xml_directories := xml_excluded_vendor_product_odm_vendor_dlkm_odm_dlkm
+system_notice_file_message := "Notices for files contained in all filesystem images except vendor/system_ext/product/odm/vendor_dlkm/odm_dlkm in this directory:"
 else
 license_modules_vendor += $(license_modules_rehomed)
 system_xml_directories := xml_system
@@ -1056,10 +1087,10 @@
 	        $(TARGET_OUT_NOTICE_FILES), \
 	        $(license_modules_system), \
 	        $(exclude_target_dirs)))
-$(eval $(call combine-notice-files, xml_excluded_system_product_odm, \
+$(eval $(call combine-notice-files, xml_excluded_system_product_odm_vendor_dlkm_odm_dlkm, \
 	        $(target_vendor_notice_file_txt), \
 	        $(target_vendor_notice_file_xml), \
-	        "Notices for files contained in all filesystem images except system/system_ext/product/odm in this directory:", \
+	        "Notices for files contained in all filesystem images except system/system_ext/product/odm/vendor_dlkm/odm_dlkm in this directory:", \
 	        $(TARGET_OUT_NOTICE_FILES), \
 	        $(license_modules_vendor), \
 	        $(exclude_target_dirs)))
@@ -1084,6 +1115,20 @@
 	        $(TARGET_OUT_NOTICE_FILES), \
 	        $(license_modules_odm), \
 	        $(exclude_target_dirs)))
+$(eval $(call combine-notice-files, xml_vendor_dlkm, \
+	        $(target_vendor_dlkm_notice_file_txt), \
+	        $(target_vendor_dlkm_notice_file_xml), \
+	        "Notices for files contained in the vendor_dlkm filesystem image in this directory:", \
+	        $(TARGET_OUT_NOTICE_FILES), \
+	        $(license_modules_vendor_dlkm), \
+	        $(exclude_target_dirs)))
+$(eval $(call combine-notice-files, xml_odm_dlkm, \
+	        $(target_odm_dlkm_notice_file_txt), \
+	        $(target_odm_dlkm_notice_file_xml), \
+	        "Notices for files contained in the odm_dlkm filesystem image in this directory:", \
+	        $(TARGET_OUT_NOTICE_FILES), \
+	        $(license_modules_odm_dlkm), \
+	        $(exclude_target_dirs)))
 
 $(target_notice_file_xml_gz): $(target_notice_file_xml) | $(MINIGZIP)
 	$(hide) $(MINIGZIP) -9 < $< > $@
@@ -1095,6 +1140,10 @@
 	$(hide) $(MINIGZIP) -9 < $< > $@
 $(target_odm_notice_file_xml_gz): $(target_odm_notice_file_xml) | $(MINIGZIP)
 	$(hide) $(MINIGZIP) -9 < $< > $@
+$(target_vendor_dlkm_notice_file_xml_gz): $(target_vendor_dlkm_notice_file_xml) | $(MINIGZIP)
+	$(hide) $(MINIGZIP) -9 < $< > $@
+$(target_odm_dlkm_notice_file_xml_gz): $(target_odm_dlkm_notice_file_xml) | $(MINIGZIP)
+	$(hide) $(MINIGZIP) -9 < $< > $@
 $(installed_notice_html_or_xml_gz): $(target_notice_file_xml_gz)
 	$(copy-file-to-target)
 $(installed_vendor_notice_xml_gz): $(target_vendor_notice_file_xml_gz)
@@ -1105,12 +1154,18 @@
 	$(copy-file-to-target)
 $(installed_odm_notice_xml_gz): $(target_odm_notice_file_xml_gz)
 	$(copy-file-to-target)
+$(installed_vendor_dlkm_notice_xml_gz): $(target_vendor_dlkm_notice_file_xml_gz)
+	$(copy-file-to-target)
+$(installed_odm_dlkm_notice_xml_gz): $(target_odm_dlkm_notice_file_xml_gz)
+	$(copy-file-to-target)
 
 ALL_DEFAULT_INSTALLED_MODULES += $(installed_notice_html_or_xml_gz)
 ALL_DEFAULT_INSTALLED_MODULES += $(installed_vendor_notice_xml_gz)
 ALL_DEFAULT_INSTALLED_MODULES += $(installed_product_notice_xml_gz)
 ALL_DEFAULT_INSTALLED_MODULES += $(installed_system_ext_notice_xml_gz)
 ALL_DEFAULT_INSTALLED_MODULES += $(installed_odm_notice_xml_gz)
+ALL_DEFAULT_INSTALLED_MODULES += $(installed_vendor_dlkm_notice_xml_gz)
+ALL_DEFAULT_INSTALLED_MODULES += $(installed_odm_dlkm_notice_xml_gz)
 endif # PRODUCT_NOTICE_SPLIT
 
 ALL_DEFAULT_INSTALLED_MODULES += $(installed_notice_html_or_xml_gz)
@@ -1177,7 +1232,15 @@
 INTERNAL_USERIMAGES_DEPS += $(MKF2FSUSERIMG)
 endif
 
-ifneq ($(filter $(BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE) $(BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE) $(BOARD_ODMIMAGE_FILE_SYSTEM_TYPE) $(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE) $(BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE),squashfs),)
+ifneq ($(filter \
+    $(BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE) \
+    $(BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE) \
+    $(BOARD_ODMIMAGE_FILE_SYSTEM_TYPE) \
+    $(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE) \
+    $(BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE) \
+    $(BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE) \
+    $(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE) \
+  ,squashfs),)
 INTERNAL_USERIMAGES_DEPS += $(MKSQUASHFSUSERIMG)
 endif
 
@@ -1207,7 +1270,7 @@
 endif # PRODUCT_USE_DYNAMIC_PARTITIONS
 
 # $(1): the path of the output dictionary file
-# $(2): a subset of "system vendor cache userdata product system_ext oem odm"
+# $(2): a subset of "system vendor cache userdata product system_ext oem odm vendor_dlkm odm_dlkm"
 # $(3): additional "key=value" pairs to append to the dictionary file.
 define generate-image-prop-dictionary
 $(if $(filter $(2),system),\
@@ -1303,6 +1366,34 @@
     $(hide) echo "odm_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_odm_image=$(BUILDING_ODM_IMAGE)" >> $(1)
 )
+$(if $(filter $(2),vendor_dlkm),\
+    $(if $(BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "vendor_dlkm_fs_type=$(BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_EXTFS_INODE_COUNT),$(hide) echo "vendor_dlkm_extfs_inode_count=$(BOARD_VENDOR_DLKMIMAGE_EXTFS_INODE_COUNT)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_EXTFS_RSV_PCT),$(hide) echo "vendor_dlkm_extfs_rsv_pct=$(BOARD_VENDOR_DLKMIMAGE_EXTFS_RSV_PCT)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_PARTITION_SIZE),$(hide) echo "vendor_dlkm_size=$(BOARD_VENDOR_DLKMIMAGE_PARTITION_SIZE)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_JOURNAL_SIZE),$(hide) echo "vendor_dlkm_journal_size=$(BOARD_VENDOR_DLKMIMAGE_JOURNAL_SIZE)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_COMPRESSOR),$(hide) echo "vendor_dlkm_squashfs_compressor=$(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_COMPRESSOR)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_COMPRESSOR_OPT),$(hide) echo "vendor_dlkm_squashfs_compressor_opt=$(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_COMPRESSOR_OPT)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "vendor_dlkm_squashfs_block_size=$(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "vendor_dlkm_squashfs_disable_4k_align=$(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
+    $(if $(BOARD_VENDOR_DLKMIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "vendor_dlkm_reserved_size=$(BOARD_VENDOR_DLKMIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(hide) echo "vendor_dlkm_selinux_fc=$(SELINUX_FC)" >> $(1)
+    $(hide) echo "building_vendor_dlkm_image=$(BUILDING_VENDOR_DLKM_IMAGE)" >> $(1)
+)
+$(if $(filter $(2),odm_dlkm),\
+    $(if $(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "odm_dlkm_fs_type=$(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_EXTFS_INODE_COUNT),$(hide) echo "odm_dlkm_extfs_inode_count=$(BOARD_ODM_DLKMIMAGE_EXTFS_INODE_COUNT)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_EXTFS_RSV_PCT),$(hide) echo "odm_dlkm_extfs_rsv_pct=$(BOARD_ODM_DLKMIMAGE_EXTFS_RSV_PCT)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_PARTITION_SIZE),$(hide) echo "odm_dlkm_size=$(BOARD_ODM_DLKMIMAGE_PARTITION_SIZE)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_JOURNAL_SIZE),$(hide) echo "odm_dlkm_journal_size=$(BOARD_ODM_DLKMIMAGE_JOURNAL_SIZE)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_SQUASHFS_COMPRESSOR),$(hide) echo "odm_dlkm_squashfs_compressor=$(BOARD_ODM_DLKMIMAGE_SQUASHFS_COMPRESSOR)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_SQUASHFS_COMPRESSOR_OPT),$(hide) echo "odm_dlkm_squashfs_compressor_opt=$(BOARD_ODM_DLKMIMAGE_SQUASHFS_COMPRESSOR_OPT)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "odm_dlkm_squashfs_block_size=$(BOARD_ODM_DLKMIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "odm_dlkm_squashfs_disable_4k_align=$(BOARD_ODM_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
+    $(if $(BOARD_ODM_DLKMIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "odm_dlkm_reserved_size=$(BOARD_ODM_DLKMIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(hide) echo "odm_dlkm_selinux_fc=$(SELINUX_FC)" >> $(1)
+    $(hide) echo "building_odm_dlkm_image=$(BUILDING_ODM_DLKM_IMAGE)" >> $(1)
+)
 $(if $(filter $(2),oem),\
     $(if $(BOARD_OEMIMAGE_PARTITION_SIZE),$(hide) echo "oem_size=$(BOARD_OEMIMAGE_PARTITION_SIZE)" >> $(1))
     $(if $(BOARD_OEMIMAGE_JOURNAL_SIZE),$(hide) echo "oem_journal_size=$(BOARD_OEMIMAGE_JOURNAL_SIZE)" >> $(1))
@@ -1329,6 +1420,8 @@
 $(if $(PRODUCT_VENDOR_VERITY_PARTITION),$(hide) echo "vendor_verity_block_device=$(PRODUCT_VENDOR_VERITY_PARTITION)" >> $(1))
 $(if $(PRODUCT_PRODUCT_VERITY_PARTITION),$(hide) echo "product_verity_block_device=$(PRODUCT_PRODUCT_VERITY_PARTITION)" >> $(1))
 $(if $(PRODUCT_SYSTEM_EXT_VERITY_PARTITION),$(hide) echo "system_ext_verity_block_device=$(PRODUCT_SYSTEM_EXT_VERITY_PARTITION)" >> $(1))
+$(if $(PRODUCT_VENDOR_DLKM_VERITY_PARTITION),$(hide) echo "vendor_dlkm_verity_block_device=$(PRODUCT_VENDOR_DLKM_VERITY_PARTITION)" >> $(1))
+$(if $(PRODUCT_ODM_DLKM_VERITY_PARTITION),$(hide) echo "odm_dlkm_verity_block_device=$(PRODUCT_ODM_DLKM_VERITY_PARTITION)" >> $(1))
 $(if $(PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot=$(PRODUCT_SUPPORTS_VBOOT)" >> $(1))
 $(if $(PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot_key=$(PRODUCT_VBOOT_SIGNING_KEY)" >> $(1))
 $(if $(PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot_subkey=$(PRODUCT_VBOOT_SIGNING_SUBKEY)" >> $(1))
@@ -1377,6 +1470,22 @@
         $(hide) echo "avb_odm_key_path=$(BOARD_AVB_ODM_KEY_PATH)" >> $(1)
         $(hide) echo "avb_odm_algorithm=$(BOARD_AVB_ODM_ALGORITHM)" >> $(1)
         $(hide) echo "avb_odm_rollback_index_location=$(BOARD_AVB_ODM_ROLLBACK_INDEX_LOCATION)" >> $(1)))
+$(if $(BOARD_AVB_ENABLE),$(hide) echo "avb_vendor_dlkm_hashtree_enable=$(BOARD_AVB_ENABLE)" >> $(1))
+$(if $(BOARD_AVB_ENABLE),\
+    $(hide) echo "avb_vendor_dlkm_add_hashtree_footer_args=$(BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS)" >> $(1))
+$(if $(BOARD_AVB_ENABLE),\
+    $(if $(BOARD_AVB_VENDOR_DLKM_KEY_PATH),\
+        $(hide) echo "avb_vendor_dlkm_key_path=$(BOARD_AVB_VENDOR_DLKM_KEY_PATH)" >> $(1)
+        $(hide) echo "avb_vendor_dlkm_algorithm=$(BOARD_AVB_VENDOR_DLKM_ALGORITHM)" >> $(1)
+        $(hide) echo "avb_vendor_dlkm_rollback_index_location=$(BOARD_AVB_VENDOR_DLKM_ROLLBACK_INDEX_LOCATION)" >> $(1)))
+$(if $(BOARD_AVB_ENABLE),$(hide) echo "avb_odm_dlkm_hashtree_enable=$(BOARD_AVB_ENABLE)" >> $(1))
+$(if $(BOARD_AVB_ENABLE),\
+    $(hide) echo "avb_odm_dlkm_add_hashtree_footer_args=$(BOARD_AVB_ODM_DLKM_ADD_HASHTREE_FOOTER_ARGS)" >> $(1))
+$(if $(BOARD_AVB_ENABLE),\
+    $(if $(BOARD_AVB_ODM_DLKM_KEY_PATH),\
+        $(hide) echo "avb_odm_dlkm_key_path=$(BOARD_AVB_ODM_DLKM_KEY_PATH)" >> $(1)
+        $(hide) echo "avb_odm_dlkm_algorithm=$(BOARD_AVB_ODM_DLKM_ALGORITHM)" >> $(1)
+        $(hide) echo "avb_odm_dlkm_rollback_index_location=$(BOARD_AVB_ODM_DLKM_ROLLBACK_INDEX_LOCATION)" >> $(1)))
 $(if $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)),\
     $(hide) echo "recovery_as_boot=true" >> $(1))
 $(if $(filter true,$(BOARD_BUILD_SYSTEM_ROOT_IMAGE)),\
@@ -1414,6 +1523,12 @@
 ifdef BUILDING_ODM_IMAGE
   PROP_DICTIONARY_IMAGES += odm
 endif
+ifdef BUILDING_VENDOR_DLKM_IMAGE
+  PROP_DICTIONARY_IMAGES += vendor_dlkm
+endif
+ifdef BUILDING_ODM_DLKM_IMAGE
+  PROP_DICTIONARY_IMAGES += odm_dlkm
+endif
 define generate-userimage-prop-dictionary
   $(call generate-image-prop-dictionary,$(1),$(PROP_DICTIONARY_IMAGES),$(2))
 endef
@@ -2406,6 +2521,12 @@
 ifdef BUILDING_ODM_IMAGE
 	echo "-D $(TARGET_OUT_ODM)" >> $@.lst
 endif
+ifdef BUILDING_VENDOR_DLKM_IMAGE
+	echo "-D $(TARGET_OUT_VENDOR_DLKM)" >> $@.lst
+endif
+ifdef BUILDING_ODM_DLKM_IMAGE
+	echo "-D $(TARGET_OUT_ODM_DLKM)" >> $@.lst
+endif
 ifneq ($(PDK_PLATFORM_JAVA_ZIP_CONTENTS),)
 	echo "-C $(OUT_DIR)" >> $@.lst
 	for f in $(filter-out $(PRIVATE_DEX_FILES),$(addprefix -f $(OUT_DIR)/,$(PDK_PLATFORM_JAVA_ZIP_CONTENTS))); do \
@@ -2667,6 +2788,64 @@
 endef
 endif
 
+# Create symlinks for vendor_dlkm on devices with a vendor_dlkm partition:
+# /vendor/lib/modules -> /vendor_dlkm/lib/modules
+#
+# On devices with a vendor_dlkm partition,
+# - /vendor/lib/modules is a symlink to a directory that stores vendor DLKMs.
+# - /vendor_dlkm/{etc,...} store other vendor_dlkm files directly. The vendor_dlkm partition is
+#   mounted at /vendor_dlkm at runtime and the symlinks created in system/core/rootdir/Android.mk
+#   are hidden.
+# On devices without a vendor_dlkm partition,
+# - /vendor/lib/modules stores vendor DLKMs directly.
+# - /vendor_dlkm/{etc,...} are symlinks to directories that store other vendor_dlkm files.
+#   See system/core/rootdir/Android.mk for a list of created symlinks.
+# The vendor DLKMs and other vendor_dlkm files must not be accessed using other paths because they
+# are not guaranteed to exist on all devices.
+ifdef BOARD_USES_VENDOR_DLKMIMAGE
+define create-vendor-vendor_dlkm-symlink
+$(hide) mkdir -p $(TARGET_OUT_VENDOR)/lib
+$(hide) if [ -d $(TARGET_OUT_VENDOR)/lib/modules ] && [ ! -h $(TARGET_OUT_VENDOR)/lib/modules ]; then \
+  echo 'Non-symlink $(TARGET_OUT_VENDOR)/lib/modules detected!' 1>&2; \
+  echo 'You cannot install files to $(TARGET_OUT_VENDOR)/lib/modules while building a separate vendor_dlkm.img!' 1>&2; \
+  exit 1; \
+fi
+$(hide) ln -sf /vendor_dlkm/lib/modules $(TARGET_OUT_VENDOR)/lib/modules
+endef
+else
+define create-vendor-vendor_dlkm-symlink
+endef
+endif
+
+# Create symlinks for odm_dlkm on devices with a odm_dlkm partition:
+# /odm/lib/modules -> /odm_dlkm/lib/modules
+#
+# On devices with a odm_dlkm partition,
+# - /odm/lib/modules is a symlink to a directory that stores odm DLKMs.
+# - /odm_dlkm/{etc,...} store other odm_dlkm files directly. The odm_dlkm partition is
+#   mounted at /odm_dlkm at runtime and the symlinks created in system/core/rootdir/Android.mk
+#   are hidden.
+# On devices without a odm_dlkm partition,
+# - /odm/lib/modules stores odm DLKMs directly.
+# - /odm_dlkm/{etc,...} are symlinks to directories that store other odm_dlkm files.
+#   See system/core/rootdir/Android.mk for a list of created symlinks.
+# The odm DLKMs and other odm_dlkm files must not be accessed using other paths because they
+# are not guaranteed to exist on all devices.
+ifdef BOARD_USES_ODM_DLKMIMAGE
+define create-odm-odm_dlkm-symlink
+$(hide) mkdir -p $(TARGET_OUT_ODM)/lib
+$(hide) if [ -d $(TARGET_OUT_ODM)/lib/modules ] && [ ! -h $(TARGET_OUT_ODM)/lib/modules ]; then \
+  echo 'Non-symlink $(TARGET_OUT_ODM)/lib/modules detected!' 1>&2; \
+  echo 'You cannot install files to $(TARGET_OUT_ODM)/lib/modules while building a separate odm_dlkm.img!' 1>&2; \
+  exit 1; \
+fi
+$(hide) ln -sf /odm_dlkm/lib/modules $(TARGET_OUT_ODM)/lib/modules
+endef
+else
+define create-odm-odm_dlkm-symlink
+endef
+endif
+
 vendorimage_intermediates := \
     $(call intermediates-dir-for,PACKAGING,vendor)
 BUILT_VENDORIMAGE_TARGET := $(PRODUCT_OUT)/vendor.img
@@ -2674,6 +2853,8 @@
   $(call pretty,"Target vendor fs image: $(INSTALLED_VENDORIMAGE_TARGET)")
   @mkdir -p $(TARGET_OUT_VENDOR)
   $(call create-vendor-odm-symlink)
+  $(call create-vendor-vendor_dlkm-symlink)
+  $(call create-odm-odm_dlkm-symlink)
   @mkdir -p $(vendorimage_intermediates) && rm -rf $(vendorimage_intermediates)/vendor_image_info.txt
   $(call generate-image-prop-dictionary, $(vendorimage_intermediates)/vendor_image_info.txt,vendor,skip_fsck=true)
   PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
@@ -2873,6 +3054,117 @@
 endif
 
 # -----------------------------------------------------------------
+# vendor_dlkm partition image
+ifdef BUILDING_VENDOR_DLKM_IMAGE
+INTERNAL_VENDOR_DLKMIMAGE_FILES := \
+    $(filter $(TARGET_OUT_VENDOR_DLKM)/%,\
+      $(ALL_DEFAULT_INSTALLED_MODULES)\
+      $(ALL_PDK_FUSION_FILES)) \
+    $(PDK_FUSION_SYMLINK_STAMP)
+# platform.zip depends on $(INTERNAL_VENDOR_DLKMIMAGE_FILES).
+$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_VENDOR_DLKMIMAGE_FILES)
+
+INSTALLED_FILES_FILE_VENDOR_DLKM := $(PRODUCT_OUT)/installed-files-vendor_dlkm.txt
+INSTALLED_FILES_JSON_VENDOR_DLKM := $(INSTALLED_FILES_FILE_VENDOR_DLKM:.txt=.json)
+$(INSTALLED_FILES_FILE_VENDOR_DLKM): .KATI_IMPLICIT_OUTPUTS := $(INSTALLED_FILES_JSON_VENDOR_DLKM)
+$(INSTALLED_FILES_FILE_VENDOR_DLKM) : $(INTERNAL_VENDOR_DLKMIMAGE_FILES) $(FILESLIST) $(FILESLIST_UTIL)
+	@echo Installed file list: $@
+	@mkdir -p $(dir $@)
+	@rm -f $@
+	$(hide) $(FILESLIST) $(TARGET_OUT_VENDOR_DLKM) > $(@:.txt=.json)
+	$(hide) $(FILESLIST_UTIL) -c $(@:.txt=.json) > $@
+
+vendor_dlkmimage_intermediates := \
+    $(call intermediates-dir-for,PACKAGING,vendor_dlkm)
+BUILT_VENDOR_DLKMIMAGE_TARGET := $(PRODUCT_OUT)/vendor_dlkm.img
+define build-vendor_dlkmimage-target
+  $(call pretty,"Target vendor_dlkm fs image: $(INSTALLED_VENDOR_DLKMIMAGE_TARGET)")
+  @mkdir -p $(TARGET_OUT_VENDOR_DLKM)
+  @mkdir -p $(vendor_dlkmimage_intermediates) && rm -rf $(vendor_dlkmimage_intermediates)/vendor_dlkm_image_info.txt
+  $(call generate-userimage-prop-dictionary, $(vendor_dlkmimage_intermediates)/vendor_dlkm_image_info.txt, skip_fsck=true)
+  PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
+      $(BUILD_IMAGE) \
+          $(TARGET_OUT_VENDOR_DLKM) $(vendor_dlkmimage_intermediates)/vendor_dlkm_image_info.txt \
+          $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) $(TARGET_OUT)
+  $(call assert-max-image-size,$(INSTALLED_VENDOR_DLKMIMAGE_TARGET),$(BOARD_VENDOR_DLKMIMAGE_PARTITION_SIZE))
+endef
+
+# We just build this directly to the install location.
+INSTALLED_VENDOR_DLKMIMAGE_TARGET := $(BUILT_VENDOR_DLKMIMAGE_TARGET)
+$(INSTALLED_VENDOR_DLKMIMAGE_TARGET): \
+    $(INTERNAL_USERIMAGES_DEPS) \
+    $(INTERNAL_VENDOR_DLKMIMAGE_FILES) \
+    $(INSTALLED_FILES_FILE_VENDOR_DLKM)
+	$(build-vendor_dlkmimage-target)
+
+.PHONY: vendor_dlkmimage-nodeps vdnod
+vendor_dlkmimage-nodeps vdnod: | $(INTERNAL_USERIMAGES_DEPS)
+	$(build-vendor_dlkmimage-target)
+
+sync: $(INTERNAL_VENDOR_DLKMIMAGE_FILES)
+
+else ifdef BOARD_PREBUILT_VENDOR_DLKMIMAGE
+INSTALLED_VENDOR_DLKMIMAGE_TARGET := $(PRODUCT_OUT)/vendor_dlkm.img
+$(eval $(call copy-one-file,$(BOARD_PREBUILT_VENDOR_DLKMIMAGE),$(INSTALLED_VENDOR_DLKMIMAGE_TARGET)))
+endif
+
+# -----------------------------------------------------------------
+# odm_dlkm partition image
+ifdef BUILDING_ODM_DLKM_IMAGE
+INTERNAL_ODM_DLKMIMAGE_FILES := \
+    $(filter $(TARGET_OUT_ODM_DLKM)/%,\
+      $(ALL_DEFAULT_INSTALLED_MODULES)\
+      $(ALL_PDK_FUSION_FILES)) \
+    $(PDK_FUSION_SYMLINK_STAMP)
+# platform.zip depends on $(INTERNAL_ODM_DLKMIMAGE_FILES).
+$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_ODM_DLKMIMAGE_FILES)
+
+INSTALLED_FILES_FILE_ODM_DLKM := $(PRODUCT_OUT)/installed-files-odm_dlkm.txt
+INSTALLED_FILES_JSON_ODM_DLKM := $(INSTALLED_FILES_FILE_ODM_DLKM:.txt=.json)
+$(INSTALLED_FILES_FILE_ODM_DLKM): .KATI_IMPLICIT_OUTPUTS := $(INSTALLED_FILES_JSON_ODM_DLKM)
+$(INSTALLED_FILES_FILE_ODM_DLKM) : $(INTERNAL_ODM_DLKMIMAGE_FILES) $(FILESLIST) $(FILESLIST_UTIL)
+	@echo Installed file list: $@
+	@mkdir -p $(dir $@)
+	@rm -f $@
+	$(hide) $(FILESLIST) $(TARGET_OUT_ODM_DLKM) > $(@:.txt=.json)
+	$(hide) $(FILESLIST_UTIL) -c $(@:.txt=.json) > $@
+
+odm_dlkmimage_intermediates := \
+    $(call intermediates-dir-for,PACKAGING,odm_dlkm)
+BUILT_ODM_DLKMIMAGE_TARGET := $(PRODUCT_OUT)/odm_dlkm.img
+define build-odm_dlkmimage-target
+  $(call pretty,"Target odm_dlkm fs image: $(INSTALLED_ODM_DLKMIMAGE_TARGET)")
+  @mkdir -p $(TARGET_OUT_ODM_DLKM)
+  @mkdir -p $(odm_dlkmimage_intermediates) && rm -rf $(odm_dlkmimage_intermediates)/odm_dlkm_image_info.txt
+  $(call generate-userimage-prop-dictionary, $(odm_dlkmimage_intermediates)/odm_dlkm_image_info.txt, skip_fsck=true)
+  PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
+      $(BUILD_IMAGE) \
+          $(TARGET_OUT_ODM_DLKM) $(odm_dlkmimage_intermediates)/odm_dlkm_image_info.txt \
+          $(INSTALLED_ODM_DLKMIMAGE_TARGET) $(TARGET_OUT)
+  $(call assert-max-image-size,$(INSTALLED_ODM_DLKMIMAGE_TARGET),$(BOARD_ODM_DLKMIMAGE_PARTITION_SIZE))
+endef
+
+# We just build this directly to the install location.
+INSTALLED_ODM_DLKMIMAGE_TARGET := $(BUILT_ODM_DLKMIMAGE_TARGET)
+$(INSTALLED_ODM_DLKMIMAGE_TARGET): \
+    $(INTERNAL_USERIMAGES_DEPS) \
+    $(INTERNAL_ODM_DLKMIMAGE_FILES) \
+    $(INSTALLED_FILES_FILE_ODM_DLKM)
+	$(build-odm_dlkmimage-target)
+
+.PHONY: odm_dlkmimage-nodeps odnod
+odm_dlkmimage-nodeps odnod: | $(INTERNAL_USERIMAGES_DEPS)
+	$(build-odm_dlkmimage-target)
+
+sync: $(INTERNAL_ODM_DLKMIMAGE_FILES)
+
+else ifdef BOARD_PREBUILT_ODM_DLKMIMAGE
+INSTALLED_ODM_DLKMIMAGE_TARGET := $(PRODUCT_OUT)/odm_dlkm.img
+$(eval $(call copy-one-file,$(BOARD_PREBUILT_ODM_DLKMIMAGE),$(INSTALLED_ODM_DLKMIMAGE_TARGET)))
+endif
+
+
+# -----------------------------------------------------------------
 # dtbo image
 ifdef BOARD_PREBUILT_DTBOIMAGE
 INSTALLED_DTBOIMAGE_TARGET := $(PRODUCT_OUT)/dtbo.img
@@ -3028,6 +3320,14 @@
     --prop com.android.build.odm.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
     --prop com.android.build.odm.os_version:$(PLATFORM_VERSION)
 
+BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS += \
+    --prop com.android.build.vendor_dlkm.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
+    --prop com.android.build.vendor_dlkm.os_version:$(PLATFORM_VERSION_LAST_STABLE)
+
+BOARD_AVB_ODM_DLKM_ADD_HASHTREE_FOOTER_ARGS += \
+    --prop com.android.build.odm_dlkm.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
+    --prop com.android.build.odm_dlkm.os_version:$(PLATFORM_VERSION_LAST_STABLE)
+
 BOARD_AVB_DTBO_ADD_HASH_FOOTER_ARGS += \
     --prop com.android.build.dtbo.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE)
 
@@ -3047,6 +3347,16 @@
     --prop com.android.build.odm.security_patch:$(ODM_SECURITY_PATCH)
 endif
 
+ifdef VENDOR_DLKM_SECURITY_PATCH
+BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS += \
+    --prop com.android.build.vendor_dlkm.security_patch:$(VENDOR_DLKM_SECURITY_PATCH)
+endif
+
+ifdef ODM_DLKM_SECURITY_PATCH
+BOARD_AVB_ODM_DLKM_ADD_HASHTREE_FOOTER_ARGS += \
+    --prop com.android.build.odm_dlkm.security_patch:$(ODM_DLKM_SECURITY_PATCH)
+endif
+
 BOOT_FOOTER_ARGS := BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS
 VENDOR_BOOT_FOOTER_ARGS := BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS
 DTBO_FOOTER_ARGS := BOARD_AVB_DTBO_ADD_HASH_FOOTER_ARGS
@@ -3056,6 +3366,8 @@
 PRODUCT_FOOTER_ARGS := BOARD_AVB_PRODUCT_ADD_HASHTREE_FOOTER_ARGS
 SYSTEM_EXT_FOOTER_ARGS := BOARD_AVB_SYSTEM_EXT_ADD_HASHTREE_FOOTER_ARGS
 ODM_FOOTER_ARGS := BOARD_AVB_ODM_ADD_HASHTREE_FOOTER_ARGS
+VENDOR_DLKM_FOOTER_ARGS := BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS
+ODM_DLKM_FOOTER_ARGS := BOARD_AVB_ODM_DLKM_ADD_HASHTREE_FOOTER_ARGS
 
 # Helper function that checks and sets required build variables for an AVB chained partition.
 # $(1): the partition to enable AVB chain, e.g., boot or system or vbmeta_system.
@@ -3150,6 +3462,14 @@
 $(eval $(call check-and-set-avb-args,odm))
 endif
 
+ifdef INSTALLED_VENDOR_DLKMIMAGE_TARGET
+$(eval $(call check-and-set-avb-args,vendor_dlkm))
+endif
+
+ifdef INSTALLED_ODM_DLKMIMAGE_TARGET
+$(eval $(call check-and-set-avb-args,odm_dlkm))
+endif
+
 ifdef INSTALLED_DTBOIMAGE_TARGET
 $(eval $(call check-and-set-avb-args,dtbo))
 endif
@@ -3230,6 +3550,12 @@
   $(if $(BOARD_AVB_ODM_KEY_PATH),\
     $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_ODM_KEY_PATH) \
       --output $(1)/odm.avbpubkey)
+  $(if $(BOARD_AVB_VENDOR_DLKM_KEY_PATH),\
+    $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_VENDOR_DLKM_KEY_PATH) \
+      --output $(1)/vendor_dlkm.avbpubkey)
+  $(if $(BOARD_AVB_ODM_DLKM_KEY_PATH),\
+    $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_ODM_DLKM_KEY_PATH) \
+      --output $(1)/odm_dlkm.avbpubkey)
   $(if $(BOARD_AVB_DTBO_KEY_PATH),\
     $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_DTBO_KEY_PATH) \
       --output $(1)/dtbo.avbpubkey)
@@ -3312,6 +3638,8 @@
 	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
 	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
+	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+	    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
 	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
 	    $(INSTALLED_RECOVERYIMAGE_TARGET) \
@@ -3334,7 +3662,9 @@
 # -----------------------------------------------------------------
 # Check VINTF of build
 
+# Note: vendor_dlkm and odm_dlkm does not have VINTF files.
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
+
 intermediates := $(call intermediates-dir-for,PACKAGING,check_vintf_all)
 check_vintf_all_deps :=
 
@@ -4119,6 +4449,8 @@
 	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
 	    $(INSTALLED_VBMETAIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
+	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+	    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
 	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
 	    $(INTERNAL_SYSTEMOTHERIMAGE_FILES) \
@@ -4134,6 +4466,8 @@
 	    $(PRODUCT_PRODUCT_BASE_FS_PATH) \
 	    $(PRODUCT_SYSTEM_EXT_BASE_FS_PATH) \
 	    $(PRODUCT_ODM_BASE_FS_PATH) \
+	    $(PRODUCT_VENDOR_DLKM_BASE_FS_PATH) \
+	    $(PRODUCT_ODM_DLKM_BASE_FS_PATH) \
 	    $(LPMAKE) \
 	    $(SELINUX_FC) \
 	    $(INSTALLED_MISC_INFO_TARGET) \
@@ -4151,6 +4485,8 @@
 	$(call create-system-product-symlink)
 	$(call create-system-system_ext-symlink)
 	$(call create-vendor-odm-symlink)
+	$(call create-vendor-vendor_dlkm-symlink)
+	$(call create-odm-odm_dlkm-symlink)
 	$(hide) rm -rf $@ $@.list $(zip_root)
 	$(hide) mkdir -p $(dir $@) $(zip_root)
 ifneq (,$(INSTALLED_RECOVERYIMAGE_TARGET)$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
@@ -4271,6 +4607,16 @@
 	$(hide) $(call package_files-copy-root, \
 	    $(TARGET_OUT_ODM),$(zip_root)/ODM)
 endif
+ifdef BUILDING_VENDOR_DLKM_IMAGE
+	@# Contents of the vendor_dlkm image
+	$(hide) $(call package_files-copy-root, \
+	    $(TARGET_OUT_VENDOR_DLKM),$(zip_root)/VENDOR_DLKM)
+endif
+ifdef BUILDING_ODM_DLKM_IMAGE
+	@# Contents of the odm_dlkm image
+	$(hide) $(call package_files-copy-root, \
+	    $(TARGET_OUT_ODM_DLKM),$(zip_root)/ODM_DLKM)
+endif
 ifdef BUILDING_SYSTEM_OTHER_IMAGE
 	@# Contents of the system_other image
 	$(hide) $(call package_files-copy-root, \
@@ -4316,6 +4662,14 @@
 	$(hide) cp $(PRODUCT_ODM_BASE_FS_PATH) \
 	  $(zip_root)/META/$(notdir $(PRODUCT_ODM_BASE_FS_PATH))
 endif
+ifneq ($(PRODUCT_VENDOR_DLKM_BASE_FS_PATH),)
+	$(hide) cp $(PRODUCT_VENDOR_DLKM_BASE_FS_PATH) \
+	  $(zip_root)/META/$(notdir $(PRODUCT_VENDOR_DLKM_BASE_FS_PATH))
+endif
+ifneq ($(PRODUCT_ODM_DLKM_BASE_FS_PATH),)
+	$(hide) cp $(PRODUCT_ODM_DLKM_BASE_FS_PATH) \
+	  $(zip_root)/META/$(notdir $(PRODUCT_ODM_DLKM_BASE_FS_PATH))
+endif
 ifeq ($(TARGET_OTA_ALLOW_NON_AB),true)
 ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
 	$(hide) PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH MKBOOTIMG=$(MKBOOTIMG) \
@@ -4361,6 +4715,10 @@
 	$(hide) mkdir -p $(zip_root)/IMAGES
 	$(hide) cp $(INSTALLED_ODMIMAGE_TARGET) $(zip_root)/IMAGES/
 endif
+ifdef BOARD_PREBUILT_VENDOR_DLKIMMAGE
+	$(hide) mkdir -p $(zip_root)/IMAGES
+	$(hide) cp $(INSTALLED_VENDOR_DLKIMMAGE_TARGET) $(zip_root)/IMAGES/
+endif
 ifdef BOARD_PREBUILT_DTBOIMAGE
 	$(hide) mkdir -p $(zip_root)/PREBUILT_IMAGES
 	$(hide) cp $(INSTALLED_DTBOIMAGE_TARGET) $(zip_root)/PREBUILT_IMAGES/
@@ -4392,6 +4750,12 @@
 ifdef BUILDING_ODM_IMAGE
 	$(hide) $(call fs_config,$(zip_root)/ODM,odm/) > $(zip_root)/META/odm_filesystem_config.txt
 endif
+ifdef BUILDING_VENDOR_DLKM_IMAGE
+	$(hide) $(call fs_config,$(zip_root)/VENDOR_DLKM,vendor_dlkm/) > $(zip_root)/META/vendor_dlkm_filesystem_config.txt
+endif
+ifdef BUILDING_ODM_DLKM_IMAGE
+	$(hide) $(call fs_config,$(zip_root)/ODM_DLKM,odm_dlkm/) > $(zip_root)/META/odm_dlkm_filesystem_config.txt
+endif
 	@# ROOT always contains the files for the root under normal boot.
 	$(hide) $(call fs_config,$(zip_root)/ROOT,) > $(zip_root)/META/root_filesystem_config.txt
 ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
@@ -4550,6 +4914,8 @@
 	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
 	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
+	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+	    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
 	    $(updater_dep)
 endif
 $(SYMBOLS_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,symbols)/filelist
@@ -4575,7 +4941,9 @@
 	    $(INSTALLED_VENDORIMAGE_TARGET) \
 	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
 	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
-	    $(INSTALLED_ODMIMAGE_TARGET)
+	    $(INSTALLED_ODMIMAGE_TARGET) \
+	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+	    $(INSTALLED_ODM_DLKMIMAGE_TARGET)
 endif
 $(COVERAGE_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,coverage)/filelist
 $(COVERAGE_ZIP): $(SOONG_ZIP)
@@ -4652,6 +5020,8 @@
     $(INSTALLED_PRODUCTIMAGE_TARGET) \
     $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
     $(INSTALLED_ODMIMAGE_TARGET) \
+    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
     $(updater_dep)
 endif
 $(PROGUARD_DICT_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,proguard)/filelist
@@ -4890,6 +5260,26 @@
 droidcore: $(INSTALLED_QEMU_ODMIMAGE)
 endif
 
+ifdef INSTALLED_VENDOR_DLKMIMAGE_TARGET
+INSTALLED_QEMU_VENDOR_DLKMIMAGE := $(PRODUCT_OUT)/vendor_dlkm-qemu.img
+$(INSTALLED_QEMU_VENDOR_DLKMIMAGE): $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) $(MK_QEMU_IMAGE_SH) $(SGDISK_HOST)
+	@echo Create vendor_dlkm-qemu.img
+	(export SGDISK=$(SGDISK_HOST); $(MK_QEMU_IMAGE_SH) $(INSTALLED_VENDOR_DLKMIMAGE_TARGET))
+
+vendor_dlkmimage: $(INSTALLED_QEMU_VENDOR_DLKMIMAGE)
+droidcore: $(INSTALLED_QEMU_VENDOR_DLKMIMAGE)
+endif
+
+ifdef INSTALLED_ODM_DLKMIMAGE_TARGET
+INSTALLED_QEMU_ODM_DLKMIMAGE := $(PRODUCT_OUT)/odm_dlkm-qemu.img
+$(INSTALLED_QEMU_ODM_DLKMIMAGE): $(INSTALLED_ODM_DLKMIMAGE_TARGET) $(MK_QEMU_IMAGE_SH) $(SGDISK_HOST)
+	@echo Create odm_dlkm-qemu.img
+	(export SGDISK=$(SGDISK_HOST); $(MK_QEMU_IMAGE_SH) $(INSTALLED_ODM_DLKMIMAGE_TARGET))
+
+odm_dlkmimage: $(INSTALLED_QEMU_ODM_DLKMIMAGE)
+droidcore: $(INSTALLED_QEMU_ODM_DLKMIMAGE)
+endif
+
 QEMU_VERIFIED_BOOT_PARAMS := $(PRODUCT_OUT)/VerifiedBootParams.textproto
 $(QEMU_VERIFIED_BOOT_PARAMS): $(INSTALLED_VBMETAIMAGE_TARGET) $(INSTALLED_SYSTEMIMAGE_TARGET) \
     $(MK_VBMETA_BOOT_KERNEL_CMDLINE_SH) $(AVBTOOL)
diff --git a/core/base_rules.mk b/core/base_rules.mk
index d604480..3f93c2c 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -592,12 +592,22 @@
 ifneq ($(strip $(LOCAL_TEST_DATA)),)
 ifneq (true,$(LOCAL_UNINSTALLABLE_MODULE))
 
+# Soong LOCAL_TEST_DATA is of the form <from_base>:<file>:<relative_install_path>
+# or <from_base>:<file>, to be installed to
+# <install_root>/<relative_install_path>/<file> or <install_root>/<file>,
+# respectively.
 ifeq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
   define copy_test_data_pairs
     _src_base := $$(call word-colon,1,$$(td))
     _file := $$(call word-colon,2,$$(td))
-    my_test_data_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(call append-path,$$(my_module_path),$$(_file))
-    my_test_data_file_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(_file)
+    _relative_install_path := $$(call word-colon,3,$$(td))
+    ifeq (,$$(_relative_install_path))
+        _relative_dest_file := $$(_file)
+    else
+        _relative_dest_file := $$(call append-path,$$(_relative_install_path),$$(_file))
+    endif
+    my_test_data_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(call append-path,$$(my_module_path),$$(_relative_dest_file))
+    my_test_data_file_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(_relative_dest_file)
   endef
 else
   define copy_test_data_pairs
diff --git a/core/binary.mk b/core/binary.mk
index 6c1c4db..29a78a3 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -1818,6 +1818,10 @@
         $(my_shared_libraries) \
         $(my_system_shared_libraries))
 SOONG_CONV.$(LOCAL_MODULE).TYPE := native
+SOONG_CONV.$(LOCAL_MODULE).MAKEFILES := \
+    $(SOONG_CONV.$(LOCAL_MODULE).MAKEFILES) $(LOCAL_MODULE_MAKEFILE)
+SOONG_CONV.$(LOCAL_MODULE).INSTALLED:= \
+    $(SOONG_CONV.$(LOCAL_MODULE).INSTALLED) $(LOCAL_INSTALLED_MODULE)
 SOONG_CONV := $(SOONG_CONV) $(LOCAL_MODULE)
 
 ###########################################################
diff --git a/core/board_config.mk b/core/board_config.mk
index a6e586d..4141cee 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -72,12 +72,18 @@
   BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE \
   BOARD_ODMIMAGE_PARTITION_SIZE \
   BOARD_ODMIMAGE_FILE_SYSTEM_TYPE \
+  BOARD_VENDOR_DLKMIMAGE_PARTITION_SIZE \
+  BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE \
+  BOARD_ODM_DLKMIMAGE_PARTITION_SIZE \
+  BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE \
 
 # Logical partitions related variables.
 _dynamic_partitions_var_list += \
   BOARD_SYSTEMIMAGE_PARTITION_RESERVED_SIZE \
   BOARD_VENDORIMAGE_PARTITION_RESERVED_SIZE \
   BOARD_ODMIMAGE_PARTITION_RESERVED_SIZE \
+  BOARD_VENDOR_DLKMIMAGE_PARTITION_RESERVED_SIZE \
+  BOARD_ODM_DLKMIMAGE_PARTITION_RESERVED_SIZE \
   BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE \
   BOARD_SYSTEM_EXTIMAGE_PARTITION_RESERVED_SIZE \
   BOARD_SUPER_PARTITION_SIZE \
@@ -512,6 +518,40 @@
 .KATI_READONLY := BUILDING_SYSTEM_EXT_IMAGE
 
 ###########################################
+# Now we can substitute with the real value of TARGET_COPY_OUT_VENDOR_DLKM
+ifeq ($(TARGET_COPY_OUT_VENDOR_DLKM),$(_vendor_dlkm_path_placeholder))
+  TARGET_COPY_OUT_VENDOR_DLKM := $(TARGET_COPY_OUT_VENDOR)/vendor_dlkm
+else ifeq ($(filter vendor_dlkm system/vendor/vendor_dlkm vendor/vendor_dlkm,$(TARGET_COPY_OUT_VENDOR_DLKM)),)
+  $(error TARGET_COPY_OUT_VENDOR_DLKM must be either 'vendor_dlkm', 'system/vendor/vendor_dlkm' or 'vendor/vendor_dlkm', seeing '$(TARGET_COPY_OUT_VENDOR_DLKM)'.)
+endif
+PRODUCT_COPY_FILES := $(subst $(_vendor_dlkm_path_placeholder),$(TARGET_COPY_OUT_VENDOR_DLKM),$(PRODUCT_COPY_FILES))
+
+BOARD_USES_VENDOR_DLKMIMAGE :=
+ifdef BOARD_PREBUILT_VENDOR_DLKMIMAGE
+  BOARD_USES_VENDOR_DLKMIMAGE := true
+endif
+ifdef BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE
+  BOARD_USES_VENDOR_DLKMIMAGE := true
+endif
+$(call check_image_config,vendor_dlkm)
+
+BUILDING_VENDOR_DLKM_IMAGE :=
+ifeq ($(PRODUCT_BUILD_VENDOR_DLKM_IMAGE),)
+  ifdef BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE
+    BUILDING_VENDOR_DLKM_IMAGE := true
+  endif
+else ifeq ($(PRODUCT_BUILD_VENDOR_DLKM_IMAGE),true)
+  BUILDING_VENDOR_DLKM_IMAGE := true
+  ifndef BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE
+    $(error PRODUCT_BUILD_VENDOR_DLKM_IMAGE set to true, but BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE not defined)
+  endif
+endif
+ifdef BOARD_PREBUILT_VENDOR_DLKMIMAGE
+  BUILDING_VENDOR_DLKM_IMAGE :=
+endif
+.KATI_READONLY := BUILDING_VENDOR_DLKM_IMAGE
+
+###########################################
 # Now we can substitute with the real value of TARGET_COPY_OUT_ODM
 ifeq ($(TARGET_COPY_OUT_ODM),$(_odm_path_placeholder))
   TARGET_COPY_OUT_ODM := $(TARGET_COPY_OUT_VENDOR)/odm
@@ -545,6 +585,41 @@
 endif
 .KATI_READONLY := BUILDING_ODM_IMAGE
 
+
+###########################################
+# Now we can substitute with the real value of TARGET_COPY_OUT_ODM_DLKM
+ifeq ($(TARGET_COPY_OUT_ODM_DLKM),$(_odm_dlkm_path_placeholder))
+  TARGET_COPY_OUT_ODM_DLKM := $(TARGET_COPY_OUT_VENDOR)/odm_dlkm
+else ifeq ($(filter odm_dlkm system/vendor/odm_dlkm vendor/odm_dlkm,$(TARGET_COPY_OUT_ODM_DLKM)),)
+  $(error TARGET_COPY_OUT_ODM_DLKM must be either 'odm_dlkm', 'system/vendor/odm_dlkm' or 'vendor/odm_dlkm', seeing '$(TARGET_COPY_OUT_ODM_DLKM)'.)
+endif
+PRODUCT_COPY_FILES := $(subst $(_odm_dlkm_path_placeholder),$(TARGET_COPY_OUT_ODM_DLKM),$(PRODUCT_COPY_FILES))
+
+BOARD_USES_ODM_DLKMIMAGE :=
+ifdef BOARD_PREBUILT_ODM_DLKMIMAGE
+  BOARD_USES_ODM_DLKMIMAGE := true
+endif
+ifdef BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE
+  BOARD_USES_ODM_DLKMIMAGE := true
+endif
+$(call check_image_config,odm_dlkm)
+
+BUILDING_ODM_DLKM_IMAGE :=
+ifeq ($(PRODUCT_BUILD_ODM_DLKM_IMAGE),)
+  ifdef BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE
+    BUILDING_ODM_DLKM_IMAGE := true
+  endif
+else ifeq ($(PRODUCT_BUILD_ODM_DLKM_IMAGE),true)
+  BUILDING_ODM_DLKM_IMAGE := true
+  ifndef BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE
+    $(error PRODUCT_BUILD_ODM_DLKM_IMAGE set to true, but BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE not defined)
+  endif
+endif
+ifdef BOARD_PREBUILT_ODM_DLKMIMAGE
+  BUILDING_ODM_DLKM_IMAGE :=
+endif
+.KATI_READONLY := BUILDING_ODM_DLKM_IMAGE
+
 ###########################################
 # Ensure consistency among TARGET_RECOVERY_UPDATER_LIBS, AB_OTA_UPDATER, and PRODUCT_OTA_FORCE_NON_AB_PACKAGE.
 TARGET_RECOVERY_UPDATER_LIBS ?=
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 20319a8..e2acf96 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -273,6 +273,7 @@
 LOCAL_SOONG_HEADER_JAR :=
 LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=
 LOCAL_SOONG_LINK_TYPE :=
+LOCAL_SOONG_LINT_REPORTS :=
 LOCAL_SOONG_PROGUARD_DICT :=
 LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=
 LOCAL_SOONG_DEVICE_RRO_DIRS :=
@@ -340,6 +341,7 @@
 LOCAL_REQUIRED_MODULES_$(TARGET_ARCH):=
 LOCAL_SHARED_LIBRARIES_$(TARGET_ARCH):=
 LOCAL_SOONG_JNI_LIBS_$(TARGET_ARCH):=
+LOCAL_SOONG_JNI_LIBS_SYMBOLS:=
 LOCAL_SRC_FILES_EXCLUDE_$(TARGET_ARCH):=
 LOCAL_SRC_FILES_$(TARGET_ARCH):=
 LOCAL_STATIC_LIBRARIES_$(TARGET_ARCH):=
diff --git a/core/config.mk b/core/config.mk
index 5092e90..b928af0 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -930,6 +930,20 @@
 endif
 endif
 
+ifneq ($(BOARD_VENDOR_DLKMIMAGE_PARTITION_SIZE),)
+ifneq ($(BOARD_VENDOR_DLKMIMAGE_PARTITION_RESERVED_SIZE),)
+$(error Should not define BOARD_VENDOR_DLKMIMAGE_PARTITION_SIZE and \
+    BOARD_VENDOR_DLKMIMAGE_PARTITION_RESERVED_SIZE together)
+endif
+endif
+
+ifneq ($(BOARD_ODM_DLKMIMAGE_PARTITION_SIZE),)
+ifneq ($(BOARD_ODM_DLKMIMAGE_PARTITION_RESERVED_SIZE),)
+$(error Should not define BOARD_ODM_DLKMIMAGE_PARTITION_SIZE and \
+    BOARD_ODM_DLKMIMAGE_PARTITION_RESERVED_SIZE together)
+endif
+endif
+
 ifneq ($(BOARD_PRODUCTIMAGE_PARTITION_SIZE),)
 ifneq ($(BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE),)
 $(error Should not define BOARD_PRODUCTIMAGE_PARTITION_SIZE and \
@@ -965,7 +979,7 @@
 )
 
 # BOARD_*_PARTITION_LIST: a list of the following tokens
-valid_super_partition_list := system vendor product system_ext odm
+valid_super_partition_list := system vendor product system_ext odm vendor_dlkm odm_dlkm
 $(foreach group,$(call to-upper,$(BOARD_SUPER_PARTITION_GROUPS)), \
     $(if $(filter-out $(valid_super_partition_list),$(BOARD_$(group)_PARTITION_LIST)), \
         $(error BOARD_$(group)_PARTITION_LIST contains invalid partition name \
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 3aff007..f78ecb4 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -253,6 +253,8 @@
 _product_path_placeholder := ||PRODUCT-PATH-PH||
 _system_ext_path_placeholder := ||SYSTEM_EXT-PATH-PH||
 _odm_path_placeholder := ||ODM-PATH-PH||
+_vendor_dlkm_path_placeholder := ||VENDOR_DLKM-PATH-PH||
+_odm_dlkm_path_placeholder := ||ODM_DLKM-PATH-PH||
 TARGET_COPY_OUT_VENDOR := $(_vendor_path_placeholder)
 TARGET_COPY_OUT_VENDOR_RAMDISK := vendor-ramdisk
 TARGET_COPY_OUT_PRODUCT := $(_product_path_placeholder)
@@ -261,6 +263,8 @@
 TARGET_COPY_OUT_PRODUCT_SERVICES := $(_product_path_placeholder)
 TARGET_COPY_OUT_SYSTEM_EXT := $(_system_ext_path_placeholder)
 TARGET_COPY_OUT_ODM := $(_odm_path_placeholder)
+TARGET_COPY_OUT_VENDOR_DLKM := $(_vendor_dlkm_path_placeholder)
+TARGET_COPY_OUT_ODM_DLKM := $(_odm_dlkm_path_placeholder)
 
 # Returns the non-sanitized version of the path provided in $1.
 define get_non_asan_path
@@ -719,6 +723,74 @@
   $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_APPS \
   $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_APPS_PRIVILEGED
 
+TARGET_OUT_VENDOR_DLKM := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR_DLKM)
+
+TARGET_OUT_VENDOR_DLKM_ETC := $(TARGET_OUT_VENDOR_DLKM)/etc
+.KATI_READONLY := \
+  TARGET_OUT_VENDOR_DLKM_ETC
+
+# Unlike other partitions, vendor_dlkm should only contain kernel modules.
+TARGET_OUT_VENDOR_DLKM_EXECUTABLES :=
+TARGET_OUT_VENDOR_DLKM_OPTIONAL_EXECUTABLES :=
+TARGET_OUT_VENDOR_DLKM_SHARED_LIBRARIES :=
+TARGET_OUT_VENDOR_DLKM_RENDERSCRIPT_BITCODE :=
+TARGET_OUT_VENDOR_DLKM_JAVA_LIBRARIES :=
+TARGET_OUT_VENDOR_DLKM_APPS :=
+TARGET_OUT_VENDOR_DLKM_APPS_PRIVILEGED :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_EXECUTABLES :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_SHARED_LIBRARIES :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_RENDERSCRIPT_BITCODE :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_APPS :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_APPS_PRIVILEGED :=
+$(KATI_obsolete_var \
+    TARGET_OUT_VENDOR_DLKM_EXECUTABLES \
+    TARGET_OUT_VENDOR_DLKM_OPTIONAL_EXECUTABLES \
+    TARGET_OUT_VENDOR_DLKM_SHARED_LIBRARIES \
+    TARGET_OUT_VENDOR_DLKM_RENDERSCRIPT_BITCODE \
+    TARGET_OUT_VENDOR_DLKM_JAVA_LIBRARIES \
+    TARGET_OUT_VENDOR_DLKM_APPS \
+    TARGET_OUT_VENDOR_DLKM_APPS_PRIVILEGED \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_EXECUTABLES \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_SHARED_LIBRARIES \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_RENDERSCRIPT_BITCODE \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_APPS \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_VENDOR_DLKM_APPS_PRIVILEGED \
+    , vendor_dlkm should not contain any executables, libraries, or apps)
+
+TARGET_OUT_ODM_DLKM := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_ODM_DLKM)
+
+TARGET_OUT_ODM_DLKM_ETC := $(TARGET_OUT_ODM_DLKM)/etc
+.KATI_READONLY := \
+  TARGET_OUT_ODM_DLKM_ETC
+
+# Unlike other partitions, odm_dlkm should only contain kernel modules.
+TARGET_OUT_ODM_DLKM_EXECUTABLES :=
+TARGET_OUT_ODM_DLKM_OPTIONAL_EXECUTABLES :=
+TARGET_OUT_ODM_DLKM_SHARED_LIBRARIES :=
+TARGET_OUT_ODM_DLKM_RENDERSCRIPT_BITCODE :=
+TARGET_OUT_ODM_DLKM_JAVA_LIBRARIES :=
+TARGET_OUT_ODM_DLKM_APPS :=
+TARGET_OUT_ODM_DLKM_APPS_PRIVILEGED :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_EXECUTABLES :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_SHARED_LIBRARIES :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_RENDERSCRIPT_BITCODE :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_APPS :=
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_APPS_PRIVILEGED :=
+$(KATI_obsolete_var \
+    TARGET_OUT_ODM_DLKM_EXECUTABLES \
+    TARGET_OUT_ODM_DLKM_OPTIONAL_EXECUTABLES \
+    TARGET_OUT_ODM_DLKM_SHARED_LIBRARIES \
+    TARGET_OUT_ODM_DLKM_RENDERSCRIPT_BITCODE \
+    TARGET_OUT_ODM_DLKM_JAVA_LIBRARIES \
+    TARGET_OUT_ODM_DLKM_APPS \
+    TARGET_OUT_ODM_DLKM_APPS_PRIVILEGED \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_EXECUTABLES \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_SHARED_LIBRARIES \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_RENDERSCRIPT_BITCODE \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_APPS \
+    $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_DLKM_APPS_PRIVILEGED \
+    , odm_dlkm should not contain any executables, libraries, or apps)
+
 TARGET_OUT_PRODUCT := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_PRODUCT)
 TARGET_OUT_PRODUCT_EXECUTABLES := $(TARGET_OUT_PRODUCT)/bin
 .KATI_READONLY := TARGET_OUT_PRODUCT
diff --git a/core/java_common.mk b/core/java_common.mk
index 658296d..373c5d0 100644
--- a/core/java_common.mk
+++ b/core/java_common.mk
@@ -6,10 +6,6 @@
 my_soong_problems += dotdot_srcs
 endif
 
-ifneq (,$(LOCAL_JNI_SHARED_LIBRARIES))
-my_soong_problems += jni_libs
-endif
-
 ###########################################################
 ## Java version
 ###########################################################
@@ -546,6 +542,10 @@
     $(LOCAL_JAVA_LIBRARIES) \
     $(LOCAL_JNI_SHARED_LIBRARIES)
 SOONG_CONV.$(LOCAL_MODULE).TYPE := java
+SOONG_CONV.$(LOCAL_MODULE).MAKEFILES := \
+    $(SOONG_CONV.$(LOCAL_MODULE).MAKEFILES) $(LOCAL_MODULE_MAKEFILE)
+SOONG_CONV.$(LOCAL_MODULE).INSTALLED := \
+    $(SOONG_CONV.$(LOCAL_MODULE).INSTALLED) $(LOCAL_INSTALLED_MODULE)
 SOONG_CONV := $(SOONG_CONV) $(LOCAL_MODULE)
 
 endif
diff --git a/core/main.mk b/core/main.mk
index 5204132..20b50cd 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1144,7 +1144,9 @@
     $(subst $(_product_path_placeholder),$(TARGET_COPY_OUT_PRODUCT),\
       $(subst $(_system_ext_path_placeholder),$(TARGET_COPY_OUT_SYSTEM_EXT),\
         $(subst $(_odm_path_placeholder),$(TARGET_COPY_OUT_ODM),\
-          $(foreach p,$(1),$(call append-path,$(PRODUCT_OUT),$(p)$(2)))))))
+          $(subst $(_vendor_dlkm_path_placeholder),$(TARGET_COPY_OUT_VENDOR_DLKM),\
+            $(subst $(_odm_dlkm_path_placeholder),$(TARGET_COPY_OUT_ODM_DLKM),\
+              $(foreach p,$(1),$(call append-path,$(PRODUCT_OUT),$(p)$(2)))))))))
 endef
 
 # Returns modules included automatically as a result of certain BoardConfig
@@ -1522,6 +1524,12 @@
 .PHONY: odmimage
 odmimage: $(INSTALLED_ODMIMAGE_TARGET)
 
+.PHONY: vendor_dlkmimage
+vendor_dlkmimage: $(INSTALLED_VENDOR_DLKMIMAGE_TARGET)
+
+.PHONY: odm_dlkmimage
+odm_dlkmimage: $(INSTALLED_ODM_DLKMIMAGE_TARGET)
+
 .PHONY: systemotherimage
 systemotherimage: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET)
 
@@ -1540,6 +1548,12 @@
 .PHONY: vbmetaimage
 vbmetaimage: $(INSTALLED_VBMETAIMAGE_TARGET)
 
+.PHONY: vbmetasystemimage
+vbmetasystemimage: $(INSTALLED_VBMETA_SYSTEMIMAGE_TARGET)
+
+.PHONY: vbmetavendorimage
+vbmetavendorimage: $(INSTALLED_VBMETA_VENDORIMAGE_TARGET)
+
 # Build files and then package it into the rom formats
 .PHONY: droidcore
 droidcore: $(filter $(HOST_OUT_ROOT)/%,$(modules_to_install)) \
@@ -1551,6 +1565,8 @@
     $(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \
     $(INSTALLED_RECOVERYIMAGE_TARGET) \
     $(INSTALLED_VBMETAIMAGE_TARGET) \
+    $(INSTALLED_VBMETA_SYSTEMIMAGE_TARGET) \
+    $(INSTALLED_VBMETA_VENDORIMAGE_TARGET) \
     $(INSTALLED_USERDATAIMAGE_TARGET) \
     $(INSTALLED_CACHEIMAGE_TARGET) \
     $(INSTALLED_BPTIMAGE_TARGET) \
@@ -1559,6 +1575,8 @@
     $(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET) \
     $(INSTALLED_VENDOR_DEBUG_BOOTIMAGE_TARGET) \
     $(INSTALLED_ODMIMAGE_TARGET) \
+    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
     $(INSTALLED_SUPERIMAGE_EMPTY_TARGET) \
     $(INSTALLED_PRODUCTIMAGE_TARGET) \
     $(INSTALLED_SYSTEMOTHERIMAGE_TARGET) \
@@ -1568,6 +1586,10 @@
     $(INSTALLED_FILES_JSON_VENDOR) \
     $(INSTALLED_FILES_FILE_ODM) \
     $(INSTALLED_FILES_JSON_ODM) \
+    $(INSTALLED_FILES_FILE_VENDOR_DLKM) \
+    $(INSTALLED_FILES_JSON_VENDOR_DLKM) \
+    $(INSTALLED_FILES_FILE_ODM_DLKM) \
+    $(INSTALLED_FILES_JSON_ODM_DLKM) \
     $(INSTALLED_FILES_FILE_PRODUCT) \
     $(INSTALLED_FILES_JSON_PRODUCT) \
     $(INSTALLED_FILES_FILE_SYSTEM_EXT) \
@@ -1611,6 +1633,14 @@
     $(if $(ALL_MODULES.$(m).BUNDLE),$(ALL_MODULES.$(m).BUNDLE):$(m)-base.zip))
   $(call dist-for-goals,apps_only, $(apps_only_bundle_files))
 
+  # Dist the lint reports if they exist.
+  apps_only_lint_report_files := $(foreach m,$(unbundled_build_modules),\
+    $(foreach report,$(ALL_MODULES.$(m).LINT_REPORTS),\
+      $(report):$(m)-$(notdir $(report))))
+  .PHONY: lint-check
+  lint-check: $(foreach f, $(apps_only_lint_report_files), $(call word-colon,1,$(f)))
+  $(call dist-for-goals,lint-check, $(apps_only_lint_report_files))
+
   # For uninstallable modules such as static Java library, we have to dist the built file,
   # as <module_name>.<suffix>
   apps_only_dist_built_files := $(foreach m,$(unbundled_build_modules),$(if $(ALL_MODULES.$(m).INSTALLED),,\
@@ -1663,6 +1693,10 @@
     $(INSTALLED_FILES_JSON_VENDOR) \
     $(INSTALLED_FILES_FILE_ODM) \
     $(INSTALLED_FILES_JSON_ODM) \
+    $(INSTALLED_FILES_FILE_VENDOR_DLKM) \
+    $(INSTALLED_FILES_JSON_VENDOR_DLKM) \
+    $(INSTALLED_FILES_FILE_ODM_DLKM) \
+    $(INSTALLED_FILES_JSON_ODM_DLKM) \
     $(INSTALLED_FILES_FILE_PRODUCT) \
     $(INSTALLED_FILES_JSON_PRODUCT) \
     $(INSTALLED_FILES_FILE_SYSTEM_EXT) \
@@ -1813,9 +1847,9 @@
 
 .PHONY: dump-files
 dump-files:
-	$(info product_target_FILES for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)
-	$(foreach p,$(sort $(product_target_FILES)),$(info :   $(p)))
-	@echo Successfully dumped product file list
+	@echo "Target files for $(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT) ($(INTERNAL_PRODUCT)):"
+	@echo $(sort $(patsubst $(PRODUCT_OUT)/%,%,$(filter $(PRODUCT_OUT)/%,$(modules_to_install)))) | tr -s ' ' '\n'
+	@echo Successfully dumped product target file list.
 
 .PHONY: nothing
 nothing:
diff --git a/core/product.mk b/core/product.mk
index f531319..324010c 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -251,6 +251,8 @@
 _product_single_value_vars += PRODUCT_PRODUCT_VERITY_PARTITION
 _product_single_value_vars += PRODUCT_SYSTEM_EXT_VERITY_PARTITION
 _product_single_value_vars += PRODUCT_ODM_VERITY_PARTITION
+_product_single_value_vars += PRODUCT_VENDOR_DLKM_VERITY_PARTITION
+_product_single_value_vars += PRODUCT_ODM_DLKM_VERITY_PARTITION
 _product_single_value_vars += PRODUCT_SYSTEM_SERVER_DEBUG_INFO
 _product_single_value_vars += PRODUCT_OTHER_JAVA_DEBUG_INFO
 
@@ -278,6 +280,8 @@
 _product_single_value_vars += PRODUCT_PRODUCT_BASE_FS_PATH
 _product_single_value_vars += PRODUCT_SYSTEM_EXT_BASE_FS_PATH
 _product_single_value_vars += PRODUCT_ODM_BASE_FS_PATH
+_product_single_value_vars += PRODUCT_VENDOR_DLKM_BASE_FS_PATH
+_product_single_value_vars += PRODUCT_ODM_DLKM_BASE_FS_PATH
 
 # The first API level this product shipped with
 _product_single_value_vars += PRODUCT_SHIPPING_API_LEVEL
@@ -369,6 +373,8 @@
 _product_single_value_vars += PRODUCT_BUILD_PRODUCT_IMAGE
 _product_single_value_vars += PRODUCT_BUILD_SYSTEM_EXT_IMAGE
 _product_single_value_vars += PRODUCT_BUILD_ODM_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_VENDOR_DLKM_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_ODM_DLKM_IMAGE
 _product_single_value_vars += PRODUCT_BUILD_CACHE_IMAGE
 _product_single_value_vars += PRODUCT_BUILD_RAMDISK_IMAGE
 _product_single_value_vars += PRODUCT_BUILD_USERDATA_IMAGE
diff --git a/core/product_config.mk b/core/product_config.mk
index 7a7c4b7..bb806bb 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -399,6 +399,8 @@
     PRODUCT \
     SYSTEM_EXT \
     ODM \
+    VENDOR_DLKM \
+    ODM_DLKM \
     CACHE \
     RAMDISK \
     USERDATA \
diff --git a/core/robolectric_test_config_template.xml b/core/robolectric_test_config_template.xml
new file mode 100644
index 0000000..78863b7
--- /dev/null
+++ b/core/robolectric_test_config_template.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Runs {MODULE}">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-junit" />
+
+    {EXTRA_CONFIGS}
+
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="jar" value="{MODULE}.jar" />
+    </test>
+</configuration>
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index 3549c1d..46b16ac 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -11,6 +11,7 @@
 # LOCAL_SOONG_RRO_DIRS
 # LOCAL_SOONG_JNI_LIBS_$(TARGET_ARCH)
 # LOCAL_SOONG_JNI_LIBS_$(TARGET_2ND_ARCH)
+# LOCAL_SOONG_JNI_LIBS_SYMBOLS
 
 ifneq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
   $(call pretty-error,soong_app_prebuilt.mk may only be used from Soong)
@@ -118,6 +119,11 @@
 $(call create-suite-dependencies)
 endif
 
+# install symbol files of JNI libraries
+my_jni_lib_symbols_copy_files := $(foreach f,$(LOCAL_SOONG_JNI_LIBS_SYMBOLS),\
+  $(call word-colon,1,$(f)):$(patsubst $(PRODUCT_OUT)/%,$(TARGET_OUT_UNSTRIPPED)/%,$(call word-colon,2,$(f))))
+$(LOCAL_BUILT_MODULE): $(call copy-many-files, $(my_jni_lib_symbols_copy_files))
+
 # embedded JNI will already have been handled by soong
 my_embed_jni :=
 my_prebuilt_jni_libs :=
@@ -170,6 +176,10 @@
   ALL_MODULES.$(my_register_name).BUNDLE := $(LOCAL_SOONG_BUNDLE)
 endif
 
+ifdef LOCAL_SOONG_LINT_REPORTS
+  ALL_MODULES.$(my_register_name).LINT_REPORTS := $(LOCAL_SOONG_LINT_REPORTS)
+endif
+
 ifndef LOCAL_IS_HOST_MODULE
 ifeq ($(LOCAL_SDK_VERSION),system_current)
 my_link_type := java:system
diff --git a/core/soong_config.mk b/core/soong_config.mk
index bc0dc6e..b826024 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -155,6 +155,8 @@
 $(call add_json_bool, Use_lmkd_stats_log,                $(filter true,$(TARGET_LMKD_STATS_LOG)))
 $(call add_json_str,  VendorPath,                        $(TARGET_COPY_OUT_VENDOR))
 $(call add_json_str,  OdmPath,                           $(TARGET_COPY_OUT_ODM))
+$(call add_json_str,  VendorDlkmPath,                    $(TARGET_COPY_OUT_VENDOR_DLKM))
+$(call add_json_str,  OdmDlkmPath,                       $(TARGET_COPY_OUT_ODM_DLKM))
 $(call add_json_str,  ProductPath,                       $(TARGET_COPY_OUT_PRODUCT))
 $(call add_json_str,  SystemExtPath,                     $(TARGET_COPY_OUT_SYSTEM_EXT))
 $(call add_json_bool, MinimizeJavaDebugInfo,             $(filter true,$(PRODUCT_MINIMIZE_JAVA_DEBUG_INFO)))
@@ -172,6 +174,8 @@
 
 $(call add_json_list, BoardVendorSepolicyDirs,           $(BOARD_VENDOR_SEPOLICY_DIRS) $(BOARD_SEPOLICY_DIRS))
 $(call add_json_list, BoardOdmSepolicyDirs,              $(BOARD_ODM_SEPOLICY_DIRS))
+$(call add_json_list, BoardVendorDlkmSepolicyDirs,       $(BOARD_VENDOR_DLKM_SEPOLICY_DIRS))
+$(call add_json_list, BoardOdmDlkmSepolicyDirs,          $(BOARD_ODM_DLKM_SEPOLICY_DIRS))
 $(call add_json_list, BoardPlatPublicSepolicyDirs,       $(BOARD_PLAT_PUBLIC_SEPOLICY_DIR))
 $(call add_json_list, BoardPlatPrivateSepolicyDirs,      $(BOARD_PLAT_PRIVATE_SEPOLICY_DIR))
 $(call add_json_list, BoardSepolicyM4Defs,               $(BOARD_SEPOLICY_M4DEFS))
diff --git a/core/sysprop.mk b/core/sysprop.mk
index 002e1b5..d01255f 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -230,7 +230,7 @@
 $(strip $(subst _,-, $(firstword $(1))))
 endef
 
-gen_from_buildinfo_sh := $(call intermediates-dir-for,ETC,system_build_prop)/buildinfo.prop
+gen_from_buildinfo_sh := $(call intermediates-dir-for,PACKAGING,system_build_prop)/buildinfo.prop
 $(gen_from_buildinfo_sh): $(INTERNAL_BUILD_ID_MAKEFILE) $(API_FINGERPRINT)
 	$(hide) TARGET_BUILD_TYPE="$(TARGET_BUILD_VARIANT)" \
 	        TARGET_BUILD_FLAVOR="$(TARGET_BUILD_FLAVOR)" \
@@ -392,6 +392,24 @@
     $(_prop_vars_),\
     $(empty)))
 
+# ----------------------------------------------------------------
+# vendor_dlkm/etc/build.prop
+#
+
+INSTALLED_VENDOR_DLKM_BUILD_PROP_TARGET := $(TARGET_OUT_VENDOR_DLKM)/etc/build.prop
+$(eval $(call build-properties,\
+    vendor_dlkm,\
+    $(INSTALLED_VENDOR_DLKM_BUILD_PROP_TARGET)))
+
+# ----------------------------------------------------------------
+# odm_dlkm/etc/build.prop
+#
+
+INSTALLED_ODM_DLKM_BUILD_PROP_TARGET := $(TARGET_OUT_ODM_DLKM)/etc/build.prop
+$(eval $(call build-properties,\
+    odm_dlkm,\
+    $(INSTALLED_ODM_DLKM_BUILD_PROP_TARGET)))
+
 # -----------------------------------------------------------------
 # system_ext/etc/build.prop
 #
diff --git a/core/tasks/ide.mk b/core/tasks/ide.mk
index e557e60..a3aa0cd 100644
--- a/core/tasks/ide.mk
+++ b/core/tasks/ide.mk
@@ -40,8 +40,7 @@
   endif
 
   source_paths := $(foreach m,$(eclipse_project_modules),$(ALL_MODULES.$(m).PATH)) \
-              $(foreach m,$(eclipse_project_modules),$(ALL_MODULES.$(m).INTERMEDIATE_SOURCE_DIR)) \
-              $(INTERNAL_SDK_SOURCE_DIRS)
+              $(foreach m,$(eclipse_project_modules),$(ALL_MODULES.$(m).INTERMEDIATE_SOURCE_DIR))
   source_paths := $(sort $(source_paths))
 
 .classpath: PRIVATE_MODULES := $(eclipse_project_modules)
diff --git a/core/tasks/vendor_module_check.mk b/core/tasks/vendor_module_check.mk
index b4c5a3b..4d7d67e 100644
--- a/core/tasks/vendor_module_check.mk
+++ b/core/tasks/vendor_module_check.mk
@@ -108,10 +108,10 @@
 
 $(foreach m, $(_vendor_check_modules), \
   $(if $(filter-out ,$(ALL_MODULES.$(m).INSTALLED)),\
-    $(if $(filter $(TARGET_OUT_VENDOR)/% $(TARGET_OUT_ODM)/% $(HOST_OUT)/%, $(ALL_MODULES.$(m).INSTALLED)),,\
+    $(if $(filter $(TARGET_OUT_VENDOR)/% $(TARGET_OUT_ODM)/% $(TARGET_OUT_VENDOR_DLKM)/% $(TARGET_OUT_ODM_DLKM)/% $(HOST_OUT)/%, $(ALL_MODULES.$(m).INSTALLED)),,\
       $(error Error: vendor module "$(m)" in $(ALL_MODULES.$(m).PATH) \
         in product "$(TARGET_PRODUCT)" being installed to \
-        $(ALL_MODULES.$(m).INSTALLED) which is not in the vendor tree or odm tree))))
+        $(ALL_MODULES.$(m).INSTALLED) which is not in the vendor, odm, vendor_dlkm or odm_dlkm tree))))
 
 endif
 
diff --git a/help.sh b/help.sh
index b02b14c..4af5154 100755
--- a/help.sh
+++ b/help.sh
@@ -43,7 +43,11 @@
     senod                   Quickly rebuild the system_ext image from built packages
                             Stands for "SystemExt, NO Dependencies"
     onod                    Quickly rebuild the odm image from built packages
-                            Stands for "ODM, NO Dependencies"
+                            Stands for "Odm, NO Dependencies"
+    vdnod                   Quickly rebuild the vendor_dlkm image from built packages
+                            Stands for "VendorDlkm, NO Dependencies"
+    odnod                   Quickly rebuild the odm_dlkm image from built packages
+                            Stands for "OdmDlkm, NO Dependencies"
 
 
 So, for example, you could run:
diff --git a/target/board/BoardConfigGsiCommon.mk b/target/board/BoardConfigGsiCommon.mk
index 0f36aae..d0aeb1c 100644
--- a/target/board/BoardConfigGsiCommon.mk
+++ b/target/board/BoardConfigGsiCommon.mk
@@ -33,12 +33,25 @@
 #   updating the last seen rollback index in the tamper-evident storage.
 BOARD_AVB_ROLLBACK_INDEX := 0
 
-# Enable chain partition for system.
-# GSI need to sign on system.img instead of vbmeta.
+ifndef BUILDING_GSI
+# Enable AVB chained partition for system.
+# https://android.googlesource.com/platform/external/avb/+/master/README.md
 BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
 BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048
 BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
 BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
+else
+# Enable vbmeta_system on GSI targets
+BOARD_AVB_VBMETA_SYSTEM := system
+BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
+BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048
+BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
+BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
+BOARD_SUPER_PARTITION_SIZE := 3229614080
+BOARD_SUPER_PARTITION_GROUPS := gsi_dynamic_partitions
+BOARD_GSI_DYNAMIC_PARTITIONS_PARTITION_LIST := system
+BOARD_GSI_DYNAMIC_PARTITIONS_SIZE := 3221225472
+endif
 
 # Enable chain partition for boot, mainly for GKI images.
 BOARD_AVB_BOOT_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk
index 8624ed7..87c16da 100644
--- a/target/board/generic/BoardConfig.mk
+++ b/target/board/generic/BoardConfig.mk
@@ -30,6 +30,8 @@
 TARGET_CPU_ABI2 := armeabi
 
 include build/make/target/board/BoardConfigGsiCommon.mk
+
+ifndef BUILDING_GSI
 include build/make/target/board/BoardConfigEmuCommon.mk
 
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
@@ -44,3 +46,4 @@
 WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
 WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
 WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
+endif
diff --git a/target/board/generic_x86/BoardConfig.mk b/target/board/generic_x86/BoardConfig.mk
index 83d7ecc..c40c15b 100644
--- a/target/board/generic_x86/BoardConfig.mk
+++ b/target/board/generic_x86/BoardConfig.mk
@@ -21,6 +21,7 @@
 TARGET_PRELINK_MODULE := false
 
 include build/make/target/board/BoardConfigGsiCommon.mk
+ifndef BUILDING_GSI
 include build/make/target/board/BoardConfigEmuCommon.mk
 
 # Resize to 4G to accomodate ASAN and CTS
@@ -38,3 +39,4 @@
 WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
 WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
 WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
+endif
diff --git a/target/board/generic_x86_64/BoardConfig.mk b/target/board/generic_x86_64/BoardConfig.mk
index 07bbc07..660ec6e 100755
--- a/target/board/generic_x86_64/BoardConfig.mk
+++ b/target/board/generic_x86_64/BoardConfig.mk
@@ -24,6 +24,7 @@
 
 TARGET_PRELINK_MODULE := false
 include build/make/target/board/BoardConfigGsiCommon.mk
+ifndef BUILDING_GSI
 include build/make/target/board/BoardConfigEmuCommon.mk
 
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
@@ -40,3 +41,4 @@
 WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
 WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
 WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
+endif
diff --git a/target/board/gsi_system_ext.prop b/target/board/gsi_system_ext.prop
index dd3227e..780aadc 100644
--- a/target/board/gsi_system_ext.prop
+++ b/target/board/gsi_system_ext.prop
@@ -12,8 +12,3 @@
 
 # TODO(b/78105955): disable privapp_permissions checking before the bug solved
 ro.control_privapp_permissions=disable
-
-# TODO(b/136212765): the default for LMK
-ro.lmk.kill_heaviest_task=true
-ro.lmk.kill_timeout_ms=100
-ro.lmk.use_minfree_levels=true
diff --git a/target/board/gsi_system_ext_user.prop b/target/board/gsi_system_ext_user.prop
index db6d880..217bd01 100644
--- a/target/board/gsi_system_ext_user.prop
+++ b/target/board/gsi_system_ext_user.prop
@@ -9,8 +9,3 @@
 
 # TODO(b/78105955): disable privapp_permissions checking before the bug solved
 ro.control_privapp_permissions=disable
-
-# TODO(b/136212765): the default for LMK
-ro.lmk.kill_heaviest_task=true
-ro.lmk.kill_timeout_ms=100
-ro.lmk.use_minfree_levels=true
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index d66136e..345faa4 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -18,6 +18,8 @@
 LLNDK: libsync.so
 LLNDK: libvndksupport.so
 LLNDK: libvulkan.so
+VNDK-SP: android.hardware.common-V1-ndk_platform.so
+VNDK-SP: android.hardware.graphics.common-V1-ndk_platform.so
 VNDK-SP: android.hardware.graphics.common@1.0.so
 VNDK-SP: android.hardware.graphics.common@1.1.so
 VNDK-SP: android.hardware.graphics.common@1.2.so
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index a61585e..5421ee0 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -24,6 +24,8 @@
 # - etc.
 #
 
+BUILDING_GSI := true
+
 # Exclude all files under system/product and system/system_ext
 PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
     system/product/% \
diff --git a/target/product/mainline_system_arm64.mk b/target/product/mainline_system_arm64.mk
index 60035c1..a0c3e6d 100644
--- a/target/product/mainline_system_arm64.mk
+++ b/target/product/mainline_system_arm64.mk
@@ -26,6 +26,8 @@
 
 PRODUCT_BUILD_CACHE_IMAGE := false
 PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
 PRODUCT_BUILD_PRODUCT_IMAGE  := false
 PRODUCT_BUILD_RAMDISK_IMAGE := false
 PRODUCT_BUILD_SYSTEM_IMAGE := true
diff --git a/target/product/mainline_system_x86.mk b/target/product/mainline_system_x86.mk
index a30a1fc..3c4a867 100644
--- a/target/product/mainline_system_x86.mk
+++ b/target/product/mainline_system_x86.mk
@@ -25,6 +25,8 @@
 
 PRODUCT_BUILD_CACHE_IMAGE := false
 PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
 PRODUCT_BUILD_PRODUCT_IMAGE  := false
 PRODUCT_BUILD_RAMDISK_IMAGE := false
 PRODUCT_BUILD_SYSTEM_IMAGE := true
diff --git a/target/product/mainline_system_x86_64.mk b/target/product/mainline_system_x86_64.mk
index 473ff72..410c998 100644
--- a/target/product/mainline_system_x86_64.mk
+++ b/target/product/mainline_system_x86_64.mk
@@ -26,6 +26,8 @@
 
 PRODUCT_BUILD_CACHE_IMAGE := false
 PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
 PRODUCT_BUILD_PRODUCT_IMAGE  := false
 PRODUCT_BUILD_RAMDISK_IMAGE := false
 PRODUCT_BUILD_SYSTEM_IMAGE := true
diff --git a/target/product/mainline_system_x86_arm.mk b/target/product/mainline_system_x86_arm.mk
index 2e01cde..8c6611e 100644
--- a/target/product/mainline_system_x86_arm.mk
+++ b/target/product/mainline_system_x86_arm.mk
@@ -25,6 +25,8 @@
 
 PRODUCT_BUILD_CACHE_IMAGE := false
 PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
 PRODUCT_BUILD_PRODUCT_IMAGE  := false
 PRODUCT_BUILD_RAMDISK_IMAGE := false
 PRODUCT_BUILD_SYSTEM_IMAGE := true
diff --git a/tools/fs_config/Android.mk b/tools/fs_config/Android.mk
index 64fabe6..41e8ca5 100644
--- a/tools/fs_config/Android.mk
+++ b/tools/fs_config/Android.mk
@@ -27,11 +27,13 @@
 system_android_filesystem_config := system/core/include/private/android_filesystem_config.h
 system_capability_header := bionic/libc/kernel/uapi/linux/capability.h
 
-# List of supported vendor, oem, odm, product and system_ext Partitions
+# List of supported vendor, oem, odm, vendor_dlkm, odm_dlkm, product and system_ext Partitions
 fs_config_generate_extra_partition_list := $(strip \
   $(if $(BOARD_USES_VENDORIMAGE)$(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE),vendor) \
   $(if $(BOARD_USES_OEMIMAGE)$(BOARD_OEMIMAGE_FILE_SYSTEM_TYPE),oem) \
   $(if $(BOARD_USES_ODMIMAGE)$(BOARD_ODMIMAGE_FILE_SYSTEM_TYPE),odm) \
+  $(if $(BOARD_USES_VENDOR_DLKMIMAGE)$(BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE),vendor_dlkm) \
+  $(if $(BOARD_USES_ODM_DLKMIMAGE)$(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE),odm_dlkm) \
   $(if $(BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE),product) \
   $(if $(BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE),system_ext) \
 )
@@ -282,6 +284,108 @@
 
 endif
 
+ifneq ($(filter vendor_dlkm,$(fs_config_generate_extra_partition_list)),)
+##################################
+# Generate the vendor_dlkm/etc/fs_config_dirs binary file for the target
+# Add fs_config_dirs or fs_config_dirs_vendor_dlkm to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_dirs_vendor_dlkm
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_dirs
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_DLKM)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_CAP_HDR := $(system_capability_header)
+$(LOCAL_BUILT_MODULE): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/fs_config_generator.py $(TARGET_FS_CONFIG_GEN) $(system_android_filesystem_config) $(system_capability_header)
+	@mkdir -p $(dir $@)
+	$< fsconfig \
+	   --aid-header $(PRIVATE_ANDROID_FS_HDR) \
+	   --capability-header $(PRIVATE_ANDROID_CAP_HDR) \
+	   --partition vendor_dlkm \
+	   --dirs \
+	   --out_file $@ \
+	   $(or $(PRIVATE_TARGET_FS_CONFIG_GEN),/dev/null)
+
+##################################
+# Generate the vendor_dlkm/etc/fs_config_files binary file for the target
+# Add fs_config_files of fs_config_files_vendor_dlkm to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_files_vendor_dlkm
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_files
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_DLKM)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_CAP_HDR := $(system_capability_header)
+$(LOCAL_BUILT_MODULE): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/fs_config_generator.py $(TARGET_FS_CONFIG_GEN) $(system_android_filesystem_config) $(system_capability_header)
+	@mkdir -p $(dir $@)
+	$< fsconfig \
+	   --aid-header $(PRIVATE_ANDROID_FS_HDR) \
+	   --capability-header $(PRIVATE_ANDROID_CAP_HDR) \
+	   --partition vendor_dlkm \
+	   --files \
+	   --out_file $@ \
+	   $(or $(PRIVATE_TARGET_FS_CONFIG_GEN),/dev/null)
+
+endif
+
+ifneq ($(filter odm_dlkm,$(fs_config_generate_extra_partition_list)),)
+##################################
+# Generate the odm_dlkm/etc/fs_config_dirs binary file for the target
+# Add fs_config_dirs or fs_config_dirs_odm_dlkm to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_dirs_odm_dlkm
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_dirs
+LOCAL_MODULE_PATH := $(TARGET_OUT_ODM_DLKM)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_CAP_HDR := $(system_capability_header)
+$(LOCAL_BUILT_MODULE): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/fs_config_generator.py $(TARGET_FS_CONFIG_GEN) $(system_android_filesystem_config) $(system_capability_header)
+	@mkdir -p $(dir $@)
+	$< fsconfig \
+	   --aid-header $(PRIVATE_ANDROID_FS_HDR) \
+	   --capability-header $(PRIVATE_ANDROID_CAP_HDR) \
+	   --partition odm_dlkm \
+	   --dirs \
+	   --out_file $@ \
+	   $(or $(PRIVATE_TARGET_FS_CONFIG_GEN),/dev/null)
+
+##################################
+# Generate the odm_dlkm/etc/fs_config_files binary file for the target
+# Add fs_config_files of fs_config_files_odm_dlkm to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_files_odm_dlkm
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_files
+LOCAL_MODULE_PATH := $(TARGET_OUT_ODM_DLKM)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_FS_HDR := $(system_android_filesystem_config)
+$(LOCAL_BUILT_MODULE): PRIVATE_ANDROID_CAP_HDR := $(system_capability_header)
+$(LOCAL_BUILT_MODULE): PRIVATE_TARGET_FS_CONFIG_GEN := $(TARGET_FS_CONFIG_GEN)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/fs_config_generator.py $(TARGET_FS_CONFIG_GEN) $(system_android_filesystem_config) $(system_capability_header)
+	@mkdir -p $(dir $@)
+	$< fsconfig \
+	   --aid-header $(PRIVATE_ANDROID_FS_HDR) \
+	   --capability-header $(PRIVATE_ANDROID_CAP_HDR) \
+	   --partition odm_dlkm \
+	   --files \
+	   --out_file $@ \
+	   $(or $(PRIVATE_TARGET_FS_CONFIG_GEN),/dev/null)
+
+endif
+
 ifneq ($(filter product,$(fs_config_generate_extra_partition_list)),)
 ##################################
 # Generate the product/etc/fs_config_dirs binary file for the target
diff --git a/tools/mk2bp_catalog.py b/tools/mk2bp_catalog.py
new file mode 100755
index 0000000..83abd62
--- /dev/null
+++ b/tools/mk2bp_catalog.py
@@ -0,0 +1,892 @@
+#!/usr/bin/env python3
+
+"""
+Command to print info about makefiles remaining to be converted to soong.
+
+See usage / argument parsing below for commandline options.
+"""
+
+import argparse
+import csv
+import itertools
+import json
+import os
+import re
+import sys
+
+DIRECTORY_PATTERNS = [x.split("/") for x in (
+  "device/*",
+  "frameworks/*",
+  "hardware/*",
+  "packages/*",
+  "vendor/*",
+  "*",
+)]
+
+def match_directory_group(pattern, filename):
+  match = []
+  filename = filename.split("/")
+  if len(filename) < len(pattern):
+    return None
+  for i in range(len(pattern)):
+    pattern_segment = pattern[i]
+    filename_segment = filename[i]
+    if pattern_segment == "*" or pattern_segment == filename_segment:
+      match.append(filename_segment)
+    else:
+      return None
+  if match:
+    return os.path.sep.join(match)
+  else:
+    return None
+
+def directory_group(filename):
+  for pattern in DIRECTORY_PATTERNS:
+    match = match_directory_group(pattern, filename)
+    if match:
+      return match
+  return os.path.dirname(filename)
+
+class Analysis(object):
+  def __init__(self, filename, line_matches):
+    self.filename = filename;
+    self.line_matches = line_matches
+
+def analyze_lines(filename, lines, func):
+  line_matches = []
+  for i in range(len(lines)):
+    line = lines[i]
+    stripped = line.strip()
+    if stripped.startswith("#"):
+      continue
+    if func(stripped):
+      line_matches.append((i+1, line))
+  if line_matches:
+    return Analysis(filename, line_matches);
+
+def analyze_has_conditional(line):
+  return (line.startswith("ifeq") or line.startswith("ifneq")
+          or line.startswith("ifdef") or line.startswith("ifndef"))
+
+NORMAL_INCLUDES = [re.compile(pattern) for pattern in (
+  "include \$+\(CLEAR_VARS\)", # These are in defines which are tagged separately
+  "include \$+\(BUILD_.*\)",
+  "include \$\(call first-makefiles-under, *\$\(LOCAL_PATH\)\)",
+  "include \$\(call all-subdir-makefiles\)",
+  "include \$\(all-subdir-makefiles\)",
+  "include \$\(call all-makefiles-under, *\$\(LOCAL_PATH\)\)",
+  "include \$\(call all-makefiles-under, *\$\(call my-dir\).*\)",
+  "include \$\(BUILD_SYSTEM\)/base_rules.mk", # called out separately
+  "include \$\(call all-named-subdir-makefiles,.*\)",
+  "include \$\(subdirs\)",
+)]
+def analyze_has_wacky_include(line):
+  if not (line.startswith("include") or line.startswith("-include")
+          or line.startswith("sinclude")):
+    return False
+  for matcher in NORMAL_INCLUDES:
+    if matcher.fullmatch(line):
+      return False
+  return True
+
+BASE_RULES_RE = re.compile("include \$\(BUILD_SYSTEM\)/base_rules.mk")
+
+class Analyzer(object):
+  def __init__(self, title, func):
+    self.title = title;
+    self.func = func
+
+
+ANALYZERS = (
+  Analyzer("ifeq / ifneq", analyze_has_conditional),
+  Analyzer("Wacky Includes", analyze_has_wacky_include),
+  Analyzer("Calls base_rules", lambda line: BASE_RULES_RE.fullmatch(line)),
+  Analyzer("Calls define", lambda line: line.startswith("define ")),
+  Analyzer("Has ../", lambda line: "../" in line),
+  Analyzer("dist-for-&#8203;goals", lambda line: "dist-for-goals" in line),
+  Analyzer(".PHONY", lambda line: ".PHONY" in line),
+  Analyzer("render-&#8203;script", lambda line: ".rscript" in line),
+  Analyzer("vts src", lambda line: ".vts" in line),
+  Analyzer("COPY_&#8203;HEADERS", lambda line: "LOCAL_COPY_HEADERS" in line),
+)
+
+class Summary(object):
+  def __init__(self):
+    self.makefiles = dict()
+    self.directories = dict()
+
+  def Add(self, makefile):
+    self.makefiles[makefile.filename] = makefile
+    self.directories.setdefault(directory_group(makefile.filename), []).append(makefile)
+
+class Makefile(object):
+  def __init__(self, filename):
+    self.filename = filename
+
+    # Analyze the file
+    with open(filename, "r", errors="ignore") as f:
+      try:
+        lines = f.readlines()
+      except UnicodeDecodeError as ex:
+        sys.stderr.write("Filename: %s\n" % filename)
+        raise ex
+    lines = [line.strip() for line in lines]
+
+    self.analyses = dict([(analyzer, analyze_lines(filename, lines, analyzer.func)) for analyzer
+        in ANALYZERS])
+
+def find_android_mk():
+  cwd = os.getcwd()
+  for root, dirs, files in os.walk(cwd):
+    for filename in files:
+      if filename == "Android.mk":
+        yield os.path.join(root, filename)[len(cwd) + 1:]
+    for ignore in (".git", ".repo"):
+      if ignore in dirs:
+        dirs.remove(ignore)
+
+def is_aosp(dirname):
+  for d in ("device/sample", "hardware/interfaces", "hardware/libhardware",
+          "hardware/ril"):
+    if dirname.startswith(d):
+      return True
+  for d in ("device/", "hardware/", "vendor/"):
+    if dirname.startswith(d):
+      return False
+  return True
+
+def is_google(dirname):
+  for d in ("device/google",
+            "hardware/google",
+            "test/sts",
+            "vendor/auto",
+            "vendor/google",
+            "vendor/unbundled_google",
+            "vendor/widevine",
+            "vendor/xts"):
+    if dirname.startswith(d):
+      return True
+  return False
+
+def make_annotation_link(annotations, analysis, modules):
+  if analysis:
+    return "<a href='javascript:update_details(%d)'>%s</a>" % (
+      annotations.Add(analysis, modules),
+      len(analysis)
+    )
+  else:
+    return "";
+
+
+def is_clean(makefile):
+  for analysis in makefile.analyses.values():
+    if analysis:
+      return False
+  return True
+
+class Annotations(object):
+  def __init__(self):
+    self.entries = []
+    self.count = 0
+
+  def Add(self, makefiles, modules):
+    self.entries.append((makefiles, modules))
+    self.count += 1
+    return self.count-1
+
+class SoongData(object):
+  def __init__(self, reader):
+    """Read the input file and store the modules and dependency mappings.
+    """
+    self.problems = dict()
+    self.deps = dict()
+    self.reverse_deps = dict()
+    self.module_types = dict()
+    self.makefiles = dict()
+    self.reverse_makefiles = dict()
+    self.installed = dict()
+    self.modules = set()
+
+    for (module, module_type, problem, dependencies, makefiles, installed) in reader:
+      self.modules.add(module)
+      makefiles = [f for f in makefiles.strip().split(' ') if f != ""]
+      self.module_types[module] = module_type
+      self.problems[module] = problem
+      self.deps[module] = [d for d in dependencies.strip().split(' ') if d != ""]
+      for dep in self.deps[module]:
+        if not dep in self.reverse_deps:
+          self.reverse_deps[dep] = []
+        self.reverse_deps[dep].append(module)
+      self.makefiles[module] = makefiles
+      for f in makefiles:
+        self.reverse_makefiles.setdefault(f, []).append(module)
+      for f in installed.strip().split(' '):
+        self.installed[f] = module
+
+def count_deps(depsdb, module, seen):
+  """Based on the depsdb, count the number of transitive dependencies.
+
+  You can pass in an reversed dependency graph to count the number of
+  modules that depend on the module."""
+  count = 0
+  seen.append(module)
+  if module in depsdb:
+    for dep in depsdb[module]:
+      if dep in seen:
+        continue
+      count += 1 + count_deps(depsdb, dep, seen)
+  return count
+
+def contains_unblocked_modules(soong, modules):
+  for m in modules:
+    if len(soong.deps[m]) == 0:
+      return True
+  return False
+
+def contains_blocked_modules(soong, modules):
+  for m in modules:
+    if len(soong.deps[m]) > 0:
+      return True
+  return False
+
+OTHER_PARTITON = "_other"
+HOST_PARTITON = "_host"
+
+def get_partition_from_installed(HOST_OUT_ROOT, PRODUCT_OUT, filename):
+  host_prefix = HOST_OUT_ROOT + "/"
+  device_prefix = PRODUCT_OUT + "/"
+
+  if filename.startswith(host_prefix):
+    return HOST_PARTITON
+
+  elif filename.startswith(device_prefix):
+    index = filename.find("/", len(device_prefix))
+    if index < 0:
+      return OTHER_PARTITON
+    return filename[len(device_prefix):index]
+
+  return OTHER_PARTITON
+
+def format_module_link(module):
+  return "<a class='ModuleLink' href='#module_%s'>%s</a>" % (module, module)
+
+def format_module_list(modules):
+  return "".join(["<div>%s</div>" % format_module_link(m) for m in modules])
+
+def main():
+  parser = argparse.ArgumentParser(description="Info about remaining Android.mk files.")
+  parser.add_argument("--device", type=str, required=True,
+                      help="TARGET_DEVICE")
+  parser.add_argument("--title", type=str,
+                      help="page title")
+  parser.add_argument("--codesearch", type=str,
+                      default="https://cs.android.com/android/platform/superproject/+/master:",
+                      help="page title")
+  parser.add_argument("--out_dir", type=str,
+                      default=None,
+                      help="Equivalent of $OUT_DIR, which will also be checked if"
+                        + " --out_dir is unset. If neither is set, default is"
+                        + " 'out'.")
+
+  args = parser.parse_args()
+
+  # Guess out directory name
+  if not args.out_dir:
+    args.out_dir = os.getenv("OUT_DIR", "out")
+  while args.out_dir.endswith("/") and len(args.out_dir) > 1:
+    args.out_dir = args.out_dir[:-1]
+
+  TARGET_DEVICE = args.device
+  HOST_OUT_ROOT = args.out_dir + "host"
+  PRODUCT_OUT = args.out_dir + "/target/product/%s" % TARGET_DEVICE
+
+  if args.title:
+    page_title = args.title
+  else:
+    page_title = "Remaining Android.mk files"
+
+  # Read target information
+  # TODO: Pull from configurable location. This is also slightly different because it's
+  # only a single build, where as the tree scanning we do below is all Android.mk files.
+  with open("%s/obj/PACKAGING/soong_conversion_intermediates/soong_conv_data"
+      % PRODUCT_OUT, "r", errors="ignore") as csvfile:
+    soong = SoongData(csv.reader(csvfile))
+
+  # Which modules are installed where
+  modules_by_partition = dict()
+  partitions = set()
+  for installed, module in soong.installed.items():
+    partition = get_partition_from_installed(HOST_OUT_ROOT, PRODUCT_OUT, installed)
+    modules_by_partition.setdefault(partition, []).append(module)
+    partitions.add(partition)
+
+  print("""
+  <html>
+    <head>
+      <title>%(page_title)s</title>
+      <style type="text/css">
+        body, table {
+          font-family: Roboto, sans-serif;
+          font-size: 9pt;
+        }
+        body {
+          margin: 0;
+          padding: 0;
+          display: flex;
+          flex-direction: column;
+          height: 100vh;
+        }
+        #container {
+          flex: 1;
+          display: flex;
+          flex-direction: row;
+          overflow: hidden;
+        }
+        #tables {
+          padding: 0 20px 0 20px;
+          overflow: scroll;
+          flex: 2 2 600px;
+        }
+        #details {
+          display: none;
+          overflow: scroll;
+          flex: 1 1 650px;
+          padding: 0 20px 0 20px;
+        }
+        h1 {
+          margin: 16px 0 16px 20px;
+        }
+        h2 {
+          margin: 12px 0 4px 0;
+        }
+        .DirName {
+          text-align: left;
+          width: 200px;
+          min-width: 200px;
+        }
+        .Count {
+          text-align: center;
+          width: 60px;
+          min-width: 60px;
+          max-width: 60px;
+        }
+        th.Clean,
+        th.Unblocked {
+          background-color: #1e8e3e;
+        }
+        th.Blocked {
+          background-color: #d93025;
+        }
+        th.Warning {
+          background-color: #e8710a;
+        }
+        th {
+          background-color: #1a73e8;
+          color: white;
+          font-weight: bold;
+        }
+        td.Unblocked {
+          background-color: #81c995;
+        }
+        td.Blocked {
+          background-color: #f28b82;
+        }
+        td, th {
+          padding: 2px 4px;
+          border-right: 2px solid white;
+        }
+        tr.AospDir td {
+          background-color: #e6f4ea;
+          border-right-color: #e6f4ea;
+        }
+        tr.GoogleDir td {
+          background-color: #e8f0fe;
+          border-right-color: #e8f0fe;
+        }
+        tr.PartnerDir td {
+          background-color: #fce8e6;
+          border-right-color: #fce8e6;
+        }
+        table {
+          border-spacing: 0;
+          border-collapse: collapse;
+        }
+        div.Makefile {
+          margin: 12px 0 0 0;
+        }
+        div.Makefile:first {
+          margin-top: 0;
+        }
+        div.FileModules {
+          padding: 4px 0 0 20px;
+        }
+        td.LineNo {
+          vertical-align: baseline;
+          padding: 6px 0 0 20px;
+          width: 50px;
+          vertical-align: baseline;
+        }
+        td.LineText {
+          vertical-align: baseline;
+          font-family: monospace;
+          padding: 6px 0 0 0;
+        }
+        a.CsLink {
+          font-family: monospace;
+        }
+        div.Help {
+          width: 550px;
+        }
+        table.HelpColumns tr {
+          border-bottom: 2px solid white;
+        }
+        .ModuleName {
+          vertical-align: baseline;
+          padding: 6px 0 0 20px;
+          width: 275px;
+        }
+        .ModuleDeps {
+          vertical-align: baseline;
+          padding: 6px 0 0 0;
+        }
+        table#Modules td {
+          vertical-align: baseline;
+        }
+        tr.Alt {
+          background-color: #ececec;
+        }
+        tr.Alt td {
+          border-right-color: #ececec;
+        }
+        .AnalysisCol {
+          width: 300px;
+          padding: 2px;
+          line-height: 21px;
+        }
+        .Analysis {
+          color: white;
+          font-weight: bold;
+          background-color: #e8710a;
+          border-radius: 6px;
+          margin: 4px;
+          padding: 2px 6px;
+          white-space: nowrap;
+        }
+        .Nav {
+          margin: 4px 0 16px 20px;
+        }
+        .NavSpacer {
+          display: inline-block;
+          width: 6px;
+        }
+        .ModuleDetails {
+          margin-top: 20px;
+        }
+        .ModuleDetails td {
+          vertical-align: baseline;
+        }
+      </style>
+    </head>
+    <body>
+      <h1>%(page_title)s</h1>
+      <div class="Nav">
+        <a href='#help'>Help</a>
+        <span class='NavSpacer'></span><span class='NavSpacer'> </span>
+        Partitions:
+  """ % {
+    "page_title": page_title,
+  })
+  for partition in sorted(partitions):
+    print("<a href='#partition_%s'>%s</a><span class='NavSpacer'></span>" % (partition, partition))
+
+  print("""
+        <span class='NavSpacer'></span><span class='NavSpacer'> </span>
+      </div>
+      <div id="container">
+        <div id="tables">
+        <a name="help"></a>
+        <div class="Help">
+          <p>
+          This page analyzes the remaining Android.mk files in the Android Source tree.
+          <p>
+          The modules are first broken down by which of the device filesystem partitions
+          they are installed to. This also includes host tools and testcases which don't
+          actually reside in their own partition but convenitely group together.
+          <p>
+          The makefiles for each partition are further are grouped into a set of directories
+          aritrarily picked to break down the problem size by owners.
+          <ul style="width: 300px">
+            <li style="background-color: #e6f4ea">AOSP directories are colored green.</li>
+            <li style="background-color: #e8f0fe">Google directories are colored blue.</li>
+            <li style="background-color: #fce8e6">Other partner directories are colored red.</li>
+          </ul>
+          Each of the makefiles are scanned for issues that are likely to come up during
+          conversion to soong.  Clicking the number in each cell shows additional information,
+          including the line that triggered the warning.
+          <p>
+          <table class="HelpColumns">
+            <tr>
+              <th>Total</th>
+              <td>The total number of makefiles in this each directory.</td>
+            </tr>
+            <tr>
+              <th class="Unblocked">Unblocked</th>
+              <td>Makefiles containing one or more modules that don't have any
+                  additional dependencies pending before conversion.</td>
+            </tr>
+            <tr>
+              <th class="Blocked">Blocked</th>
+              <td>Makefiles containiong one or more modules which <i>do</i> have
+                  additional prerequesite depenedencies that are not yet converted.</td>
+            </tr>
+            <tr>
+              <th class="Clean">Clean</th>
+              <td>The number of makefiles that have none of the following warnings.</td>
+            </tr>
+            <tr>
+              <th class="Warning">ifeq / ifneq</th>
+              <td>Makefiles that use <code>ifeq</code> or <code>ifneq</code>. i.e.
+              conditionals.</td>
+            </tr>
+            <tr>
+              <th class="Warning">Wacky Includes</th>
+              <td>Makefiles that <code>include</code> files other than the standard build-system
+                  defined template and macros.</td>
+            </tr>
+            <tr>
+              <th class="Warning">Calls base_rules</th>
+              <td>Makefiles that include base_rules.mk directly.</td>
+            </tr>
+            <tr>
+              <th class="Warning">Calls define</th>
+              <td>Makefiles that define their own macros. Some of these are easy to convert
+                  to soong <code>defaults</code>, but others are complex.</td>
+            </tr>
+            <tr>
+              <th class="Warning">Has ../</th>
+              <td>Makefiles containing the string "../" outside of a comment. These likely
+                  access files outside their directories.</td>
+            </tr>
+            <tr>
+              <th class="Warning">dist-for-goals</th>
+              <td>Makefiles that call <code>dist-for-goals</code> directly.</td>
+            </tr>
+            <tr>
+              <th class="Warning">.PHONY</th>
+              <td>Makefiles that declare .PHONY targets.</td>
+            </tr>
+            <tr>
+              <th class="Warning">renderscript</th>
+              <td>Makefiles defining targets that depend on <code>.rscript</code> source files.</td>
+            </tr>
+            <tr>
+              <th class="Warning">vts src</th>
+              <td>Makefiles defining targets that depend on <code>.vts</code> source files.</td>
+            </tr>
+            <tr>
+              <th class="Warning">COPY_HEADERS</th>
+              <td>Makefiles using LOCAL_COPY_HEADERS.</td>
+            </tr>
+          </table>
+          <p>
+          Following the list of directories is a list of the modules that are installed on
+          each partition. Potential issues from their makefiles are listed, as well as the
+          total number of dependencies (both blocking that module and blocked by that module)
+          and the list of direct dependencies.  Note: The number is the number of all transitive
+          dependencies and the list of modules is only the direct dependencies.
+        </div>
+  """)
+
+  annotations = Annotations()
+
+  # For each partition
+  makefiles_for_partitions = dict()
+  for partition in sorted(partitions):
+    modules = modules_by_partition[partition]
+
+    makefiles = set(itertools.chain.from_iterable(
+        [soong.makefiles[module] for module in modules]))
+
+    # Read makefiles
+    summary = Summary()
+    for filename in makefiles:
+      if not filename.startswith(args.out_dir + "/"):
+        summary.Add(Makefile(filename))
+
+    # Categorize directories by who is responsible
+    aosp_dirs = []
+    google_dirs = []
+    partner_dirs = []
+    for dirname in sorted(summary.directories.keys()):
+      if is_aosp(dirname):
+        aosp_dirs.append(dirname)
+      elif is_google(dirname):
+        google_dirs.append(dirname)
+      else:
+        partner_dirs.append(dirname)
+
+    print("""
+      <a name="partition_%(partition)s"></a>
+      <h2>%(partition)s</h2>
+      <table>
+        <tr>
+          <th class="DirName">Directory</th>
+          <th class="Count">Total</th>
+          <th class="Count Unblocked">Unblocked</th>
+          <th class="Count Blocked">Blocked</th>
+          <th class="Count Clean">Clean</th>
+    """ % {
+      "partition": partition
+    })
+
+    for analyzer in ANALYZERS:
+      print("""<th class="Count Warning">%s</th>""" % analyzer.title)
+
+    print("      </tr>")
+    for dirgroup, rowclass in [(aosp_dirs, "AospDir"),
+                               (google_dirs, "GoogleDir"),
+                               (partner_dirs, "PartnerDir"),]:
+      for dirname in dirgroup:
+        makefiles = summary.directories[dirname]
+
+        all_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles]
+        clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+            if is_clean(makefile)]
+        unblocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+            if contains_unblocked_modules(soong,
+              soong.reverse_makefiles[makefile.filename])]
+        blocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+            if contains_blocked_modules(soong,
+              soong.reverse_makefiles[makefile.filename])]
+
+        print("""
+          <tr class="%(rowclass)s">
+            <td class="DirName">%(dirname)s</td>
+            <td class="Count">%(makefiles)s</td>
+            <td class="Count">%(unblocked)s</td>
+            <td class="Count">%(blocked)s</td>
+            <td class="Count">%(clean)s</td>
+        """ % {
+          "rowclass": rowclass,
+          "dirname": dirname,
+          "makefiles": make_annotation_link(annotations, all_makefiles, modules),
+          "unblocked": make_annotation_link(annotations, unblocked_makefiles, modules),
+          "blocked": make_annotation_link(annotations, blocked_makefiles, modules),
+          "clean": make_annotation_link(annotations, clean_makefiles, modules),
+        })
+        for analyzer in ANALYZERS:
+          analyses = [m.analyses.get(analyzer) for m in makefiles if m.analyses.get(analyzer)]
+          print("""<td class="Count">%s</td>"""
+              % make_annotation_link(annotations, analyses, modules))
+
+        print("      </tr>")
+    print("""
+      </table>
+    """)
+
+    module_details = [(count_deps(soong.deps, m, []), -count_deps(soong.reverse_deps, m, []), m)
+               for m in modules]
+    module_details.sort()
+    module_details = [m[2] for m in module_details]
+    print("""
+      <table class="ModuleDetails">""")
+    print("<tr>")
+    print("  <th>Module Name</th>")
+    print("  <th>Issues</th>")
+    print("  <th colspan='2'>Blocked By</th>")
+    print("  <th colspan='2'>Blocking</th>")
+    print("</tr>")
+    altRow = True
+    for module in module_details:
+      analyses = set()
+      for filename in soong.makefiles[module]:
+        makefile = summary.makefiles.get(filename)
+        if makefile:
+          for analyzer, analysis in makefile.analyses.items():
+            if analysis:
+              analyses.add(analyzer.title)
+
+      altRow = not altRow
+      print("<tr class='%s'>" % ("Alt" if altRow else "",))
+      print("  <td><a name='module_%s'></a>%s</td>" % (module, module))
+      print("  <td class='AnalysisCol'>%s</td>" % " ".join(["<span class='Analysis'>%s</span>" % title
+          for title in analyses]))
+      print("  <td>%s</td>" % count_deps(soong.deps, module, []))
+      print("  <td>%s</td>" % format_module_list(soong.deps.get(module, [])))
+      print("  <td>%s</td>" % count_deps(soong.reverse_deps, module, []))
+      print("  <td>%s</td>" % format_module_list(soong.reverse_deps.get(module, [])))
+      print("</tr>")
+    print("""</table>""")
+
+  print("""
+    <script type="text/javascript">
+    function close_details() {
+      document.getElementById('details').style.display = 'none';
+    }
+
+    class LineMatch {
+      constructor(lineno, text) {
+        this.lineno = lineno;
+        this.text = text;
+      }
+    }
+
+    class Analysis {
+      constructor(filename, modules, line_matches) {
+        this.filename = filename;
+        this.modules = modules;
+        this.line_matches = line_matches;
+      }
+    }
+
+    class Module {
+      constructor(deps) {
+        this.deps = deps;
+      }
+    }
+
+    function make_module_link(module) {
+      var a = document.createElement('a');
+      a.className = 'ModuleLink';
+      a.innerText = module;
+      a.href = '#module_' + module;
+      return a;
+    }
+
+    function update_details(id) {
+      document.getElementById('details').style.display = 'block';
+
+      var analyses = ANALYSIS[id];
+
+      var details = document.getElementById("details_data");
+      while (details.firstChild) {
+          details.removeChild(details.firstChild);
+      }
+
+      for (var i=0; i<analyses.length; i++) {
+        var analysis = analyses[i];
+
+        var makefileDiv = document.createElement('div');
+        makefileDiv.className = 'Makefile';
+        details.appendChild(makefileDiv);
+
+        var fileA = document.createElement('a');
+        makefileDiv.appendChild(fileA);
+        fileA.className = 'CsLink';
+        fileA.href = '%(codesearch)s' + analysis.filename;
+        fileA.innerText = analysis.filename;
+        fileA.target = "_blank";
+
+        if (analysis.modules.length > 0) {
+          var moduleTable = document.createElement('table');
+          details.appendChild(moduleTable);
+
+          for (var j=0; j<analysis.modules.length; j++) {
+            var moduleRow = document.createElement('tr');
+            moduleTable.appendChild(moduleRow);
+
+            var moduleNameCell = document.createElement('td');
+            moduleRow.appendChild(moduleNameCell);
+            moduleNameCell.className = 'ModuleName';
+            moduleNameCell.appendChild(make_module_link(analysis.modules[j]));
+
+            var moduleData = MODULE_DATA[analysis.modules[j]];
+            console.log(moduleData);
+
+            var depCell = document.createElement('td');
+            moduleRow.appendChild(depCell);
+
+            if (moduleData.deps.length == 0) {
+              depCell.className = 'ModuleDeps Unblocked';
+              depCell.innerText = 'UNBLOCKED';
+            } else {
+              depCell.className = 'ModuleDeps Blocked';
+
+              for (var k=0; k<moduleData.deps.length; k++) {
+                depCell.appendChild(make_module_link(moduleData.deps[k]));
+                depCell.appendChild(document.createElement('br'));
+              }
+            }
+          }
+        }
+
+        if (analysis.line_matches.length > 0) {
+          var lineTable = document.createElement('table');
+          details.appendChild(lineTable);
+
+          for (var j=0; j<analysis.line_matches.length; j++) {
+            var line_match = analysis.line_matches[j];
+
+            var lineRow = document.createElement('tr');
+            lineTable.appendChild(lineRow);
+
+            var linenoCell = document.createElement('td');
+            lineRow.appendChild(linenoCell);
+            linenoCell.className = 'LineNo';
+
+            var linenoA = document.createElement('a');
+            linenoCell.appendChild(linenoA);
+            linenoA.className = 'CsLink';
+            linenoA.href = '%(codesearch)s' + analysis.filename
+                + ';l=' + line_match.lineno;
+            linenoA.innerText = line_match.lineno;
+            linenoA.target = "_blank";
+
+            var textCell = document.createElement('td');
+            lineRow.appendChild(textCell);
+            textCell.className = 'LineText';
+            textCell.innerText = line_match.text;
+          }
+        }
+      }
+    }
+
+    var ANALYSIS = [
+    """ % {
+        "codesearch": args.codesearch,
+    })
+  for entry, mods in annotations.entries:
+    print("  [")
+    for analysis in entry:
+      print("    new Analysis('%(filename)s', %(modules)s, [%(line_matches)s])," % {
+        "filename": analysis.filename,
+        #"modules": json.dumps([m for m in mods if m in filename in soong.makefiles[m]]),
+        "modules": json.dumps(
+            [m for m in soong.reverse_makefiles[analysis.filename] if m in mods]),
+        "line_matches": ", ".join([
+            "new LineMatch(%d, %s)" % (lineno, json.dumps(text))
+            for lineno, text in analysis.line_matches]),
+      })
+    print("  ],")
+  print("""
+    ];
+    var MODULE_DATA = {
+  """)
+  for module in soong.modules:
+    print("      '%(name)s': new Module(%(deps)s)," % {
+      "name": module,
+      "deps": json.dumps(soong.deps[module]),
+    })
+  print("""
+    };
+    </script>
+
+  """)
+
+  print("""
+      </div> <!-- id=tables -->
+      <div id="details">
+        <div style="text-align: right;">
+          <a href="javascript:close_details();">
+            <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
+          </a>
+        </div>
+        <div id="details_data"></div>
+      </div>
+    </body>
+  </html>
+  """)
+
+if __name__ == "__main__":
+  main()
+
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 723fe94..a1f8e31 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -281,6 +281,37 @@
   return img.name
 
 
+def AddVendorDlkm(output_zip):
+  """Turn the contents of VENDOR_DLKM into an vendor_dlkm image and store it in output_zip."""
+
+  img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor_dlkm.img")
+  if os.path.exists(img.name):
+    logger.info("vendor_dlkm.img already exists; no need to rebuild...")
+    return img.name
+
+  block_list = OutputFile(
+      output_zip, OPTIONS.input_tmp, "IMAGES", "vendor_dlkm.map")
+  CreateImage(
+      OPTIONS.input_tmp, OPTIONS.info_dict, "vendor_dlkm", img,
+      block_list=block_list)
+  return img.name
+
+def AddOdmDlkm(output_zip):
+  """Turn the contents of OdmDlkm into an odm_dlkm image and store it in output_zip."""
+
+  img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "odm_dlkm.img")
+  if os.path.exists(img.name):
+    logger.info("odm_dlkm.img already exists; no need to rebuild...")
+    return img.name
+
+  block_list = OutputFile(
+      output_zip, OPTIONS.input_tmp, "IMAGES", "odm_dlkm.map")
+  CreateImage(
+      OPTIONS.input_tmp, OPTIONS.info_dict, "odm_dlkm", img,
+      block_list=block_list)
+  return img.name
+
+
 def AddDtbo(output_zip):
   """Adds the DTBO image.
 
@@ -736,8 +767,9 @@
   has_boot = OPTIONS.info_dict.get("no_boot") != "true"
   has_vendor_boot = OPTIONS.info_dict.get("vendor_boot") == "true"
 
-  # {vendor,odm,product,system_ext}.img are unlike system.img or
-  # system_other.img. Because it could be built from source, or dropped into
+  # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm}.img
+  # are unlike system.img or
+  # system_other.img, because it could be built from source, or  dropped into
   # target_files.zip as a prebuilt blob. We consider either of them as
   # {vendor,product,system_ext}.img being available, which could be
   # used when generating vbmeta.img for AVB.
@@ -749,6 +781,19 @@
               OPTIONS.info_dict.get("building_odm_image") == "true") or
              os.path.exists(
                  os.path.join(OPTIONS.input_tmp, "IMAGES", "odm.img")))
+  has_vendor_dlkm = ((os.path.isdir(os.path.join(OPTIONS.input_tmp,
+                                                 "VENDOR_DLKM")) and
+                      OPTIONS.info_dict.get("building_vendor_dlkm_image")
+                      == "true") or
+                     os.path.exists(
+                         os.path.join(OPTIONS.input_tmp, "IMAGES",
+                                      "vendor_dlkm.img")))
+  has_odm_dlkm = ((os.path.isdir(os.path.join(OPTIONS.input_tmp,
+                                              "ODM_DLKM")) and
+                   OPTIONS.info_dict.get("building_odm_dlkm_image")
+                   == "true") or
+                  os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
+                                              "odm_dlkm.img")))
   has_product = ((os.path.isdir(os.path.join(OPTIONS.input_tmp, "PRODUCT")) and
                   OPTIONS.info_dict.get("building_product_image") == "true") or
                  os.path.exists(
@@ -874,6 +919,14 @@
     banner("odm")
     partitions['odm'] = AddOdm(output_zip)
 
+  if has_vendor_dlkm:
+    banner("vendor_dlkm")
+    partitions['vendor_dlkm'] = AddVendorDlkm(output_zip)
+
+  if has_odm_dlkm:
+    banner("odm_dlkm")
+    partitions['odm_dlkm'] = AddOdmDlkm(output_zip)
+
   if has_system_other:
     banner("system_other")
     AddSystemOther(output_zip)
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 7567346..9cc072f 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -708,6 +708,52 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("odm_reserved_size", "partition_reserved_size")
     copy_prop("odm_selinux_fc", "selinux_fc")
+  elif mount_point == "vendor_dlkm":
+    copy_prop("avb_vendor_dlkm_hashtree_enable", "avb_hashtree_enable")
+    copy_prop("avb_vendor_dlkm_add_hashtree_footer_args",
+              "avb_add_hashtree_footer_args")
+    copy_prop("avb_vendor_dlkm_key_path", "avb_key_path")
+    copy_prop("avb_vendor_dlkm_algorithm", "avb_algorithm")
+    copy_prop("avb_vendor_dlkm_salt", "avb_salt")
+    copy_prop("vendor_dlkm_fs_type", "fs_type")
+    copy_prop("vendor_dlkm_size", "partition_size")
+    if not copy_prop("vendor_dlkm_journal_size", "journal_size"):
+      d["journal_size"] = "0"
+    copy_prop("vendor_dlkm_verity_block_device", "verity_block_device")
+    copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
+    copy_prop("vendor_dlkm_squashfs_compressor", "squashfs_compressor")
+    copy_prop("vendor_dlkm_squashfs_compressor_opt", "squashfs_compressor_opt")
+    copy_prop("vendor_dlkm_squashfs_block_size", "squashfs_block_size")
+    copy_prop("vendor_dlkm_squashfs_disable_4k_align", "squashfs_disable_4k_align")
+    copy_prop("vendor_dlkm_base_fs_file", "base_fs_file")
+    copy_prop("vendor_dlkm_extfs_inode_count", "extfs_inode_count")
+    if not copy_prop("vendor_dlkm_extfs_rsv_pct", "extfs_rsv_pct"):
+      d["extfs_rsv_pct"] = "0"
+    copy_prop("vendor_dlkm_reserved_size", "partition_reserved_size")
+    copy_prop("vendor_dlkm_selinux_fc", "selinux_fc")
+  elif mount_point == "odm_dlkm":
+    copy_prop("avb_odm_dlkm_hashtree_enable", "avb_hashtree_enable")
+    copy_prop("avb_odm_dlkm_add_hashtree_footer_args",
+              "avb_add_hashtree_footer_args")
+    copy_prop("avb_odm_dlkm_key_path", "avb_key_path")
+    copy_prop("avb_odm_dlkm_algorithm", "avb_algorithm")
+    copy_prop("avb_odm_dlkm_salt", "avb_salt")
+    copy_prop("odm_dlkm_fs_type", "fs_type")
+    copy_prop("odm_dlkm_size", "partition_size")
+    if not copy_prop("odm_dlkm_journal_size", "journal_size"):
+      d["journal_size"] = "0"
+    copy_prop("odm_dlkm_verity_block_device", "verity_block_device")
+    copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
+    copy_prop("odm_dlkm_squashfs_compressor", "squashfs_compressor")
+    copy_prop("odm_dlkm_squashfs_compressor_opt", "squashfs_compressor_opt")
+    copy_prop("odm_dlkm_squashfs_block_size", "squashfs_block_size")
+    copy_prop("odm_dlkm_squashfs_disable_4k_align", "squashfs_disable_4k_align")
+    copy_prop("odm_dlkm_base_fs_file", "base_fs_file")
+    copy_prop("odm_dlkm_extfs_inode_count", "extfs_inode_count")
+    if not copy_prop("odm_dlkm_extfs_rsv_pct", "extfs_rsv_pct"):
+      d["extfs_rsv_pct"] = "0"
+    copy_prop("odm_dlkm_reserved_size", "partition_reserved_size")
+    copy_prop("odm_dlkm_selinux_fc", "selinux_fc")
   elif mount_point == "oem":
     copy_prop("fs_type", "fs_type")
     copy_prop("oem_size", "partition_size")
@@ -752,6 +798,10 @@
     copy_prop("partition_size", "vendor_size")
   elif mount_point == "odm":
     copy_prop("partition_size", "odm_size")
+  elif mount_point == "vendor_dlkm":
+    copy_prop("partition_size", "vendor_dlkm_size")
+  elif mount_point == "odm_dlkm":
+    copy_prop("partition_size", "odm_dlkm_size")
   elif mount_point == "product":
     copy_prop("partition_size", "product_size")
   elif mount_point == "system_ext":
@@ -791,6 +841,10 @@
       mount_point = "vendor"
     elif image_filename == "odm.img":
       mount_point = "odm"
+    elif image_filename == "vendor_dlkm.img":
+      mount_point = "vendor_dlkm"
+    elif image_filename == "odm_dlkm.img":
+      mount_point = "odm_dlkm"
     elif image_filename == "oem.img":
       mount_point = "oem"
     elif image_filename == "product.img":
diff --git a/tools/releasetools/check_target_files_signatures.py b/tools/releasetools/check_target_files_signatures.py
index 8c1bb9a..6e02e4d 100755
--- a/tools/releasetools/check_target_files_signatures.py
+++ b/tools/releasetools/check_target_files_signatures.py
@@ -120,19 +120,18 @@
   def __init__(self):
     self.certs = {}
 
-  def Add(self, cert, name=None):
-    if cert in self.certs:
+  def Add(self, cert_digest, subject, name=None):
+    if cert_digest in self.certs:
       if name:
-        self.certs[cert] = self.certs[cert] + "," + name
+        self.certs[cert_digest] = self.certs[cert_digest] + "," + name
     else:
       if name is None:
-        name = "unknown cert %s (%s)" % (common.sha1(cert).hexdigest()[:12],
-                                         GetCertSubject(cert))
-      self.certs[cert] = name
+        name = "unknown cert %s (%s)" % (cert_digest[:12], subject)
+      self.certs[cert_digest] = name
 
-  def Get(self, cert):
-    """Return the name for a given cert."""
-    return self.certs.get(cert, None)
+  def Get(self, cert_digest):
+    """Return the name for a given cert digest."""
+    return self.certs.get(cert_digest, None)
 
   def FindLocalCerts(self):
     to_load = []
@@ -148,7 +147,10 @@
         cert = common.ParseCertificate(f.read())
       name, _ = os.path.splitext(i)
       name, _ = os.path.splitext(name)
-      self.Add(cert, name)
+
+      cert_sha1 = common.sha1(cert).hexdigest()
+      cert_subject = GetCertSubject(cert)
+      self.Add(cert_sha1, cert_subject, name)
 
 
 ALL_CERTS = CertDB()
@@ -184,7 +186,7 @@
 
   def __init__(self, full_filename, filename):
     self.filename = filename
-    self.certs = None
+    self.cert_digests = frozenset()
     self.shared_uid = None
     self.package = None
 
@@ -195,22 +197,68 @@
     finally:
       Pop()
 
-  def RecordCerts(self, full_filename):
-    out = set()
+  def ReadCertsDeprecated(self, full_filename):
+    print("reading certs in deprecated way for {}".format(full_filename))
+    cert_digests = set()
     with zipfile.ZipFile(full_filename) as apk:
-      pkcs7 = None
       for info in apk.infolist():
         filename = info.filename
         if (filename.startswith("META-INF/") and
             info.filename.endswith((".DSA", ".RSA"))):
           pkcs7 = apk.read(filename)
           cert = CertFromPKCS7(pkcs7, filename)
-          out.add(cert)
-          ALL_CERTS.Add(cert)
-      if not pkcs7:
-        AddProblem("no signature")
+          if not cert:
+            continue
+          cert_sha1 = common.sha1(cert).hexdigest()
+          cert_subject = GetCertSubject(cert)
+          ALL_CERTS.Add(cert_sha1, cert_subject)
+          cert_digests.add(cert_sha1)
+    if not cert_digests:
+      AddProblem("No signature found")
+      return
+    self.cert_digests = frozenset(cert_digests)
 
-    self.certs = frozenset(out)
+  def RecordCerts(self, full_filename):
+    """Parse and save the signature of an apk file."""
+
+    # Dump the cert info with apksigner
+    cmd = ["apksigner", "verify", "--print-certs", full_filename]
+    p = common.Run(cmd, stdout=subprocess.PIPE)
+    output, _ = p.communicate()
+    if p.returncode != 0:
+      self.ReadCertsDeprecated(full_filename)
+      return
+
+    # Sample output:
+    # Signer #1 certificate DN: ...
+    # Signer #1 certificate SHA-256 digest: ...
+    # Signer #1 certificate SHA-1 digest: ...
+    # ...
+    certs_info = {}
+    certificate_regex = re.compile(r"(Signer #[0-9]+) (certificate .*):(.*)")
+    for line in output.splitlines():
+      m = certificate_regex.match(line)
+      if not m:
+        continue
+      signer, key, val = m.group(1), m.group(2), m.group(3)
+      if certs_info.get(signer):
+        certs_info[signer].update({key.strip(): val.strip()})
+      else:
+        certs_info.update({signer: {key.strip(): val.strip()}})
+    if not certs_info:
+      AddProblem("Failed to parse cert info")
+      return
+
+    cert_digests = set()
+    for signer, props in certs_info.items():
+      subject = props.get("certificate DN")
+      digest = props.get("certificate SHA-1 digest")
+      if not subject or not digest:
+        AddProblem("Failed to parse cert subject or digest")
+        return
+      ALL_CERTS.Add(digest, subject)
+      cert_digests.add(digest)
+    self.cert_digests = frozenset(cert_digests)
 
   def ReadManifest(self, full_filename):
     p = common.Run(["aapt2", "dump", "xmltree", full_filename, "--file",
@@ -316,8 +364,8 @@
       print("uid %s is shared by packages with different cert sets:" % (uid,))
       for apk in apks:
         print("%-*s  [%s]" % (self.max_pkg_len, apk.package, apk.filename))
-        for cert in apk.certs:
-          print("   ", ALL_CERTS.Get(cert))
+        for digest in apk.cert_digests:
+          print("   ", ALL_CERTS.Get(digest))
       print()
 
   def CheckExternalSignatures(self):
@@ -328,25 +376,30 @@
         # predexopting.  Consider it an error if this app is now
         # signed with any key that is present in our tree.
         apk = self.apks_by_basename[apk_filename]
-        name = ALL_CERTS.Get(apk.cert)
-        if not name.startswith("unknown "):
+        signed_with_external = False
+        for digest in apk.cert_digests:
+          name = ALL_CERTS.Get(digest)
+          if name and name.startswith("unknown "):
+            signed_with_external = True
+
+        if not signed_with_external:
           Push(apk.filename)
           AddProblem("hasn't been signed with EXTERNAL cert")
           Pop()
 
   def PrintCerts(self):
     """Display a table of packages grouped by cert."""
-    by_cert = {}
+    by_digest = {}
     for apk in self.apks.values():
-      for cert in apk.certs:
-        by_cert.setdefault(cert, []).append((apk.package, apk))
+      for digest in apk.cert_digests:
+        by_digest.setdefault(digest, []).append((apk.package, apk))
 
-    order = [(-len(v), k) for (k, v) in by_cert.items()]
+    order = [(-len(v), k) for (k, v) in by_digest.items()]
     order.sort()
 
-    for _, cert in order:
-      print("%s:" % (ALL_CERTS.Get(cert),))
-      apks = by_cert[cert]
+    for _, digest in order:
+      print("%s:" % (ALL_CERTS.Get(digest),))
+      apks = by_digest[digest]
       apks.sort()
       for _, apk in apks:
         if apk.shared_uid:
@@ -366,15 +419,15 @@
 
     max_pkg_len = max(self.max_pkg_len, other.max_pkg_len)
 
-    by_certpair = {}
+    by_digestpair = {}
 
     for i in all_apks:
       if i in self.apks:
         if i in other.apks:
           # in both; should have same set of certs
-          if self.apks[i].certs != other.apks[i].certs:
-            by_certpair.setdefault((other.apks[i].certs,
-                                    self.apks[i].certs), []).append(i)
+          if self.apks[i].cert_digests != other.apks[i].cert_digests:
+            by_digestpair.setdefault((other.apks[i].cert_digests,
+                                      self.apks[i].cert_digests), []).append(i)
         else:
           print("%s [%s]: new APK (not in comparison target_files)" % (
               i, self.apks[i].filename))
@@ -383,10 +436,10 @@
           print("%s [%s]: removed APK (only in comparison target_files)" % (
               i, other.apks[i].filename))
 
-    if by_certpair:
+    if by_digestpair:
       AddProblem("some APKs changed certs")
       Banner("APK signing differences")
-      for (old, new), packages in sorted(by_certpair.items()):
+      for (old, new), packages in sorted(by_digestpair.items()):
         for i, o in enumerate(old):
           if i == 0:
             print("was", ALL_CERTS.Get(o))
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index 95d09cc..ef66112 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -46,6 +46,7 @@
     '/product': ('PRODUCT', 'SYSTEM/product'),
     '/odm': ('ODM', 'VENDOR/odm', 'SYSTEM/vendor/odm'),
     '/system_ext': ('SYSTEM_EXT', 'SYSTEM/system_ext'),
+    # vendor_dlkm and odm_dlkm does not have VINTF files.
 }
 
 UNZIP_PATTERN = ['META/*', '*/build.prop']
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 8bbc35e..25ccea0 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -110,13 +110,22 @@
 # that system_other is not in the list because we don't want to include its
 # descriptor into vbmeta.img.
 AVB_PARTITIONS = ('boot', 'dtbo', 'odm', 'product', 'recovery', 'system',
-                  'system_ext', 'vendor', 'vendor_boot')
+                  'system_ext', 'vendor', 'vendor_boot', 'vendor_dlkm',
+                  'odm_dlkm')
 
 # Chained VBMeta partitions.
 AVB_VBMETA_PARTITIONS = ('vbmeta_system', 'vbmeta_vendor')
 
 # Partitions that should have their care_map added to META/care_map.pb
-PARTITIONS_WITH_CARE_MAP = ('system', 'vendor', 'product', 'system_ext', 'odm')
+PARTITIONS_WITH_CARE_MAP = (
+    'system',
+    'vendor',
+    'product',
+    'system_ext',
+    'odm',
+    'vendor_dlkm',
+    'odm_dlkm',
+)
 
 
 class ErrorCode(object):
@@ -655,7 +664,8 @@
         input_file, "META", "root_filesystem_config.txt")
 
     # Redirect {partition}_base_fs_file for each of the named partitions.
-    for part_name in ["system", "vendor", "system_ext", "product", "odm"]:
+    for part_name in ["system", "vendor", "system_ext", "product", "odm",
+                      "vendor_dlkm", "odm_dlkm"]:
       key_name = part_name + "_base_fs_file"
       if key_name not in d:
         continue
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index ed42b20..45532f5 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -197,6 +197,8 @@
     'PREBUILT_IMAGES/*',
     'RADIO/*',
     'VENDOR/*',
+    'VENDOR_DLKM/*',
+    'ODM_DLKM/*',
 )
 
 # VENDOR_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
@@ -223,6 +225,8 @@
     'SYSTEM/',
     'SYSTEM_OTHER/',
     'VENDOR/',
+    'VENDOR_DLKM/',
+    'ODM_DLKM/',
 )
 
 
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 7fb0a77..c3dcf0d 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -277,13 +277,14 @@
 UNZIP_PATTERN = ['IMAGES/*', 'META/*', 'OTA/*', 'RADIO/*']
 # Files to be unzipped for target diffing purpose.
 TARGET_DIFFING_UNZIP_PATTERN = ['BOOT', 'RECOVERY', 'SYSTEM/*', 'VENDOR/*',
-                                'PRODUCT/*', 'SYSTEM_EXT/*', 'ODM/*']
+                                'PRODUCT/*', 'SYSTEM_EXT/*', 'ODM/*',
+                                'VENDOR_DLKM/*', 'ODM_DLKM/*']
 RETROFIT_DAP_UNZIP_PATTERN = ['OTA/super_*.img', AB_PARTITIONS]
 
 # Images to be excluded from secondary payload. We essentially only keep
 # 'system_other' and bootloader partitions.
 SECONDARY_PAYLOAD_SKIPPED_IMAGES = [
-    'boot', 'dtbo', 'modem', 'odm', 'product', 'radio', 'recovery',
+    'boot', 'dtbo', 'modem', 'odm', 'odm_dlkm', 'product', 'radio', 'recovery',
     'system_ext', 'vbmeta', 'vbmeta_system', 'vbmeta_vendor', 'vendor',
     'vendor_boot']
 
@@ -668,7 +669,8 @@
     assert blockimgdiff_version >= 3
 
   block_diff_dict = collections.OrderedDict()
-  partition_names = ["system", "vendor", "product", "odm", "system_ext"]
+  partition_names = ["system", "vendor", "product", "odm", "system_ext",
+                     "vendor_dlkm", "odm_dlkm"]
   for partition in partition_names:
     if not HasPartition(target_zip, partition):
       continue
diff --git a/tools/soong_to_convert.py b/tools/soong_to_convert.py
index 083f6f7..949131b 100755
--- a/tools/soong_to_convert.py
+++ b/tools/soong_to_convert.py
@@ -78,7 +78,7 @@
     reverse_deps = dict()
     module_types = dict()
 
-    for (module, module_type, problem, dependencies) in reader:
+    for (module, module_type, problem, dependencies, makefiles, installed) in reader:
         module_types[module] = module_type
         problems[module] = problem
         deps[module] = [d for d in dependencies.strip().split(' ') if d != ""]