Merge "Revert "Add a check for apex/allowed_deps.txt to droidcore.""
diff --git a/core/Makefile b/core/Makefile
index 759f541..8395e45 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -385,7 +385,7 @@
   $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-vendor-ramdisk-recovery-load,$(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)))))
@@ -902,9 +902,10 @@
 .PHONY: notice_files
 
 # Create the rule to combine the files into text and html/xml forms
-# $(1) - xml_excluded_system_product_odm_vendor_dlkm|
-#        xml_excluded_vendor_product_odm_vendor_dlkm|
-#        xml_product|xml_odm|xml_system_ext|xml_system|xml_vendor_dlkm|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
@@ -930,15 +931,16 @@
 $(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_vendor_dlkm),-e vendor -e product -e system_ext -e odm -e vendor_dlkm --xml-output, \
-	      $(if $(filter $(1),xml_excluded_system_product_odm_vendor_dlkm),-e system -e product -e system_ext -e odm -e vendor_dlkm --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, \
 	                $(if $(filter $(1),xml_vendor_dlkm),-i vendor_dlkm --xml-output, \
-	                  --html-output))))))) $(3) \
-	    -t $$(PRIVATE_MESSAGE) -s $$(PRIVATE_DIR)/src
+	                  $(if $(filter $(1),xml_odm_dlkm),-i odm_dlkm --xml-output, \
+	                    --html-output)))))))) $(3) \
+	    -t $$(PRIVATE_MESSAGE) $$(foreach dir,$$(sort $$(PRIVATE_DIR)), -s $$(dir)/src)
 notice_files: $(2) $(3)
 endef
 
@@ -1006,6 +1008,11 @@
 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.
@@ -1016,19 +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, odm, and vendor_dlkm
+# 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_vendor_dlkm)
+                       $(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))
 
@@ -1063,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_vendor_dlkm
-system_notice_file_message := "Notices for files contained in all filesystem images except vendor/system_ext/product/odm/vendor_dlkm 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
@@ -1078,10 +1087,10 @@
 	        $(TARGET_OUT_NOTICE_FILES), \
 	        $(license_modules_system), \
 	        $(exclude_target_dirs)))
-$(eval $(call combine-notice-files, xml_excluded_system_product_odm_vendor_dlkm, \
+$(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/vendor_dlkm 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)))
@@ -1113,6 +1122,13 @@
 	        $(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 < $< > $@
@@ -1126,6 +1142,8 @@
 	$(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)
@@ -1138,6 +1156,8 @@
 	$(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)
@@ -1145,6 +1165,7 @@
 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)
@@ -1218,6 +1239,7 @@
     $(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
@@ -1248,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 vendor_dlkm"
+# $(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),\
@@ -1358,6 +1380,20 @@
     $(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))
@@ -1385,6 +1421,7 @@
 $(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))
@@ -1441,6 +1478,14 @@
         $(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)),\
@@ -1481,6 +1526,9 @@
 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
@@ -2476,6 +2524,9 @@
 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 \
@@ -2753,6 +2804,7 @@
 # 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; \
@@ -2765,6 +2817,35 @@
 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
@@ -2773,6 +2854,7 @@
   @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 \
@@ -3027,6 +3109,62 @@
 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
@@ -3186,6 +3324,10 @@
     --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)
 
@@ -3210,6 +3352,11 @@
     --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
@@ -3220,6 +3367,7 @@
 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.
@@ -3318,6 +3466,10 @@
 $(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
@@ -3401,6 +3553,9 @@
   $(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)
@@ -3484,6 +3639,7 @@
 	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
 	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+	    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
 	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
 	    $(INSTALLED_RECOVERYIMAGE_TARGET) \
@@ -3506,7 +3662,7 @@
 # -----------------------------------------------------------------
 # Check VINTF of build
 
-# Note: vendor_dlkm does not have VINTF files.
+# Note: vendor_dlkm and odm_dlkm does not have VINTF files.
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
 
 intermediates := $(call intermediates-dir-for,PACKAGING,check_vintf_all)
@@ -4294,6 +4450,7 @@
 	    $(INSTALLED_VBMETAIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
 	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
+	    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
 	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
 	    $(INTERNAL_SYSTEMOTHERIMAGE_FILES) \
@@ -4310,6 +4467,7 @@
 	    $(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) \
@@ -4328,6 +4486,7 @@
 	$(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)))
