Merge "Add netd-client for tethering apex and update allowed-deps.txt"
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 49671df..57b18de 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -384,6 +384,7 @@
 libring(minSdkVersion:29)
 libring-core(minSdkVersion:29)
 librustc_demangle.rust_sysroot(minSdkVersion:29)
+libsdk_proto(minSdkVersion:30)
 libsfplugin_ccodec_utils(minSdkVersion:29)
 libsonivoxwithoutjet(minSdkVersion:29)
 libspeexresampler(minSdkVersion:29)
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 69d4fde..404be8c 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -16,6 +16,8 @@
 
 import (
 	"encoding/json"
+	"fmt"
+	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
@@ -24,8 +26,14 @@
 // artifact contains relevant portions of Bazel's aquery proto, Artifact.
 // Represents a single artifact, whether it's a source file or a derived output file.
 type artifact struct {
-	Id       string
-	ExecPath string
+	Id             int
+	PathFragmentId int
+}
+
+type pathFragment struct {
+	Id       int
+	Label    string
+	ParentId int
 }
 
 // KeyValuePair represents Bazel's aquery proto, KeyValuePair.
@@ -38,9 +46,9 @@
 // Represents a data structure containing one or more files. Depsets in Bazel are an efficient
 // data structure for storing large numbers of file paths.
 type depSetOfFiles struct {
-	Id string
+	Id int
 	// TODO(cparsons): Handle non-flat depsets.
-	DirectArtifactIds []string
+	DirectArtifactIds []int
 }
 
 // action contains relevant portions of Bazel's aquery proto, Action.
@@ -48,9 +56,9 @@
 type action struct {
 	Arguments            []string
 	EnvironmentVariables []KeyValuePair
-	InputDepSetIds       []string
+	InputDepSetIds       []int
 	Mnemonic             string
-	OutputIds            []string
+	OutputIds            []int
 }
 
 // actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
@@ -59,6 +67,7 @@
 	Artifacts     []artifact
 	Actions       []action
 	DepSetOfFiles []depSetOfFiles
+	PathFragments []pathFragment
 }
 
 // BuildStatement contains information to register a build statement corresponding (one to one)
@@ -80,11 +89,20 @@
 	var aqueryResult actionGraphContainer
 	json.Unmarshal(aqueryJsonProto, &aqueryResult)
 
-	artifactIdToPath := map[string]string{}
-	for _, artifact := range aqueryResult.Artifacts {
-		artifactIdToPath[artifact.Id] = artifact.ExecPath
+	pathFragments := map[int]pathFragment{}
+	for _, pathFragment := range aqueryResult.PathFragments {
+		pathFragments[pathFragment.Id] = pathFragment
 	}
-	depsetIdToArtifactIds := map[string][]string{}
+	artifactIdToPath := map[int]string{}
+	for _, artifact := range aqueryResult.Artifacts {
+		artifactPath, err := expandPathFragment(artifact.PathFragmentId, pathFragments)
+		if err != nil {
+			// TODO(cparsons): Better error handling.
+			panic(err.Error())
+		}
+		artifactIdToPath[artifact.Id] = artifactPath
+	}
+	depsetIdToArtifactIds := map[int][]int{}
 	for _, depset := range aqueryResult.DepSetOfFiles {
 		depsetIdToArtifactIds[depset.Id] = depset.DirectArtifactIds
 	}
@@ -114,3 +132,18 @@
 
 	return buildStatements
 }
+
+func expandPathFragment(id int, pathFragmentsMap map[int]pathFragment) (string, error) {
+	labels := []string{}
+	currId := id
+	// Only positive IDs are valid for path fragments. An ID of zero indicates a terminal node.
+	for currId > 0 {
+		currFragment, ok := pathFragmentsMap[currId]
+		if !ok {
+			return "", fmt.Errorf("undefined path fragment id '%s'", currId)
+		}
+		labels = append([]string{currFragment.Label}, labels...)
+		currId = currFragment.ParentId
+	}
+	return filepath.Join(labels...), nil
+}
diff --git a/cc/cc.go b/cc/cc.go
index f45b654..c0c85f9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -57,14 +57,14 @@
 	})
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("asan_deps", sanitizerDepsMutator(asan))
-		ctx.BottomUp("asan", sanitizerMutator(asan)).Parallel()
+		ctx.TopDown("asan_deps", sanitizerDepsMutator(Asan))
+		ctx.BottomUp("asan", sanitizerMutator(Asan)).Parallel()
 
 		ctx.TopDown("hwasan_deps", sanitizerDepsMutator(hwasan))
 		ctx.BottomUp("hwasan", sanitizerMutator(hwasan)).Parallel()
 
-		ctx.TopDown("fuzzer_deps", sanitizerDepsMutator(fuzzer))
-		ctx.BottomUp("fuzzer", sanitizerMutator(fuzzer)).Parallel()
+		ctx.TopDown("fuzzer_deps", sanitizerDepsMutator(Fuzzer))
+		ctx.BottomUp("fuzzer", sanitizerMutator(Fuzzer)).Parallel()
 
 		// cfi mutator shouldn't run before sanitizers that return true for
 		// incompatibleWithCfi()
@@ -369,10 +369,7 @@
 	// If set to false, this module becomes inaccessible from /vendor modules.
 	//
 	// The modules with vndk: {enabled: true} must define 'vendor_available'
-	// to either 'true' or 'false'. In this case, 'vendor_available: false' has
-	// a different meaning than that of non-VNDK modules.
-	// 'vendor_available: false' for a VNDK module means 'VNDK-private' that
-	// can only be depended on by VNDK libraries, not by non-VNDK vendor modules.
+	// to 'true'.
 	//
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	Vendor_available *bool
@@ -394,13 +391,6 @@
 	// vndk: {enabled: true} don't have to define 'product_available'. The VNDK
 	// library without 'product_available' may not be depended on by any other
 	// modules that has product variants including the product available VNDKs.
-	// However, for the modules with vndk: {enabled: true},
-	// 'product_available: false' creates the product variant that is available
-	// only for the other product available VNDK modules but not by non-VNDK
-	// product modules.
-	// In the case of the modules with vndk: {enabled: true}, if
-	// 'product_available' is defined, it must have the same value with the
-	// 'vendor_available'.
 	//
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	// and PRODUCT_PRODUCT_VNDK_VERSION isn't set.
@@ -785,6 +775,14 @@
 	hideApexVariantFromMake bool
 }
 
