Refactor cc/rust to prep for Rust stubs

This CL largely handles this refactoring in preparation for Rust stubs
support.

Rust modules need to be able to communicate stubs information to cc, and
certain bits of cc needs to be exported so rust can reuse them.

A new VersionedLinkableInterface is added to capture most of the
stubs-related interface definitions.

Bug: 203478530
Test: m blueprint_tests
Change-Id: I380225402fa85a3c39e7b18deb657054b3a52fbe
diff --git a/apex/apex.go b/apex/apex.go
index d39a17f..428d57e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1386,12 +1386,12 @@
 // apexFileFor<Type> functions below create an apexFile struct for a given Soong module. The
 // returned apexFile saves information about the Soong module that will be used for creating the
 // build rules.
-func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, handleSpecialLibs bool) apexFile {
+func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod cc.VersionedLinkableInterface, handleSpecialLibs bool) apexFile {
 	// Decide the APEX-local directory by the multilib of the library In the future, we may
 	// query this to the module.
 	// TODO(jiyong): use the new PackagingSpec
 	var dirInApex string
-	switch ccMod.Arch().ArchType.Multilib {
+	switch ccMod.Multilib() {
 	case "lib32":
 		dirInApex = "lib"
 	case "lib64":
@@ -1418,7 +1418,7 @@
 	dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
 
 	fileToCopy := android.OutputFileForModule(ctx, ccMod, "")
-	androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName
+	androidMkModuleName := ccMod.BaseModuleName() + ccMod.SubName()
 	return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod)
 }
 
@@ -1448,25 +1448,6 @@
 	return af
 }
 
