Merge "Add Wifi supplicant AIDL interface support."
diff --git a/core/Makefile b/core/Makefile
index b3841e9..a580ac8 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1597,6 +1597,7 @@
     $(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE) \
   ,erofs),)
 INTERNAL_USERIMAGES_DEPS += $(MKEROFSUSERIMG)
+BOARD_EROFS_COMPRESSOR ?= "lz4hc,9"
 endif
 
 ifneq ($(filter \
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index cd42e1f..d24449b 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -88,7 +88,7 @@
   # This sets the default for building ART APEXes from source rather than
   # prebuilts (in packages/modules/ArtPrebuilt and prebuilt/module_sdk/art) in
   # all other platform builds.
-  SOONG_CONFIG_art_module_source_build ?= false
+  SOONG_CONFIG_art_module_source_build ?= true
 endif
 
 # Apex build mode variables
diff --git a/core/board_config.mk b/core/board_config.mk
index 821607e..6bbb3a0 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -159,6 +159,7 @@
 _board_strip_list += BOARD_GKI_SIGNING_KEY_PATH
 _board_strip_list += BOARD_MKBOOTIMG_ARGS
 _board_strip_list += BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE
+_board_strip_list += ODM_MANIFEST_SKUS
 
 
 _build_broken_var_list := \
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 15db9a8..415334f 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -288,6 +288,7 @@
 LOCAL_SOONG_INSTALL_SYMLINKS :=
 LOCAL_SOONG_INSTALLED_MODULE :=
 LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=
+LOCAL_SOONG_LICENSE_METADATA :=
 LOCAL_SOONG_LINK_TYPE :=
 LOCAL_SOONG_LINT_REPORTS :=
 LOCAL_SOONG_PROGUARD_DICT :=
diff --git a/core/combo/HOST_CROSS_linux_bionic-arm64.mk b/core/combo/HOST_CROSS_linux_bionic-arm64.mk
deleted file mode 100644
index df6865f..0000000
--- a/core/combo/HOST_CROSS_linux_bionic-arm64.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# 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.
-#
-
-# Configuration for builds hosted on linux_arm-arm64
-# Included by combo/select.mk
-
-define $(combo_var_prefix)transform-shared-lib-to-toc
-$(call _gen_toc_command_for_elf,$(1),$(2))
-endef
diff --git a/core/combo/HOST_CROSS_windows-x86.mk b/core/combo/HOST_CROSS_windows-x86.mk
deleted file mode 100644
index d924901..0000000
--- a/core/combo/HOST_CROSS_windows-x86.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Copyright (C) 2006 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.
-#
-
-# Settings to use MinGW as a cross-compiler under Linux
-# Included by combo/select.make
-
-define $(combo_var_prefix)transform-shared-lib-to-toc
-$(hide) $($(PRIVATE_2ND_ARCH_VAR_PREFIX)$(PRIVATE_PREFIX)OBJDUMP) -x $(1) | grep "^Name" | cut -f3 -d" " > $(2)
-$(hide) $($(PRIVATE_2ND_ARCH_VAR_PREFIX)$(PRIVATE_PREFIX)NM) -g -f p $(1) | cut -f1-2 -d" " >> $(2)
-endef
diff --git a/core/combo/HOST_CROSS_windows-x86_64.mk b/core/combo/HOST_CROSS_windows-x86_64.mk
deleted file mode 100644
index d924901..0000000
--- a/core/combo/HOST_CROSS_windows-x86_64.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Copyright (C) 2006 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.
-#
-
-# Settings to use MinGW as a cross-compiler under Linux
-# Included by combo/select.make
-
-define $(combo_var_prefix)transform-shared-lib-to-toc
-$(hide) $($(PRIVATE_2ND_ARCH_VAR_PREFIX)$(PRIVATE_PREFIX)OBJDUMP) -x $(1) | grep "^Name" | cut -f3 -d" " > $(2)
-$(hide) $($(PRIVATE_2ND_ARCH_VAR_PREFIX)$(PRIVATE_PREFIX)NM) -g -f p $(1) | cut -f1-2 -d" " >> $(2)
-endef
diff --git a/core/combo/select.mk b/core/combo/select.mk
index 33c8e6d..7617558 100644
--- a/core/combo/select.mk
+++ b/core/combo/select.mk
@@ -27,6 +27,13 @@
 combo_var_prefix := $(combo_2nd_arch_prefix)$(combo_target)
 
 # Set reasonable defaults for the various variables
+ifeq ($(combo_target),HOST_CROSS_)
+$(KATI_obsolete_var \
+  $(combo_var_prefix)GLOBAL_ARFLAGS \
+  $(combo_var_prefix)STATIC_LIB_SUFFIX \
+  $(combo_var_prefix)transform-shared-lib-to-toc \
+  ,HOST_CROSS builds are not supported in Make)
+else
 
 $(combo_var_prefix)GLOBAL_ARFLAGS := crsPD -format=gnu
 
@@ -34,3 +41,5 @@
 
 # Now include the combo for this specific target.
 include $(BUILD_COMBOS)/$(combo_target)$(combo_os_arch).mk
+
+endif
diff --git a/core/config.mk b/core/config.mk
index 4794816..bfff84e 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -831,6 +831,15 @@
 sepolicy_major_vers :=
 sepolicy_minor_vers :=
 
+# BOARD_SEPOLICY_VERS must take the format "NN.m" and contain the sepolicy
+# version identifier corresponding to the sepolicy on which the non-platform
+# policy is to be based. If unspecified, this will build against the current
+# public platform policy in tree
+ifndef BOARD_SEPOLICY_VERS
+# The default platform policy version.
+BOARD_SEPOLICY_VERS := $(PLATFORM_SEPOLICY_VERSION)
+endif
+
 # A list of SEPolicy versions, besides PLATFORM_SEPOLICY_VERSION, that the framework supports.
 PLATFORM_SEPOLICY_COMPAT_VERSIONS := \
     28.0 \
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 21eac7f..b673050 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -167,6 +167,10 @@
   else
     $(error Unsupported HOST_CROSS_OS $(HOST_CROSS_OS))
   endif
+else ifeq ($(HOST_OS),darwin)
+  HOST_CROSS_OS := darwin
+  HOST_CROSS_ARCH := arm64
+  HOST_CROSS_2ND_ARCH :=
 endif
 
 ifeq ($(HOST_OS),)
diff --git a/core/notice_files.mk b/core/notice_files.mk
index b3eedc0..4edbbb8 100644
--- a/core/notice_files.mk
+++ b/core/notice_files.mk
@@ -136,16 +136,23 @@
 
   ALL_MODULES.$(my_register_name).META_LIC := $(strip $(ALL_MODULES.$(my_register_name).META_LIC) $(module_license_metadata))
 
-  ALL_MODULES.$(my_register_name).DELAYED_META_LIC := $(strip $(ALL_MODULES.$(my_register_name).DELAYED_META_LIC) $(module_license_metadata))
-  ALL_MODULES.$(my_register_name).LICENSE_PACKAGE_NAME := $(strip $(license_package_name))
-  ALL_MODULES.$(my_register_name).MODULE_TYPE := $(strip $(ALL_MODULES.$(my_register_name).MODULE_TYPE) $(LOCAL_MODULE_TYPE))
-  ALL_MODULES.$(my_register_name).MODULE_CLASS := $(strip $(ALL_MODULES.$(my_register_name).MODULE_CLASS) $(LOCAL_MODULE_CLASS))
-  ALL_MODULES.$(my_register_name).LICENSE_KINDS := $(ALL_MODULES.$(my_register_name).LICENSE_KINDS) $(license_kinds)
-  ALL_MODULES.$(my_register_name).LICENSE_CONDITIONS := $(ALL_MODULES.$(my_register_name).LICENSE_CONDITIONS) $(license_conditions)
-  ALL_MODULES.$(my_register_name).LICENSE_INSTALL_MAP := $(ALL_MODULES.$(my_register_name).LICENSE_INSTALL_MAP) $(install_map)
-  ALL_MODULES.$(my_register_name).NOTICE_DEPS := $(ALL_MODULES.$(my_register_name).NOTICE_DEPS) $(notice_deps)
-  ALL_MODULES.$(my_register_name).IS_CONTAINER := $(strip $(filter-out false,$(ALL_MODULES.$(my_register_name).IS_CONTAINER) $(is_container)))
-  ALL_MODULES.$(my_register_name).PATH := $(strip $(ALL_MODULES.$(my_register_name).PATH) $(local_path))
+  ifdef LOCAL_SOONG_LICENSE_METADATA
+    # Soong modules have already produced a license metadata file, copy it to where Make expects it.
+    $(eval $(call copy-one-file, $(LOCAL_SOONG_LICENSE_METADATA), $(module_license_metadata)))
+  else
+    # Make modules don't have enough information to produce a license metadata rule until after fix-notice-deps
+    # has been called, store the necessary information until later.
+    ALL_MODULES.$(my_register_name).DELAYED_META_LIC := $(strip $(ALL_MODULES.$(my_register_name).DELAYED_META_LIC) $(module_license_metadata))
+    ALL_MODULES.$(my_register_name).LICENSE_PACKAGE_NAME := $(strip $(license_package_name))
+    ALL_MODULES.$(my_register_name).MODULE_TYPE := $(strip $(ALL_MODULES.$(my_register_name).MODULE_TYPE) $(LOCAL_MODULE_TYPE))
+    ALL_MODULES.$(my_register_name).MODULE_CLASS := $(strip $(ALL_MODULES.$(my_register_name).MODULE_CLASS) $(LOCAL_MODULE_CLASS))
+    ALL_MODULES.$(my_register_name).LICENSE_KINDS := $(ALL_MODULES.$(my_register_name).LICENSE_KINDS) $(license_kinds)
+    ALL_MODULES.$(my_register_name).LICENSE_CONDITIONS := $(ALL_MODULES.$(my_register_name).LICENSE_CONDITIONS) $(license_conditions)
+    ALL_MODULES.$(my_register_name).LICENSE_INSTALL_MAP := $(ALL_MODULES.$(my_register_name).LICENSE_INSTALL_MAP) $(install_map)
+    ALL_MODULES.$(my_register_name).NOTICE_DEPS := $(ALL_MODULES.$(my_register_name).NOTICE_DEPS) $(notice_deps)
+    ALL_MODULES.$(my_register_name).IS_CONTAINER := $(strip $(filter-out false,$(ALL_MODULES.$(my_register_name).IS_CONTAINER) $(is_container)))
+    ALL_MODULES.$(my_register_name).PATH := $(strip $(ALL_MODULES.$(my_register_name).PATH) $(local_path))
+  endif
 endif
 
 ifdef notice_file
diff --git a/core/product_config.rbc b/core/product_config.rbc
index 45eca9f..f26b428 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -533,7 +533,10 @@
 
 def _expand_wildcard(pattern):
     """Expands shell wildcard pattern."""
-    return rblf_wildcard(pattern)
+    result = []
+    for word in __words(pattern):
+        result.extend(rblf_wildcard(word))
+    return result
 
 def _mkdist_for_goals(g, goal, src_dst_list):
     """Implements dist-for-goals macro."""
diff --git a/core/soong_config.mk b/core/soong_config.mk
index a48b4d8..617abdf 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -189,6 +189,7 @@
 
 $(call add_json_list, PgoAdditionalProfileDirs,          $(PGO_ADDITIONAL_PROFILE_DIRS))
 
+$(call add_json_list, BoardPlatVendorPolicy,             $(BOARD_PLAT_VENDOR_POLICY))
 $(call add_json_list, BoardReqdMaskPolicy,               $(BOARD_REQD_MASK_POLICY))
 $(call add_json_list, BoardVendorSepolicyDirs,           $(BOARD_VENDOR_SEPOLICY_DIRS) $(BOARD_SEPOLICY_DIRS))
 $(call add_json_list, BoardOdmSepolicyDirs,              $(BOARD_ODM_SEPOLICY_DIRS))
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 1f1ec3f..8432513 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -85,7 +85,7 @@
     #  It must be of the form "YYYY-MM-DD" on production devices.
     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
-      PLATFORM_SECURITY_PATCH := 2021-11-05
+    PLATFORM_SECURITY_PATCH := 2021-11-05
 endif
 .KATI_READONLY := PLATFORM_SECURITY_PATCH
 
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index 94917f5..b1266ee 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -34,7 +34,7 @@
 # GSI should always support up-to-date platform features.
 # Keep this value at the latest API level to ensure latest build system
 # default configs are applied.
-PRODUCT_SHIPPING_API_LEVEL := 30
+PRODUCT_SHIPPING_API_LEVEL := 31
 
 # Enable dynamic partitions to facilitate mixing onto Cuttlefish
 PRODUCT_USE_DYNAMIC_PARTITIONS := true
@@ -62,8 +62,12 @@
     init.gsi.rc \
     init.vndk-nodef.rc \
 
-# Support additional P, Q and R VNDK packages
-PRODUCT_EXTRA_VNDK_VERSIONS := 28 29 30
+# Support additional VNDK snapshots
+PRODUCT_EXTRA_VNDK_VERSIONS := \
+    28 \
+    29 \
+    30 \
+    31 \
 
 # Do not build non-GSI partition images.
 PRODUCT_BUILD_CACHE_IMAGE := false
diff --git a/target/product/virtual_ab_ota/compression.mk b/target/product/virtual_ab_ota/compression.mk
index 8301047..88c58b8 100644
--- a/target/product/virtual_ab_ota/compression.mk
+++ b/target/product/virtual_ab_ota/compression.mk
@@ -17,6 +17,7 @@
 $(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota/launch_with_vendor_ramdisk.mk)
 
 PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.enabled=true
+PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true
 PRODUCT_VIRTUAL_AB_COMPRESSION := true
 PRODUCT_PACKAGES += \
     snapuserd.vendor_ramdisk \
diff --git a/tests/run.rbc b/tests/run.rbc
index 53eda16..b82887f 100644
--- a/tests/run.rbc
+++ b/tests/run.rbc
@@ -59,6 +59,19 @@
 assert_eq("", rblf.notdir("/"))
 assert_eq("", rblf.notdir(""))
 
+assert_eq(
+    ["build/make/tests/board.rbc", "build/make/tests/board_input_vars.rbc"],
+    rblf.expand_wildcard("build/make/tests/board*.rbc")
+)
+assert_eq(
+    ["build/make/tests/run.rbc", "build/make/tests/product.rbc"],
+    rblf.expand_wildcard("build/make/tests/run.rbc build/make/tests/product.rbc")
+)
+assert_eq(
+    ["build/make/tests/run.rbc"],
+    rblf.expand_wildcard("build/make/tests/run.rbc build/make/tests/nonexistent.rbc")
+)
+
 (globals, config, globals_base) = rblf.product_configuration("test/device", init, input_variables_init)
 assert_eq(
     {
diff --git a/tools/compliance/actionset.go b/tools/compliance/actionset.go
index d575321..656c5de 100644
--- a/tools/compliance/actionset.go
+++ b/tools/compliance/actionset.go
@@ -108,3 +108,12 @@
 	}
 	return true
 }
+
+// conditions returns the set of conditions resolved by the action set.
+func (as actionSet) conditions() *LicenseConditionSet {
+	result := newLicenseConditionSet()
+	for _, cs := range as {
+		result.AddSet(cs)
+	}
+	return result
+}
diff --git a/tools/compliance/cmd/dumpresolutions_test.go b/tools/compliance/cmd/dumpresolutions_test.go
index 1328a36..cab1cc8 100644
--- a/tools/compliance/cmd/dumpresolutions_test.go
+++ b/tools/compliance/cmd/dumpresolutions_test.go
@@ -577,7 +577,9 @@
 				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
 				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
 				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
+				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice",
 			},
 		},