+func (c *Module) SetPreventInstall() {
+	c.Properties.PreventInstall = true
+}
+
+func (c *Module) SetHideFromMake() {
+	c.Properties.HideFromMake = true
+}
+
 func (c *Module) Toc() android.OptionalPath {
 	if c.linker != nil {
 		if library, ok := c.linker.(libraryInterface); ok {
@@ -1026,7 +1024,7 @@
 
 // Returns true for dependency roots (binaries)
 // TODO(ccross): also handle dlopenable libraries
-func (c *Module) isDependencyRoot() bool {
+func (c *Module) IsDependencyRoot() bool {
 	if root, ok := c.linker.(interface {
 		isDependencyRoot() bool
 	}); ok {
@@ -1264,7 +1262,7 @@
 }
 
 func (ctx *moduleContextImpl) header() bool {
-	return ctx.mod.header()
+	return ctx.mod.Header()
 }
 
 func (ctx *moduleContextImpl) binary() bool {
@@ -1421,6 +1419,10 @@
 	return nil
 }
 
+func (c *Module) IsPrebuilt() bool {
+	return c.Prebuilt() != nil
+}
+
 func (c *Module) Name() string {
 	name := c.ModuleBase.Name()
 	if p, ok := c.linker.(interface {
@@ -2847,7 +2849,7 @@
 				return baseName + ".vendor"
 			}
 
-			if c.inVendor() && vendorSuffixModules[baseName] {
+			if c.InVendor() && vendorSuffixModules[baseName] {
 				return baseName + ".vendor"
 			} else if c.InRecovery() && recoverySuffixModules[baseName] {
 				return baseName + ".recovery"
@@ -2959,7 +2961,8 @@
 	return false
 }
 
-func (c *Module) header() bool {
+// Header returns true if the module is a header-only variant. (See cc/library.go header()).
+func (c *Module) Header() bool {
 	if h, ok := c.linker.(interface {
 		header() bool
 	}); ok {
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 6b17c48..d7da5ab 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -41,6 +41,12 @@
 	// Specify who should be acknowledged for CVEs in the Android Security
 	// Bulletin.
 	Acknowledgement []string `json:"acknowledgement,omitempty"`
+	// Additional options to be passed to libfuzzer when run in Haiku.
+	Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
+	// Additional options to be passed to HWASAN when running on-device in Haiku.
+	Hwasan_options []string `json:"hwasan_options,omitempty"`
+	// Additional options to be passed to HWASAN when running on host in Haiku.
+	Asan_options []string `json:"asan_options,omitempty"`
 }
 
 func (f *FuzzConfig) String() string {
@@ -315,7 +321,7 @@
 	module, binary := NewBinary(hod)
 
 	binary.baseInstaller = NewFuzzInstaller()
-	module.sanitize.SetSanitizer(fuzzer, true)
+	module.sanitize.SetSanitizer(Fuzzer, true)
 
 	fuzz := &fuzzBinary{
 		binaryDecorator: binary,
diff --git a/cc/image.go b/cc/image.go
index 12bd65b..13095fc 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -26,36 +26,18 @@
 
 var _ android.ImageInterface = (*Module)(nil)
 
-type imageVariantType string
+type ImageVariantType string
 
 const (
-	coreImageVariant          imageVariantType = "core"
-	vendorImageVariant        imageVariantType = "vendor"
-	productImageVariant       imageVariantType = "product"
-	ramdiskImageVariant       imageVariantType = "ramdisk"
-	vendorRamdiskImageVariant imageVariantType = "vendor_ramdisk"
-	recoveryImageVariant      imageVariantType = "recovery"
-	hostImageVariant          imageVariantType = "host"
+	coreImageVariant          ImageVariantType = "core"
+	vendorImageVariant        ImageVariantType = "vendor"
+	productImageVariant       ImageVariantType = "product"
+	ramdiskImageVariant       ImageVariantType = "ramdisk"
+	vendorRamdiskImageVariant ImageVariantType = "vendor_ramdisk"
+	recoveryImageVariant      ImageVariantType = "recovery"
+	hostImageVariant          ImageVariantType = "host"
 )
 
-func (c *Module) getImageVariantType() imageVariantType {
-	if c.Host() {
-		return hostImageVariant
-	} else if c.inVendor() {
-		return vendorImageVariant
-	} else if c.InProduct() {
-		return productImageVariant
-	} else if c.InRamdisk() {
-		return ramdiskImageVariant
-	} else if c.InVendorRamdisk() {
-		return vendorRamdiskImageVariant
-	} else if c.InRecovery() {
-		return recoveryImageVariant
-	} else {
-		return coreImageVariant
-	}
-}
-
 const (
 	// VendorVariationPrefix is the variant prefix used for /vendor code that compiles
 	// against the VNDK.
@@ -75,7 +57,7 @@
 func (ctx *moduleContext) SocSpecific() bool {
 	// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
 	// module. As well as SoC specific modules, vendor variants must be installed to /vendor.
-	return ctx.ModuleContext.SocSpecific() || ctx.mod.inVendor()
+	return ctx.ModuleContext.SocSpecific() || ctx.mod.InVendor()
 }
 
 func (ctx *moduleContextImpl) inProduct() bool {
@@ -83,7 +65,7 @@
 }
 
 func (ctx *moduleContextImpl) inVendor() bool {
-	return ctx.mod.inVendor()
+	return ctx.mod.InVendor()
 }
 
 func (ctx *moduleContextImpl) inRamdisk() bool {
@@ -119,7 +101,7 @@
 }
 
 // Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
-func (c *Module) inVendor() bool {
+func (c *Module) InVendor() bool {
 	return c.Properties.ImageVariationPrefix == VendorVariationPrefix
 }
 
diff --git a/cc/linkable.go b/cc/linkable.go
index 489063f..ab5a552 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -6,6 +6,59 @@
 	"github.com/google/blueprint"
 )
 
+// PlatformSanitizeable is an interface for sanitizing platform modules.
+type PlatformSanitizeable interface {
+	LinkableInterface
+
+	// SanitizePropDefined returns whether the Sanitizer properties struct for this module is defined.
+	SanitizePropDefined() bool
+
+	// IsDependencyRoot returns whether a module is of a type which cannot be a linkage dependency
+	// of another module. For example, cc_binary and rust_binary represent dependency roots as other
+	// modules cannot have linkage dependencies against these types.
+	IsDependencyRoot() bool
+
+	// IsSanitizerEnabled returns whether a sanitizer is enabled.
+	IsSanitizerEnabled(t SanitizerType) bool
+
+	// IsSanitizerExplicitlyDisabled returns whether a sanitizer has been explicitly disabled (set to false) rather
+	// than left undefined.
+	IsSanitizerExplicitlyDisabled(t SanitizerType) bool
+
+	// SanitizeDep returns the value of the SanitizeDep flag, which is set if a module is a dependency of a
+	// sanitized module.
+	SanitizeDep() bool
+
+	// SetSanitizer enables or disables the specified sanitizer type if it's supported, otherwise this should panic.
+	SetSanitizer(t SanitizerType, b bool)
+
+	// SetSanitizerDep returns true if the module is statically linked.
+	SetSanitizeDep(b bool)
+
+	// StaticallyLinked returns true if the module is statically linked.
+	StaticallyLinked() bool
+
+	// SetInSanitizerDir sets the module installation to the sanitizer directory.
+	SetInSanitizerDir()
+
+	// SanitizeNever returns true if this module should never be sanitized.
+	SanitizeNever() bool
+
+	// SanitizerSupported returns true if a sanitizer type is supported by this modules compiler.
+	SanitizerSupported(t SanitizerType) bool
+
+	// SanitizableDepTagChecker returns a SantizableDependencyTagChecker function type.
+	SanitizableDepTagChecker() SantizableDependencyTagChecker
+}
+
+// SantizableDependencyTagChecker functions check whether or not a dependency
+// tag can be sanitized. These functions should return true if the tag can be
+// sanitized, otherwise they should return false. These functions should also
+// handle all possible dependency tags in the dependency tree. For example,
+// Rust modules can depend on both Rust and CC libraries, so the Rust module
+// implementation should handle tags from both.
+type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool
+
 // LinkableInterface is an interface for a type of module that is linkable in a C++ library.
 type LinkableInterface interface {
 	android.Module
@@ -27,6 +80,8 @@
 	SetShared()
 	Static() bool
 	Shared() bool
+	Header() bool
+	IsPrebuilt() bool
 	Toc() android.OptionalPath
 
 	Host() bool
@@ -40,6 +95,8 @@
 	InRecovery() bool
 	OnlyInRecovery() bool
 
+	InVendor() bool
+
 	UseSdk() bool
 	UseVndk() bool
 	MustUseVendorVariant() bool
@@ -56,6 +113,11 @@
 	IsSdkVariant() bool
 
 	SplitPerApiLevel() bool
+
+	// SetPreventInstall sets the PreventInstall property to 'true' for this module.
+	SetPreventInstall()
+	// SetHideFromMake sets the HideFromMake property to 'true' for this module.
+	SetHideFromMake()
 }
 
 var (
@@ -67,6 +129,26 @@
 	CoverageDepTag = dependencyTag{name: "coverage"}
 )
 
+// GetImageVariantType returns the ImageVariantType string value for the given module
+// (these are defined in cc/image.go).
+func GetImageVariantType(c LinkableInterface) ImageVariantType {
+	if c.Host() {
+		return hostImageVariant
+	} else if c.InVendor() {
+		return vendorImageVariant
+	} else if c.InProduct() {
+		return productImageVariant
+	} else if c.InRamdisk() {
+		return ramdiskImageVariant
+	} else if c.InVendorRamdisk() {
+		return vendorRamdiskImageVariant
+	} else if c.InRecovery() {
+		return recoveryImageVariant
+	} else {
+		return coreImageVariant
+	}
+}
+
 // SharedDepTag returns the dependency tag for any C++ shared libraries.
 func SharedDepTag() blueprint.DependencyTag {
 	return libraryDependencyTag{Kind: sharedLibraryDependency}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index bb92a88..5992611 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -71,7 +71,7 @@
 		"export_memory_stats=0", "max_malloc_fill_size=0"}
 )
 
-type sanitizerType int
+type SanitizerType int
 
 func boolPtr(v bool) *bool {
 	if v {
@@ -82,19 +82,19 @@
 }
 
 const (
-	asan sanitizerType = iota + 1
+	Asan SanitizerType = iota + 1
 	hwasan
 	tsan
 	intOverflow
 	cfi
 	scs
-	fuzzer
+	Fuzzer
 )
 
 // Name of the sanitizer variation for this sanitizer type
-func (t sanitizerType) variationName() string {
+func (t SanitizerType) variationName() string {
 	switch t {
-	case asan:
+	case Asan:
 		return "asan"
 	case hwasan:
 		return "hwasan"
@@ -106,17 +106,17 @@
 		return "cfi"
 	case scs:
 		return "scs"
-	case fuzzer:
+	case Fuzzer:
 		return "fuzzer"
 	default:
-		panic(fmt.Errorf("unknown sanitizerType %d", t))
+		panic(fmt.Errorf("unknown SanitizerType %d", t))
 	}
 }
 
 // This is the sanitizer names in SANITIZE_[TARGET|HOST]
-func (t sanitizerType) name() string {
+func (t SanitizerType) name() string {
 	switch t {
-	case asan:
+	case Asan:
 		return "address"
 	case hwasan:
 		return "hwaddress"
@@ -128,15 +128,37 @@
 		return "cfi"
 	case scs:
 		return "shadow-call-stack"
-	case fuzzer:
+	case Fuzzer:
 		return "fuzzer"
 	default:
-		panic(fmt.Errorf("unknown sanitizerType %d", t))
+		panic(fmt.Errorf("unknown SanitizerType %d", t))
 	}
 }
 
-func (t sanitizerType) incompatibleWithCfi() bool {
-	return t == asan || t == fuzzer || t == hwasan
+func (*Module) SanitizerSupported(t SanitizerType) bool {
+	switch t {
+	case Asan:
+		return true
+	case hwasan:
+		return true
+	case tsan:
+		return true
+	case intOverflow:
+		return true
+	case cfi:
+		return true
+	case scs:
+		return true
+	case Fuzzer:
+		return true
+	default:
+		return false
+	}
+}
+
+// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI.
+func (t SanitizerType) incompatibleWithCfi() bool {
+	return t == Asan || t == Fuzzer || t == hwasan
 }
 
 type SanitizeUserProps struct {
@@ -680,9 +702,10 @@
 	return sanitize.Properties.InSanitizerDir
 }
 
-func (sanitize *sanitize) getSanitizerBoolPtr(t sanitizerType) *bool {
+// getSanitizerBoolPtr returns the SanitizerTypes associated bool pointer from SanitizeProperties.
+func (sanitize *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool {
 	switch t {
-	case asan:
+	case Asan:
 		return sanitize.Properties.Sanitize.Address
 	case hwasan:
 		return sanitize.Properties.Sanitize.Hwaddress
@@ -694,32 +717,34 @@
 		return sanitize.Properties.Sanitize.Cfi
 	case scs:
 		return sanitize.Properties.Sanitize.Scs
-	case fuzzer:
+	case Fuzzer:
 		return sanitize.Properties.Sanitize.Fuzzer
 	default:
-		panic(fmt.Errorf("unknown sanitizerType %d", t))
+		panic(fmt.Errorf("unknown SanitizerType %d", t))
 	}
 }
 
+// isUnsanitizedVariant returns true if no sanitizers are enabled.
 func (sanitize *sanitize) isUnsanitizedVariant() bool {
-	return !sanitize.isSanitizerEnabled(asan) &&
+	return !sanitize.isSanitizerEnabled(Asan) &&
 		!sanitize.isSanitizerEnabled(hwasan) &&
 		!sanitize.isSanitizerEnabled(tsan) &&
 		!sanitize.isSanitizerEnabled(cfi) &&
 		!sanitize.isSanitizerEnabled(scs) &&
-		!sanitize.isSanitizerEnabled(fuzzer)
+		!sanitize.isSanitizerEnabled(Fuzzer)
 }
 
+// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled).
 func (sanitize *sanitize) isVariantOnProductionDevice() bool {
-	return !sanitize.isSanitizerEnabled(asan) &&
+	return !sanitize.isSanitizerEnabled(Asan) &&
 		!sanitize.isSanitizerEnabled(hwasan) &&
 		!sanitize.isSanitizerEnabled(tsan) &&
-		!sanitize.isSanitizerEnabled(fuzzer)
+		!sanitize.isSanitizerEnabled(Fuzzer)
 }
 
-func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
+func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) {
 	switch t {
-	case asan:
+	case Asan:
 		sanitize.Properties.Sanitize.Address = boolPtr(b)
 	case hwasan:
 		sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
@@ -731,10 +756,10 @@
 		sanitize.Properties.Sanitize.Cfi = boolPtr(b)
 	case scs:
 		sanitize.Properties.Sanitize.Scs = boolPtr(b)
-	case fuzzer:
+	case Fuzzer:
 		sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
 	default:
-		panic(fmt.Errorf("unknown sanitizerType %d", t))
+		panic(fmt.Errorf("unknown SanitizerType %d", t))
 	}
 	if b {
 		sanitize.Properties.SanitizerEnabled = true
@@ -743,7 +768,7 @@
 
 // Check if the sanitizer is explicitly disabled (as opposed to nil by
 // virtue of not being set).
-func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t sanitizerType) bool {
+func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t SanitizerType) bool {
 	if sanitize == nil {
 		return false
 	}
@@ -757,7 +782,7 @@
 // indirectly (via a mutator) sets the bool ptr to true, and you can't
 // distinguish between the cases. It isn't needed though - both cases can be
 // treated identically.
-func (sanitize *sanitize) isSanitizerEnabled(t sanitizerType) bool {
+func (sanitize *sanitize) isSanitizerEnabled(t SanitizerType) bool {
 	if sanitize == nil {
 		return false
 	}
@@ -766,7 +791,8 @@
 	return sanitizerVal != nil && *sanitizerVal == true
 }
 
-func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
+// IsSanitizableDependencyTag returns true if the dependency tag is sanitizable.
+func IsSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
 	switch t := tag.(type) {
 	case dependencyTag:
 		return t == reuseObjTag || t == objDepTag
@@ -777,6 +803,10 @@
 	}
 }
 
+func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker {
+	return IsSanitizableDependencyTag
+}
+
 // Determines if the current module is a static library going to be captured
 // as vendor snapshot. Such modules must create both cfi and non-cfi variants,
 // except for ones which explicitly disable cfi.
@@ -785,51 +815,58 @@
 		return false
 	}
 
-	c := mctx.Module().(*Module)
+	c := mctx.Module().(PlatformSanitizeable)
 
-	if !c.inVendor() {
+	if !c.InVendor() {
 		return false
 	}
 
-	if !c.static() {
+	if !c.StaticallyLinked() {
 		return false
 	}
 
-	if c.Prebuilt() != nil {
+	if c.IsPrebuilt() {
 		return false
 	}
 
-	return c.sanitize != nil &&
-		!Bool(c.sanitize.Properties.Sanitize.Never) &&
-		!c.sanitize.isSanitizerExplicitlyDisabled(cfi)
+	if !c.SanitizerSupported(cfi) {
+		return false
+	}
+
+	return c.SanitizePropDefined() &&
+		!c.SanitizeNever() &&
+		!c.IsSanitizerExplicitlyDisabled(cfi)
 }
 
 // Propagate sanitizer requirements down from binaries
-func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) {
+func sanitizerDepsMutator(t SanitizerType) func(android.TopDownMutatorContext) {
 	return func(mctx android.TopDownMutatorContext) {
-		if c, ok := mctx.Module().(*Module); ok {
-			enabled := c.sanitize.isSanitizerEnabled(t)
+		if c, ok := mctx.Module().(PlatformSanitizeable); ok {
+			enabled := c.IsSanitizerEnabled(t)
 			if t == cfi && needsCfiForVendorSnapshot(mctx) {
 				// We shouldn't change the result of isSanitizerEnabled(cfi) to correctly
 				// determine defaultVariation in sanitizerMutator below.
 				// Instead, just mark SanitizeDep to forcefully create cfi variant.
 				enabled = true
-				c.sanitize.Properties.SanitizeDep = true
+				c.SetSanitizeDep(true)
 			}
 			if enabled {
+				isSanitizableDependencyTag := c.SanitizableDepTagChecker()
 				mctx.WalkDeps(func(child, parent android.Module) bool {
 					if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
 						return false
 					}
-					if d, ok := child.(*Module); ok && d.sanitize != nil &&
-						!Bool(d.sanitize.Properties.Sanitize.Never) &&
-						!d.sanitize.isSanitizerExplicitlyDisabled(t) {
+					if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
+						!d.SanitizeNever() &&
+						!d.IsSanitizerExplicitlyDisabled(t) {
 						if t == cfi || t == hwasan || t == scs {
-							if d.static() {
-								d.sanitize.Properties.SanitizeDep = true
+							if d.StaticallyLinked() && d.SanitizerSupported(t) {
+								// Rust does not support some of these sanitizers, so we need to check if it's
+								// supported before setting this true.
+								d.SetSanitizeDep(true)
 							}
 						} else {
-							d.sanitize.Properties.SanitizeDep = true
+							d.SetSanitizeDep(true)
 						}
 					}
 					return true
@@ -847,9 +884,19 @@
 	}
 }
 
+func (c *Module) SanitizeNever() bool {
+	return Bool(c.sanitize.Properties.Sanitize.Never)
+}
+
+func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool {
+	return c.sanitize.isSanitizerExplicitlyDisabled(t)
+}
+
 // Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
 func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) {
+	// Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers.
 	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
+		isSanitizableDependencyTag := c.SanitizableDepTagChecker()
 		mctx.WalkDeps(func(child, parent android.Module) bool {
 			if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
 				return false
@@ -1057,7 +1104,7 @@
 					variations = append(variations, c.ImageVariation())
 				}
 				mctx.AddFarVariationDependencies(variations, depTag, deps...)
-			} else if !c.static() && !c.header() {
+			} else if !c.static() && !c.Header() {
 				// If we're using snapshots and in vendor, redirect to snapshot whenever possible
 				if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() {
 					snapshots := vendorSnapshotSharedLibs(mctx.Config())
@@ -1098,16 +1145,52 @@
 	AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
 }
 
+func (c *Module) SanitizePropDefined() bool {
+	return c.sanitize != nil
+}
+
+func (c *Module) IsSanitizerEnabled(t SanitizerType) bool {
+	return c.sanitize.isSanitizerEnabled(t)
+}
+
+func (c *Module) SanitizeDep() bool {
+	return c.sanitize.Properties.SanitizeDep
+}
+
+func (c *Module) StaticallyLinked() bool {
+	return c.static()
+}
+
+func (c *Module) SetInSanitizerDir() {
+	if c.sanitize != nil {
+		c.sanitize.Properties.InSanitizerDir = true
+	}
+}
+
+func (c *Module) SetSanitizer(t SanitizerType, b bool) {
+	if c.sanitize != nil {
+		c.sanitize.SetSanitizer(t, b)
+	}
+}
+
+func (c *Module) SetSanitizeDep(b bool) {
+	if c.sanitize != nil {
+		c.sanitize.Properties.SanitizeDep = b
+	}
+}
+
+var _ PlatformSanitizeable = (*Module)(nil)
+
 // Create sanitized variants for modules that need them
-func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) {
+func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
 	return func(mctx android.BottomUpMutatorContext) {
-		if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
-			if c.isDependencyRoot() && c.sanitize.isSanitizerEnabled(t) {
+		if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+			if c.IsDependencyRoot() && c.IsSanitizerEnabled(t) {
 				modules := mctx.CreateVariations(t.variationName())
-				modules[0].(*Module).sanitize.SetSanitizer(t, true)
-			} else if c.sanitize.isSanitizerEnabled(t) || c.sanitize.Properties.SanitizeDep {
-				isSanitizerEnabled := c.sanitize.isSanitizerEnabled(t)
-				if c.static() || c.header() || t == asan || t == fuzzer {
+				modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
+			} else if c.IsSanitizerEnabled(t) || c.SanitizeDep() {
+				isSanitizerEnabled := c.IsSanitizerEnabled(t)
+				if c.StaticallyLinked() || c.Header() || t == Asan || t == Fuzzer {
 					// Static and header libs are split into non-sanitized and sanitized variants.
 					// Shared libs are not split. However, for asan and fuzzer, we split even for shared
 					// libs because a library sanitized for asan/fuzzer can't be linked from a library
@@ -1121,17 +1204,20 @@
 					// module. By setting it to the name of the sanitized variation, the dangling dependency
 					// is redirected to the sanitized variant of the dependent module.
 					defaultVariation := t.variationName()
+					// Not all PlatformSanitizeable modules support the CFI sanitizer
+					cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
 					mctx.SetDefaultDependencyVariation(&defaultVariation)
-					modules := mctx.CreateVariations("", t.variationName())
-					modules[0].(*Module).sanitize.SetSanitizer(t, false)
-					modules[1].(*Module).sanitize.SetSanitizer(t, true)
-					modules[0].(*Module).sanitize.Properties.SanitizeDep = false
-					modules[1].(*Module).sanitize.Properties.SanitizeDep = false
 
-					if mctx.Device() && t.incompatibleWithCfi() {
+					modules := mctx.CreateVariations("", t.variationName())
+					modules[0].(PlatformSanitizeable).SetSanitizer(t, false)
+					modules[1].(PlatformSanitizeable).SetSanitizer(t, true)
+					modules[0].(PlatformSanitizeable).SetSanitizeDep(false)
+					modules[1].(PlatformSanitizeable).SetSanitizeDep(false)
+
+					if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
 						// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
 						// are incompatible with cfi
-						modules[1].(*Module).sanitize.SetSanitizer(cfi, false)
+						modules[1].(PlatformSanitizeable).SetSanitizer(cfi, false)
 					}
 
 					// For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
@@ -1139,46 +1225,48 @@
 					// For other types of sanitizers, suppress the variation that is disabled.
 					if t != cfi && t != scs && t != hwasan {
 						if isSanitizerEnabled {
-							modules[0].(*Module).Properties.PreventInstall = true
-							modules[0].(*Module).Properties.HideFromMake = true
+							modules[0].(PlatformSanitizeable).SetPreventInstall()
+							modules[0].(PlatformSanitizeable).SetHideFromMake()
 						} else {
-							modules[1].(*Module).Properties.PreventInstall = true
-							modules[1].(*Module).Properties.HideFromMake = true
+							modules[1].(PlatformSanitizeable).SetPreventInstall()
+							modules[1].(PlatformSanitizeable).SetHideFromMake()
 						}
 					}
 
 					// Export the static lib name to make
-					if c.static() && c.ExportedToMake() {
+					if c.StaticallyLinked() && c.ExportedToMake() {
 						if t == cfi {
-							cfiStaticLibs(mctx.Config()).add(c, c.Name())
+							cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
 						} else if t == hwasan {
-							hwasanStaticLibs(mctx.Config()).add(c, c.Name())
+							hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
 						}
 					}
 				} else {
 					// Shared libs are not split. Only the sanitized variant is created.
 					modules := mctx.CreateVariations(t.variationName())
-					modules[0].(*Module).sanitize.SetSanitizer(t, true)
-					modules[0].(*Module).sanitize.Properties.SanitizeDep = false
+					modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
+					modules[0].(PlatformSanitizeable).SetSanitizeDep(false)
 
 					// locate the asan libraries under /data/asan
-					if mctx.Device() && t == asan && isSanitizerEnabled {
-						modules[0].(*Module).sanitize.Properties.InSanitizerDir = true
+					if mctx.Device() && t == Asan && isSanitizerEnabled {
+						modules[0].(PlatformSanitizeable).SetInSanitizerDir()
 					}
 
 					if mctx.Device() && t.incompatibleWithCfi() {
 						// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
 						// are incompatible with cfi
-						modules[0].(*Module).sanitize.SetSanitizer(cfi, false)
+						modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
 					}
 				}
 			}
-			c.sanitize.Properties.SanitizeDep = false
+			c.SetSanitizeDep(false)
 		} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
 			// APEX modules fall here
 			sanitizeable.AddSanitizerDependencies(mctx, t.name())
 			mctx.CreateVariations(t.variationName())
 		} else if c, ok := mctx.Module().(*Module); ok {
+			//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
+
 			// Check if it's a snapshot module supporting sanitizer
 			if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) {
 				// Set default variation as above.
@@ -1203,23 +1291,23 @@
 type sanitizerStaticLibsMap struct {
 	// libsMap contains one list of modules per each image and each arch.
 	// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
-	libsMap       map[imageVariantType]map[string][]string
+	libsMap       map[ImageVariantType]map[string][]string
 	libsMapLock   sync.Mutex
-	sanitizerType sanitizerType
+	sanitizerType SanitizerType
 }
 
-func newSanitizerStaticLibsMap(t sanitizerType) *sanitizerStaticLibsMap {
+func newSanitizerStaticLibsMap(t SanitizerType) *sanitizerStaticLibsMap {
 	return &sanitizerStaticLibsMap{
 		sanitizerType: t,
-		libsMap:       make(map[imageVariantType]map[string][]string),
+		libsMap:       make(map[ImageVariantType]map[string][]string),
 	}
 }
 
 // Add the current module to sanitizer static libs maps
 // Each module should pass its exported name as names of Make and Soong can differ.
-func (s *sanitizerStaticLibsMap) add(c *Module, name string) {
-	image := c.getImageVariantType()
-	arch := c.Arch().ArchType.String()
+func (s *sanitizerStaticLibsMap) add(c LinkableInterface, name string) {
+	image := GetImageVariantType(c)
+	arch := c.Module().Target().Arch.ArchType.String()
 
 	s.libsMapLock.Lock()
 	defer s.libsMapLock.Unlock()
@@ -1238,7 +1326,7 @@
 // See build/make/core/binary.mk for more details.
 func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) {
 	for _, image := range android.SortedStringKeys(s.libsMap) {
-		archMap := s.libsMap[imageVariantType(image)]
+		archMap := s.libsMap[ImageVariantType(image)]
 		for _, arch := range android.SortedStringKeys(archMap) {
 			libs := archMap[arch]
 			sort.Strings(libs)
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index e3f3a4d..8979846 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -104,7 +104,7 @@
 }
 
 func (vendorSnapshotImage) inImage(m *Module) func() bool {
-	return m.inVendor
+	return m.InVendor
 }
 
 func (vendorSnapshotImage) available(m *Module) *bool {
@@ -507,8 +507,8 @@
 }
 
 type snapshotSanitizer interface {
-	isSanitizerEnabled(t sanitizerType) bool
-	setSanitizerVariation(t sanitizerType, enabled bool)
+	isSanitizerEnabled(t SanitizerType) bool
+	setSanitizerVariation(t SanitizerType, enabled bool)
 }
 
 type snapshotLibraryDecorator struct {
@@ -546,7 +546,7 @@
 func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
 	m := ctx.Module().(*Module)
 
-	if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] {
+	if m.InVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = vendorSuffix
 	} else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = recoverySuffix
@@ -613,7 +613,7 @@
 	return false
 }
 
-func (p *snapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
+func (p *snapshotLibraryDecorator) isSanitizerEnabled(t SanitizerType) bool {
 	switch t {
 	case cfi:
 		return p.sanitizerProperties.Cfi.Src != nil
@@ -622,7 +622,7 @@
 	}
 }
 
-func (p *snapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
+func (p *snapshotLibraryDecorator) setSanitizerVariation(t SanitizerType, enabled bool) {
 	if !enabled {
 		return
 	}
@@ -769,7 +769,7 @@
 	binName := in.Base()
 
 	m := ctx.Module().(*Module)
-	if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] {
+	if m.InVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = vendorSuffix
 	} else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = recoverySuffix
@@ -868,7 +868,7 @@
 
 	m := ctx.Module().(*Module)
 
-	if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] {
+	if m.InVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = vendorSuffix
 	} else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] {
 		p.androidMkSuffix = recoverySuffix
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 622ebec..0a89e47 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -247,7 +247,7 @@
 		if m.sanitize != nil {
 			// scs and hwasan export both sanitized and unsanitized variants for static and header
 			// Always use unsanitized variants of them.
-			for _, t := range []sanitizerType{scs, hwasan} {
+			for _, t := range []SanitizerType{scs, hwasan} {
 				if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
 					return false
 				}
diff --git a/cc/vndk.go b/cc/vndk.go
index c1264f7..daae1f7 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -394,7 +394,7 @@
 
 		useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
 			mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
-		return lib.shared() && m.inVendor() && m.IsVndk() && !m.IsVndkExt() && !useCoreVariant
+		return lib.shared() && m.InVendor() && m.IsVndk() && !m.IsVndkExt() && !useCoreVariant
 	}
 	return false
 }
@@ -586,7 +586,7 @@
 	// !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants.
 	// !installable: Snapshot only cares about "installable" modules.
 	// isSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
-	if !m.inVendor() || !m.installable(apexInfo) || m.isSnapshotPrebuilt() {
+	if !m.InVendor() || !m.installable(apexInfo) || m.isSnapshotPrebuilt() {
 		return nil, "", false
 	}
 	l, ok := m.linker.(snapshotLibraryInterface)
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index ab789aa..532d8fc 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -255,24 +255,13 @@
 
 // Add class loader context for the given library to the map entry for the given SDK version.
 func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
-	hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) error {
-
-	// If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is
-	// not found. However, this is likely to result is disabling dexpreopt, as it won't be
-	// possible to construct class loader context without on-host and on-device library paths.
-	strict = strict && !ctx.Config().AllowMissingDependencies()
-
-	if hostPath == nil && strict {
-		return fmt.Errorf("unknown build path to <uses-library> \"%s\"", lib)
-	}
+	hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) error {
 
 	devicePath := UnknownInstallLibraryPath
 	if installPath == nil {
 		if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) {
 			// Assume that compatibility libraries are installed in /system/framework.
 			installPath = android.PathForModuleInstall(ctx, "framework", lib+".jar")
-		} else if strict {
-			return fmt.Errorf("unknown install path to <uses-library> \"%s\"", lib)
 		} else {
 			// For some stub libraries the only known thing is the name of their implementation
 			// library, but the library itself is unavailable (missing or part of a prebuilt). In
@@ -310,40 +299,17 @@
 	return nil
 }
 
-// Wrapper around addContext that reports errors.
-func (clcMap ClassLoaderContextMap) addContextOrReportError(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
-	hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) {
-
-	err := clcMap.addContext(ctx, sdkVer, lib, hostPath, installPath, strict, nestedClcMap)
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-	}
-}
-
-// Add class loader context. Fail on unknown build/install paths.
-func (clcMap ClassLoaderContextMap) AddContext(ctx android.ModuleInstallPathContext, lib string,
-	hostPath, installPath android.Path) {
-
-	clcMap.addContextOrReportError(ctx, AnySdkVersion, lib, hostPath, installPath, true, nil)
-}
-
-// Add class loader context if the library exists. Don't fail on unknown build/install paths.
-func (clcMap ClassLoaderContextMap) MaybeAddContext(ctx android.ModuleInstallPathContext, lib *string,
-	hostPath, installPath android.Path) {
-
-	if lib != nil {
-		clcMap.addContextOrReportError(ctx, AnySdkVersion, *lib, hostPath, installPath, false, nil)
-	}
-}
-
 // Add class loader context for the given SDK version. Don't fail on unknown build/install paths, as
 // libraries with unknown paths still need to be processed by manifest_fixer (which doesn't care
 // about paths). For the subset of libraries that are used in dexpreopt, their build/install paths
 // are validated later before CLC is used (in validateClassLoaderContext).
-func (clcMap ClassLoaderContextMap) AddContextForSdk(ctx android.ModuleInstallPathContext, sdkVer int,
+func (clcMap ClassLoaderContextMap) AddContext(ctx android.ModuleInstallPathContext, sdkVer int,
 	lib string, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
 
-	clcMap.addContextOrReportError(ctx, sdkVer, lib, hostPath, installPath, false, nestedClcMap)
+	err := clcMap.addContext(ctx, sdkVer, lib, hostPath, installPath, nestedClcMap)
+	if err != nil {
+		ctx.ModuleErrorf(err.Error())
+	}
 }
 
 // Merge the other class loader context map into this one, do not override existing entries.
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 6b6b162..86f7871 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -18,6 +18,7 @@
 // For class loader context tests involving .bp files, see TestUsesLibraries in java package.
 
 import (
+	"fmt"
 	"reflect"
 	"strings"
 	"testing"
@@ -50,36 +51,30 @@
 
 	m := make(ClassLoaderContextMap)
 
-	m.AddContext(ctx, "a", buildPath(ctx, "a"), installPath(ctx, "a"))
-	m.AddContext(ctx, "b", buildPath(ctx, "b"), installPath(ctx, "b"))
-
-	// "Maybe" variant in the good case: add as usual.
-	c := "c"
-	m.MaybeAddContext(ctx, &c, buildPath(ctx, "c"), installPath(ctx, "c"))
-
-	// "Maybe" variant in the bad case: don't add library with unknown name, keep going.
-	m.MaybeAddContext(ctx, nil, nil, nil)
+	m.AddContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+	m.AddContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+	m.AddContext(ctx, AnySdkVersion, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
 
 	// Add some libraries with nested subcontexts.
 
 	m1 := make(ClassLoaderContextMap)
-	m1.AddContext(ctx, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"))
-	m1.AddContext(ctx, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"))
+	m1.AddContext(ctx, AnySdkVersion, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
+	m1.AddContext(ctx, AnySdkVersion, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
 
 	m2 := make(ClassLoaderContextMap)
-	m2.AddContext(ctx, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"))
-	m2.AddContext(ctx, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"))
-	m2.AddContextForSdk(ctx, AnySdkVersion, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
+	m2.AddContext(ctx, AnySdkVersion, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
+	m2.AddContext(ctx, AnySdkVersion, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
+	m2.AddContext(ctx, AnySdkVersion, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
 
 	m3 := make(ClassLoaderContextMap)
-	m3.AddContext(ctx, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"))
-	m3.AddContext(ctx, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"))
+	m3.AddContext(ctx, AnySdkVersion, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
+	m3.AddContext(ctx, AnySdkVersion, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
 
-	m.AddContextForSdk(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
+	m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
 	// When the same library is both in conditional and unconditional context, it should be removed
 	// from conditional context.
-	m.AddContextForSdk(ctx, 42, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
-	m.AddContextForSdk(ctx, AnySdkVersion, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+	m.AddContext(ctx, 42, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+	m.AddContext(ctx, AnySdkVersion, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
 
 	// Merge map with implicit root library that is among toplevel contexts => does nothing.
 	m.AddContextMap(m1, "c")
@@ -88,12 +83,12 @@
 	m.AddContextMap(m3, "m_g")
 
 	// Compatibility libraries with unknown install paths get default paths.
-	m.AddContextForSdk(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
-	m.AddContextForSdk(ctx, 29, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil, nil)
+	m.AddContext(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
+	m.AddContext(ctx, 29, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil, nil)
 
 	// Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
 	// needed as a compatibility library if "android.test.runner" is in CLC as well.
-	m.AddContextForSdk(ctx, 30, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil, nil)
+	m.AddContext(ctx, 30, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil, nil)
 
 	valid, validationError := validateClassLoaderContext(m)
 
@@ -160,31 +155,19 @@
 	})
 }
 
-// Test that an unexpected unknown build path causes immediate error.
-func TestCLCUnknownBuildPath(t *testing.T) {
-	ctx := testContext()
-	m := make(ClassLoaderContextMap)
-	err := m.addContext(ctx, AnySdkVersion, "a", nil, nil, true, nil)
-	checkError(t, err, "unknown build path to <uses-library> \"a\"")
-}
-
-// Test that an unexpected unknown install path causes immediate error.
-func TestCLCUnknownInstallPath(t *testing.T) {
-	ctx := testContext()
-	m := make(ClassLoaderContextMap)
-	err := m.addContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, true, nil)
-	checkError(t, err, "unknown install path to <uses-library> \"a\"")
-}
-
-func TestCLCMaybeAdd(t *testing.T) {
+// Test that unknown library paths cause a validation error.
+func testCLCUnknownPath(t *testing.T, whichPath string) {
 	ctx := testContext()
 
 	m := make(ClassLoaderContextMap)
-	a := "a"
-	m.MaybeAddContext(ctx, &a, nil, nil)
+	if whichPath == "build" {
+		m.AddContext(ctx, AnySdkVersion, "a", nil, nil, nil)
+	} else {
+		m.AddContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, nil)
+	}
 
 	// The library should be added to <uses-library> tags by the manifest_fixer.
-	t.Run("maybe add", func(t *testing.T) {
+	t.Run("uses libs", func(t *testing.T) {
 		haveUsesLibs := m.UsesLibs()
 		wantUsesLibs := []string{"a"}
 		if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
@@ -192,20 +175,28 @@
 		}
 	})
 
-	// But class loader context in such cases should raise an error on validation.
-	t.Run("validate", func(t *testing.T) {
-		_, err := validateClassLoaderContext(m)
-		checkError(t, err, "invalid build path for <uses-library> \"a\"")
-	})
+	// But CLC cannot be constructed: there is a validation error.
+	_, err := validateClassLoaderContext(m)
+	checkError(t, err, fmt.Sprintf("invalid %s path for <uses-library> \"a\"", whichPath))
+}
+
+// Test that unknown build path is an error.
+func TestCLCUnknownBuildPath(t *testing.T) {
+	testCLCUnknownPath(t, "build")
+}
+
+// Test that unknown install path is an error.
+func TestCLCUnknownInstallPath(t *testing.T) {
+	testCLCUnknownPath(t, "install")
 }
 
 // An attempt to add conditional nested subcontext should fail.
 func TestCLCNestedConditional(t *testing.T) {
 	ctx := testContext()
 	m1 := make(ClassLoaderContextMap)
-	m1.AddContextForSdk(ctx, 42, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+	m1.AddContext(ctx, 42, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
 	m := make(ClassLoaderContextMap)
-	err := m.addContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), true, m1)
+	err := m.addContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), m1)
 	checkError(t, err, "nested class loader context shouldn't have conditional part")
 }
 
@@ -214,10 +205,10 @@
 func TestCLCSdkVersionOrder(t *testing.T) {
 	ctx := testContext()
 	m := make(ClassLoaderContextMap)
-	m.AddContextForSdk(ctx, 28, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
-	m.AddContextForSdk(ctx, 29, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
-	m.AddContextForSdk(ctx, 30, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
-	m.AddContextForSdk(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), nil)
+	m.AddContext(ctx, 28, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+	m.AddContext(ctx, 29, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+	m.AddContext(ctx, 30, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
+	m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), nil)
 
 	valid, validationError := validateClassLoaderContext(m)
 
diff --git a/go.mod b/go.mod
index 117fa65..7297dea 100644
--- a/go.mod
+++ b/go.mod
@@ -8,4 +8,4 @@
 
 replace github.com/google/blueprint v0.0.0 => ../blueprint
 
-go 1.15.6
+go 1.15
diff --git a/java/app.go b/java/app.go
index 574472c..e6c9a2d 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1226,7 +1226,7 @@
 			if tag, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
 				dep := ctx.OtherModuleName(m)
 				if lib, ok := m.(UsesLibraryDependency); ok {
-					clcMap.AddContextForSdk(ctx, tag.sdkVersion, dep,
+					clcMap.AddContext(ctx, tag.sdkVersion, dep,
 						lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
 				} else if ctx.Config().AllowMissingDependencies() {
 					ctx.AddMissingDependencies([]string{dep})
diff --git a/java/java.go b/java/java.go
index 82b53be..f684a00 100644
--- a/java/java.go
+++ b/java/java.go
@@ -3305,7 +3305,7 @@
 	}
 
 	if implicitSdkLib != nil {
-		clcMap.AddContextForSdk(ctx, dexpreopt.AnySdkVersion, *implicitSdkLib,
+		clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *implicitSdkLib,
 			dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
 	} else {
 		depName := ctx.OtherModuleName(depModule)
diff --git a/rust/binary.go b/rust/binary.go
index c2d97f3..ca07d07 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -164,3 +164,7 @@
 	}
 	return binary.baseCompiler.stdLinkage(ctx)
 }
+
+func (binary *binaryDecorator) isDependencyRoot() bool {
+	return true
+}
diff --git a/rust/compiler.go b/rust/compiler.go
index ee88a27..bcea6cc 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -236,6 +236,10 @@
 	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
 }
 
+func (compiler *baseCompiler) isDependencyRoot() bool {
+	return false
+}
+
 func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
 	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
 	deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
diff --git a/rust/rust.go b/rust/rust.go
index 1053846..1fa97af 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -106,6 +106,42 @@
 	hideApexVariantFromMake bool
 }
 
+func (mod *Module) Header() bool {
+	//TODO: If Rust libraries provide header variants, this needs to be updated.
+	return false
+}
+
+func (mod *Module) SetPreventInstall() {
+	mod.Properties.PreventInstall = true
+}
+
+// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
+func (mod *Module) InVendor() bool {
+	return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix
+}
+
+func (mod *Module) SetHideFromMake() {
+	mod.Properties.HideFromMake = true
+}
+
+func (mod *Module) SanitizePropDefined() bool {
+	return false
+}
+
+func (mod *Module) IsDependencyRoot() bool {
+	if mod.compiler != nil {
+		return mod.compiler.isDependencyRoot()
+	}
+	panic("IsDependencyRoot called on a non-compiler Rust module")
+}
+
+func (mod *Module) IsPrebuilt() bool {
+	if _, ok := mod.compiler.(*prebuiltLibraryDecorator); ok {
+		return true
+	}
+	return false
+}
+
 func (mod *Module) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
@@ -281,6 +317,7 @@
 	SetDisabled()
 
 	stdLinkage(ctx *depsContext) RustLinkage
+	isDependencyRoot() bool
 }
 
 type exportedFlagsProducer interface {
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 8db33a3..18749b5 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -345,15 +345,8 @@
 		depTag := ctx.OtherModuleDependencyTag(dep)
 		switch depTag {
 		case shTestDataBinsTag, shTestDataDeviceBinsTag:
-			if cc, isCc := dep.(*cc.Module); isCc {
-				s.addToDataModules(ctx, cc.OutputFile().Path().Base(), cc.OutputFile().Path())
-				return
-			}
-			property := "data_bins"
-			if depTag == shTestDataDeviceBinsTag {
-				property = "data_device_bins"
-			}
-			ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+			path := android.OutputFileForModule(ctx, dep, "")
+			s.addToDataModules(ctx, path.Base(), path)
 		case shTestDataLibsTag, shTestDataDeviceLibsTag:
 			if cc, isCc := dep.(*cc.Module); isCc {
 				// Copy to an intermediate output directory to append "lib[64]" to the path,