@@ -4453,6 +4612,11 @@
 	$(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, \
@@ -4502,6 +4666,10 @@
 	$(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) \
@@ -4585,6 +4753,9 @@
 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)
@@ -4744,6 +4915,7 @@
 	    $(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
@@ -4770,7 +4942,8 @@
 	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
 	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
-	    $(INSTALLED_VENDOR_DLKMIMAGE_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)
@@ -4848,6 +5021,7 @@
     $(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
@@ -5096,6 +5270,15 @@
 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) \
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/board_config.mk b/core/board_config.mk
index 70c1589..4141cee 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -74,6 +74,8 @@
   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 += \
@@ -81,6 +83,7 @@
   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 \
@@ -582,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/config.mk b/core/config.mk
index 2689d80..b928af0 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -937,6 +937,13 @@
 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 \
@@ -972,7 +979,7 @@
 )
 
 # BOARD_*_PARTITION_LIST: a list of the following tokens
-valid_super_partition_list := system vendor product system_ext odm vendor_dlkm
+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/dex_preopt.mk b/core/dex_preopt.mk
index 20b4051..dd31999 100644
--- a/core/dex_preopt.mk
+++ b/core/dex_preopt.mk
@@ -21,32 +21,38 @@
 my_boot_image_arch := TARGET_ARCH
 my_boot_image_out := $(PRODUCT_OUT)
 my_boot_image_syms := $(TARGET_OUT_UNSTRIPPED)
-my_boot_image_root := DEFAULT_DEX_PREOPT_INSTALLED_IMAGE
-DEFAULT_DEX_PREOPT_INSTALLED_IMAGE :=
-$(foreach my_boot_image_name,$(DEXPREOPT_IMAGE_NAMES),$(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk))
+DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE := \
+  $(foreach my_boot_image_name,$(DEXPREOPT_IMAGE_NAMES),$(strip \
+    $(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk) \
+    $(my_boot_image_module)))
 ifdef TARGET_2ND_ARCH
   my_boot_image_arch := TARGET_2ND_ARCH
-  my_boot_image_root := 2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE
-  2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE :=
-  $(foreach my_boot_image_name,$(DEXPREOPT_IMAGE_NAMES),$(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk))
+  2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE := \
+    $(foreach my_boot_image_name,$(DEXPREOPT_IMAGE_NAMES),$(strip \
+      $(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk) \
+      $(my_boot_image_module)))
 endif
 # Install boot images for testing on host. We exclude framework image as it is not part of art manifest.
 my_boot_image_arch := HOST_ARCH
 my_boot_image_out := $(HOST_OUT)
 my_boot_image_syms := $(HOST_OUT)/symbols
-my_boot_image_root := HOST_BOOT_IMAGE
-HOST_BOOT_IMAGE :=
-$(foreach my_boot_image_name,art_host,$(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk))
+HOST_BOOT_IMAGE_MODULE := \
+  $(foreach my_boot_image_name,art_host,$(strip \
+    $(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk) \
+    $(my_boot_image_module)))
+HOST_BOOT_IMAGE := $(call module-installed-files,$(HOST_BOOT_IMAGE_MODULE))
 ifdef HOST_2ND_ARCH
   my_boot_image_arch := HOST_2ND_ARCH
-  my_boot_image_root := 2ND_HOST_BOOT_IMAGE
-  2ND_HOST_BOOT_IMAGE :=
-  $(foreach my_boot_image_name,art_host,$(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk))
+  2ND_HOST_BOOT_IMAGE_MODULE := \
+    $(foreach my_boot_image_name,art_host,$(strip \
+      $(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk) \
+      $(my_boot_image_module)))
+  2ND_HOST_BOOT_IMAGE := $(call module-installed-files,$(2ND_HOST_BOOT_IMAGE_MODULE))
 endif
 my_boot_image_arch :=
 my_boot_image_out :=
 my_boot_image_syms :=
-my_boot_image_root :=
+my_boot_image_module :=
 
 # Build the boot.zip which contains the boot jars and their compilation output
 # We can do this only if preopt is enabled and if the product uses libart config (which sets the