@@ -610,7 +612,9 @@
 				"highest.apex.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
 				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
 				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
 				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
+				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
 				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice",
 			},
 		},
@@ -723,7 +727,9 @@
 				"highest.apex.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
 				"lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted restricted",
 				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
+				"lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/liba.so.meta_lic:restricted restricted",
 				"lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal",
+				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
 				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice",
 			},
 		},
@@ -755,7 +761,9 @@
 				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
 				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
 				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
+				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice",
 			},
 		},
@@ -772,6 +780,7 @@
 				"testdata/restricted/application.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 				"testdata/restricted/bin/bin3.meta_lic testdata/restricted/bin/bin3.meta_lic testdata/restricted/bin/bin3.meta_lic restricted",
 				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
+				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 			},
 		},
@@ -786,6 +795,7 @@
 				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
 				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
 				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
+				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
 				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
 			},
 		},
@@ -821,6 +831,7 @@
 				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
 				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 				"testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
+				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice",
 			},
 		},
@@ -849,6 +860,7 @@
 				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic by_exception_only:proprietary",
 				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
 				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic by_exception_only:proprietary",
+				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
 				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice",
 			},
 		},
@@ -950,6 +962,7 @@
 				"lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
 				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
 				"lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
+				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
 				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice",
 			},
 		},