-func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) apexFile {
-	// Decide the APEX-local directory by the multilib of the library
-	// In the future, we may query this to the module.
-	var dirInApex string
-	switch rustm.Arch().ArchType.Multilib {
-	case "lib32":
-		dirInApex = "lib"
-	case "lib64":
-		dirInApex = "lib64"
-	}
-	if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
-		dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
-	}
-	dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath())
-	fileToCopy := android.OutputFileForModule(ctx, rustm, "")
-	androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
-	return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm)
-}
-
 func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
 	dirInApex := filepath.Join("bin", sh.SubDir())
 	if sh.Target().NativeBridge == android.NativeBridgeEnabled {
@@ -1900,8 +1881,8 @@
 			if isJniLib {
 				propertyName = "jni_libs"
 			}
-			switch ch := child.(type) {
-			case *cc.Module:
+
+			if ch, ok := child.(cc.VersionedLinkableInterface); ok {
 				if ch.IsStubs() {
 					ctx.PropertyErrorf(propertyName, "%q is a stub. Remove it from the list.", depName)
 				}
@@ -1915,14 +1896,11 @@
 					vctx.provideNativeLibs = append(vctx.provideNativeLibs, fi.stem())
 				}
 				return true // track transitive dependencies
-			case *rust.Module:
-				fi := apexFileForRustLibrary(ctx, ch)
-				fi.isJniLib = isJniLib
-				vctx.filesInfo = append(vctx.filesInfo, fi)
-				return true // track transitive dependencies
-			default:
-				ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
+			} else {
+				ctx.PropertyErrorf(propertyName,
+					"%q is not a VersionLinkableInterface (e.g. cc_library or rust_ffi module)", depName)
 			}
+
 		case executableTag:
 			switch ch := child.(type) {
 			case *cc.Module:
@@ -2074,7 +2052,7 @@
 	// We cannot use a switch statement on `depTag` here as the checked
 	// tags used below are private (e.g. `cc.sharedDepTag`).
 	if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
-		if ch, ok := child.(*cc.Module); ok {
+		if ch, ok := child.(cc.VersionedLinkableInterface); ok {
 			af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
 			af.transitiveDep = true
 
@@ -2089,9 +2067,10 @@
 				//
 				// Skip the dependency in unbundled builds where the device image is not
 				// being built.
-				if ch.IsStubsImplementationRequired() && !am.NotInPlatform() && !ctx.Config().UnbundledBuild() {
+				if ch.VersionedInterface().IsStubsImplementationRequired() &&
+					!am.NotInPlatform() && !ctx.Config().UnbundledBuild() {
 					// we need a module name for Make
-					name := ch.ImplementationModuleNameForMake(ctx) + ch.Properties.SubName
+					name := ch.ImplementationModuleNameForMake(ctx) + ch.SubName()
 					if !android.InList(name, a.makeModulesToInstall) {
 						a.makeModulesToInstall = append(a.makeModulesToInstall, name)
 					}
@@ -2116,15 +2095,6 @@
 
 			vctx.filesInfo = append(vctx.filesInfo, af)
 			return true // track transitive dependencies
-		} else if rm, ok := child.(*rust.Module); ok {
-			if !android.IsDepInSameApex(ctx, parent, am) {
-				return false
-			}
-
-			af := apexFileForRustLibrary(ctx, rm)
-			af.transitiveDep = true
-			vctx.filesInfo = append(vctx.filesInfo, af)
-			return true // track transitive dependencies
 		}
 	} else if cc.IsHeaderDepTag(depTag) {
 		// nothing
@@ -2143,7 +2113,7 @@
 				return false
 			}
 
-			af := apexFileForRustLibrary(ctx, rustm)
+			af := apexFileForNativeLibrary(ctx, child.(cc.VersionedLinkableInterface), vctx.handleSpecialLibs)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
 			return true // track transitive dependencies
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 8037272..03f229e 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -231,7 +231,7 @@
 	} else if library.shared() {
 		entries.Class = "SHARED_LIBRARIES"
 		entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
-		if !library.buildStubs() && library.unstrippedOutputFile != nil {
+		if !library.BuildStubs() && library.unstrippedOutputFile != nil {
 			entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
 		}
 		if len(library.Properties.Overrides) > 0 {
@@ -260,16 +260,16 @@
 		entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
 	}
 
-	if library.shared() && !library.buildStubs() {
+	if library.shared() && !library.BuildStubs() {
 		ctx.subAndroidMk(config, entries, library.baseInstaller)
 	} else {
-		if library.buildStubs() && library.stubsVersion() != "" {
-			entries.SubName = "." + library.stubsVersion()
+		if library.BuildStubs() && library.StubsVersion() != "" {
+			entries.SubName = "." + library.StubsVersion()
 		}
 		// library.makeUninstallable() depends on this to bypass HideFromMake() for
 		// static libraries.
 		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-		if library.buildStubs() {
+		if library.BuildStubs() {
 			entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
 		}
 	}
@@ -281,10 +281,10 @@
 	// very early stage in the boot process).
 	if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.NotInPlatform() &&
 		!ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.InVendorOrProduct() && !ctx.static() {
-		if library.buildStubs() && library.isLatestStubVersion() {
+		if library.BuildStubs() && library.isLatestStubVersion() {
 			entries.SubName = ""
 		}
-		if !library.buildStubs() {
+		if !library.BuildStubs() {
 			entries.SubName = ".bootstrap"
 		}
 	}
@@ -423,7 +423,7 @@
 	entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String()
 	entries.Class = "SHARED_LIBRARIES"
 
-	if !c.buildStubs() {
+	if !c.BuildStubs() {
 		entries.Disabled = true
 		return
 	}
diff --git a/cc/api_level.go b/cc/api_level.go
index 3dac571..deca723 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -55,7 +55,7 @@
 	return apiLevel
 }
 
-func nativeApiLevelFromUser(ctx android.BaseModuleContext,
+func NativeApiLevelFromUser(ctx android.BaseModuleContext,
 	raw string) (android.ApiLevel, error) {
 
 	if raw == "minimum" {
@@ -73,7 +73,7 @@
 func nativeApiLevelOrPanic(ctx android.BaseModuleContext,
 	raw string) android.ApiLevel {
 
-	value, err := nativeApiLevelFromUser(ctx, raw)
+	value, err := NativeApiLevelFromUser(ctx, raw)
 	if err != nil {
 		panic(err.Error())
 	}
diff --git a/cc/builder.go b/cc/builder.go
index b98bef9..56b7139 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -472,8 +472,8 @@
 }
 
 // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
-func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths,
-	flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths) Objects {
+func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths,
+	flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths, sharedFlags *SharedFlags) Objects {
 	// Source files are one-to-one with tidy, coverage, or kythe files, if enabled.
 	objFiles := make(android.Paths, len(srcFiles))
 	var tidyFiles android.Paths
@@ -552,10 +552,8 @@
 	}
 
 	// Multiple source files have build rules usually share the same cFlags or tidyFlags.
-	// Define only one version in this module and share it in multiple build rules.
-	// To simplify the code, the shared variables are all named as $flags<nnn>.
-	shared := ctx.getSharedFlags()
-
+	// SharedFlags provides one version for this module and shares it in multiple build rules.
+	// To simplify the code, the SharedFlags variables are all named as $flags<nnn>.
 	// Share flags only when there are multiple files or tidy rules.
 	var hasMultipleRules = len(srcFiles) > 1 || flags.tidy
 
@@ -566,11 +564,11 @@
 			return flags
 		}
 		mapKey := kind + flags
-		n, ok := shared.flagsMap[mapKey]
+		n, ok := sharedFlags.FlagsMap[mapKey]
 		if !ok {
-			shared.numSharedFlags += 1
-			n = strconv.Itoa(shared.numSharedFlags)
-			shared.flagsMap[mapKey] = n
+			sharedFlags.NumSharedFlags += 1
+			n = strconv.Itoa(sharedFlags.NumSharedFlags)
+			sharedFlags.FlagsMap[mapKey] = n
 			ctx.Variable(pctx, kind+n, flags)
 		}
 		return "$" + kind + n
diff --git a/cc/cc.go b/cc/cc.go
index af1b259..0db5c40 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -623,7 +623,6 @@
 	binary() bool
 	object() bool
 	toolchain() config.Toolchain
-	canUseSdk() bool
 	useSdk() bool
 	sdkVersion() string
 	minSdkVersion() string
@@ -647,9 +646,7 @@
 	isFuzzer() bool
 	isNDKStubLibrary() bool
 	useClangLld(actx ModuleContext) bool
-	isForPlatform() bool
 	apexVariationName() string
-	apexSdkVersion() android.ApiLevel
 	bootstrap() bool
 	nativeCoverage() bool
 	isPreventInstall() bool
@@ -661,8 +658,8 @@
 }
 
 type SharedFlags struct {
-	numSharedFlags int
-	flagsMap       map[string]string
+	NumSharedFlags int
+	FlagsMap       map[string]string
 }
 
 type ModuleContext interface {
@@ -920,7 +917,7 @@
 	dataLibDepTag         = dependencyTag{name: "data lib"}
 	dataBinDepTag         = dependencyTag{name: "data bin"}
 	runtimeDepTag         = installDependencyTag{name: "runtime lib"}
-	stubImplDepTag        = dependencyTag{name: "stub_impl"}
+	StubImplDepTag        = dependencyTag{name: "stub_impl"}
 	JniFuzzLibTag         = dependencyTag{name: "jni_fuzz_lib_tag"}
 	FdoProfileTag         = dependencyTag{name: "fdo_profile"}
 	aidlLibraryTag        = dependencyTag{name: "aidl_library"}
@@ -1169,7 +1166,21 @@
 	return String(c.Properties.Min_sdk_version)
 }
 
-func (c *Module) isCrt() bool {
+func (c *Module) SetSdkVersion(s string) {
+	c.Properties.Sdk_version = StringPtr(s)
+}
+
+func (c *Module) SetMinSdkVersion(s string) {
+	c.Properties.Min_sdk_version = StringPtr(s)
+}
+
+func (c *Module) SetStl(s string) {
+	if c.stl != nil {
+		c.stl.Properties.Stl = StringPtr(s)
+	}
+}
+
+func (c *Module) IsCrt() bool {
 	if linker, ok := c.linker.(*objectLinker); ok {
 		return linker.isCrt()
 	}
@@ -1177,7 +1188,7 @@
 }
 
 func (c *Module) SplitPerApiLevel() bool {
-	return c.canUseSdk() && c.isCrt()
+	return CanUseSdk(c) && c.IsCrt()
 }
 
 func (c *Module) AlwaysSdk() bool {
@@ -1197,7 +1208,7 @@
 }
 
 func (c *Module) CcLibraryInterface() bool {
-	if _, ok := c.linker.(libraryInterface); ok {
+	if c.library != nil {
 		return true
 	}
 	return false
@@ -1310,6 +1321,13 @@
 
 var _ LinkableInterface = (*Module)(nil)
 
+func (c *Module) VersionedInterface() VersionedInterface {
+	if c.library != nil {
+		return c.library
+	}
+	return nil
+}
+
 func (c *Module) UnstrippedOutputFile() android.Path {
 	if c.linker != nil {
 		return c.linker.unstrippedOutputFilePath()
@@ -1394,13 +1412,13 @@
 	return c.Properties.VndkVersion != ""
 }
 
-func (c *Module) canUseSdk() bool {
-	return c.Os() == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled &&
+func CanUseSdk(c LinkableInterface) bool {
+	return c.Module().Target().Os == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled &&
 		!c.InVendorOrProduct() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk()
 }
 
 func (c *Module) UseSdk() bool {
-	if c.canUseSdk() {
+	if CanUseSdk(c) {
 		return String(c.Properties.Sdk_version) != ""
 	}
 	return false
@@ -1419,13 +1437,13 @@
 }
 
 func (m *Module) NeedsLlndkVariants() bool {
-	lib := moduleLibraryInterface(m)
-	return lib != nil && (lib.hasLLNDKStubs() || lib.hasLLNDKHeaders())
+	lib := moduleVersionedInterface(m)
+	return lib != nil && (lib.HasLLNDKStubs() || lib.HasLLNDKHeaders())
 }
 
 func (m *Module) NeedsVendorPublicLibraryVariants() bool {
-	lib := moduleLibraryInterface(m)
-	return lib != nil && (lib.hasVendorPublicLibrary())
+	lib := moduleVersionedInterface(m)
+	return lib != nil && (lib.HasVendorPublicLibrary())
 }
 
 // IsVendorPublicLibrary returns true for vendor public libraries.
@@ -1445,13 +1463,13 @@
 }
 
 func (c *Module) HasLlndkStubs() bool {
-	lib := moduleLibraryInterface(c)
-	return lib != nil && lib.hasLLNDKStubs()
+	lib := moduleVersionedInterface(c)
+	return lib != nil && lib.HasLLNDKStubs()
 }
 
 func (c *Module) StubsVersion() string {
-	if lib, ok := c.linker.(versionedInterface); ok {
-		return lib.stubsVersion()
+	if lib, ok := c.linker.(VersionedInterface); ok {
+		return lib.StubsVersion()
 	}
 	panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", c.BaseModuleName()))
 }
@@ -1460,7 +1478,7 @@
 // and does not set llndk.vendor_available: false.
 func (c *Module) isImplementationForLLNDKPublic() bool {
 	library, _ := c.library.(*libraryDecorator)
-	return library != nil && library.hasLLNDKStubs() &&
+	return library != nil && library.HasLLNDKStubs() &&
 		!Bool(library.Properties.Llndk.Private)
 }
 
@@ -1499,21 +1517,21 @@
 
 func (c *Module) IsStubs() bool {
 	if lib := c.library; lib != nil {
-		return lib.buildStubs()
+		return lib.BuildStubs()
 	}
 	return false
 }
 
 func (c *Module) HasStubsVariants() bool {
 	if lib := c.library; lib != nil {
-		return lib.hasStubsVariants()
+		return lib.HasStubsVariants()
 	}
 	return false
 }
 
 func (c *Module) IsStubsImplementationRequired() bool {
 	if lib := c.library; lib != nil {
-		return lib.isStubsImplementationRequired()
+		return lib.IsStubsImplementationRequired()
 	}
 	return false
 }
@@ -1522,21 +1540,21 @@
 // the implementation.  If it is an implementation library it returns its own name.
 func (c *Module) ImplementationModuleName(ctx android.BaseModuleContext) string {
 	name := ctx.OtherModuleName(c)
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		name = versioned.implementationModuleName(name)
+	if versioned, ok := c.linker.(VersionedInterface); ok {
+		name = versioned.ImplementationModuleName(name)
 	}
 	return name
 }
 
-// Similar to ImplementationModuleName, but uses the Make variant of the module
+// Similar to ImplementationModuleNameByCtx, but uses the Make variant of the module
 // name as base name, for use in AndroidMk output. E.g. for a prebuilt module
 // where the Soong name is prebuilt_foo, this returns foo (which works in Make
 // under the premise that the prebuilt module overrides its source counterpart
 // if it is exposed to Make).
 func (c *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
 	name := c.BaseModuleName()
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		name = versioned.implementationModuleName(name)
+	if versioned, ok := c.linker.(VersionedInterface); ok {
+		name = versioned.ImplementationModuleName(name)
 	}
 	return name
 }
@@ -1644,10 +1662,6 @@
 	return ctx.mod.OptimizeForSize()
 }
 
-func (ctx *moduleContextImpl) canUseSdk() bool {
-	return ctx.mod.canUseSdk()
-}
-
 func (ctx *moduleContextImpl) useSdk() bool {
 	return ctx.mod.UseSdk()
 }
@@ -1659,21 +1673,23 @@
 	return ""
 }
 
-func (ctx *moduleContextImpl) minSdkVersion() string {
-	ver := ctx.mod.MinSdkVersion()
-	if ver == "apex_inherit" && !ctx.isForPlatform() {
-		ver = ctx.apexSdkVersion().String()
+func MinSdkVersion(mod VersionedLinkableInterface, ctxIsForPlatform bool, device bool,
+	platformSdkVersion string) string {
+
+	ver := mod.MinSdkVersion()
+	if ver == "apex_inherit" && !ctxIsForPlatform {
+		ver = mod.ApexSdkVersion().String()
 	}
 	if ver == "apex_inherit" || ver == "" {
-		ver = ctx.sdkVersion()
+		ver = mod.SdkVersion()
 	}
 
-	if ctx.ctx.Device() {
+	if device {
 		// When building for vendor/product, use the latest _stable_ API as "current".
 		// This is passed to clang/aidl compilers so that compiled/generated code works
 		// with the system.
-		if (ctx.inVendor() || ctx.inProduct()) && (ver == "" || ver == "current") {
-			ver = ctx.ctx.Config().PlatformSdkVersion().String()
+		if (mod.InVendor() || mod.InProduct()) && (ver == "" || ver == "current") {
+			ver = platformSdkVersion
 		}
 	}
 
@@ -1687,19 +1703,19 @@
 	// support such an old version. The version is set to the later version in case when the
 	// non-sdk variant is for the platform, or the min_sdk_version of the containing APEX if
 	// it's for an APEX.
-	if ctx.mod.isCrt() && !ctx.isSdkVariant() {
-		if ctx.isForPlatform() {
+	if mod.IsCrt() && !mod.IsSdkVariant() {
+		if ctxIsForPlatform {
 			ver = strconv.Itoa(android.FutureApiLevelInt)
 		} else { // for apex
-			ver = ctx.apexSdkVersion().String()
+			ver = mod.ApexSdkVersion().String()
 			if ver == "" { // in case when min_sdk_version was not set by the APEX
-				ver = ctx.sdkVersion()
+				ver = mod.SdkVersion()
 			}
 		}
 	}
 
 	// Also make sure that minSdkVersion is not greater than sdkVersion, if they are both numbers
-	sdkVersionInt, err := strconv.Atoi(ctx.sdkVersion())
+	sdkVersionInt, err := strconv.Atoi(mod.SdkVersion())
 	minSdkVersionInt, err2 := strconv.Atoi(ver)
 	if err == nil && err2 == nil {
 		if sdkVersionInt < minSdkVersionInt {
@@ -1709,6 +1725,14 @@
 	return ver
 }
 
+func (ctx *moduleContextImpl) minSdkVersion() string {
+	platformSdkVersion := ""
+	if ctx.ctx.Device() {
+		platformSdkVersion = ctx.ctx.Config().PlatformSdkVersion().String()
+	}
+	return MinSdkVersion(ctx.mod, CtxIsForPlatform(ctx.ctx), ctx.ctx.Device(), platformSdkVersion)
+}
+
 func (ctx *moduleContextImpl) isSdkVariant() bool {
 	return ctx.mod.IsSdkVariant()
 }
@@ -1772,8 +1796,8 @@
 	return ctx.mod.BaseModuleName()
 }
 
-func (ctx *moduleContextImpl) isForPlatform() bool {
-	apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider)
+func CtxIsForPlatform(ctx android.BaseModuleContext) bool {
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	return apexInfo.IsForPlatform()
 }
 
@@ -1782,10 +1806,6 @@
 	return apexInfo.ApexVariationName
 }
 
-func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel {
-	return ctx.mod.apexSdkVersion
-}
-
 func (ctx *moduleContextImpl) bootstrap() bool {
 	return ctx.mod.Bootstrap()
 }
@@ -1800,9 +1820,9 @@
 
 func (ctx *moduleContextImpl) getSharedFlags() *SharedFlags {
 	shared := &ctx.mod.sharedFlags
-	if shared.flagsMap == nil {
-		shared.numSharedFlags = 0
-		shared.flagsMap = make(map[string]string)
+	if shared.FlagsMap == nil {
+		shared.NumSharedFlags = 0
+		shared.FlagsMap = make(map[string]string)
 	}
 	return shared
 }
@@ -1866,6 +1886,14 @@
 	return name
 }
 
+func (c *Module) Multilib() string {
+	return c.Arch().ArchType.Multilib
+}
+
+func (c *Module) ApexSdkVersion() android.ApiLevel {
+	return c.apexSdkVersion
+}
+
 func (c *Module) Symlinks() []string {
 	if p, ok := c.installer.(interface {
 		symlinkList() []string
@@ -2223,8 +2251,8 @@
 	}
 
 	linkableInfo := CreateCommonLinkableInfo(c)
-	if lib, ok := c.linker.(versionedInterface); ok {
-		linkableInfo.StubsVersion = lib.stubsVersion()
+	if lib, ok := c.linker.(VersionedInterface); ok {
+		linkableInfo.StubsVersion = lib.StubsVersion()
 	}
 	if c.linker != nil {
 		if library, ok := c.linker.(libraryInterface); ok {
@@ -2290,14 +2318,14 @@
 				SnapshotAndroidMkSuffix: s.SnapshotAndroidMkSuffix(),
 			}
 		}
-		if v, ok := c.linker.(versionedInterface); ok {
-			name := v.implementationModuleName(ctx.OtherModuleName(c))
+		if v, ok := c.linker.(VersionedInterface); ok {
+			name := v.ImplementationModuleName(ctx.OtherModuleName(c))
 			ccInfo.LinkerInfo.ImplementationModuleName = &name
 		}
 	}
 	if c.library != nil {
 		ccInfo.LibraryInfo = &LibraryInfo{
-			BuildStubs: c.library.buildStubs(),
+			BuildStubs: c.library.BuildStubs(),
 		}
 	}
 	android.SetProvider(ctx, CcInfoProvider, &ccInfo)
@@ -2309,7 +2337,7 @@
 	}
 }
 
-func CreateCommonLinkableInfo(mod LinkableInterface) *LinkableInfo {
+func CreateCommonLinkableInfo(mod VersionedLinkableInterface) *LinkableInfo {
 	return &LinkableInfo{
 		StaticExecutable:     mod.StaticExecutable(),
 		HasStubsVariants:     mod.HasStubsVariants(),
@@ -2465,7 +2493,7 @@
 		c.orderfile.begin(ctx)
 	}
 	if ctx.useSdk() && c.IsSdkVariant() {
-		version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
+		version, err := NativeApiLevelFromUser(ctx, ctx.sdkVersion())
 		if err != nil {
 			ctx.PropertyErrorf("sdk_version", err.Error())
 			c.Properties.Sdk_version = nil
@@ -2979,6 +3007,7 @@
 		// Recovery code is not NDK
 		return
 	}
+	// Change this to LinkableInterface if Rust gets NDK support, which stubDecorators are for
 	if c, ok := to.(*Module); ok {
 		if c.StubDecorator() {
 			// These aren't real libraries, but are the stub shared libraries that are included in
@@ -3085,7 +3114,7 @@
 		if depTag == staticVariantTag {
 			return false
 		}
-		if depTag == stubImplDepTag {
+		if depTag == StubImplDepTag {
 			return false
 		}
 		if depTag == android.RequiredDepTag {
@@ -3116,7 +3145,7 @@
 	}
 	if module, ok := ctx.Module().(*Module); ok {
 		if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
-			if lib.hasLLNDKStubs() {
+			if lib.HasLLNDKStubs() {
 				ctx.WalkDeps(check)
 			}
 		}
@@ -3254,7 +3283,7 @@
 			// The reuseObjTag dependency still exists because the LinkageMutator runs before the
 			// version mutator, so the stubs variant is created from the shared variant that
 			// already has the reuseObjTag dependency on the static variant.
-			if !c.library.buildStubs() {
+			if !c.library.BuildStubs() {
 				staticAnalogue, _ := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
 				objs := staticAnalogue.ReuseObjects
 				depPaths.Objs = depPaths.Objs.Append(objs)
@@ -3820,6 +3849,10 @@
 	return false
 }
 
+func (c *Module) ForceDisableSanitizers() {
+	c.sanitize.Properties.ForceDisable = true
+}
+
 func (c *Module) StaticExecutable() bool {
 	if b, ok := c.linker.(*binaryDecorator); ok {
 		return b.static()
@@ -3875,7 +3908,7 @@
 	if lib := c.library; lib != nil {
 		// Stub libs and prebuilt libs in a versioned SDK are not
 		// installable to APEX even though they are shared libs.
-		return lib.shared() && !lib.buildStubs()
+		return lib.shared() && !lib.BuildStubs()
 	}
 	return false
 }
@@ -3951,7 +3984,7 @@
 
 // Implements android.ApexModule
 func (c *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
-	if depTag == stubImplDepTag {
+	if depTag == StubImplDepTag {
 		// We don't track from an implementation library to its stubs.
 		return false
 	}
diff --git a/cc/compiler.go b/cc/compiler.go
index f2bced1..d237c6e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -785,7 +785,7 @@
 	objs := compileObjs(ctx, buildFlags, "", srcs,
 		append(android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_disabled_srcs), compiler.generatedSources...),
 		android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_timeout_srcs),
-		pathDeps, compiler.cFlagsDeps)
+		pathDeps, compiler.cFlagsDeps, ctx.getSharedFlags())
 
 	if ctx.Failed() {
 		return Objects{}
@@ -795,10 +795,12 @@
 }
 
 // Compile a list of source files into objects a specified subdirectory
-func compileObjs(ctx ModuleContext, flags builderFlags, subdir string,
-	srcFiles, noTidySrcs, timeoutTidySrcs, pathDeps android.Paths, cFlagsDeps android.Paths) Objects {
+func compileObjs(ctx android.ModuleContext, flags builderFlags, subdir string,
+	srcFiles, noTidySrcs, timeoutTidySrcs, pathDeps android.Paths, cFlagsDeps android.Paths,
+	sharedFlags *SharedFlags) Objects {
 
-	return transformSourceToObj(ctx, subdir, srcFiles, noTidySrcs, timeoutTidySrcs, flags, pathDeps, cFlagsDeps)
+	return transformSourceToObj(ctx, subdir, srcFiles, noTidySrcs, timeoutTidySrcs, flags, pathDeps, cFlagsDeps,
+		sharedFlags)
 }
 
 // Properties for rust_bindgen related to generating rust bindings.
diff --git a/cc/coverage.go b/cc/coverage.go
index dbb424f..4e058bd 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -354,10 +354,10 @@
 	}
 }
 
-func parseSymbolFileForAPICoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath {
+func parseSymbolFileForAPICoverage(ctx android.ModuleContext, symbolFile string) android.ModuleOutPath {
 	apiLevelsJson := android.GetApiLevelsJson(ctx)
 	symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
-	outputFile := ctx.baseModuleName() + ".xml"
+	outputFile := ctx.Module().(LinkableInterface).BaseModuleName() + ".xml"
 	parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFile)
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 056b0da..a8e4cb7 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -244,7 +244,7 @@
 	// libraries must be handled differently - by looking for the stubDecorator.
 	// Discard LLNDK prebuilts stubs as well.
 	if hasCcInfo {
-		if ccInfo.LinkerInfo.StubDecoratorInfo != nil {
+		if ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.StubDecoratorInfo != nil {
 			return false
 		}
 		// Discard installable:false libraries because they are expected to be absent
diff --git a/cc/library.go b/cc/library.go
index 0566182..b218bce 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -64,21 +64,7 @@
 	Static_ndk_lib *bool
 
 	// Generate stubs to make this library accessible to APEXes.
-	Stubs struct {
-		// Relative path to the symbol map. The symbol map provides the list of
-		// symbols that are exported for stubs variant of this library.
-		Symbol_file *string `android:"path,arch_variant"`
-
-		// List versions to generate stubs libs for. The version name "current" is always
-		// implicitly added.
-		Versions []string
-
-		// Whether to not require the implementation of the library to be installed if a
-		// client of the stubs is installed. Defaults to true; set to false if the
-		// implementation is made available by some other means, e.g. in a Microdroid
-		// virtual machine.
-		Implementation_installable *bool
-	} `android:"arch_variant"`
+	Stubs StubsProperties `android:"arch_variant"`
 
 	// set the name of the output
 	Stem *string `android:"arch_variant"`
@@ -127,6 +113,22 @@
 	Vendor_public_library vendorPublicLibraryProperties
 }
 
+type StubsProperties struct {
+	// Relative path to the symbol map. The symbol map provides the list of
+	// symbols that are exported for stubs variant of this library.
+	Symbol_file *string `android:"path,arch_variant"`
+
+	// List versions to generate stubs libs for. The version name "current" is always
+	// implicitly added.
+	Versions []string
+
+	// Whether to not require the implementation of the library to be installed if a
+	// client of the stubs is installed. Defaults to true; set to false if the
+	// implementation is made available by some other means, e.g. in a Microdroid
+	// virtual machine.
+	Implementation_installable *bool
+}
+
 // StaticProperties is a properties stanza to affect only attributes of the "static" variants of a
 // library module.
 type StaticProperties struct {
@@ -527,7 +529,7 @@
 		// Wipe all the module-local properties, leaving only the global properties.
 		flags.Local = LocalOrGlobalFlags{}
 	}
-	if library.buildStubs() {
+	if library.BuildStubs() {
 		// Remove -include <file> when compiling stubs. Otherwise, the force included
 		// headers might cause conflicting types error with the symbols in the
 		// generated stubs source code. e.g.
@@ -567,6 +569,8 @@
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+	sharedFlags := ctx.getSharedFlags()
+
 	if ctx.IsLlndk() {
 		// Get the matching SDK version for the vendor API level.
 		version, err := android.GetSdkVersionForVendorApiLevel(ctx.Config().VendorApiLevel())
@@ -575,27 +579,27 @@
 		}
 
 		// This is the vendor variant of an LLNDK library, build the LLNDK stubs.
-		nativeAbiResult := parseNativeAbiDefinition(ctx,
+		nativeAbiResult := ParseNativeAbiDefinition(ctx,
 			String(library.Properties.Llndk.Symbol_file),
 			nativeClampedApiLevel(ctx, version), "--llndk")
-		objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
+		objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, sharedFlags)
 		if !Bool(library.Properties.Llndk.Unversioned) {
 			library.versionScriptPath = android.OptionalPathForPath(
-				nativeAbiResult.versionScript)
+				nativeAbiResult.VersionScript)
 		}
 		return objs
 	}
 	if ctx.IsVendorPublicLibrary() {
-		nativeAbiResult := parseNativeAbiDefinition(ctx,
+		nativeAbiResult := ParseNativeAbiDefinition(ctx,
 			String(library.Properties.Vendor_public_library.Symbol_file),
 			android.FutureApiLevel, "")
-		objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
+		objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, sharedFlags)
 		if !Bool(library.Properties.Vendor_public_library.Unversioned) {
-			library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.versionScript)
+			library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript)
 		}
 		return objs
 	}
-	if library.buildStubs() {
+	if library.BuildStubs() {
 		return library.compileModuleLibApiStubs(ctx, flags, deps)
 	}
 
@@ -635,18 +639,65 @@
 		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary, srcs,
 			android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Tidy_disabled_srcs),
 			android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Tidy_timeout_srcs),
-			library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps))
+			library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps, sharedFlags))
 	} else if library.shared() {
 		srcs := android.PathsForModuleSrc(ctx, sharedSrcs)
 		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary, srcs,
 			android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Tidy_disabled_srcs),
 			android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Tidy_timeout_srcs),
-			library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps))
+			library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps, sharedFlags))
 	}
 
 	return objs
 }
 
+type ApiStubsParams struct {
+	NotInPlatform  bool
+	IsNdk          bool
+	BaseModuleName string
+	ModuleName     string
+}
+
+// GetApiStubsFlags calculates the genstubFlags string to pass to ParseNativeAbiDefinition
+func GetApiStubsFlags(api ApiStubsParams) string {
+	var flag string
+
+	// b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
+	// systemapi, respectively. The former is for symbols defined in platform libraries
+	// and the latter is for symbols defined in APEXes.
+	// A single library can contain either # apex or # systemapi, but not both.
+	// The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
+	// However, having this distinction helps guard accidental
+	// promotion or demotion of API and also helps the API review process b/191371676
+	if api.NotInPlatform {
+		flag = "--apex"
+	} else {
+		flag = "--systemapi"
+	}
+
+	// b/184712170, unless the lib is an NDK library, exclude all public symbols from
+	// the stub so that it is mandated that all symbols are explicitly marked with
+	// either apex or systemapi.
+	if !api.IsNdk &&
+		// the symbol files of libclang libs are autogenerated and do not contain systemapi tags
+		// TODO (spandandas): Update mapfile.py to include #systemapi tag on all symbols
+		!strings.Contains(api.ModuleName, "libclang_rt") {
+		flag = flag + " --no-ndk"
+	}
+
+	// TODO(b/361303067): Remove this special case if bionic/ projects are added to ART development branches.
+	if isBionic(api.BaseModuleName) {
+		// set the flags explicitly for bionic libs.
+		// this is necessary for development in minimal branches which does not contain bionic/*.
+		// In such minimal branches, e.g. on the prebuilt libc stubs
+		// 1. IsNdk will return false (since the ndk_library definition for libc does not exist)
+		// 2. NotInPlatform will return true (since the source com.android.runtime does not exist)
+		flag = "--apex"
+	}
+
+	return flag
+}
+
 // Compile stubs for the API surface between platform and apex
 // This method will be used by source and prebuilt cc module types.
 func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -654,48 +705,26 @@
 	if library.Properties.Stubs.Symbol_file == nil {
 		return Objects{}
 	}
+
 	symbolFile := String(library.Properties.Stubs.Symbol_file)
 	library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
-	// b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
-	// systemapi, respectively. The former is for symbols defined in platform libraries
-	// and the latter is for symbols defined in APEXes.
-	// A single library can contain either # apex or # systemapi, but not both.
-	// The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
-	// However, having this distinction helps guard accidental
-	// promotion or demotion of API and also helps the API review process b/191371676
-	var flag string
-	if ctx.notInPlatform() {
-		flag = "--apex"
-	} else {
-		flag = "--systemapi"
+
+	apiParams := ApiStubsParams{
+		NotInPlatform:  ctx.notInPlatform(),
+		IsNdk:          ctx.Module().(*Module).IsNdk(ctx.Config()),
+		BaseModuleName: ctx.baseModuleName(),
+		ModuleName:     ctx.ModuleName(),
 	}
-	// b/184712170, unless the lib is an NDK library, exclude all public symbols from
-	// the stub so that it is mandated that all symbols are explicitly marked with
-	// either apex or systemapi.
-	if !ctx.Module().(*Module).IsNdk(ctx.Config()) &&
-		// the symbol files of libclang libs are autogenerated and do not contain systemapi tags
-		// TODO (spandandas): Update mapfile.py to include #systemapi tag on all symbols
-		!strings.Contains(ctx.ModuleName(), "libclang_rt") {
-		flag = flag + " --no-ndk"
-	}
-	// TODO(b/361303067): Remove this special case if bionic/ projects are added to ART development branches.
-	if isBionic(ctx.baseModuleName()) {
-		// set the flags explicitly for bionic libs.
-		// this is necessary for development in minimal branches which does not contain bionic/*.
-		// In such minimal branches, e.g. on the prebuilt libc stubs
-		// 1. IsNdk will return false (since the ndk_library definition for libc does not exist)
-		// 2. NotInPlatform will return true (since the source com.android.runtime does not exist)
-		flag = "--apex"
-	}
-	nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
+	flag := GetApiStubsFlags(apiParams)
+
+	nativeAbiResult := ParseNativeAbiDefinition(ctx, symbolFile,
 		android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
-	objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
+	objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, ctx.getSharedFlags())
 
 	library.versionScriptPath = android.OptionalPathForPath(
-		nativeAbiResult.versionScript)
-
+		nativeAbiResult.VersionScript)
 	// Parse symbol file to get API list for coverage
-	if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
+	if library.StubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
 		library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
 	}
 
@@ -703,7 +732,7 @@
 }
 
 type libraryInterface interface {
-	versionedInterface
+	VersionedInterface
 
 	static() bool
 	shared() bool
@@ -727,32 +756,49 @@
 
 	apexAvailable() []string
 
-	getAPIListCoverageXMLPath() android.ModuleOutPath
+	setAPIListCoverageXMLPath(out android.ModuleOutPath)
+	symbolsFile() *string
+	setSymbolFilePath(path android.Path)
+	setVersionScriptPath(path android.OptionalPath)
 
 	installable() *bool
 }
 
-type versionedInterface interface {
-	buildStubs() bool
-	setBuildStubs(isLatest bool)
-	hasStubsVariants() bool
-	isStubsImplementationRequired() bool
-	setStubsVersion(string)
-	stubsVersion() string
+func (library *libraryDecorator) symbolsFile() *string {
+	return library.Properties.Stubs.Symbol_file
+}
 
-	stubsVersions(ctx android.BaseModuleContext) []string
-	setAllStubsVersions([]string)
-	allStubsVersions() []string
+func (library *libraryDecorator) setSymbolFilePath(path android.Path) {
+	library.stubsSymbolFilePath = path
+}
 
-	implementationModuleName(name string) string
-	hasLLNDKStubs() bool
-	hasLLNDKHeaders() bool
-	hasVendorPublicLibrary() bool
-	isLLNDKMovedToApex() bool
+func (library *libraryDecorator) setVersionScriptPath(path android.OptionalPath) {
+	library.versionScriptPath = path
+}
+
+type VersionedInterface interface {
+	BuildStubs() bool
+	SetBuildStubs(isLatest bool)
+	HasStubsVariants() bool
+	IsStubsImplementationRequired() bool
+	SetStubsVersion(string)
+	StubsVersion() string
+
+	StubsVersions(ctx android.BaseModuleContext) []string
+	SetAllStubsVersions([]string)
+	AllStubsVersions() []string
+
+	ImplementationModuleName(name string) string
+	HasLLNDKStubs() bool
+	HasLLNDKHeaders() bool
+	HasVendorPublicLibrary() bool
+	IsLLNDKMovedToApex() bool
+
+	GetAPIListCoverageXMLPath() android.ModuleOutPath
 }
 
 var _ libraryInterface = (*libraryDecorator)(nil)
-var _ versionedInterface = (*libraryDecorator)(nil)
+var _ VersionedInterface = (*libraryDecorator)(nil)
 
 func (library *libraryDecorator) getLibNameHelper(baseModuleName string, inVendor bool, inProduct bool) string {
 	name := library.libName
@@ -801,9 +847,9 @@
 	library.baseLinker.linkerInit(ctx)
 	// Let baseLinker know whether this variant is for stubs or not, so that
 	// it can omit things that are not required for linking stubs.
-	library.baseLinker.dynamicProperties.BuildStubs = library.buildStubs()
+	library.baseLinker.dynamicProperties.BuildStubs = library.BuildStubs()
 
-	if library.buildStubs() {
+	if library.BuildStubs() {
 		macroNames := versioningMacroNamesList(ctx.Config())
 		myName := versioningMacroName(ctx.ModuleName())
 		versioningMacroNamesListMutex.Lock()
@@ -962,8 +1008,8 @@
 		moduleInfoJSON.Uninstallable = true
 	}
 
-	if library.buildStubs() && library.stubsVersion() != "" {
-		moduleInfoJSON.SubName += "." + library.stubsVersion()
+	if library.BuildStubs() && library.StubsVersion() != "" {
+		moduleInfoJSON.SubName += "." + library.StubsVersion()
 	}
 
 	// If a library providing a stub is included in an APEX, the private APIs of the library
@@ -974,10 +1020,10 @@
 	// very early stage in the boot process).
 	if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.notInPlatform() &&
 		!ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && !ctx.useVndk() && !ctx.static() {
-		if library.buildStubs() && library.isLatestStubVersion() {
+		if library.BuildStubs() && library.isLatestStubVersion() {
 			moduleInfoJSON.SubName = ""
 		}
-		if !library.buildStubs() {
+		if !library.BuildStubs() {
 			moduleInfoJSON.SubName = ".bootstrap"
 		}
 	}
@@ -1120,7 +1166,7 @@
 
 	stripFlags := flagsToStripFlags(flags)
 	needsStrip := library.stripper.NeedsStrip(ctx)
-	if library.buildStubs() {
+	if library.BuildStubs() {
 		// No need to strip stubs libraries
 		needsStrip = false
 	}
@@ -1174,7 +1220,7 @@
 	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
 
-	if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.buildStubs() {
+	if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.BuildStubs() {
 		if ctx.Module().(*Module).WholeRustStaticlib {
 			deps.WholeStaticLibs = append(deps.WholeStaticLibs, generatedLib)
 		} else {
@@ -1205,18 +1251,18 @@
 		SharedLibrary:                        unstrippedOutputFile,
 		TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering,
 		Target:                               ctx.Target(),
-		IsStubs:                              library.buildStubs(),
+		IsStubs:                              library.BuildStubs(),
 	})
 
-	addStubDependencyProviders(ctx)
+	AddStubDependencyProviders(ctx)
 
 	return unstrippedOutputFile
 }
 
 // Visits the stub variants of the library and returns a struct containing the stub .so paths
-func addStubDependencyProviders(ctx ModuleContext) []SharedStubLibrary {
+func AddStubDependencyProviders(ctx android.BaseModuleContext) []SharedStubLibrary {
 	stubsInfo := []SharedStubLibrary{}
-	stubs := ctx.GetDirectDepsProxyWithTag(stubImplDepTag)
+	stubs := ctx.GetDirectDepsProxyWithTag(StubImplDepTag)
 	if len(stubs) > 0 {
 		for _, stub := range stubs {
 			stubInfo, ok := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
@@ -1237,10 +1283,11 @@
 		if len(stubsInfo) > 0 {
 			android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
 				SharedStubLibraries: stubsInfo,
-				IsLLNDK:             ctx.IsLlndk(),
+				IsLLNDK:             ctx.Module().(LinkableInterface).IsLlndk(),
 			})
 		}
 	}
+
 	return stubsInfo
 }
 
@@ -1257,7 +1304,7 @@
 }
 
 func (library *libraryDecorator) nativeCoverage() bool {
-	if library.header() || library.buildStubs() {
+	if library.header() || library.BuildStubs() {
 		return false
 	}
 	return true
@@ -1726,9 +1773,9 @@
 }
 
 func (library *libraryDecorator) exportVersioningMacroIfNeeded(ctx android.BaseModuleContext) {
-	if library.buildStubs() && library.stubsVersion() != "" && !library.skipAPIDefine {
+	if library.BuildStubs() && library.StubsVersion() != "" && !library.skipAPIDefine {
 		name := versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx))
-		apiLevel, err := android.ApiLevelFromUser(ctx, library.stubsVersion())
+		apiLevel, err := android.ApiLevelFromUser(ctx, library.StubsVersion())
 		if err != nil {
 			ctx.ModuleErrorf("Can't export version macro: %s", err.Error())
 		}
@@ -1780,8 +1827,8 @@
 func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if library.shared() {
 		translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
-		if library.hasStubsVariants() && !ctx.Host() && !ctx.isSdkVariant() &&
-			InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() &&
+		if library.HasStubsVariants() && !ctx.Host() && !ctx.isSdkVariant() &&
+			InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.BuildStubs() &&
 			!translatedArch && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() {
 			// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
 			// The original path becomes a symlink to the corresponding file in the
@@ -1798,7 +1845,7 @@
 	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
 		!ctx.InVendorOrProduct() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() &&
 		library.baseLinker.sanitize.isUnsanitizedVariant() &&
-		ctx.isForPlatform() && !ctx.isPreventInstall() {
+		CtxIsForPlatform(ctx) && !ctx.isPreventInstall() {
 		installPath := getUnversionedLibraryInstallPath(ctx).Join(ctx, file.Base())
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
@@ -1868,32 +1915,32 @@
 	library.MutatedProperties.BuildStatic = false
 }
 
-// hasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs.
-func (library *libraryDecorator) hasLLNDKStubs() bool {
+// HasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs.
+func (library *libraryDecorator) HasLLNDKStubs() bool {
 	return String(library.Properties.Llndk.Symbol_file) != ""
 }
 
 // hasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs.
-func (library *libraryDecorator) hasLLNDKHeaders() bool {
+func (library *libraryDecorator) HasLLNDKHeaders() bool {
 	return Bool(library.Properties.Llndk.Llndk_headers)
 }
 
-// isLLNDKMovedToApex returns true if this cc_library module sets the llndk.moved_to_apex property.
-func (library *libraryDecorator) isLLNDKMovedToApex() bool {
+// IsLLNDKMovedToApex returns true if this cc_library module sets the llndk.moved_to_apex property.
+func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
 	return Bool(library.Properties.Llndk.Moved_to_apex)
 }
 
-// hasVendorPublicLibrary returns true if this cc_library module has a variant that will build
+// HasVendorPublicLibrary returns true if this cc_library module has a variant that will build
 // vendor public library stubs.
-func (library *libraryDecorator) hasVendorPublicLibrary() bool {
+func (library *libraryDecorator) HasVendorPublicLibrary() bool {
 	return String(library.Properties.Vendor_public_library.Symbol_file) != ""
 }
 
-func (library *libraryDecorator) implementationModuleName(name string) string {
+func (library *libraryDecorator) ImplementationModuleName(name string) string {
 	return name
 }
 
-func (library *libraryDecorator) buildStubs() bool {
+func (library *libraryDecorator) BuildStubs() bool {
 	return library.MutatedProperties.BuildStubs
 }
 
@@ -1901,7 +1948,7 @@
 	if props := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module)); props.Symbol_file != nil {
 		return props.Symbol_file
 	}
-	if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
+	if library.HasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
 		return library.Properties.Stubs.Symbol_file
 	}
 	// TODO(b/309880485): Distinguish platform, NDK, LLNDK, and APEX version scripts.
@@ -1911,35 +1958,35 @@
 	return nil
 }
 
-func (library *libraryDecorator) hasStubsVariants() bool {
+func (library *libraryDecorator) HasStubsVariants() bool {
 	// Just having stubs.symbol_file is enough to create a stub variant. In that case
 	// the stub for the future API level is created.
 	return library.Properties.Stubs.Symbol_file != nil ||
 		len(library.Properties.Stubs.Versions) > 0
 }
 
-func (library *libraryDecorator) isStubsImplementationRequired() bool {
+func (library *libraryDecorator) IsStubsImplementationRequired() bool {
 	return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
 }
 
-func (library *libraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
-	if !library.hasStubsVariants() {
+func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
+	if !library.HasStubsVariants() {
 		return nil
 	}
 
-	if library.hasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() {
+	if library.HasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() {
 		// LLNDK libraries only need a single stubs variant (""), which is
 		// added automatically in createVersionVariations().
 		return nil
 	}
 
 	// Future API level is implicitly added if there isn't
-	versions := addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
-	normalizeVersions(ctx, versions)
+	versions := AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+	NormalizeVersions(ctx, versions)
 	return versions
 }
 
-func addCurrentVersionIfNotPresent(vers []string) []string {
+func AddCurrentVersionIfNotPresent(vers []string) []string {
 	if inList(android.FutureApiLevel.String(), vers) {
 		return vers
 	}
@@ -1952,24 +1999,24 @@
 	return append(vers, android.FutureApiLevel.String())
 }
 
-func (library *libraryDecorator) setStubsVersion(version string) {
+func (library *libraryDecorator) SetStubsVersion(version string) {
 	library.MutatedProperties.StubsVersion = version
 }
 
-func (library *libraryDecorator) stubsVersion() string {
+func (library *libraryDecorator) StubsVersion() string {
 	return library.MutatedProperties.StubsVersion
 }
 
-func (library *libraryDecorator) setBuildStubs(isLatest bool) {
+func (library *libraryDecorator) SetBuildStubs(isLatest bool) {
 	library.MutatedProperties.BuildStubs = true
 	library.MutatedProperties.IsLatestVersion = isLatest
 }
 
-func (library *libraryDecorator) setAllStubsVersions(versions []string) {
+func (library *libraryDecorator) SetAllStubsVersions(versions []string) {
 	library.MutatedProperties.AllStubsVersions = versions
 }
 
-func (library *libraryDecorator) allStubsVersions() []string {
+func (library *libraryDecorator) AllStubsVersions() []string {
 	return library.MutatedProperties.AllStubsVersions
 }
 
@@ -1998,7 +2045,7 @@
 }
 
 func (library *libraryDecorator) makeUninstallable(mod *Module) {
-	if library.static() && library.buildStatic() && !library.buildStubs() {
+	if library.static() && library.buildStatic() && !library.BuildStubs() {
 		// If we're asked to make a static library uninstallable we don't do
 		// anything since AndroidMkEntries always sets LOCAL_UNINSTALLABLE_MODULE
 		// for these entries. This is done to still get the make targets for NOTICE
@@ -2012,10 +2059,14 @@
 	return library.path.Partition()
 }
 
-func (library *libraryDecorator) getAPIListCoverageXMLPath() android.ModuleOutPath {
+func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath {
 	return library.apiListCoverageXmlPath
 }
 
+func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) {
+	library.apiListCoverageXmlPath = xml
+}
+
 func (library *libraryDecorator) overriddenModules() []string {
 	return library.Properties.Overrides
 }
@@ -2242,10 +2293,10 @@
 	}
 }
 
-// normalizeVersions modifies `versions` in place, so that each raw version
+// NormalizeVersions modifies `versions` in place, so that each raw version
 // string becomes its normalized canonical form.
 // Validates that the versions in `versions` are specified in least to greatest order.
-func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
+func NormalizeVersions(ctx android.BaseModuleContext, versions []string) {
 	var previous android.ApiLevel
 	for i, v := range versions {
 		ver, err := android.ApiLevelFromUser(ctx, v)
@@ -2262,7 +2313,7 @@
 }
 
 func perApiVersionVariations(mctx android.BaseModuleContext, minSdkVersion string) []string {
-	from, err := nativeApiLevelFromUser(mctx, minSdkVersion)
+	from, err := NativeApiLevelFromUser(mctx, minSdkVersion)
 	if err != nil {
 		mctx.PropertyErrorf("min_sdk_version", err.Error())
 		return []string{""}
@@ -2290,25 +2341,29 @@
 		module.CcLibraryInterface() && module.Shared()
 }
 
-func moduleLibraryInterface(module blueprint.Module) libraryInterface {
-	if m, ok := module.(*Module); ok {
-		return m.library
+func moduleVersionedInterface(module blueprint.Module) VersionedInterface {
+	if m, ok := module.(VersionedLinkableInterface); ok {
+		return m.VersionedInterface()
 	}
 	return nil
 }
 
 // setStubsVersions normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions.
-func setStubsVersions(mctx android.BaseModuleContext, library libraryInterface, module *Module) {
-	if !library.buildShared() || !canBeVersionVariant(module) {
+func setStubsVersions(mctx android.BaseModuleContext, module VersionedLinkableInterface) {
+	// TODO(ivanlozano) remove this when Rust supports stubs
+	if module.RustLibraryInterface() {
 		return
 	}
-	versions := library.stubsVersions(mctx)
+	if !module.BuildSharedVariant() || !canBeVersionVariant(module) {
+		return
+	}
+	versions := module.VersionedInterface().StubsVersions(mctx)
 	if mctx.Failed() {
 		return
 	}
 	// Set the versions on the pre-mutated module so they can be read by any llndk modules that
 	// depend on the implementation library and haven't been mutated yet.
-	library.setAllStubsVersions(versions)
+	module.VersionedInterface().SetAllStubsVersions(versions)
 }
 
 // versionTransitionMutator splits a module into the mandatory non-stubs variant
@@ -2319,14 +2374,17 @@
 	if ctx.Os() != android.Android {
 		return []string{""}
 	}
-
-	m, ok := ctx.Module().(*Module)
-	if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
-		setStubsVersions(ctx, library, m)
-
-		return append(slices.Clone(library.allStubsVersions()), "")
-	} else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() {
-		return perApiVersionVariations(ctx, m.MinSdkVersion())
+	if m, ok := ctx.Module().(VersionedLinkableInterface); ok {
+		// TODO(ivanlozano) remove this when Rust supports stubs
+		if m.RustLibraryInterface() {
+			return []string{""}
+		}
+		if m.CcLibraryInterface() && canBeVersionVariant(m) {
+			setStubsVersions(ctx, m)
+			return append(slices.Clone(m.VersionedInterface().AllStubsVersions()), "")
+		} else if m.SplitPerApiLevel() && m.IsSdkVariant() {
+			return perApiVersionVariations(ctx, m.MinSdkVersion())
+		}
 	}
 
 	return []string{""}
@@ -2340,11 +2398,11 @@
 	if ctx.Os() != android.Android {
 		return ""
 	}
-	m, ok := ctx.Module().(*Module)
-	if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+	m, ok := ctx.Module().(VersionedLinkableInterface)
+	if library := moduleVersionedInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
 		if incomingVariation == "latest" {
 			latestVersion := ""
-			versions := library.allStubsVersions()
+			versions := library.AllStubsVersions()
 			if len(versions) > 0 {
 				latestVersion = versions[len(versions)-1]
 			}
@@ -2369,39 +2427,44 @@
 		return
 	}
 
-	m, ok := ctx.Module().(*Module)
-	if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+	m, ok := ctx.Module().(VersionedLinkableInterface)
+	if library := moduleVersionedInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+		// TODO(ivanlozano) remove this when Rust supports stubs
+		if m.RustLibraryInterface() {
+			return
+		}
+
 		isLLNDK := m.IsLlndk()
 		isVendorPublicLibrary := m.IsVendorPublicLibrary()
 
 		if variation != "" || isLLNDK || isVendorPublicLibrary {
 			// A stubs or LLNDK stubs variant.
-			if m.sanitize != nil {
-				m.sanitize.Properties.ForceDisable = true
+			if sm, ok := ctx.Module().(PlatformSanitizeable); ok && sm.SanitizePropDefined() {
+				sm.ForceDisableSanitizers()
 			}
-			if m.stl != nil {
-				m.stl.Properties.Stl = StringPtr("none")
-			}
-			m.Properties.PreventInstall = true
-			lib := moduleLibraryInterface(m)
-			allStubsVersions := library.allStubsVersions()
+			m.SetStl("none")
+			m.SetPreventInstall()
+			allStubsVersions := m.VersionedInterface().AllStubsVersions()
 			isLatest := len(allStubsVersions) > 0 && variation == allStubsVersions[len(allStubsVersions)-1]
-			lib.setBuildStubs(isLatest)
+			m.VersionedInterface().SetBuildStubs(isLatest)
 		}
 		if variation != "" {
 			// A non-LLNDK stubs module is hidden from make
-			library.setStubsVersion(variation)
-			m.Properties.HideFromMake = true
+			m.VersionedInterface().SetStubsVersion(variation)
+			m.SetHideFromMake()
 		} else {
 			// A non-LLNDK implementation module has a dependency to all stubs versions
-			for _, version := range library.allStubsVersions() {
-				ctx.AddVariationDependencies([]blueprint.Variation{{"version", version}},
-					stubImplDepTag, ctx.ModuleName())
+			for _, version := range m.VersionedInterface().AllStubsVersions() {
+				ctx.AddVariationDependencies(
+					[]blueprint.Variation{
+						{Mutator: "version", Variation: version},
+						{Mutator: "link", Variation: "shared"}},
+					StubImplDepTag, ctx.ModuleName())
 			}
 		}
 	} else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() {
-		m.Properties.Sdk_version = StringPtr(variation)
-		m.Properties.Min_sdk_version = StringPtr(variation)
+		m.SetSdkVersion(variation)
+		m.SetMinSdkVersion(variation)
 	}
 }
 
@@ -2415,7 +2478,8 @@
 	injectBoringSSLHash := Bool(inject)
 	ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) {
 		if tag, ok := ctx.OtherModuleDependencyTag(dep).(libraryDependencyTag); ok && tag.static() {
-			if ccInfo, ok := android.OtherModuleProvider(ctx, dep, CcInfoProvider); ok && ccInfo.LinkerInfo.LibraryDecoratorInfo != nil {
+			if ccInfo, ok := android.OtherModuleProvider(ctx, dep, CcInfoProvider); ok &&
+				ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.LibraryDecoratorInfo != nil {
 				if ccInfo.LinkerInfo.LibraryDecoratorInfo.InjectBsslHash {
 					injectBoringSSLHash = true
 				}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index af3658d..d1440ea 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -546,7 +546,7 @@
 		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps)
 
 		if lib := ccModule.library; lib != nil {
-			if !lib.hasStubsVariants() {
+			if !lib.HasStubsVariants() {
 				// Propagate dynamic dependencies for implementation libs, but not stubs.
 				p.SharedLibs = specifiedDeps.sharedLibs
 			} else {
@@ -554,8 +554,8 @@
 				// ccModule.StubsVersion()) if the module is versioned. 2. Ensure that all
 				// the versioned stub libs are retained in the prebuilt tree; currently only
 				// the stub corresponding to ccModule.StubsVersion() is.
-				p.StubsVersions = lib.allStubsVersions()
-				if lib.buildStubs() && ccModule.stubsSymbolFilePath() == nil {
+				p.StubsVersions = lib.AllStubsVersions()
+				if lib.BuildStubs() && ccModule.stubsSymbolFilePath() == nil {
 					ctx.ModuleErrorf("Could not determine symbol_file")
 				} else {
 					p.StubsSymbolFilePath = ccModule.stubsSymbolFilePath()
diff --git a/cc/linkable.go b/cc/linkable.go
index 78ea71c..d0fda64 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -53,6 +53,9 @@
 
 	// SanitizableDepTagChecker returns a SantizableDependencyTagChecker function type.
 	SanitizableDepTagChecker() SantizableDependencyTagChecker
+
+	// ForceDisableSanitizers sets the ForceDisable sanitize property
+	ForceDisableSanitizers()
 }
 
 // SantizableDependencyTagChecker functions check whether or not a dependency
@@ -63,6 +66,26 @@
 // implementation should handle tags from both.
 type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool
 
+type VersionedLinkableInterface interface {
+	LinkableInterface
+	android.ApexModule
+
+	// VersionedInterface returns the VersionedInterface for this module
+	// (e.g. c.library), or nil if this is module is not a VersionedInterface.
+	VersionedInterface() VersionedInterface
+
+	// HasStubsVariants true if this module is a stub or has a sibling variant
+	// that is a stub.
+	HasStubsVariants() bool
+
+	// SetStl sets the stl property for CC modules. Does not panic if for other module types.
+	SetStl(string)
+	SetSdkVersion(string)
+	SetMinSdkVersion(version string)
+	ApexSdkVersion() android.ApiLevel
+	ImplementationModuleNameForMake(ctx android.BaseModuleContext) string
+}
+
 // LinkableInterface is an interface for a type of module that is linkable in a C++ library.
 type LinkableInterface interface {
 	android.Module
@@ -132,28 +155,18 @@
 	// IsNdk returns true if the library is in the configs known NDK list.
 	IsNdk(config android.Config) bool
 
-	// HasStubsVariants true if this module is a stub or has a sibling variant
-	// that is a stub.
-	HasStubsVariants() bool
-
 	// IsStubs returns true if the this is a stubs library.
 	IsStubs() bool
 
 	// IsLlndk returns true for both LLNDK (public) and LLNDK-private libs.
 	IsLlndk() bool
 
-	// HasLlndkStubs returns true if this library has a variant that will build LLNDK stubs.
-	HasLlndkStubs() bool
-
 	// NeedsLlndkVariants returns true if this module has LLNDK stubs or provides LLNDK headers.
 	NeedsLlndkVariants() bool
 
 	// NeedsVendorPublicLibraryVariants returns true if this module has vendor public library stubs.
 	NeedsVendorPublicLibraryVariants() bool
 
-	//StubsVersion returns the stubs version for this module.
-	StubsVersion() string
-
 	// UseVndk returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
 	// "product" and "vendor" variant modules return true for this function.
 	// When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
@@ -182,6 +195,7 @@
 	MinSdkVersion() string
 	AlwaysSdk() bool
 	IsSdkVariant() bool
+	Multilib() string
 
 	SplitPerApiLevel() bool
 
@@ -250,6 +264,7 @@
 
 	// FuzzModule returns the fuzz.FuzzModule associated with the module.
 	FuzzModuleStruct() fuzz.FuzzModule
+	IsCrt() bool
 }
 
 var (
diff --git a/cc/linker.go b/cc/linker.go
index b96d139..159bca4 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -457,7 +457,7 @@
 	if ctx.minSdkVersion() == "current" {
 		return true
 	}
-	parsedSdkVersion, err := nativeApiLevelFromUser(ctx, ctx.minSdkVersion())
+	parsedSdkVersion, err := NativeApiLevelFromUser(ctx, ctx.minSdkVersion())
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version",
 			"Invalid min_sdk_version value (must be int or current): %q",
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 8cc3852..5586576 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -83,9 +83,9 @@
 	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to generate the linker config.
 	movedToApexLlndkLibrariesMap := make(map[string]bool)
 	ctx.VisitAllModules(func(module android.Module) {
-		if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
-			if library.isLLNDKMovedToApex() {
-				name := library.implementationModuleName(module.(*Module).BaseModuleName())
+		if library := moduleVersionedInterface(module); library != nil && library.HasLLNDKStubs() {
+			if library.IsLLNDKMovedToApex() {
+				name := library.ImplementationModuleName(module.(*Module).BaseModuleName())
 				movedToApexLlndkLibrariesMap[name] = true
 			}
 		}
@@ -223,10 +223,10 @@
 	lib, isLib := m.linker.(*libraryDecorator)
 	prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker)
 
-	if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() {
+	if m.InVendorOrProduct() && isLib && lib.HasLLNDKStubs() {
 		m.VendorProperties.IsLLNDK = true
 	}
-	if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
+	if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.HasLLNDKStubs() {
 		m.VendorProperties.IsLLNDK = true
 	}
 
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 27a9f66..4321beb 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -133,13 +133,13 @@
 	unversionedUntil android.ApiLevel
 }
 
-var _ versionedInterface = (*stubDecorator)(nil)
+var _ VersionedInterface = (*stubDecorator)(nil)
 
 func shouldUseVersionScript(ctx BaseModuleContext, stub *stubDecorator) bool {
 	return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil)
 }
 
-func (stub *stubDecorator) implementationModuleName(name string) string {
+func (stub *stubDecorator) ImplementationModuleName(name string) string {
 	return strings.TrimSuffix(name, ndkLibrarySuffix)
 }
 
@@ -155,7 +155,7 @@
 	return versionStrs
 }
 
-func (this *stubDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
+func (this *stubDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
 	if !ctx.Module().Enabled(ctx) {
 		return nil
 	}
@@ -163,7 +163,7 @@
 		ctx.Module().Disable()
 		return nil
 	}
-	firstVersion, err := nativeApiLevelFromUser(ctx,
+	firstVersion, err := NativeApiLevelFromUser(ctx,
 		String(this.properties.First_version))
 	if err != nil {
 		ctx.PropertyErrorf("first_version", err.Error())
@@ -173,10 +173,10 @@
 }
 
 func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool {
-	this.apiLevel = nativeApiLevelOrPanic(ctx, this.stubsVersion())
+	this.apiLevel = nativeApiLevelOrPanic(ctx, this.StubsVersion())
 
 	var err error
-	this.firstVersion, err = nativeApiLevelFromUser(ctx,
+	this.firstVersion, err = NativeApiLevelFromUser(ctx,
 		String(this.properties.First_version))
 	if err != nil {
 		ctx.PropertyErrorf("first_version", err.Error())
@@ -184,7 +184,7 @@
 	}
 
 	str := proptools.StringDefault(this.properties.Unversioned_until, "minimum")
-	this.unversionedUntil, err = nativeApiLevelFromUser(ctx, str)
+	this.unversionedUntil, err = NativeApiLevelFromUser(ctx, str)
 	if err != nil {
 		ctx.PropertyErrorf("unversioned_until", err.Error())
 		return false
@@ -250,14 +250,14 @@
 	return addStubLibraryCompilerFlags(flags)
 }
 
-type ndkApiOutputs struct {
-	stubSrc       android.ModuleGenPath
-	versionScript android.ModuleGenPath
+type NdkApiOutputs struct {
+	StubSrc       android.ModuleGenPath
+	VersionScript android.ModuleGenPath
 	symbolList    android.ModuleGenPath
 }
 
-func parseNativeAbiDefinition(ctx ModuleContext, symbolFile string,
-	apiLevel android.ApiLevel, genstubFlags string) ndkApiOutputs {
+func ParseNativeAbiDefinition(ctx android.ModuleContext, symbolFile string,
+	apiLevel android.ApiLevel, genstubFlags string) NdkApiOutputs {
 
 	stubSrcPath := android.PathForModuleGen(ctx, "stub.c")
 	versionScriptPath := android.PathForModuleGen(ctx, "stub.map")
@@ -279,20 +279,20 @@
 		},
 	})
 
-	return ndkApiOutputs{
-		stubSrc:       stubSrcPath,
-		versionScript: versionScriptPath,
+	return NdkApiOutputs{
+		StubSrc:       stubSrcPath,
+		VersionScript: versionScriptPath,
 		symbolList:    symbolListPath,
 	}
 }
 
-func compileStubLibrary(ctx ModuleContext, flags Flags, src android.Path) Objects {
+func CompileStubLibrary(ctx android.ModuleContext, flags Flags, src android.Path, sharedFlags *SharedFlags) Objects {
 	// libc/libm stubs libraries end up mismatching with clang's internal definition of these
 	// functions (which have noreturn attributes and other things). Because we just want to create a
 	// stub with symbol definitions, and types aren't important in C, ignore the mismatch.
 	flags.Local.ConlyFlags = append(flags.Local.ConlyFlags, "-fno-builtin")
 	return compileObjs(ctx, flagsToBuilderFlags(flags), "",
-		android.Paths{src}, nil, nil, nil, nil)
+		android.Paths{src}, nil, nil, nil, nil, sharedFlags)
 }
 
 func (this *stubDecorator) findImplementationLibrary(ctx ModuleContext) android.Path {
@@ -489,7 +489,7 @@
 		ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
 	}
 
-	if !c.buildStubs() {
+	if !c.BuildStubs() {
 		// NDK libraries have no implementation variant, nothing to do
 		return Objects{}
 	}
@@ -500,9 +500,9 @@
 	}
 
 	symbolFile := String(c.properties.Symbol_file)
-	nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "")
-	objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
-	c.versionScriptPath = nativeAbiResult.versionScript
+	nativeAbiResult := ParseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "")
+	objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, ctx.getSharedFlags())
+	c.versionScriptPath = nativeAbiResult.VersionScript
 	if c.canDumpAbi(ctx) {
 		c.dumpAbi(ctx, nativeAbiResult.symbolList)
 		if c.canDiffAbi(ctx.Config()) {
@@ -541,7 +541,7 @@
 func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
 	objs Objects) android.Path {
 
-	if !stub.buildStubs() {
+	if !stub.BuildStubs() {
 		// NDK libraries have no implementation variant, nothing to do
 		return nil
 	}
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 92da172..a5f014b 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -245,7 +245,7 @@
 		}
 
 		if m, ok := module.(*Module); ok {
-			if installer, ok := m.installer.(*stubDecorator); ok && m.library.buildStubs() {
+			if installer, ok := m.installer.(*stubDecorator); ok && m.library.BuildStubs() {
 				installPaths = append(installPaths, installer.installPath)
 			}
 
diff --git a/cc/object.go b/cc/object.go
index c89520a..bbfca94 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -159,7 +159,7 @@
 	// isForPlatform is terribly named and actually means isNotApex.
 	if Bool(object.Properties.Crt) &&
 		!Bool(object.Properties.Exclude_from_ndk_sysroot) && ctx.useSdk() &&
-		ctx.isSdkVariant() && ctx.isForPlatform() {
+		ctx.isSdkVariant() && CtxIsForPlatform(ctx) {
 
 		output = getVersionedLibraryInstallPath(ctx,
 			nativeApiLevelOrPanic(ctx, ctx.sdkVersion())).Join(ctx, outputName)
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 96a07bc..70ee5e3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -114,10 +114,10 @@
 
 	// TODO(ccross): verify shared library dependencies
 	srcs := p.prebuiltSrcs(ctx)
-	stubInfo := addStubDependencyProviders(ctx)
+	stubInfo := AddStubDependencyProviders(ctx)
 
 	// Stub variants will create a stub .so file from stub .c files
-	if p.buildStubs() && objs.objFiles != nil {
+	if p.BuildStubs() && objs.objFiles != nil {
 		// TODO (b/275273834): Make objs.objFiles == nil a hard error when the symbol files have been added to module sdk.
 		return p.linkShared(ctx, flags, deps, objs)
 	}
@@ -204,7 +204,7 @@
 				Target:        ctx.Target(),
 
 				TableOfContents: p.tocFile,
-				IsStubs:         p.buildStubs(),
+				IsStubs:         p.BuildStubs(),
 			})
 
 			return outputFile
@@ -268,7 +268,7 @@
 }
 
 // Implements versionedInterface
-func (p *prebuiltLibraryLinker) implementationModuleName(name string) string {
+func (p *prebuiltLibraryLinker) ImplementationModuleName(name string) string {
 	return android.RemoveOptionalPrebuiltPrefix(name)
 }
 
@@ -298,7 +298,7 @@
 }
 
 func (p *prebuiltLibraryLinker) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
-	if p.buildStubs() && p.stubsVersion() != "" {
+	if p.BuildStubs() && p.StubsVersion() != "" {
 		return p.compileModuleLibApiStubs(ctx, flags, deps)
 	}
 	return Objects{}
diff --git a/cc/sabi.go b/cc/sabi.go
index bc61b6c..06ab6ec 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -137,7 +137,7 @@
 		if m.isImplementationForLLNDKPublic() {
 			result = append(result, llndkLsdumpTag)
 		}
-		if m.library.hasStubsVariants() {
+		if m.library.HasStubsVariants() {
 			result = append(result, apexLsdumpTag)
 		}
 		if headerAbiChecker.enabled() {
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 75d649f..2291153 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -43,7 +43,7 @@
 }
 
 // Get target file name to be installed from this module
-func getInstalledFileName(ctx android.SingletonContext, m *Module) string {
+func getInstalledFileName(ctx android.SingletonContext, m LinkableInterface) string {
 	for _, ps := range android.OtherModuleProviderOrDefault(
 		ctx, m.Module(), android.InstallFilesProvider).PackagingSpecs {
 		if name := ps.FileName(); name != "" {
@@ -58,7 +58,11 @@
 	stubLibraryMap := make(map[string]bool)
 	vendorStubLibraryMap := make(map[string]bool)
 	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*Module); ok {
+		if m, ok := module.(VersionedLinkableInterface); ok {
+			// TODO(ivanlozano) remove this when Rust supports stubs
+			if m.RustLibraryInterface() {
+				return
+			}
 			if IsStubTarget(android.OtherModuleProviderOrDefault(ctx, m, LinkableInfoProvider)) {
 				if name := getInstalledFileName(ctx, m); name != "" {
 					stubLibraryMap[name] = true
@@ -67,8 +71,8 @@
 					}
 				}
 			}
-			if m.library != nil && android.IsModulePreferred(m) {
-				if p := m.library.getAPIListCoverageXMLPath().String(); p != "" {
+			if m.CcLibraryInterface() && android.IsModulePreferred(m) {
+				if p := m.VersionedInterface().GetAPIListCoverageXMLPath().String(); p != "" {
 					s.apiListCoverageXmlPaths = append(s.apiListCoverageXmlPaths, p)
 				}
 			}
diff --git a/java/app.go b/java/app.go
index 12705b0..8a2afbd 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1127,9 +1127,10 @@
 			parentLinkable, _ := parent.(cc.LinkableInterface)
 			useStubsOfDep := childLinkable.IsStubs()
 			if apkInApex && parentLinkable != nil {
+				vintf := childLinkable.(cc.VersionedLinkableInterface).VersionedInterface()
 				// APK-in-APEX
 				// If the parent is a linkable interface, use stubs if the dependency edge crosses an apex boundary.
-				useStubsOfDep = useStubsOfDep || (childLinkable.HasStubsVariants() && cc.ShouldUseStubForApex(ctx, parent, child))
+				useStubsOfDep = useStubsOfDep || (vintf.HasStubsVariants() && cc.ShouldUseStubForApex(ctx, parent, child))
 			}
 			return !childLinkable.IsNdk(ctx.Config()) && !useStubsOfDep
 		})
diff --git a/rust/library.go b/rust/library.go
index 2d62dcf..9912c94 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -277,6 +277,71 @@
 var _ compiler = (*libraryDecorator)(nil)
 var _ libraryInterface = (*libraryDecorator)(nil)
 var _ exportedFlagsProducer = (*libraryDecorator)(nil)
+var _ cc.VersionedInterface = (*libraryDecorator)(nil)
+
+func (library *libraryDecorator) HasLLNDKStubs() bool {
+	// Rust does not support LLNDK yet.
+	return false
+}
+
+func (library *libraryDecorator) HasVendorPublicLibrary() bool {
+	// Rust does not support vendor public library.
+	return false
+}
+
+func (library *libraryDecorator) HasLLNDKHeaders() bool {
+	// Rust does not support LLNDK yet.
+	return false
+}
+
+func (library *libraryDecorator) HasStubsVariants() bool {
+	return false
+}
+
+func (library *libraryDecorator) IsStubsImplementationRequired() bool {
+	return false
+}
+
+func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath {
+	panic(fmt.Errorf("GetAPIListCoverageXMLPath called on unsupported Rust module"))
+}
+
+func (library *libraryDecorator) AllStubsVersions() []string {
+	panic(fmt.Errorf("AllStubsVersions called on unsupported Rust module"))
+}
+
+func (library *libraryDecorator) SetAllStubsVersions(versions []string) {
+	panic(fmt.Errorf("ApexSdkVersion called on unsupported Rust module"))
+}
+
+func (library *libraryDecorator) SetStubsVersion(version string) {
+	panic(fmt.Errorf("SetStubsVersion called on unsupported Rust module"))
+}
+
+func (library *libraryDecorator) SetBuildStubs(isLatest bool) {
+	panic(fmt.Errorf("SetBuildStubs called on unsupported Rust module"))
+}
+
+func (library *libraryDecorator) BuildStubs() bool {
+	return false
+}
+
+func (library *libraryDecorator) ImplementationModuleName(name string) string {
+	panic(fmt.Errorf("ImplementationModuleName called on unsupported Rust module"))
+}
+
+func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
+	// Rust does not support LLNDK.
+	return false
+}
+
+func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
+	panic(fmt.Errorf("StubsVersions called on unsupported Rust module"))
+}
+
+func (library *libraryDecorator) StubsVersion() string {
+	panic(fmt.Errorf("StubsVersions called on unsupported Rust module"))
+}
 
 // rust_library produces all Rust variants (rust_library_dylib and
 // rust_library_rlib).
diff --git a/rust/rust.go b/rust/rust.go
index ba6e293..a4c1afd 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -406,10 +406,6 @@
 	return false
 }
 
-func (mod *Module) StubsVersion() string {
-	panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", mod.BaseModuleName()))
-}
-
 func (mod *Module) SdkVersion() string {
 	return ""
 }
@@ -561,6 +557,9 @@
 func (mod *Module) PreventInstall() bool {
 	return mod.Properties.PreventInstall
 }
+func (c *Module) ForceDisableSanitizers() {
+	c.sanitize.Properties.ForceDisable = true
+}
 
 func (mod *Module) MarkAsCoverageVariant(coverage bool) {
 	mod.coverage.Properties.IsCoverageVariant = coverage
@@ -743,11 +742,28 @@
 	return false
 }
 
+func (mod *Module) IsStubs() bool {
+	return false
+}
+
 func (mod *Module) HasStubsVariants() bool {
 	return false
 }
 
-func (mod *Module) IsStubs() bool {
+func (mod *Module) ApexSdkVersion() android.ApiLevel {
+	panic(fmt.Errorf("ApexSdkVersion called on unsupported Rust module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
+	return mod.Name()
+}
+
+func (mod *Module) Multilib() string {
+	return mod.Arch().ArchType.Multilib
+}
+
+func (mod *Module) IsCrt() bool {
+	// Rust does not currently provide any crt modules.
 	return false
 }
 
@@ -771,6 +787,7 @@
 }
 
 var _ cc.LinkableInterface = (*Module)(nil)
+var _ cc.VersionedLinkableInterface = (*Module)(nil)
 
 func (mod *Module) Init() android.Module {
 	mod.AddProperties(&mod.Properties)
@@ -881,6 +898,25 @@
 	return mod.compiler != nil && mod.compiler.nativeCoverage()
 }
 
+func (mod *Module) SetStl(s string) {
+	// STL is a CC concept; do nothing for Rust
+}
+
+func (mod *Module) SetSdkVersion(s string) {
+	panic(fmt.Errorf("SetSdkVersion called on unsupported Rust module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) SetMinSdkVersion(s string) {
+	mod.Properties.Min_sdk_version = StringPtr(s)
+}
+
+func (mod *Module) VersionedInterface() cc.VersionedInterface {
+	if _, ok := mod.compiler.(cc.VersionedInterface); ok {
+		return mod.compiler.(cc.VersionedInterface)
+	}
+	return nil
+}
+
 func (mod *Module) EverInstallable() bool {
 	return mod.compiler != nil &&
 		// Check to see whether the module is actually ever installable.
@@ -1064,6 +1100,12 @@
 	}
 	android.SetProvider(ctx, RustInfoProvider, rustInfo)
 
+	ccInfo := &cc.CcInfo{
+		IsPrebuilt: mod.IsPrebuilt(),
+	}
+
+	android.SetProvider(ctx, cc.CcInfoProvider, ccInfo)
+
 	mod.setOutputFiles(ctx)
 
 	buildComplianceMetadataInfo(ctx, mod, deps)
diff --git a/rust/sanitize.go b/rust/sanitize.go
index b8f922f..50f55ce 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -53,6 +53,9 @@
 
 	// Used when we need to place libraries in their own directory, such as ASAN.
 	InSanitizerDir bool `blueprint:"mutated"`
+
+	// ForceDisable is set by the version mutator to disable sanitization of stubs variants
+	ForceDisable bool `blueprint:"mutated"`
 }
 
 var fuzzerFlags = []string{
@@ -103,6 +106,10 @@
 func (sanitize *sanitize) begin(ctx BaseModuleContext) {
 	s := &sanitize.Properties.Sanitize
 
+	if sanitize.Properties.ForceDisable {
+		return
+	}
+
 	// Disable sanitizers for musl x86 modules, rustc does not support any sanitizers.
 	if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 {
 		s.Never = proptools.BoolPtr(true)
@@ -221,6 +228,10 @@
 }
 
 func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+	if sanitize.Properties.ForceDisable {
+		return flags, deps
+	}
+
 	if !sanitize.Properties.SanitizerEnabled {
 		return flags, deps
 	}
@@ -253,6 +264,9 @@
 		if !mod.Enabled(mctx) {
 			return
 		}
+		if mod.sanitize.Properties.ForceDisable {
+			return
+		}
 
 		if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() {
 			noteDep := "note_memtag_heap_async"
@@ -364,7 +378,7 @@
 // distinguish between the cases. It isn't needed though - both cases can be
 // treated identically.
 func (sanitize *sanitize) isSanitizerEnabled(t cc.SanitizerType) bool {
-	if sanitize == nil || !sanitize.Properties.SanitizerEnabled {
+	if sanitize == nil || !sanitize.Properties.SanitizerEnabled || sanitize.Properties.ForceDisable {
 		return false
 	}
 
@@ -453,7 +467,7 @@
 }
 
 func (mod *Module) SanitizeNever() bool {
-	return Bool(mod.sanitize.Properties.Sanitize.Never)
+	return Bool(mod.sanitize.Properties.Sanitize.Never) || mod.sanitize.Properties.ForceDisable
 }
 
 var _ cc.PlatformSanitizeable = (*Module)(nil)