diff --git a/core/dex_preopt_libart.mk b/core/dex_preopt_libart.mk
index 12b29f4..8f0702b 100644
--- a/core/dex_preopt_libart.mk
+++ b/core/dex_preopt_libart.mk
@@ -5,38 +5,75 @@
 #   my_boot_image_arch: the architecture to install (e.g. TARGET_ARCH, not expanded)
 #   my_boot_image_out:  the install directory (e.g. $(PRODUCT_OUT))
 #   my_boot_image_syms: the symbols director (e.g. $(TARGET_OUT_UNSTRIPPED))
-#   my_boot_image_root: make variable used to store installed image path
+#
+# Output variables:
+#   my_boot_image_module: the created module name. Empty if no module is created.
+#
+# Install the boot images compiled by Soong.
+# Create a module named dexpreopt_bootjar.$(my_boot_image_name)_$($(my_boot_image_arch))
+# that installs all of boot image files.
+# If there is no file to install for $(my_boot_image_name), for example when
+# building an unbundled build, then no module is created.
 #
 ####################################
 
 # Install $(1) to $(2) so that it is shared between architectures.
+# Returns the target path of the shared vdex file and installed symlink.
 define copy-vdex-file
-my_vdex_shared := $$(dir $$(patsubst %/,%,$$(dir $(2))))$$(notdir $(2))  # Remove the arch dir.
-ifneq ($(my_boot_image_arch),$(filter $(my_boot_image_arch), TARGET_2ND_ARCH HOST_2ND_ARCH))
-$$(my_vdex_shared): $(1)  # Copy $(1) to directory one level up (i.e. with the arch dir removed).
-	@echo "Install: $$@"
-	$$(copy-file-to-target)
-endif
-$(2): $$(my_vdex_shared)  # Create symlink at $(2) which points to the actual physical copy.
-	@echo "Symlink: $$@"
-	mkdir -p $$(dir $$@)
-	ln -sfn ../$$(notdir $$@) $$@
-my_vdex_shared :=
+$(strip \
+  $(eval # Remove the arch dir) \
+  $(eval my_vdex_shared := $(dir $(patsubst %/,%,$(dir $(2))))$(notdir $(2))) \
+  $(if $(filter-out %_2ND_ARCH,$(my_boot_image_arch)), \
+    $(eval # Copy $(1) to directory one level up (i.e. with the arch dir removed).) \
+    $(eval $(call copy-one-file,$(1),$(my_vdex_shared))) \
+  ) \
+  $(eval # Create symlink at $(2) which points to the actual physical copy.) \
+  $(call symlink-file,$(my_vdex_shared),../$(notdir $(2)),$(2)) \
+  $(my_vdex_shared) $(2) \
+)
 endef
 
 # Same as 'copy-many-files' but it uses the vdex-specific helper above.
 define copy-vdex-files
-$(foreach v,$(1),$(eval $(call copy-vdex-file, $(call word-colon,1,$(v)), $(2)$(call word-colon,2,$(v)))))
-$(foreach v,$(1),$(2)$(call word-colon,2,$(v)))
+$(foreach v,$(1),$(call copy-vdex-file,$(call word-colon,1,$(v)),$(2)$(call word-colon,2,$(v))))
 endef
 
-# Install the boot images compiled by Soong.
-# The first file is saved in $(my_boot_image_root) and the rest are added as it's dependencies.
-my_suffix := BUILT_INSTALLED_$(my_boot_image_name)_$($(my_boot_image_arch))
-my_installed := $(call copy-many-files,$(DEXPREOPT_IMAGE_$(my_suffix)),$(my_boot_image_out))
-my_installed += $(call copy-many-files,$(DEXPREOPT_IMAGE_UNSTRIPPED_$(my_suffix)),$(my_boot_image_syms))
-my_installed += $(call copy-vdex-files,$(DEXPREOPT_IMAGE_VDEX_$(my_suffix)),$(my_boot_image_out))
-$(my_boot_image_root) += $(firstword $(my_installed))
-$(firstword $(my_installed)): $(wordlist 2,9999,$(my_installed))
-my_installed :=
-my_suffix :=
+my_boot_image_module :=
+
+my_suffix := $(my_boot_image_name)_$($(my_boot_image_arch))
+my_copy_pairs := $(strip $(DEXPREOPT_IMAGE_BUILT_INSTALLED_$(my_suffix)))
+
+# Generate the boot image module only if there is any file to install.
+ifneq (,$(my_copy_pairs))
+  my_first_pair := $(firstword $(my_copy_pairs))
+  my_rest_pairs := $(wordlist 2,$(words $(my_copy_pairs)),$(my_copy_pairs))
+
+  my_first_src := $(call word-colon,1,$(my_first_pair))
+  my_first_dest := $(my_boot_image_out)$(call word-colon,2,$(my_first_pair))
+
+  my_installed := $(call copy-many-files,$(my_rest_pairs),$(my_boot_image_out))
+  my_installed += $(call copy-vdex-files,$(DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_$(my_suffix)),$(my_boot_image_out))
+  my_unstripped_installed := $(call copy-many-files,$(DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_$(my_suffix)),$(my_boot_image_syms))
+
+  # We don't have a LOCAL_PATH for the auto-generated modules, so let it be the $(BUILD_SYSTEM).
+  LOCAL_PATH := $(BUILD_SYSTEM)
+
+  include $(CLEAR_VARS)
+  LOCAL_MODULE := dexpreopt_bootjar.$(my_suffix)
+  LOCAL_PREBUILT_MODULE_FILE := $(my_first_src)
+  LOCAL_MODULE_PATH := $(dir $(my_first_dest))
+  LOCAL_MODULE_STEM := $(notdir $(my_first_dest))
+  ifneq (,$(strip $(filter HOST_%,$(my_boot_image_arch))))
+    LOCAL_IS_HOST_MODULE := true
+  endif
+  LOCAL_MODULE_CLASS := ETC
+  include $(BUILD_PREBUILT)
+  $(LOCAL_BUILT_MODULE): $(my_unstripped_installed)
+  # Installing boot.art causes all boot image bits to be installed.
+  # Keep this old behavior in case anyone still needs it.
+  $(LOCAL_INSTALLED_MODULE): $(my_installed)
+  ALL_MODULES.$(my_register_name).INSTALLED += $(my_installed)
+  $(my_all_targets): $(my_installed)
+
+  my_boot_image_module := $(LOCAL_MODULE)
+endif  # my_copy_pairs != empty
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 1fb4605..f78ecb4 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -254,6 +254,7 @@
 _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)
@@ -263,6 +264,7 @@
 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
@@ -755,6 +757,40 @@
     $(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/main.mk b/core/main.mk
index c6d2128..20b50cd 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -150,9 +150,6 @@
 # Bring in standard build system definitions.
 include $(BUILD_SYSTEM)/definitions.mk
 
-# Bring in dex_preopt.mk
-include $(BUILD_SYSTEM)/dex_preopt.mk
-
 ifneq ($(filter user userdebug eng,$(MAKECMDGOALS)),)
 $(info ***************************************************************)
 $(info ***************************************************************)
@@ -473,6 +470,12 @@
 # Typical build; include any Android.mk files we can find.
 #
 
+# Bring in dex_preopt.mk
+# This creates some modules so it needs to be included after
+# should-install-to-system is defined (in order for base_rules.mk to function
+# properly), but before readonly-final-product-vars is called.
+include $(BUILD_SYSTEM)/dex_preopt.mk
+
 # Strip and readonly a few more variables so they won't be modified.
 $(readonly-final-product-vars)
 ADDITIONAL_SYSTEM_PROPERTIES := $(strip $(ADDITIONAL_SYSTEM_PROPERTIES))
@@ -1142,7 +1145,8 @@
       $(subst $(_system_ext_path_placeholder),$(TARGET_COPY_OUT_SYSTEM_EXT),\
         $(subst $(_odm_path_placeholder),$(TARGET_COPY_OUT_ODM),\
           $(subst $(_vendor_dlkm_path_placeholder),$(TARGET_COPY_OUT_VENDOR_DLKM),\
-            $(foreach p,$(1),$(call append-path,$(PRODUCT_OUT),$(p)$(2))))))))
+            $(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
@@ -1523,6 +1527,9 @@
 .PHONY: vendor_dlkmimage
 vendor_dlkmimage: $(INSTALLED_VENDOR_DLKMIMAGE_TARGET)
 
+.PHONY: odm_dlkmimage
+odm_dlkmimage: $(INSTALLED_ODM_DLKMIMAGE_TARGET)
+
 .PHONY: systemotherimage
 systemotherimage: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET)
 
@@ -1569,6 +1576,7 @@
     $(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) \
@@ -1580,6 +1588,8 @@
     $(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) \
@@ -1685,6 +1695,8 @@
     $(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) \
diff --git a/core/product.mk b/core/product.mk
index 740563f..324010c 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -252,6 +252,7 @@
 _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
 
@@ -280,6 +281,7 @@
 _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
@@ -372,6 +374,7 @@
 _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 d614e10..bb806bb 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -400,6 +400,7 @@
     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_config.mk b/core/soong_config.mk
index c7bf61e..b826024 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -156,6 +156,7 @@
 $(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)))