@@ -977,6 +990,7 @@
 				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
 				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 				"testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
+				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice",
 			},
 		},
@@ -992,6 +1006,7 @@
 				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 				"testdata/proprietary/bin/bin3.meta_lic testdata/proprietary/bin/bin3.meta_lic testdata/proprietary/bin/bin3.meta_lic restricted",
 				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
+				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 			},
 		},
@@ -2886,11 +2901,21 @@
 				matchResolution(
 					"testdata/restricted/lib/libc.a.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/restricted/lib/libd.so.meta_lic",
 					"testdata/restricted/lib/libd.so.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/lib/libd.so.meta_lic",
+					"testdata/restricted/lib/libd.so.meta_lic",
 					"testdata/restricted/lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -3026,11 +3051,21 @@
 				matchResolution(
 					"lib/libc.a.meta_lic",
 					"lib/libc.a.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"lib/libc.a.meta_lic",
+					"lib/libc.a.meta_lic",
 					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"lib/libd.so.meta_lic",
+					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -3409,11 +3444,21 @@
 				matchResolution(
 					"lib/libc.a.meta_lic",
 					"lib/libc.a.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"lib/libc.a.meta_lic",
+					"lib/libc.a.meta_lic",
 					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"lib/libd.so.meta_lic",
+					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -3548,11 +3593,21 @@
 				matchResolution(
 					"testdata/restricted/lib/libc.a.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/restricted/lib/libd.so.meta_lic",
 					"testdata/restricted/lib/libd.so.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/lib/libd.so.meta_lic",
+					"testdata/restricted/lib/libd.so.meta_lic",
 					"testdata/restricted/lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -3607,6 +3662,11 @@
 					"testdata/restricted/lib/liba.so.meta_lic",
 					"restricted"),
 				matchResolution(
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
 					"testdata/restricted/lib/libb.so.meta_lic",
 					"testdata/restricted/lib/libb.so.meta_lic",
 					"testdata/restricted/lib/libb.so.meta_lic",
@@ -3654,6 +3714,11 @@
 				matchResolution(
 					"testdata/restricted/lib/libc.a.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
 					"reciprocal"),
 			},
@@ -3789,6 +3854,11 @@
 				matchResolution(
 					"testdata/proprietary/lib/libd.so.meta_lic",
 					"testdata/proprietary/lib/libd.so.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/proprietary/lib/libd.so.meta_lic",
+					"testdata/proprietary/lib/libd.so.meta_lic",
 					"testdata/proprietary/lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -3912,6 +3982,11 @@
 				matchResolution(
 					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"lib/libd.so.meta_lic",
+					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -4240,6 +4315,11 @@
 				matchResolution(
 					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"lib/libd.so.meta_lic",
+					"lib/libd.so.meta_lic",
 					"lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -4362,6 +4442,11 @@
 				matchResolution(
 					"testdata/proprietary/lib/libd.so.meta_lic",
 					"testdata/proprietary/lib/libd.so.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/proprietary/lib/libd.so.meta_lic",
+					"testdata/proprietary/lib/libd.so.meta_lic",
 					"testdata/proprietary/lib/libd.so.meta_lic",
 					"notice"),
 			},
@@ -4413,6 +4498,11 @@
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
 					"testdata/proprietary/lib/libb.so.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
diff --git a/tools/compliance/policy/resolve.go b/tools/compliance/policy/resolve.go
index 9962e68..58547f8 100644
--- a/tools/compliance/policy/resolve.go
+++ b/tools/compliance/policy/resolve.go
@@ -41,59 +41,7 @@
 	// must be indexed for fast lookup
 	lg.indexForward()
 
-	rs = newResolutionSet()
-
-	// cmap contains an entry for every target that was previously walked as a pure aggregate only.
-	cmap := make(map[string]bool)
-
-	var walk func(f string, treatAsAggregate bool) actionSet
-
-	walk = func(f string, treatAsAggregate bool) actionSet {
-		target := lg.targets[f]
-		result := make(actionSet)
-		result[target] = newLicenseConditionSet()
-		result[target].add(target, target.proto.LicenseConditions...)
-		if preresolved, ok := rs.resolutions[target]; ok {
-			if treatAsAggregate {
-				result.addSet(preresolved)
-				return result
-			}
-			if _, asAggregate := cmap[f]; !asAggregate {
-				result.addSet(preresolved)
-				return result
-			}
-			// previously walked in a pure aggregate context,
-			// needs to walk again in non-aggregate context
-			delete(cmap, f)
-		}
-		if treatAsAggregate {
-			cmap[f] = true
-		}
-
-		// add all the conditions from all the dependencies
-		for _, edge := range lg.index[f] {
-			// walk dependency to get its conditions
-			as := walk(edge.dependency, treatAsAggregate && lg.targets[edge.dependency].IsContainer())
-
-			// turn those into the conditions that apply to the target
-			as = depActionsApplicableToTarget(TargetEdge{lg, edge}, as, treatAsAggregate)
-
-			// add them to the result
-			result.addSet(as)
-		}
-
-		// record these conditions as applicable to the target
-		rs.addConditions(target, result)
-		rs.addSelf(target, result.byName(ImpliesRestricted))
-
-		// return this up the tree
-		return result
-	}
-
-	// walk each of the roots
-	for _, r := range lg.rootFiles {
-		_ = walk(r, lg.targets[r].IsContainer())
-	}
+	rs = resolveBottomUp(lg, make(map[*TargetNode]actionSet) /* empty map; no prior resolves */)
 
 	// if not yet cached, save the result
 	lg.mu.Lock()
@@ -133,61 +81,61 @@
 	//
 	// rmap is the resulting ResolutionSet
 	rmap := make(map[*TargetNode]actionSet)
-	for attachesTo, as := range rs.resolutions {
-		rmap[attachesTo] = as.copy()
-	}
 
-	path := make([]*dependencyEdge, 0, 32)
+	// cmap contains the set of targets walked as pure aggregates. i.e. containers
+	cmap := make(map[*TargetNode]bool)
 
-	var walk func(f string, cs *LicenseConditionSet, treatAsAggregate bool)
+	var walk func(fnode *TargetNode, cs *LicenseConditionSet, treatAsAggregate bool)
 
-	walk = func(f string, cs *LicenseConditionSet, treatAsAggregate bool) {
-		fnode := lg.targets[f]
-		if !cs.IsEmpty() {
-			parentsAllAggregate := true
-			for _, e := range path {
-				target := lg.targets[e.target]
-				if _, ok := rmap[target]; !ok {
-					rmap[target] = make(actionSet)
-				}
-				rmap[target].add(fnode, cs)
-				if !target.IsContainer() {
-					parentsAllAggregate = false
-					break
-				}
-			}
-			if parentsAllAggregate {
-				if _, ok := rmap[fnode]; !ok {
-					rmap[fnode] = make(actionSet)
-				}
-				rmap[fnode].add(fnode, cs)
-			}
+	walk = func(fnode *TargetNode, cs *LicenseConditionSet, treatAsAggregate bool) {
+		if _, ok := rmap[fnode]; !ok {
+			rmap[fnode] = make(actionSet)
 		}
-		// add conditions attached to `f`
+		rmap[fnode].add(fnode, cs)
+		if treatAsAggregate {
+			cmap[fnode] = true
+		}
+		// add conditions attached to `fnode`
 		cs = cs.Copy()
 		for _, fcs := range rs.resolutions[fnode] {
 			cs.AddSet(fcs)
 		}
 		// for each dependency
-		for _, edge := range lg.index[f] {
+		for _, edge := range lg.index[fnode.name] {
 			e := TargetEdge{lg, edge}
 			// dcs holds the dpendency conditions inherited from the target
 			dcs := targetConditionsApplicableToDep(e, cs, treatAsAggregate)
-			if dcs.IsEmpty() {
-				if !treatAsAggregate || (!edgeIsDerivation(e) && !edgeIsDynamicLink(e)) {
-					continue
+			if dcs.IsEmpty() && !treatAsAggregate {
+				continue
+			}
+			dnode := lg.targets[edge.dependency]
+			if as, alreadyWalked := rmap[dnode]; alreadyWalked {
+				diff := dcs.Copy()
+				diff.RemoveSet(as.conditions())
+				if diff.IsEmpty() {
+					// no new conditions
+
+					// pure aggregates never need walking a 2nd time with same conditions
+					if treatAsAggregate {
+						continue
+					}
+					// non-aggregates don't need walking as non-aggregate a 2nd time
+					if _, asAggregate := cmap[dnode]; !asAggregate {
+						continue
+					}
+					// previously walked as pure aggregate; need to re-walk as non-aggregate
+					delete(cmap, dnode)
 				}
 			}
-			path = append(path, edge)
 			// add the conditions to the dependency
-			walk(edge.dependency, dcs, treatAsAggregate && lg.targets[edge.dependency].IsContainer())
-			path = path[:len(path)-1]
+			walk(dnode, dcs, treatAsAggregate && lg.targets[edge.dependency].IsContainer())
 		}
 	}
 
 	// walk each of the roots
 	for _, r := range lg.rootFiles {
-		as, ok := rs.resolutions[lg.targets[r]]
+		rnode := lg.targets[r]
+		as, ok := rs.resolutions[rnode]
 		if !ok {
 			// no conditions in root or transitive closure of dependencies
 			continue
@@ -196,12 +144,21 @@
 			continue
 		}
 
-		path = path[:0]
 		// add the conditions to the root and its transitive closure
-		walk(r, newLicenseConditionSet(), lg.targets[r].IsContainer())
+		walk(rnode, newLicenseConditionSet(), lg.targets[r].IsContainer())
 	}
 
-	rs = &ResolutionSet{rmap}
+	// back-fill any bottom-up conditions on targets missed by top-down walk
+	for attachesTo, as := range rs.resolutions {
+		if _, ok := rmap[attachesTo]; !ok {
+			rmap[attachesTo] = as.copy()
+		} else {
+			rmap[attachesTo].addSet(as)
+		}
+	}
+
+	// propagate any new conditions back up the graph
+	rs = resolveBottomUp(lg, rmap)
 
 	// if not yet cached, save the result
 	lg.mu.Lock()
@@ -215,3 +172,70 @@
 
 	return rs
 }
+
+// resolveBottomUp implements a bottom-up resolve propagating conditions both
+// from the graph, and from a `priors` map of resolutions.
+func resolveBottomUp(lg *LicenseGraph, priors map[*TargetNode]actionSet) *ResolutionSet {
+	rs := newResolutionSet()
+
+	// cmap contains an entry for every target that was previously walked as a pure aggregate only.
+	cmap := make(map[string]bool)
+
+	var walk func(f string, treatAsAggregate bool) actionSet
+
+	walk = func(f string, treatAsAggregate bool) actionSet {
+		target := lg.targets[f]
+		result := make(actionSet)
+		result[target] = newLicenseConditionSet()
+		result[target].add(target, target.proto.LicenseConditions...)
+		if pas, ok := priors[target]; ok {
+			result.addSet(pas)
+		}
+		if preresolved, ok := rs.resolutions[target]; ok {
+			if treatAsAggregate {
+				result.addSet(preresolved)
+				return result
+			}
+			if _, asAggregate := cmap[f]; !asAggregate {
+				result.addSet(preresolved)
+				return result
+			}
+			// previously walked in a pure aggregate context,
+			// needs to walk again in non-aggregate context
+			delete(cmap, f)
+		}
+		if treatAsAggregate {
+			cmap[f] = true
+		}
+
+		// add all the conditions from all the dependencies
+		for _, edge := range lg.index[f] {
+			// walk dependency to get its conditions
+			as := walk(edge.dependency, treatAsAggregate && lg.targets[edge.dependency].IsContainer())
+
+			// turn those into the conditions that apply to the target
+			as = depActionsApplicableToTarget(TargetEdge{lg, edge}, as, treatAsAggregate)
+
+			// add them to the result
+			result.addSet(as)
+		}
+
+		// record these conditions as applicable to the target
+		rs.addConditions(target, result)
+		if len(priors) == 0 {
+			// on the first bottom-up resolve, parents have their own sharing and notice needs
+			// on the later resolve, if priors is empty, there will be nothing new to add
+			rs.addSelf(target, result.byName(ImpliesRestricted))
+		}
+
+		// return this up the tree
+		return result
+	}
+
+	// walk each of the roots
+	for _, r := range lg.rootFiles {
+		_ = walk(r, lg.targets[r].IsContainer())
+	}
+
+	return rs
+}
diff --git a/tools/compliance/policy/resolve_test.go b/tools/compliance/policy/resolve_test.go
index aa5bb2a..4c99d35 100644
--- a/tools/compliance/policy/resolve_test.go
+++ b/tools/compliance/policy/resolve_test.go
@@ -434,6 +434,7 @@
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
@@ -480,6 +481,7 @@
 				{"mitBin.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"},
 				{"mitBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+				{"mplLib.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"mplLib.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
 			},
 		},
@@ -512,6 +514,7 @@
 				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
@@ -540,6 +543,7 @@
 				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"mitBin.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+				{"mplLib.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"mplLib.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
 			},
 		},
@@ -573,6 +577,7 @@
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
 				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
@@ -612,6 +617,7 @@
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
 				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
@@ -687,6 +693,7 @@
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
@@ -704,6 +711,7 @@
 				{"dependentModule.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 				{"dependentModule.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
@@ -735,6 +743,7 @@
 				{"dependentModule.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 				{"dependentModule.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
diff --git a/tools/compliance/policy/resolvenotices_test.go b/tools/compliance/policy/resolvenotices_test.go
index b428d5b..275c0a5 100644
--- a/tools/compliance/policy/resolvenotices_test.go
+++ b/tools/compliance/policy/resolvenotices_test.go
@@ -153,6 +153,7 @@
 				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
 				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
 				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
 			},
 		},
diff --git a/tools/compliance/policy/resolveshare_test.go b/tools/compliance/policy/resolveshare_test.go
index 7371ccf..ad3630d 100644
--- a/tools/compliance/policy/resolveshare_test.go
+++ b/tools/compliance/policy/resolveshare_test.go
@@ -176,6 +176,7 @@
 			expectedResolutions: []res{
 				{"gplBin.meta_lic", "gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
 				{"gplBin.meta_lic", "apacheLib.meta_lic", "gplBin.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "gplBin.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -218,6 +219,7 @@
 			expectedResolutions: []res{
 				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 			},
 		},
 		{
diff --git a/tools/compliance/policy/walk_test.go b/tools/compliance/policy/walk_test.go
index 2eef702..07710aa 100644
--- a/tools/compliance/policy/walk_test.go
+++ b/tools/compliance/policy/walk_test.go
@@ -336,6 +336,7 @@
 			expectedResolutions: []res{
 				{"gplBin.meta_lic", "gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
 				{"gplBin.meta_lic", "apacheLib.meta_lic", "gplBin.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "gplBin.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -428,6 +429,7 @@
 			expectedResolutions: []res{
 				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
 			},
 		},
 		{
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index a979a8e..bf7f9a0 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -553,6 +553,19 @@
     ],
 }
 
+python_binary_host {
+    name: "fsverity_metadata_generator",
+    srcs: [
+        "fsverity_metadata_generator.py",
+    ],
+    libs: [
+        "fsverity_digests_proto_python",
+    ],
+    required: [
+        "fsverity",
+    ],
+}
+
 //
 // Tests.
 //
diff --git a/tools/releasetools/fsverity_metadata_generator.py b/tools/releasetools/fsverity_metadata_generator.py
index 666efd5..a300d2e 100644
--- a/tools/releasetools/fsverity_metadata_generator.py
+++ b/tools/releasetools/fsverity_metadata_generator.py
@@ -55,6 +55,9 @@
     self.set_hash_alg("sha256")
     self.set_signature('none')
 
+  def set_key_format(self, key_format):
+    self._key_format = key_format
+
   def set_key(self, key):
     self._key = key
 
@@ -130,14 +133,17 @@
       cmd.append(input_file)
       cmd.append(sig_file)
 
-      # convert DER private key to PEM
-      pem_key = os.path.join(work_dir, 'key.pem')
-      key_cmd = ['openssl', 'pkcs8']
-      key_cmd.extend(['-inform', 'DER'])
-      key_cmd.extend(['-in', self._key])
-      key_cmd.extend(['-nocrypt'])
-      key_cmd.extend(['-out', pem_key])
-      subprocess.check_call(key_cmd)
+      # If key is DER, convert DER private key to PEM
+      if self._key_format == 'der':
+        pem_key = os.path.join(work_dir, 'key.pem')
+        key_cmd = ['openssl', 'pkcs8']
+        key_cmd.extend(['-inform', 'DER'])
+        key_cmd.extend(['-in', self._key])
+        key_cmd.extend(['-nocrypt'])
+        key_cmd.extend(['-out', pem_key])
+        subprocess.check_call(key_cmd)
+      else:
+        pem_key = self._key
 
       cmd.extend(['--key', pem_key])
       cmd.extend(['--cert', self._cert])
@@ -196,8 +202,13 @@
       'input',
       help='input file to be signed')
   p.add_argument(
+      '--key-format',
+      choices=['pem', 'der'],
+      default='der',
+      help='format of the input key. Default is der')
+  p.add_argument(
       '--key',
-      help='PKCS#8 private key file in DER format')
+      help='PKCS#8 private key file')
   p.add_argument(
       '--cert',
       help='x509 certificate file in PEM format')
@@ -227,5 +238,6 @@
       raise ValueError("To generate signature, key and cert must be set")
     generator.set_key(args.key)
     generator.set_cert(args.cert)
+  generator.set_key_format(args.key_format)
   generator.set_hash_alg(args.hash_alg)
   generator.generate(args.input, args.output)