@@ -174,6 +175,7 @@
 $(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/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index e4c84e0..05f700d 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -94,16 +94,18 @@
     boot_jars := $(foreach pair,$(PRODUCT_BOOT_JARS), $(call word-colon,2,$(pair)))
     ifneq ($(filter $(LOCAL_MODULE),$(boot_jars)),) # is_boot_jar
       ifeq (true,$(WITH_DEXPREOPT))
-        # For libart, the boot jars' odex files are replaced by $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE).
-        # We use this installed_odex trick to get boot.art installed.
-        installed_odex := $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE)
-        # Append the odex for the 2nd arch if we have one.
-        installed_odex += $($(TARGET_2ND_ARCH_VAR_PREFIX)DEFAULT_DEX_PREOPT_INSTALLED_IMAGE)
-        ALL_MODULES.$(my_register_name).INSTALLED += $(installed_odex)
-        # Make sure to install the .odex and .vdex when you run "make <module_name>"
-       $(my_all_targets): $(installed_odex)
-       # Copy $(LOCAL_BUILT_MODULE) and its dependencies when installing boot.art
-       $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE): $(LOCAL_BUILT_MODULE)
+        # $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE) contains modules that installs
+        # all of bootjars' dexpreopt files (.art, .oat, .vdex, ...)
+        # Add them to the required list so they are installed alongside this module.
+        ALL_MODULES.$(my_register_name).REQUIRED_FROM_TARGET += \
+          $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE) \
+          $(2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE)
+        # Copy $(LOCAL_BUILT_MODULE) and its dependencies when installing boot.art
+        # so that dependencies of $(LOCAL_BUILT_MODULE) (which may include
+        # jacoco-report-classes.jar) are copied for every build.
+        $(foreach m,$(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE) $(2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE), \
+          $(eval $(call add-dependency,$(firstword $(call module-installed-files,$(m))),$(LOCAL_BUILT_MODULE))) \
+        )
       endif
     endif # is_boot_jar
 
diff --git a/core/sysprop.mk b/core/sysprop.mk
index f53aa07..d01255f 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -401,6 +401,15 @@
     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/vendor_module_check.mk b/core/tasks/vendor_module_check.mk
index 89a34d6..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)/% $(TARGET_OUT_VENDOR_DLKM)/% $(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, odm or vendor_dlkm 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 37018f7..4af5154 100755
--- a/help.sh
+++ b/help.sh
@@ -46,6 +46,8 @@
                             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/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/mainline_system_arm64.mk b/target/product/mainline_system_arm64.mk
index e536e55..a0c3e6d 100644
--- a/target/product/mainline_system_arm64.mk
+++ b/target/product/mainline_system_arm64.mk
@@ -27,6 +27,7 @@
 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 484ae30..3c4a867 100644
--- a/target/product/mainline_system_x86.mk
+++ b/target/product/mainline_system_x86.mk
@@ -26,6 +26,7 @@
 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 ad31f81..410c998 100644
--- a/target/product/mainline_system_x86_64.mk
+++ b/target/product/mainline_system_x86_64.mk
@@ -27,6 +27,7 @@
 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 24f1ad7..8c6611e 100644
--- a/target/product/mainline_system_x86_arm.mk
+++ b/target/product/mainline_system_x86_arm.mk
@@ -26,6 +26,7 @@
 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 60b51b6..41e8ca5 100644
--- a/tools/fs_config/Android.mk
+++ b/tools/fs_config/Android.mk
@@ -27,12 +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, vendor_dlkm, 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) \
 )
@@ -334,6 +335,57 @@
 
 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/generate-notice-files.py b/tools/generate-notice-files.py
index 49011b2..18f2166 100755
--- a/tools/generate-notice-files.py
+++ b/tools/generate-notice-files.py
@@ -73,10 +73,10 @@
 </style>
 """
 
-def combine_notice_files_html(file_hash, input_dir, output_filename):
+def combine_notice_files_html(file_hash, input_dirs, output_filename):
     """Combine notice files in FILE_HASH and output a HTML version to OUTPUT_FILENAME."""
 
-    SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+    SRC_DIR_STRIP_RE = re.compile("(?:" + "|".join(input_dirs) + ")(/.*).txt")
 
     # Set up a filename to row id table (anchors inside tables don't work in
     # most browsers, but href's to table row ids do)
@@ -131,10 +131,10 @@
     print >> output_file, "</body></html>"
     output_file.close()
 
-def combine_notice_files_text(file_hash, input_dir, output_filename, file_title):
+def combine_notice_files_text(file_hash, input_dirs, output_filename, file_title):
     """Combine notice files in FILE_HASH and output a text version to OUTPUT_FILENAME."""
 
-    SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+    SRC_DIR_STRIP_RE = re.compile("(?:" + "|".join(input_dirs) + ")(/.*).txt")
     output_file = open(output_filename, "wb")
     print >> output_file, file_title
     for value in file_hash:
@@ -146,10 +146,10 @@
       print >> output_file, open(value[0]).read()
     output_file.close()
 
-def combine_notice_files_xml(files_with_same_hash, input_dir, output_filename):
+def combine_notice_files_xml(files_with_same_hash, input_dirs, output_filename):
     """Combine notice files in FILE_HASH and output a XML version to OUTPUT_FILENAME."""
 
-    SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+    SRC_DIR_STRIP_RE = re.compile("(?:" + "|".join(input_dirs) + ")(/.*).txt")
 
     # Set up a filename to row id table (anchors inside tables don't work in
     # most browsers, but href's to table row ids do)
@@ -205,7 +205,7 @@
         '-t', '--title', required=True,
         help='The file title.')
     parser.add_argument(
-        '-s', '--source-dir', required=True,
+        '-s', '--source-dir', required=True, action='append',
         help='The directory containing notices.')
     parser.add_argument(
         '-i', '--included-subdirs', action='append',
@@ -229,39 +229,40 @@
     if args.excluded_subdirs is not None:
         excluded_subdirs = args.excluded_subdirs
 
+    input_dirs = [os.path.normpath(source_dir) for source_dir in args.source_dir]
     # Find all the notice files and md5 them
-    input_dir = os.path.normpath(args.source_dir)
-    files_with_same_hash = defaultdict(list)
-    for root, dir, files in os.walk(input_dir):
-        for file in files:
-            matched = True
-            if len(included_subdirs) > 0:
-                matched = False
-                for subdir in included_subdirs:
-                    if (root == (input_dir + '/' + subdir) or
-                        root.startswith(input_dir + '/' + subdir + '/')):
-                        matched = True
-                        break
-            elif len(excluded_subdirs) > 0:
-                for subdir in excluded_subdirs:
-                    if (root == (input_dir + '/' + subdir) or
-                        root.startswith(input_dir + '/' + subdir + '/')):
-                        matched = False
-                        break
-            if matched and file.endswith(".txt"):
-                filename = os.path.join(root, file)
-                file_md5sum = md5sum(filename)
-                files_with_same_hash[file_md5sum].append(filename)
+    for input_dir in input_dirs:
+        files_with_same_hash = defaultdict(list)
+        for root, dir, files in os.walk(input_dir):
+            for file in files:
+                matched = True
+                if len(included_subdirs) > 0:
+                    matched = False
+                    for subdir in included_subdirs:
+                        if (root == (input_dir + '/' + subdir) or
+                            root.startswith(input_dir + '/' + subdir + '/')):
+                            matched = True
+                            break
+                elif len(excluded_subdirs) > 0:
+                    for subdir in excluded_subdirs:
+                        if (root == (input_dir + '/' + subdir) or
+                            root.startswith(input_dir + '/' + subdir + '/')):
+                            matched = False
+                            break
+                if matched and file.endswith(".txt"):
+                    filename = os.path.join(root, file)
+                    file_md5sum = md5sum(filename)
+                    files_with_same_hash[file_md5sum].append(filename)
 
-    filesets = [sorted(files_with_same_hash[md5]) for md5 in sorted(files_with_same_hash.keys())]
+        filesets = [sorted(files_with_same_hash[md5]) for md5 in sorted(files_with_same_hash.keys())]
 
-    combine_notice_files_text(filesets, input_dir, txt_output_file, file_title)
+    combine_notice_files_text(filesets, input_dirs, txt_output_file, file_title)
 
     if html_output_file is not None:
-        combine_notice_files_html(filesets, input_dir, html_output_file)
+        combine_notice_files_html(filesets, input_dirs, html_output_file)
 
     if xml_output_file is not None:
-        combine_notice_files_xml(files_with_same_hash, input_dir, xml_output_file)
+        combine_notice_files_xml(files_with_same_hash, input_dirs, xml_output_file)
 
 if __name__ == "__main__":
     main(sys.argv)
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 284c89a..a1f8e31 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -296,6 +296,21 @@
       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.
@@ -752,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,vendor_dlkm}.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.
@@ -772,6 +788,12 @@
                      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(
@@ -901,6 +923,10 @@
     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 dbfb485..9cc072f 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -731,6 +731,29 @@
       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")
@@ -777,6 +800,8 @@
     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":
@@ -818,6 +843,8 @@
       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_vintf.py b/tools/releasetools/check_target_files_vintf.py
index 79005df..ef66112 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -46,7 +46,7 @@
     '/product': ('PRODUCT', 'SYSTEM/product'),
     '/odm': ('ODM', 'VENDOR/odm', 'SYSTEM/vendor/odm'),
     '/system_ext': ('SYSTEM_EXT', 'SYSTEM/system_ext'),
-    # vendor_dlkm does not have VINTF files.
+    # 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 a26f9e4..25ccea0 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -110,7 +110,8 @@
 # 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', 'vendor_dlkm')
+                  'system_ext', 'vendor', 'vendor_boot', 'vendor_dlkm',
+                  'odm_dlkm')
 
 # Chained VBMeta partitions.
 AVB_VBMETA_PARTITIONS = ('vbmeta_system', 'vbmeta_vendor')
@@ -123,6 +124,7 @@
     'system_ext',
     'odm',
     'vendor_dlkm',
+    'odm_dlkm',
 )
 
 
@@ -663,7 +665,7 @@
 
     # Redirect {partition}_base_fs_file for each of the named partitions.
     for part_name in ["system", "vendor", "system_ext", "product", "odm",
-                      "vendor_dlkm"]:
+                      "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 ad991ca..45532f5 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -198,6 +198,7 @@
     'RADIO/*',
     'VENDOR/*',
     'VENDOR_DLKM/*',
+    'ODM_DLKM/*',
 )
 
 # VENDOR_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
@@ -225,6 +226,7 @@
     '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 f114f63..c3dcf0d 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -278,15 +278,15 @@
 # Files to be unzipped for target diffing purpose.
 TARGET_DIFFING_UNZIP_PATTERN = ['BOOT', 'RECOVERY', 'SYSTEM/*', 'VENDOR/*',
                                 'PRODUCT/*', 'SYSTEM_EXT/*', 'ODM/*',
-                                'VENDOR_DLKM/*']
+                                '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', 'vendor_dlkm']
+    'vendor_boot']
 
 
 class PayloadSigner(object):
@@ -670,7 +670,7 @@
 
   block_diff_dict = collections.OrderedDict()
   partition_names = ["system", "vendor", "product", "odm", "system_ext",
-                     "vendor_dlkm"]
+                     "vendor_dlkm", "odm_dlkm"]
   for partition in partition_names:
     if not HasPartition(target_zip, partition):
       continue