Merge "Add support for including app prebuilts in APEX."
diff --git a/Android.bp b/Android.bp
index 714ce37..05972fd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -157,6 +157,7 @@
         "cc/check.go",
         "cc/coverage.go",
         "cc/gen.go",
+        "cc/linkable.go",
         "cc/lto.go",
         "cc/makevars.go",
         "cc/pgo.go",
diff --git a/android/config.go b/android/config.go
index 90e7ed1..63994e6 100644
--- a/android/config.go
+++ b/android/config.go
@@ -212,9 +212,9 @@
 	config := &config{
 		productVariables: productVariables{
 			DeviceName:                  stringPtr("test_device"),
-			Platform_sdk_version:        intPtr(26),
+			Platform_sdk_version:        intPtr(30),
 			DeviceSystemSdkVersions:     []string{"14", "15"},
-			Platform_systemsdk_versions: []string{"25", "26"},
+			Platform_systemsdk_versions: []string{"29", "30"},
 			AAPTConfig:                  []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 			AAPTPreferredConfig:         stringPtr("xhdpi"),
 			AAPTCharacteristics:         stringPtr("nosdcard"),
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index be52879..0082d8b 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -198,6 +198,7 @@
 			"LOCAL_EXPORT_PACKAGE_RESOURCES":   "export_package_resources",
 			"LOCAL_PRIVILEGED_MODULE":          "privileged",
 			"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
+			"LOCAL_DONT_MERGE_MANIFESTS":       "dont_merge_manifests",
 			"LOCAL_USE_EMBEDDED_NATIVE_LIBS":   "use_embedded_native_libs",
 			"LOCAL_USE_EMBEDDED_DEX":           "use_embedded_dex",
 
diff --git a/apex/apex.go b/apex/apex.go
index 799809c..75da7da 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1387,6 +1387,8 @@
 			copyCommands = append(copyCommands, "ln -s "+filepath.Base(dest)+" "+symlinkDest)
 		}
 	}
+	emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
+
 	implicitInputs := append(android.Paths(nil), filesToCopy...)
 	implicitInputs = append(implicitInputs, a.manifestOut)
 
diff --git a/cc/androidmk.go b/cc/androidmk.go
index a978cb9..54cd722 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -36,10 +36,10 @@
 	Arch() android.Arch
 	Os() android.OsType
 	Host() bool
-	useVndk() bool
+	UseVndk() bool
 	vndkVersion() string
 	static() bool
-	inRecovery() bool
+	InRecovery() bool
 }
 
 type subAndroidMkProvider interface {
@@ -89,15 +89,10 @@
 					fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
 				}
 				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
-				if c.useVndk() {
+				if c.UseVndk() {
 					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
-					if c.isVndk() && !c.static() {
+					if c.IsVndk() && !c.static() {
 						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.vndkVersion())
-						// VNDK libraries available to vendor are not installed because
-						// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
-						if !c.isVndkExt() {
-							fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-						}
 					}
 				}
 			},
@@ -229,7 +224,7 @@
 		})
 	}
 	if len(library.Properties.Stubs.Versions) > 0 &&
-		android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.inRecovery() && !ctx.useVndk() &&
+		android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRecovery() && !ctx.UseVndk() &&
 		!ctx.static() {
 		if !library.buildStubs() {
 			ret.SubName = ".bootstrap"
@@ -322,6 +317,11 @@
 			filepath.Dir(fuzz.dictionary.String())+":"+fuzz.dictionary.Base())
 	}
 
+	if fuzz.config != nil {
+		fuzzFiles = append(fuzzFiles,
+			filepath.Dir(fuzz.config.String())+":config.json")
+	}
+
 	if len(fuzzFiles) > 0 {
 		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
diff --git a/cc/binary.go b/cc/binary.go
index 9f18d6c..b27142c 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -158,7 +158,7 @@
 
 		if binary.static() {
 			if ctx.selectedStl() == "libc++_static" {
-				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl")
+				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
 			}
 			// static libraries libcompiler_rt, libc and libc_nomalloc need to be linked with
 			// --start-group/--end-group along with libgcc.  If they are in deps.StaticLibs,
diff --git a/cc/cc.go b/cc/cc.go
index 67132e4..f90f1e8 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -338,81 +338,50 @@
 	relativeInstallPath() string
 }
 
-type dependencyTag struct {
-	blueprint.BaseDependencyTag
-	name    string
-	library bool
-	shared  bool
-
-	reexportFlags bool
-
-	explicitlyVersioned bool
-}
-
 type xref interface {
 	XrefCcFiles() android.Paths
 }
 
 var (
-	sharedDepTag          = dependencyTag{name: "shared", library: true, shared: true}
-	sharedExportDepTag    = dependencyTag{name: "shared", library: true, shared: true, reexportFlags: true}
-	earlySharedDepTag     = dependencyTag{name: "early_shared", library: true, shared: true}
-	lateSharedDepTag      = dependencyTag{name: "late shared", library: true, shared: true}
-	staticDepTag          = dependencyTag{name: "static", library: true}
-	staticExportDepTag    = dependencyTag{name: "static", library: true, reexportFlags: true}
-	lateStaticDepTag      = dependencyTag{name: "late static", library: true}
-	wholeStaticDepTag     = dependencyTag{name: "whole static", library: true, reexportFlags: true}
-	headerDepTag          = dependencyTag{name: "header", library: true}
-	headerExportDepTag    = dependencyTag{name: "header", library: true, reexportFlags: true}
-	genSourceDepTag       = dependencyTag{name: "gen source"}
-	genHeaderDepTag       = dependencyTag{name: "gen header"}
-	genHeaderExportDepTag = dependencyTag{name: "gen header", reexportFlags: true}
-	objDepTag             = dependencyTag{name: "obj"}
-	crtBeginDepTag        = dependencyTag{name: "crtbegin"}
-	crtEndDepTag          = dependencyTag{name: "crtend"}
-	linkerFlagsDepTag     = dependencyTag{name: "linker flags file"}
-	dynamicLinkerDepTag   = dependencyTag{name: "dynamic linker"}
-	reuseObjTag           = dependencyTag{name: "reuse objects"}
-	staticVariantTag      = dependencyTag{name: "static variant"}
-	ndkStubDepTag         = dependencyTag{name: "ndk stub", library: true}
-	ndkLateStubDepTag     = dependencyTag{name: "ndk late stub", library: true}
-	vndkExtDepTag         = dependencyTag{name: "vndk extends", library: true}
-	runtimeDepTag         = dependencyTag{name: "runtime lib"}
-	coverageDepTag        = dependencyTag{name: "coverage"}
-	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
+	sharedExportDepTag    = DependencyTag{Name: "shared", Library: true, Shared: true, ReexportFlags: true}
+	earlySharedDepTag     = DependencyTag{Name: "early_shared", Library: true, Shared: true}
+	lateSharedDepTag      = DependencyTag{Name: "late shared", Library: true, Shared: true}
+	staticExportDepTag    = DependencyTag{Name: "static", Library: true, ReexportFlags: true}
+	lateStaticDepTag      = DependencyTag{Name: "late static", Library: true}
+	wholeStaticDepTag     = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true}
+	headerDepTag          = DependencyTag{Name: "header", Library: true}
+	headerExportDepTag    = DependencyTag{Name: "header", Library: true, ReexportFlags: true}
+	genSourceDepTag       = DependencyTag{Name: "gen source"}
+	genHeaderDepTag       = DependencyTag{Name: "gen header"}
+	genHeaderExportDepTag = DependencyTag{Name: "gen header", ReexportFlags: true}
+	objDepTag             = DependencyTag{Name: "obj"}
+	linkerFlagsDepTag     = DependencyTag{Name: "linker flags file"}
+	dynamicLinkerDepTag   = DependencyTag{Name: "dynamic linker"}
+	reuseObjTag           = DependencyTag{Name: "reuse objects"}
+	staticVariantTag      = DependencyTag{Name: "static variant"}
+	ndkStubDepTag         = DependencyTag{Name: "ndk stub", Library: true}
+	ndkLateStubDepTag     = DependencyTag{Name: "ndk late stub", Library: true}
+	vndkExtDepTag         = DependencyTag{Name: "vndk extends", Library: true}
+	runtimeDepTag         = DependencyTag{Name: "runtime lib"}
+	coverageDepTag        = DependencyTag{Name: "coverage"}
+	testPerSrcDepTag      = DependencyTag{Name: "test_per_src"}
 )
 
 func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
-	ccDepTag, ok := depTag.(dependencyTag)
-	return ok && ccDepTag.shared
+	ccDepTag, ok := depTag.(DependencyTag)
+	return ok && ccDepTag.Shared
 }
 
 func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
-	ccDepTag, ok := depTag.(dependencyTag)
+	ccDepTag, ok := depTag.(DependencyTag)
 	return ok && ccDepTag == runtimeDepTag
 }
 
 func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool {
-	ccDepTag, ok := depTag.(dependencyTag)
+	ccDepTag, ok := depTag.(DependencyTag)
 	return ok && ccDepTag == testPerSrcDepTag
 }
 
-func SharedDepTag() dependencyTag {
-	return sharedDepTag
-}
-
-func StaticDepTag() dependencyTag {
-	return staticDepTag
-}
-
-func CrtBeginDepTag() dependencyTag {
-	return crtBeginDepTag
-}
-
-func CrtEndDepTag() dependencyTag {
-	return crtEndDepTag
-}
-
 // Module contains the properties and members used by all C/C++ module types, and implements
 // the blueprint.Module interface.  It delegates to compiler, linker, and installer interfaces
 // to construct the output file.  Behavior can be customized with a Customizer interface
@@ -460,17 +429,212 @@
 	depsInLinkOrder android.Paths
 
 	// only non-nil when this is a shared library that reuses the objects of a static library
-	staticVariant *Module
+	staticVariant LinkableInterface
 
 	makeLinkType string
 	// Kythe (source file indexer) paths for this compilation module
 	kytheFiles android.Paths
 }
 
+func (c *Module) Toc() android.OptionalPath {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.toc()
+		}
+	}
+	panic(fmt.Errorf("Toc() called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) ApiLevel() string {
+	if c.linker != nil {
+		if stub, ok := c.linker.(*stubDecorator); ok {
+			return stub.properties.ApiLevel
+		}
+	}
+	panic(fmt.Errorf("ApiLevel() called on non-stub library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) Static() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.static()
+		}
+	}
+	panic(fmt.Errorf("Static() called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) Shared() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.shared()
+		}
+	}
+	panic(fmt.Errorf("Shared() called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SelectedStl() string {
+	return c.stl.Properties.SelectedStl
+}
+
+func (c *Module) ToolchainLibrary() bool {
+	if _, ok := c.linker.(*toolchainLibraryDecorator); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) NdkPrebuiltStl() bool {
+	if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) StubDecorator() bool {
+	if _, ok := c.linker.(*stubDecorator); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) SdkVersion() string {
+	return String(c.Properties.Sdk_version)
+}
+
+func (c *Module) IncludeDirs(ctx android.BaseModuleContext) android.Paths {
+	if c.linker != nil {
+		if library, ok := c.linker.(exportedFlagsProducer); ok {
+			return library.exportedDirs()
+		}
+	}
+	panic(fmt.Errorf("IncludeDirs called on non-exportedFlagsProducer module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) HasStaticVariant() bool {
+	if c.staticVariant != nil {
+		return true
+	}
+	return false
+}
+
+func (c *Module) GetStaticVariant() LinkableInterface {
+	return c.staticVariant
+}
+
+func (c *Module) SetDepsInLinkOrder(depsInLinkOrder []android.Path) {
+	c.depsInLinkOrder = depsInLinkOrder
+}
+
+func (c *Module) GetDepsInLinkOrder() []android.Path {
+	return c.depsInLinkOrder
+}
+
+func (c *Module) StubsVersions() []string {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			return library.Properties.Stubs.Versions
+		}
+	}
+	panic(fmt.Errorf("StubsVersions called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) CcLibrary() bool {
+	if c.linker != nil {
+		if _, ok := c.linker.(*libraryDecorator); ok {
+			return true
+		}
+	}
+	return false
+}
+
+func (c *Module) CcLibraryInterface() bool {
+	if _, ok := c.linker.(libraryInterface); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) SetBuildStubs() {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			library.MutatedProperties.BuildStubs = true
+			c.Properties.HideFromMake = true
+			c.sanitize = nil
+			c.stl = nil
+			c.Properties.PreventInstall = true
+			return
+		}
+	}
+	panic(fmt.Errorf("SetBuildStubs called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) BuildStubs() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			return library.buildStubs()
+		}
+	}
+	panic(fmt.Errorf("BuildStubs called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SetStubsVersions(version string) {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			library.MutatedProperties.StubsVersion = version
+			return
+		}
+	}
+	panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SetStatic() {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			library.setStatic()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetStatic called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SetShared() {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			library.setShared()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetShared called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) BuildStaticVariant() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.buildStatic()
+		}
+	}
+	panic(fmt.Errorf("BuildStaticVariant called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) BuildSharedVariant() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.buildShared()
+		}
+	}
+	panic(fmt.Errorf("BuildSharedVariant called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) Module() android.Module {
+	return c
+}
+
 func (c *Module) OutputFile() android.OptionalPath {
 	return c.outputFile
 }
 
+var _ LinkableInterface = (*Module)(nil)
+
 func (c *Module) UnstrippedOutputFile() android.Path {
 	if c.linker != nil {
 		return c.linker.unstrippedOutputFilePath()
@@ -567,7 +731,7 @@
 	return false
 }
 
-func (c *Module) useVndk() bool {
+func (c *Module) UseVndk() bool {
 	return c.Properties.VndkVersion != ""
 }
 
@@ -594,7 +758,7 @@
 	return inList(c.BaseModuleName(), *vndkPrivateLibraries(config))
 }
 
-func (c *Module) isVndk() bool {
+func (c *Module) IsVndk() bool {
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		return vndkdep.isVndk()
 	}
@@ -633,7 +797,7 @@
 	return false
 }
 
-func (c *Module) mustUseVendorVariant() bool {
+func (c *Module) MustUseVendorVariant() bool {
 	return c.isVndkSp() || c.Properties.MustUseVendorVariant
 }
 
@@ -646,15 +810,15 @@
 
 // Returns true only when this module is configured to have core and vendor
 // variants.
-func (c *Module) hasVendorVariant() bool {
-	return c.isVndk() || Bool(c.VendorProperties.Vendor_available)
+func (c *Module) HasVendorVariant() bool {
+	return c.IsVndk() || Bool(c.VendorProperties.Vendor_available)
 }
 
-func (c *Module) inRecovery() bool {
+func (c *Module) InRecovery() bool {
 	return c.Properties.InRecovery || c.ModuleBase.InstallInRecovery()
 }
 
-func (c *Module) onlyInRecovery() bool {
+func (c *Module) OnlyInRecovery() bool {
 	return c.ModuleBase.InstallInRecovery()
 }
 
@@ -725,7 +889,7 @@
 
 func (ctx *moduleContext) SocSpecific() bool {
 	return ctx.ModuleContext.SocSpecific() ||
-		(ctx.mod.hasVendorVariant() && ctx.mod.useVndk() && !ctx.mod.isVndk())
+		(ctx.mod.HasVendorVariant() && ctx.mod.UseVndk() && !ctx.mod.IsVndk())
 }
 
 type moduleContextImpl struct {
@@ -775,7 +939,7 @@
 }
 
 func (ctx *moduleContextImpl) useVndk() bool {
-	return ctx.mod.useVndk()
+	return ctx.mod.UseVndk()
 }
 
 func (ctx *moduleContextImpl) isNdk() bool {
@@ -795,7 +959,7 @@
 }
 
 func (ctx *moduleContextImpl) isVndk() bool {
-	return ctx.mod.isVndk()
+	return ctx.mod.IsVndk()
 }
 
 func (ctx *moduleContextImpl) isPgoCompile() bool {
@@ -815,11 +979,11 @@
 }
 
 func (ctx *moduleContextImpl) mustUseVendorVariant() bool {
-	return ctx.mod.mustUseVendorVariant()
+	return ctx.mod.MustUseVendorVariant()
 }
 
 func (ctx *moduleContextImpl) inRecovery() bool {
-	return ctx.mod.inRecovery()
+	return ctx.mod.InRecovery()
 }
 
 // Check whether ABI dumps should be created for this module.
@@ -971,25 +1135,27 @@
 	return orderedAllDeps, orderedDeclaredDeps
 }
 
-func orderStaticModuleDeps(module *Module, staticDeps []*Module, sharedDeps []*Module) (results []android.Path) {
+func orderStaticModuleDeps(module LinkableInterface, staticDeps []LinkableInterface, sharedDeps []LinkableInterface) (results []android.Path) {
 	// convert Module to Path
+	var depsInLinkOrder []android.Path
 	allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
 	staticDepFiles := []android.Path{}
 	for _, dep := range staticDeps {
-		allTransitiveDeps[dep.outputFile.Path()] = dep.depsInLinkOrder
-		staticDepFiles = append(staticDepFiles, dep.outputFile.Path())
+		allTransitiveDeps[dep.OutputFile().Path()] = dep.GetDepsInLinkOrder()
+		staticDepFiles = append(staticDepFiles, dep.OutputFile().Path())
 	}
 	sharedDepFiles := []android.Path{}
 	for _, sharedDep := range sharedDeps {
-		staticAnalogue := sharedDep.staticVariant
-		if staticAnalogue != nil {
-			allTransitiveDeps[staticAnalogue.outputFile.Path()] = staticAnalogue.depsInLinkOrder
-			sharedDepFiles = append(sharedDepFiles, staticAnalogue.outputFile.Path())
+		if sharedDep.HasStaticVariant() {
+			staticAnalogue := sharedDep.GetStaticVariant()
+			allTransitiveDeps[staticAnalogue.OutputFile().Path()] = staticAnalogue.GetDepsInLinkOrder()
+			sharedDepFiles = append(sharedDepFiles, staticAnalogue.OutputFile().Path())
 		}
 	}
 
 	// reorder the dependencies based on transitive dependencies
-	module.depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
+	depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
+	module.SetDepsInLinkOrder(depsInLinkOrder)
 
 	return results
 }
@@ -1022,7 +1188,7 @@
 		// .vendor suffix is added for backward compatibility with VNDK snapshot whose names with
 		// such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp.
 		c.Properties.SubName += vendorSuffix
-	} else if _, ok := c.linker.(*llndkStubDecorator); ok || (c.useVndk() && c.hasVendorVariant()) {
+	} else if _, ok := c.linker.(*llndkStubDecorator); ok || (c.UseVndk() && c.HasVendorVariant()) {
 		// .vendor.{version} suffix is added only when we will have two variants: core and vendor.
 		// The suffix is not added for vendor-only module.
 		c.Properties.SubName += vendorSuffix
@@ -1033,7 +1199,7 @@
 		if c.Properties.VndkVersion != vendorVersion {
 			c.Properties.SubName += "." + c.Properties.VndkVersion
 		}
-	} else if c.inRecovery() && !c.onlyInRecovery() {
+	} else if c.InRecovery() && !c.OnlyInRecovery() {
 		c.Properties.SubName += recoverySuffix
 	}
 
@@ -1143,7 +1309,7 @@
 		// module is marked with 'bootstrap: true').
 		if c.HasStubsVariants() &&
 			android.DirectlyInAnyApex(ctx, ctx.baseModuleName()) &&
-			!c.inRecovery() && !c.useVndk() && !c.static() && !c.isCoverageVariant() &&
+			!c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
 			c.IsStubs() {
 			c.Properties.HideFromMake = false // unhide
 			// Note: this is still non-installable
@@ -1411,7 +1577,7 @@
 	}
 
 	for _, lib := range deps.StaticLibs {
-		depTag := staticDepTag
+		depTag := StaticDepTag
 		if inList(lib, deps.ReexportStaticLibHeaders) {
 			depTag = staticExportDepTag
 		}
@@ -1429,14 +1595,14 @@
 		{Mutator: "link", Variation: "static"},
 	}, lateStaticDepTag, deps.LateStaticLibs...)
 
-	addSharedLibDependencies := func(depTag dependencyTag, name string, version string) {
+	addSharedLibDependencies := func(depTag DependencyTag, name string, version string) {
 		var variations []blueprint.Variation
 		variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
-		versionVariantAvail := !ctx.useVndk() && !c.inRecovery()
+		versionVariantAvail := !ctx.useVndk() && !c.InRecovery()
 		if version != "" && versionVariantAvail {
 			// Version is explicitly specified. i.e. libFoo#30
 			variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
-			depTag.explicitlyVersioned = true
+			depTag.ExplicitlyVersioned = true
 		}
 		actx.AddVariationDependencies(variations, depTag, name)
 
@@ -1449,7 +1615,7 @@
 				{Mutator: "link", Variation: "shared"},
 				{Mutator: "version", Variation: latestVersion},
 			}, depTag, name)
-			// Note that depTag.explicitlyVersioned is false in this case.
+			// Note that depTag.ExplicitlyVersioned is false in this case.
 		}
 	}
 
@@ -1457,7 +1623,7 @@
 	var sharedLibNames []string
 
 	for _, lib := range deps.SharedLibs {
-		depTag := sharedDepTag
+		depTag := SharedDepTag
 		if inList(lib, deps.ReexportSharedLibHeaders) {
 			depTag = sharedExportDepTag
 		}
@@ -1499,10 +1665,10 @@
 	actx.AddVariationDependencies(nil, objDepTag, deps.ObjFiles...)
 
 	if deps.CrtBegin != "" {
-		actx.AddVariationDependencies(nil, crtBeginDepTag, deps.CrtBegin)
+		actx.AddVariationDependencies(nil, CrtBeginDepTag, deps.CrtBegin)
 	}
 	if deps.CrtEnd != "" {
-		actx.AddVariationDependencies(nil, crtEndDepTag, deps.CrtEnd)
+		actx.AddVariationDependencies(nil, CrtEndDepTag, deps.CrtEnd)
 	}
 	if deps.LinkerFlagsFile != "" {
 		actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile)
@@ -1545,52 +1711,58 @@
 
 // Whether a module can link to another module, taking into
 // account NDK linking.
-func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag dependencyTag) {
-	if from.Target().Os != android.Android {
+func checkLinkType(ctx android.ModuleContext, from LinkableInterface, to LinkableInterface, tag DependencyTag) {
+	if from.Module().Target().Os != android.Android {
 		// Host code is not restricted
 		return
 	}
-	if from.useVndk() {
+
+	// VNDK is cc.Module supported only for now.
+	if ccFrom, ok := from.(*Module); ok && from.UseVndk() {
 		// Though vendor code is limited by the vendor mutator,
 		// each vendor-available module needs to check
 		// link-type for VNDK.
-		if from.vndkdep != nil {
-			from.vndkdep.vndkCheckLinkType(ctx, to, tag)
+		if ccTo, ok := to.(*Module); ok {
+			if ccFrom.vndkdep != nil {
+				ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag)
+			}
+		} else {
+			ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
 		}
 		return
 	}
-	if String(from.Properties.Sdk_version) == "" {
+	if from.SdkVersion() == "" {
 		// Platform code can link to anything
 		return
 	}
-	if from.inRecovery() {
+	if from.InRecovery() {
 		// Recovery code is not NDK
 		return
 	}
-	if _, ok := to.linker.(*toolchainLibraryDecorator); ok {
+	if to.ToolchainLibrary() {
 		// These are always allowed
 		return
 	}
-	if _, ok := to.linker.(*ndkPrebuiltStlLinker); ok {
+	if to.NdkPrebuiltStl() {
 		// These are allowed, but they don't set sdk_version
 		return
 	}
-	if _, ok := to.linker.(*stubDecorator); ok {
+	if to.StubDecorator() {
 		// These aren't real libraries, but are the stub shared libraries that are included in
 		// the NDK.
 		return
 	}
 
-	if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Name() == "libc++" {
+	if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" {
 		// Bug: http://b/121358700 - Allow libclang_rt.* shared libraries (with sdk_version)
 		// to link to libc++ (non-NDK and without sdk_version).
 		return
 	}
 
-	if String(to.Properties.Sdk_version) == "" {
+	if to.SdkVersion() == "" {
 		// NDK code linking to platform code is never okay.
 		ctx.ModuleErrorf("depends on non-NDK-built library %q",
-			ctx.OtherModuleName(to))
+			ctx.OtherModuleName(to.Module()))
 		return
 	}
 
@@ -1600,36 +1772,36 @@
 	// APIs.
 
 	// Current can link against anything.
-	if String(from.Properties.Sdk_version) != "current" {
+	if from.SdkVersion() != "current" {
 		// Otherwise we need to check.
-		if String(to.Properties.Sdk_version) == "current" {
+		if to.SdkVersion() == "current" {
 			// Current can't be linked against by anything else.
 			ctx.ModuleErrorf("links %q built against newer API version %q",
-				ctx.OtherModuleName(to), "current")
+				ctx.OtherModuleName(to.Module()), "current")
 		} else {
-			fromApi, err := strconv.Atoi(String(from.Properties.Sdk_version))
+			fromApi, err := strconv.Atoi(from.SdkVersion())
 			if err != nil {
 				ctx.PropertyErrorf("sdk_version",
 					"Invalid sdk_version value (must be int or current): %q",
-					String(from.Properties.Sdk_version))
+					from.SdkVersion())
 			}
-			toApi, err := strconv.Atoi(String(to.Properties.Sdk_version))
+			toApi, err := strconv.Atoi(to.SdkVersion())
 			if err != nil {
 				ctx.PropertyErrorf("sdk_version",
 					"Invalid sdk_version value (must be int or current): %q",
-					String(to.Properties.Sdk_version))
+					to.SdkVersion())
 			}
 
 			if toApi > fromApi {
 				ctx.ModuleErrorf("links %q built against newer API version %q",
-					ctx.OtherModuleName(to), String(to.Properties.Sdk_version))
+					ctx.OtherModuleName(to.Module()), to.SdkVersion())
 			}
 		}
 	}
 
 	// Also check that the two STL choices are compatible.
-	fromStl := from.stl.Properties.SelectedStl
-	toStl := to.stl.Properties.SelectedStl
+	fromStl := from.SelectedStl()
+	toStl := to.SelectedStl()
 	if fromStl == "" || toStl == "" {
 		// Libraries that don't use the STL are unrestricted.
 	} else if fromStl == "ndk_system" || toStl == "ndk_system" {
@@ -1638,8 +1810,8 @@
 		// using either libc++ or nothing.
 	} else if getNdkStlFamily(from) != getNdkStlFamily(to) {
 		ctx.ModuleErrorf("uses %q and depends on %q which uses incompatible %q",
-			from.stl.Properties.SelectedStl, ctx.OtherModuleName(to),
-			to.stl.Properties.SelectedStl)
+			from.SelectedStl(), ctx.OtherModuleName(to.Module()),
+			to.SelectedStl())
 	}
 }
 
@@ -1661,7 +1833,7 @@
 		}
 
 		// if target lib has no vendor variant, keep checking dependency graph
-		if !to.hasVendorVariant() {
+		if !to.HasVendorVariant() {
 			return true
 		}
 
@@ -1691,8 +1863,8 @@
 func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
-	directStaticDeps := []*Module{}
-	directSharedDeps := []*Module{}
+	directStaticDeps := []LinkableInterface{}
+	directSharedDeps := []LinkableInterface{}
 
 	llndkLibraries := llndkLibraries(ctx.Config())
 	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
@@ -1708,8 +1880,9 @@
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
 
-		ccDep, _ := dep.(*Module)
-		if ccDep == nil {
+		ccDep, ok := dep.(LinkableInterface)
+		if !ok {
+
 			// handling for a few module types that aren't cc Module but that are also supported
 			switch depTag {
 			case genSourceDepTag:
@@ -1767,9 +1940,10 @@
 
 		// re-exporting flags
 		if depTag == reuseObjTag {
-			if l, ok := ccDep.compiler.(libraryInterface); ok {
+			// reusing objects only make sense for cc.Modules.
+			if ccReuseDep, ok := ccDep.(*Module); ok && ccDep.CcLibraryInterface() {
 				c.staticVariant = ccDep
-				objs, exporter := l.reuseObjs()
+				objs, exporter := ccReuseDep.compiler.(libraryInterface).reuseObjs()
 				depPaths.Objs = depPaths.Objs.Append(objs)
 				reexportExporter(exporter)
 				return
@@ -1777,30 +1951,31 @@
 		}
 
 		if depTag == staticVariantTag {
-			if _, ok := ccDep.compiler.(libraryInterface); ok {
+			// staticVariants are a cc.Module specific concept.
+			if _, ok := ccDep.(*Module); ok && ccDep.CcLibraryInterface() {
 				c.staticVariant = ccDep
 				return
 			}
 		}
 
-		// Extract explicitlyVersioned field from the depTag and reset it inside the struct.
-		// Otherwise, sharedDepTag and lateSharedDepTag with explicitlyVersioned set to true
-		// won't be matched to sharedDepTag and lateSharedDepTag.
+		// Extract ExplicitlyVersioned field from the depTag and reset it inside the struct.
+		// Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true
+		// won't be matched to SharedDepTag and lateSharedDepTag.
 		explicitlyVersioned := false
-		if t, ok := depTag.(dependencyTag); ok {
-			explicitlyVersioned = t.explicitlyVersioned
-			t.explicitlyVersioned = false
+		if t, ok := depTag.(DependencyTag); ok {
+			explicitlyVersioned = t.ExplicitlyVersioned
+			t.ExplicitlyVersioned = false
 			depTag = t
 		}
 
-		if t, ok := depTag.(dependencyTag); ok && t.library {
+		if t, ok := depTag.(DependencyTag); ok && t.Library {
 			depIsStatic := false
 			switch depTag {
-			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
+			case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
 				depIsStatic = true
 			}
-			if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok && !depIsStatic {
-				depIsStubs := dependentLibrary.buildStubs()
+			if ccDep.CcLibrary() && !depIsStatic {
+				depIsStubs := ccDep.BuildStubs()
 				depHasStubs := ccDep.HasStubsVariants()
 				depInSameApex := android.DirectlyInApex(c.ApexName(), depName)
 				depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
@@ -1817,7 +1992,7 @@
 					// If not building for APEX, use stubs only when it is from
 					// an APEX (and not from platform)
 					useThisDep = (depInPlatform != depIsStubs)
-					if c.inRecovery() || c.bootstrap() {
+					if c.InRecovery() || c.bootstrap() {
 						// However, for recovery or bootstrap modules,
 						// always link to non-stub variant
 						useThisDep = !depIsStubs
@@ -1833,85 +2008,95 @@
 				}
 			}
 
-			if i, ok := ccDep.linker.(exportedFlagsProducer); ok {
-				depPaths.IncludeDirs = append(depPaths.IncludeDirs, i.exportedDirs()...)
-				depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
-				depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedDeps()...)
-				depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
+			// Exporting flags only makes sense for cc.Modules
+			if _, ok := ccDep.(*Module); ok {
+				if i, ok := ccDep.(*Module).linker.(exportedFlagsProducer); ok {
+					depPaths.IncludeDirs = append(depPaths.IncludeDirs, i.exportedDirs()...)
+					depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
+					depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedDeps()...)
+					depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
 
-				if t.reexportFlags {
-					reexportExporter(i)
-					// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
-					// Re-exported shared library headers must be included as well since they can help us with type information
-					// about template instantiations (instantiated from their headers).
-					// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
-					// scripts.
-					c.sabi.Properties.ReexportedIncludes = append(
-						c.sabi.Properties.ReexportedIncludes, i.exportedDirs().Strings()...)
+					if t.ReexportFlags {
+						reexportExporter(i)
+						// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
+						// Re-exported shared library headers must be included as well since they can help us with type information
+						// about template instantiations (instantiated from their headers).
+						// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
+						// scripts.
+						c.sabi.Properties.ReexportedIncludes = append(
+							c.sabi.Properties.ReexportedIncludes, i.exportedDirs().Strings()...)
+					}
 				}
 			}
-
 			checkLinkType(ctx, c, ccDep, t)
 		}
 
 		var ptr *android.Paths
 		var depPtr *android.Paths
 
-		linkFile := ccDep.outputFile
+		linkFile := ccDep.OutputFile()
 		depFile := android.OptionalPath{}
 
 		switch depTag {
-		case ndkStubDepTag, sharedDepTag, sharedExportDepTag:
+		case ndkStubDepTag, SharedDepTag, sharedExportDepTag:
 			ptr = &depPaths.SharedLibs
 			depPtr = &depPaths.SharedLibsDeps
-			depFile = ccDep.linker.(libraryInterface).toc()
+			depFile = ccDep.Toc()
 			directSharedDeps = append(directSharedDeps, ccDep)
+
 		case earlySharedDepTag:
 			ptr = &depPaths.EarlySharedLibs
 			depPtr = &depPaths.EarlySharedLibsDeps
-			depFile = ccDep.linker.(libraryInterface).toc()
+			depFile = ccDep.Toc()
 			directSharedDeps = append(directSharedDeps, ccDep)
 		case lateSharedDepTag, ndkLateStubDepTag:
 			ptr = &depPaths.LateSharedLibs
 			depPtr = &depPaths.LateSharedLibsDeps
-			depFile = ccDep.linker.(libraryInterface).toc()
-		case staticDepTag, staticExportDepTag:
+			depFile = ccDep.Toc()
+		case StaticDepTag, staticExportDepTag:
 			ptr = nil
 			directStaticDeps = append(directStaticDeps, ccDep)
 		case lateStaticDepTag:
 			ptr = &depPaths.LateStaticLibs
 		case wholeStaticDepTag:
 			ptr = &depPaths.WholeStaticLibs
-			staticLib, ok := ccDep.linker.(libraryInterface)
-			if !ok || !staticLib.static() {
+			if !ccDep.CcLibraryInterface() || !ccDep.Static() {
 				ctx.ModuleErrorf("module %q not a static library", depName)
 				return
 			}
 
-			if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil {
-				postfix := " (required by " + ctx.OtherModuleName(dep) + ")"
-				for i := range missingDeps {
-					missingDeps[i] += postfix
+			// Because the static library objects are included, this only makes sense
+			// in the context of proper cc.Modules.
+			if ccWholeStaticLib, ok := ccDep.(*Module); ok {
+				staticLib := ccWholeStaticLib.linker.(libraryInterface)
+				if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil {
+					postfix := " (required by " + ctx.OtherModuleName(dep) + ")"
+					for i := range missingDeps {
+						missingDeps[i] += postfix
+					}
+					ctx.AddMissingDependencies(missingDeps)
 				}
-				ctx.AddMissingDependencies(missingDeps)
+				depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
+			} else {
+				ctx.ModuleErrorf(
+					"non-cc.Modules cannot be included as whole static libraries.", depName)
+				return
 			}
-			depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
 		case headerDepTag:
 			// Nothing
 		case objDepTag:
 			depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
-		case crtBeginDepTag:
+		case CrtBeginDepTag:
 			depPaths.CrtBegin = linkFile
-		case crtEndDepTag:
+		case CrtEndDepTag:
 			depPaths.CrtEnd = linkFile
 		case dynamicLinkerDepTag:
 			depPaths.DynamicLinker = linkFile
 		}
 
 		switch depTag {
-		case staticDepTag, staticExportDepTag, lateStaticDepTag:
-			staticLib, ok := ccDep.linker.(libraryInterface)
-			if !ok || !staticLib.static() {
+		case StaticDepTag, staticExportDepTag, lateStaticDepTag:
+			if !ccDep.CcLibraryInterface() || !ccDep.Static() {
 				ctx.ModuleErrorf("module %q not a static library", depName)
 				return
 			}
@@ -1919,11 +2104,14 @@
 			// When combining coverage files for shared libraries and executables, coverage files
 			// in static libraries act as if they were whole static libraries. The same goes for
 			// source based Abi dump files.
-			depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
-				staticLib.objs().coverageFiles...)
-			depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
-				staticLib.objs().sAbiDumpFiles...)
-
+			// This should only be done for cc.Modules
+			if c, ok := ccDep.(*Module); ok {
+				staticLib := c.linker.(libraryInterface)
+				depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
+					staticLib.objs().coverageFiles...)
+				depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
+					staticLib.objs().sAbiDumpFiles...)
+			}
 		}
 
 		if ptr != nil {
@@ -1952,13 +2140,13 @@
 			libName = strings.TrimPrefix(libName, "prebuilt_")
 			isLLndk := inList(libName, *llndkLibraries)
 			isVendorPublicLib := inList(libName, *vendorPublicLibraries)
-			bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
+			bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
 
-			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() && !c.inRecovery() {
+			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRecovery() {
 				// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 				// core module instead.
 				return libName
-			} else if c.useVndk() && bothVendorAndCoreVariantsExist {
+			} else if c.UseVndk() && bothVendorAndCoreVariantsExist {
 				// The vendor module in Make will have been renamed to not conflict with the core
 				// module, so update the dependency name here accordingly.
 				ret := libName + vendorSuffix
@@ -1972,9 +2160,9 @@
 				return ret
 			} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
 				return libName + vendorPublicLibrarySuffix
-			} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
+			} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
 				return libName + recoverySuffix
-			} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
+			} else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
 				return libName + nativeBridgeSuffix
 			} else {
 				return libName
@@ -1983,9 +2171,9 @@
 
 		// Export the shared libs to Make.
 		switch depTag {
-		case sharedDepTag, sharedExportDepTag, lateSharedDepTag, earlySharedDepTag:
-			if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok {
-				if dependentLibrary.buildStubs() && android.InAnyApex(depName) {
+		case SharedDepTag, sharedExportDepTag, lateSharedDepTag, earlySharedDepTag:
+			if ccDep.CcLibrary() {
+				if ccDep.BuildStubs() && android.InAnyApex(depName) {
 					// Add the dependency to the APEX(es) providing the library so that
 					// m <module> can trigger building the APEXes as well.
 					for _, an := range android.GetApexesForModule(depName) {
@@ -2000,11 +2188,10 @@
 			c.Properties.AndroidMkSharedLibs = append(
 				c.Properties.AndroidMkSharedLibs, makeLibName(depName))
 		case ndkStubDepTag, ndkLateStubDepTag:
-			ndkStub := ccDep.linker.(*stubDecorator)
 			c.Properties.AndroidMkSharedLibs = append(
 				c.Properties.AndroidMkSharedLibs,
-				depName+"."+ndkStub.properties.ApiLevel)
-		case staticDepTag, staticExportDepTag, lateStaticDepTag:
+				depName+"."+ccDep.ApiLevel())
+		case StaticDepTag, staticExportDepTag, lateStaticDepTag:
 			c.Properties.AndroidMkStaticLibs = append(
 				c.Properties.AndroidMkStaticLibs, makeLibName(depName))
 		case runtimeDepTag:
@@ -2054,7 +2241,7 @@
 }
 
 func (c *Module) InstallInRecovery() bool {
-	return c.inRecovery()
+	return c.InRecovery()
 }
 
 func (c *Module) HostToolPath() android.OptionalPath {
@@ -2108,28 +2295,28 @@
 }
 
 func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
-	if c.useVndk() {
+	if c.UseVndk() {
 		if lib, ok := c.linker.(*llndkStubDecorator); ok {
 			if Bool(lib.Properties.Vendor_available) {
 				return "native:vndk"
 			}
 			return "native:vndk_private"
 		}
-		if c.isVndk() && !c.isVndkExt() {
+		if c.IsVndk() && !c.isVndkExt() {
 			if Bool(c.VendorProperties.Vendor_available) {
 				return "native:vndk"
 			}
 			return "native:vndk_private"
 		}
 		return "native:vendor"
-	} else if c.inRecovery() {
+	} else if c.InRecovery() {
 		return "native:recovery"
 	} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
 		return "native:ndk:none:none"
 		// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
 		//family, link := getNdkStlFamilyAndLinkType(c)
 		//return fmt.Sprintf("native:ndk:%s:%s", family, link)
-	} else if actx.DeviceConfig().VndkUseCoreVariant() && !c.mustUseVendorVariant() {
+	} else if actx.DeviceConfig().VndkUseCoreVariant() && !c.MustUseVendorVariant() {
 		return "native:platform_vndk"
 	} else {
 		return "native:platform"
@@ -2164,9 +2351,9 @@
 }
 
 func (c *Module) imageVariation() string {
-	if c.useVndk() {
+	if c.UseVndk() {
 		return vendorMode + "." + c.Properties.VndkVersion
-	} else if c.inRecovery() {
+	} else if c.InRecovery() {
 		return recoveryMode
 	}
 	return coreMode
@@ -2189,8 +2376,8 @@
 }
 
 func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	if depTag, ok := ctx.OtherModuleDependencyTag(dep).(dependencyTag); ok {
-		if cc, ok := dep.(*Module); ok && cc.IsStubs() && depTag.shared {
+	if depTag, ok := ctx.OtherModuleDependencyTag(dep).(DependencyTag); ok {
+		if cc, ok := dep.(*Module); ok && cc.IsStubs() && depTag.Shared {
 			// dynamic dep to a stubs lib crosses APEX boundary
 			return false
 		}
@@ -2341,8 +2528,16 @@
 		}
 	}
 
+	//TODO When LinkableInterface supports VNDK, this should be mctx.Module().(LinkableInterface)
 	m, ok := mctx.Module().(*Module)
 	if !ok {
+		if linkable, ok := mctx.Module().(LinkableInterface); ok {
+			variations := []string{coreMode}
+			if linkable.InRecovery() {
+				variations = append(variations, recoveryMode)
+			}
+			mctx.CreateVariations(variations...)
+		}
 		return
 	}
 
@@ -2432,12 +2627,12 @@
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
 		vendorVariants = append(vendorVariants, lib.version())
-	} else if m.hasVendorVariant() && !vendorSpecific {
+	} else if m.HasVendorVariant() && !vendorSpecific {
 		// This will be available in both /system and /vendor
 		// or a /system directory that is available to vendor.
 		coreVariantNeeded = true
 		vendorVariants = append(vendorVariants, platformVndkVersion)
-		if m.isVndk() {
+		if m.IsVndk() {
 			vendorVariants = append(vendorVariants, deviceVndkVersion)
 		}
 	} else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 8418ec7..064b1a2 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -213,7 +213,7 @@
 	t.Helper()
 
 	mod := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
-	if !mod.hasVendorVariant() {
+	if !mod.HasVendorVariant() {
 		t.Errorf("%q must have vendor variant", name)
 	}
 
@@ -230,8 +230,8 @@
 	if mod.vndkdep == nil {
 		t.Fatalf("%q must have `vndkdep`", name)
 	}
-	if !mod.isVndk() {
-		t.Errorf("%q isVndk() must equal to true", name)
+	if !mod.IsVndk() {
+		t.Errorf("%q IsVndk() must equal to true", name)
 	}
 	if mod.isVndkSp() != isVndkSp {
 		t.Errorf("%q isVndkSp() must equal to %t", name, isVndkSp)
@@ -2309,7 +2309,7 @@
 	variant := "android_arm64_armv8-a_core"
 	binModuleRule := ctx.ModuleForTests("static_test", variant).Rule("ld")
 	libFlags := binModuleRule.Args["libFlags"]
-	systemStaticLibs := []string{"libc.a", "libm.a", "libdl.a"}
+	systemStaticLibs := []string{"libc.a", "libm.a"}
 	for _, lib := range systemStaticLibs {
 		if !strings.Contains(libFlags, lib) {
 			t.Errorf("Static lib %q was not found in %q", lib, libFlags)
diff --git a/cc/fuzz.go b/cc/fuzz.go
index a99b0bb..2c3b973 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"encoding/json"
 	"path/filepath"
 	"strings"
 
@@ -24,12 +25,35 @@
 	"android/soong/cc/config"
 )
 
+type FuzzConfig struct {
+	// Email address of people to CC on bugs or contact about this fuzz target.
+	Cc []string `json:"cc,omitempty"`
+	// Boolean specifying whether to disable the fuzz target from running
+	// automatically in continuous fuzzing infrastructure.
+	Disable *bool `json:"disable,omitempty"`
+	// Component in Google's bug tracking system that bugs should be filed to.
+	Componentid *int64 `json:"componentid,omitempty"`
+	// Hotlists in Google's bug tracking system that bugs should be marked with.
+	Hotlists []string `json:"hotlists,omitempty"`
+}
+
+func (f *FuzzConfig) String() string {
+	b, err := json.Marshal(f)
+	if err != nil {
+		panic(err)
+	}
+
+	return string(b)
+}
+
 type FuzzProperties struct {
 	// Optional list of seed files to be installed to the fuzz target's output
 	// directory.
 	Corpus []string `android:"path"`
 	// Optional dictionary to be installed to the fuzz target's output directory.
 	Dictionary *string `android:"path"`
+	// Config for running the target on fuzzing infrastructure.
+	Fuzz_config *FuzzConfig
 }
 
 func init() {
@@ -57,6 +81,7 @@
 	dictionary            android.Path
 	corpus                android.Paths
 	corpusIntermediateDir android.Path
+	config                android.Path
 }
 
 func (fuzz *fuzzBinary) linkerProps() []interface{} {
@@ -122,6 +147,19 @@
 				fuzz.dictionary.String())
 		}
 	}
+
+	if fuzz.Properties.Fuzz_config != nil {
+		configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.txt")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        android.WriteFile,
+			Description: "fuzzer infrastructure configuration",
+			Output:      configPath,
+			Args: map[string]string{
+				"content": fuzz.Properties.Fuzz_config.String(),
+			},
+		})
+		fuzz.config = configPath
+	}
 }
 
 func NewFuzz(hod android.HostOrDeviceSupported) *Module {
@@ -207,7 +245,7 @@
 
 		// Discard vendor-NDK-linked modules, they're duplicates of fuzz targets
 		// we're going to package anyway.
-		if ccModule.useVndk() || !ccModule.Enabled() {
+		if ccModule.UseVndk() || !ccModule.Enabled() {
 			return
 		}
 
@@ -234,6 +272,12 @@
 			archDirs[archDir] = append(archDirs[archDir],
 				fileToZip{fuzzModule.dictionary, ccModule.Name()})
 		}
+
+		// Additional fuzz config.
+		if fuzzModule.config != nil {
+			archDirs[archDir] = append(archDirs[archDir],
+				fileToZip{fuzzModule.config, ccModule.Name()})
+		}
 	})
 
 	for archDir, filesToZip := range archDirs {
diff --git a/cc/library.go b/cc/library.go
index 1943e89..5a08879 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1227,45 +1227,59 @@
 }
 
 func LinkageMutator(mctx android.BottomUpMutatorContext) {
+	cc_prebuilt := false
 	if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
-		switch library := m.linker.(type) {
-		case prebuiltLibraryInterface:
-			// Always create both the static and shared variants for prebuilt libraries, and then disable the one
-			// that is not being used.  This allows them to share the name of a cc_library module, which requires that
-			// all the variants of the cc_library also exist on the prebuilt.
-			modules := mctx.CreateLocalVariations("static", "shared")
-			static := modules[0].(*Module)
-			shared := modules[1].(*Module)
+		_, cc_prebuilt = m.linker.(prebuiltLibraryInterface)
+	}
+	if cc_prebuilt {
+		library := mctx.Module().(*Module).linker.(prebuiltLibraryInterface)
 
-			static.linker.(prebuiltLibraryInterface).setStatic()
-			shared.linker.(prebuiltLibraryInterface).setShared()
+		// Always create both the static and shared variants for prebuilt libraries, and then disable the one
+		// that is not being used.  This allows them to share the name of a cc_library module, which requires that
+		// all the variants of the cc_library also exist on the prebuilt.
+		modules := mctx.CreateLocalVariations("static", "shared")
+		static := modules[0].(*Module)
+		shared := modules[1].(*Module)
 
-			if !library.buildStatic() {
-				static.linker.(prebuiltLibraryInterface).disablePrebuilt()
-			}
-			if !library.buildShared() {
-				shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
-			}
+		static.linker.(prebuiltLibraryInterface).setStatic()
+		shared.linker.(prebuiltLibraryInterface).setShared()
 
-		case libraryInterface:
-			if library.buildStatic() && library.buildShared() {
-				modules := mctx.CreateLocalVariations("static", "shared")
-				static := modules[0].(*Module)
-				shared := modules[1].(*Module)
-
-				static.linker.(libraryInterface).setStatic()
-				shared.linker.(libraryInterface).setShared()
-
-				reuseStaticLibrary(mctx, static, shared)
-
-			} else if library.buildStatic() {
-				modules := mctx.CreateLocalVariations("static")
-				modules[0].(*Module).linker.(libraryInterface).setStatic()
-			} else if library.buildShared() {
-				modules := mctx.CreateLocalVariations("shared")
-				modules[0].(*Module).linker.(libraryInterface).setShared()
-			}
+		if !library.buildStatic() {
+			static.linker.(prebuiltLibraryInterface).disablePrebuilt()
 		}
+		if !library.buildShared() {
+			shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+		}
+	} else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
+		if library.BuildStaticVariant() && library.BuildSharedVariant() {
+			variations := []string{"static", "shared"}
+
+			// Non-cc.Modules need an empty variant for their mutators.
+			if _, ok := mctx.Module().(*Module); !ok {
+				variations = append(variations, "")
+			}
+
+			modules := mctx.CreateLocalVariations(variations...)
+			static := modules[0].(LinkableInterface)
+			shared := modules[1].(LinkableInterface)
+
+			static.SetStatic()
+			shared.SetShared()
+
+			if _, ok := library.(*Module); ok {
+				reuseStaticLibrary(mctx, static.(*Module), shared.(*Module))
+			}
+		} else if library.BuildStaticVariant() {
+			modules := mctx.CreateLocalVariations("static")
+			modules[0].(LinkableInterface).SetStatic()
+		} else if library.BuildSharedVariant() {
+			modules := mctx.CreateLocalVariations("shared")
+			modules[0].(LinkableInterface).SetShared()
+		} else if _, ok := mctx.Module().(*Module); !ok {
+			// Non-cc.Modules need an empty variant for their mutators.
+			mctx.CreateLocalVariations("")
+		}
+
 	}
 }
 
@@ -1292,11 +1306,10 @@
 // Version mutator splits a module into the mandatory non-stubs variant
 // (which is unnamed) and zero or more stubs variants.
 func VersionMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && !m.inRecovery() && m.linker != nil {
-		if library, ok := m.linker.(*libraryDecorator); ok && library.buildShared() &&
-			len(library.Properties.Stubs.Versions) > 0 {
+	if library, ok := mctx.Module().(LinkableInterface); ok && !library.InRecovery() {
+		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
 			versions := []string{}
-			for _, v := range library.Properties.Stubs.Versions {
+			for _, v := range library.StubsVersions() {
 				if _, err := strconv.Atoi(v); err != nil {
 					mctx.PropertyErrorf("versions", "%q is not a number", v)
 				}
@@ -1320,14 +1333,9 @@
 
 			modules := mctx.CreateVariations(versions...)
 			for i, m := range modules {
-				l := m.(*Module).linker.(*libraryDecorator)
 				if versions[i] != "" {
-					l.MutatedProperties.BuildStubs = true
-					l.MutatedProperties.StubsVersion = versions[i]
-					m.(*Module).Properties.HideFromMake = true
-					m.(*Module).sanitize = nil
-					m.(*Module).stl = nil
-					m.(*Module).Properties.PreventInstall = true
+					m.(LinkableInterface).SetBuildStubs()
+					m.(LinkableInterface).SetStubsVersions(versions[i])
 				}
 			}
 		} else {
@@ -1353,7 +1361,7 @@
 	injectBoringSSLHash := Bool(inject)
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		tag := ctx.OtherModuleDependencyTag(dep)
-		if tag == staticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag {
+		if tag == StaticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag {
 			if cc, ok := dep.(*Module); ok {
 				if library, ok := cc.linker.(*libraryDecorator); ok {
 					if Bool(library.Properties.Inject_bssl_hash) {
diff --git a/cc/linkable.go b/cc/linkable.go
new file mode 100644
index 0000000..cfbaffe
--- /dev/null
+++ b/cc/linkable.go
@@ -0,0 +1,71 @@
+package cc
+
+import (
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+type LinkableInterface interface {
+	Module() android.Module
+	CcLibrary() bool
+	CcLibraryInterface() bool
+
+	OutputFile() android.OptionalPath
+
+	IncludeDirs(ctx android.BaseModuleContext) android.Paths
+	SetDepsInLinkOrder([]android.Path)
+	GetDepsInLinkOrder() []android.Path
+
+	HasStaticVariant() bool
+	GetStaticVariant() LinkableInterface
+
+	StubsVersions() []string
+	BuildStubs() bool
+	SetBuildStubs()
+	SetStubsVersions(string)
+	HasStubsVariants() bool
+	SelectedStl() string
+	ApiLevel() string
+
+	BuildStaticVariant() bool
+	BuildSharedVariant() bool
+	SetStatic()
+	SetShared()
+	Static() bool
+	Shared() bool
+	Toc() android.OptionalPath
+
+	InRecovery() bool
+	OnlyInRecovery() bool
+
+	UseVndk() bool
+	MustUseVendorVariant() bool
+	IsVndk() bool
+	HasVendorVariant() bool
+
+	SdkVersion() string
+
+	ToolchainLibrary() bool
+	NdkPrebuiltStl() bool
+	StubDecorator() bool
+}
+
+type DependencyTag struct {
+	blueprint.BaseDependencyTag
+	Name    string
+	Library bool
+	Shared  bool
+
+	ReexportFlags bool
+
+	ExplicitlyVersioned bool
+}
+
+var (
+	SharedDepTag = DependencyTag{Name: "shared", Library: true, Shared: true}
+	StaticDepTag = DependencyTag{Name: "static", Library: true}
+
+	CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
+	CrtEndDepTag   = DependencyTag{Name: "crtend"}
+)
diff --git a/cc/lto.go b/cc/lto.go
index 431d70d..580bb09 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -148,7 +148,7 @@
 		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
 			tag := mctx.OtherModuleDependencyTag(dep)
 			switch tag {
-			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
+			case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
 				if dep, ok := dep.(*Module); ok && dep.lto != nil &&
 					!dep.lto.Disabled() {
 					if full && !Bool(dep.lto.Properties.Lto.Full) {
diff --git a/cc/sabi.go b/cc/sabi.go
index 0999151..8a9eff0 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -78,12 +78,12 @@
 
 func sabiDepsMutator(mctx android.TopDownMutatorContext) {
 	if c, ok := mctx.Module().(*Module); ok &&
-		((c.isVndk() && c.useVndk()) || inList(c.Name(), *llndkLibraries(mctx.Config())) ||
+		((c.IsVndk() && c.UseVndk()) || inList(c.Name(), *llndkLibraries(mctx.Config())) ||
 			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
 		mctx.VisitDirectDeps(func(m android.Module) {
 			tag := mctx.OtherModuleDependencyTag(m)
 			switch tag {
-			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
+			case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
 
 				cc, _ := m.(*Module)
 				if cc == nil {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 5172fc8..e4c6b1c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -678,8 +678,8 @@
 }
 
 func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
-	t, ok := tag.(dependencyTag)
-	return ok && t.library || t == reuseObjTag || t == objDepTag
+	t, ok := tag.(DependencyTag)
+	return ok && t.Library || t == reuseObjTag || t == objDepTag
 }
 
 // Propagate sanitizer requirements down from binaries
@@ -848,12 +848,14 @@
 
 		// Determine the runtime library required
 		runtimeLibrary := ""
+		var extraStaticDeps []string
 		toolchain := c.toolchain(mctx)
 		if Bool(c.sanitize.Properties.Sanitize.Address) {
 			runtimeLibrary = config.AddressSanitizerRuntimeLibrary(toolchain)
 		} else if Bool(c.sanitize.Properties.Sanitize.Hwaddress) {
 			if c.staticBinary() {
 				runtimeLibrary = config.HWAddressSanitizerStaticLibrary(toolchain)
+				extraStaticDeps = []string{"libdl"}
 			} else {
 				runtimeLibrary = config.HWAddressSanitizerRuntimeLibrary(toolchain)
 			}
@@ -871,7 +873,7 @@
 		}
 
 		if mctx.Device() && runtimeLibrary != "" {
-			if inList(runtimeLibrary, *llndkLibraries(mctx.Config())) && !c.static() && c.useVndk() {
+			if inList(runtimeLibrary, *llndkLibraries(mctx.Config())) && !c.static() && c.UseVndk() {
 				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
 			}
 
@@ -887,7 +889,7 @@
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "static"},
 					{Mutator: "image", Variation: c.imageVariation()},
-				}...), staticDepTag, runtimeLibrary)
+				}...), StaticDepTag, append([]string{runtimeLibrary}, extraStaticDeps...)...)
 			} else if !c.static() && !c.header() {
 				// dynamic executable and shared libs get shared runtime libs
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
@@ -961,7 +963,7 @@
 						if t == cfi {
 							appendStringSync(c.Name(), cfiStaticLibs(mctx.Config()), &cfiStaticLibsMutex)
 						} else if t == hwasan {
-							if c.useVndk() {
+							if c.UseVndk() {
 								appendStringSync(c.Name(), hwasanVendorStaticLibs(mctx.Config()),
 									&hwasanStaticLibsMutex)
 							} else {
diff --git a/cc/stl.go b/cc/stl.go
index aa34240..101519b 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -20,13 +20,13 @@
 	"strconv"
 )
 
-func getNdkStlFamily(m *Module) string {
+func getNdkStlFamily(m LinkableInterface) string {
 	family, _ := getNdkStlFamilyAndLinkType(m)
 	return family
 }
 
-func getNdkStlFamilyAndLinkType(m *Module) (string, string) {
-	stl := m.stl.Properties.SelectedStl
+func getNdkStlFamilyAndLinkType(m LinkableInterface) (string, string) {
+	stl := m.SelectedStl()
 	switch stl {
 	case "ndk_libc++_shared":
 		return "libc++", "shared"
@@ -175,7 +175,7 @@
 				deps.StaticLibs = append(deps.StaticLibs, "libunwind_llvm")
 			}
 			if ctx.staticBinary() {
-				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl")
+				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
 			}
 		}
 	case "":
diff --git a/cc/vndk.go b/cc/vndk.go
index 46fd7b1..ec8f023 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -98,7 +98,7 @@
 	return "native:vendor:vndkspext"
 }
 
-func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag dependencyTag) {
+func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag DependencyTag) {
 	if to.linker == nil {
 		return
 	}
@@ -125,7 +125,7 @@
 		// Other (static and LL-NDK) libraries are allowed to link.
 		return
 	}
-	if !to.useVndk() {
+	if !to.UseVndk() {
 		ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
 			vndk.typeName(), to.Name())
 		return
@@ -301,7 +301,7 @@
 	if inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
 		m.Properties.MustUseVendorVariant = true
 	}
-	if mctx.DeviceConfig().VndkUseCoreVariant() && !m.mustUseVendorVariant() {
+	if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
 		vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
 		if !inList(name, *vndkUsingCoreVariantLibraries) {
 			*vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
@@ -352,7 +352,7 @@
 		useCoreVariant := m.vndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
 			mctx.DeviceConfig().VndkUseCoreVariant() &&
 			!inList(m.BaseModuleName(), config.VndkMustUseVendorVariantList)
-		return lib.shared() && m.useVndk() && m.isVndk() && !m.isVndkExt() && !useCoreVariant
+		return lib.shared() && m.UseVndk() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
 	}
 	return false
 }
@@ -536,7 +536,7 @@
 		if m.Target().NativeBridge == android.NativeBridgeEnabled {
 			return nil, "", false
 		}
-		if !m.useVndk() || !m.IsForPlatform() || !m.installable() {
+		if !m.UseVndk() || !m.IsForPlatform() || !m.installable() {
 			return nil, "", false
 		}
 		l, ok := m.linker.(vndkSnapshotLibraryInterface)
@@ -699,7 +699,7 @@
 			if c.isVndkPrivate(config) {
 				vndkprivate = append(vndkprivate, filename)
 			}
-		} else if c.vndkVersion() == vndkVersion && c.isVndk() && !c.isVndkExt() {
+		} else if c.vndkVersion() == vndkVersion && c.IsVndk() && !c.isVndkExt() {
 			if c.isVndkSp() {
 				vndksp = append(vndksp, filename)
 			} else {
@@ -708,7 +708,7 @@
 			if c.isVndkPrivate(config) {
 				vndkprivate = append(vndkprivate, filename)
 			}
-			if ctx.DeviceConfig().VndkUseCoreVariant() && !c.mustUseVendorVariant() {
+			if ctx.DeviceConfig().VndkUseCoreVariant() && !c.MustUseVendorVariant() {
 				vndkcorevariant = append(vndkcorevariant, filename)
 			}
 		}
diff --git a/java/aar.go b/java/aar.go
index 6426ac3..afe860c 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -72,6 +72,9 @@
 
 	// paths to additional manifest files to merge with main manifest.
 	Additional_manifests []string `android:"path"`
+
+	// do not include AndroidManifest from dependent libraries
+	Dont_merge_manifests *bool
 }
 
 type aapt struct {
@@ -225,7 +228,7 @@
 	a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...)
 	a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...)
 
-	if len(a.transitiveManifestPaths) > 1 {
+	if len(a.transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
 		a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
@@ -535,6 +538,10 @@
 	return a.sdkVersion()
 }
 
+func (a *AARImport) javaVersion() string {
+	return ""
+}
+
 var _ AndroidLibraryDependency = (*AARImport)(nil)
 
 func (a *AARImport) ExportPackage() android.Path {
diff --git a/java/builder.go b/java/builder.go
index 0a5c79b..169d853 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -182,15 +182,16 @@
 }
 
 type javaBuilderFlags struct {
-	javacFlags    string
-	bootClasspath classpath
-	classpath     classpath
-	processorPath classpath
-	processor     string
-	systemModules *systemModules
-	aidlFlags     string
-	aidlDeps      android.Paths
-	javaVersion   string
+	javacFlags     string
+	bootClasspath  classpath
+	classpath      classpath
+	java9Classpath classpath
+	processorPath  classpath
+	processor      string
+	systemModules  *systemModules
+	aidlFlags      string
+	aidlDeps       android.Paths
+	javaVersion    javaVersion
 
 	errorProneExtraJavacFlags string
 	errorProneProcessorPath   classpath
@@ -239,7 +240,7 @@
 	deps = append(deps, srcJars...)
 
 	var bootClasspath string
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		var systemModuleDeps android.Paths
 		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
 		deps = append(deps, systemModuleDeps...)
@@ -279,7 +280,7 @@
 				"bootClasspath": bootClasspath,
 				"classpath":     flags.classpath.FormJavaClassPath("-classpath"),
 				"javacFlags":    flags.javacFlags,
-				"javaVersion":   flags.javaVersion,
+				"javaVersion":   flags.javaVersion.String(),
 				"outDir":        android.PathForModuleOut(ctx, "javac", "classes.xref").String(),
 				"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
 				"processor":     processor,
@@ -294,18 +295,29 @@
 
 	var deps android.Paths
 	deps = append(deps, srcJars...)
-	deps = append(deps, flags.bootClasspath...)
-	deps = append(deps, flags.classpath...)
+
+	classpath := flags.classpath
 
 	var bootClasspath string
-	if len(flags.bootClasspath) == 0 && ctx.Device() {
-		// explicitly specify -bootclasspath "" if the bootclasspath is empty to
-		// ensure java does not fall back to the default bootclasspath.
-		bootClasspath = `--bootclasspath ""`
+	if flags.javaVersion.usesJavaModules() {
+		var systemModuleDeps android.Paths
+		bootClasspath, systemModuleDeps = flags.systemModules.FormTurbineSystemModulesPath(ctx.Device())
+		deps = append(deps, systemModuleDeps...)
+		classpath = append(flags.java9Classpath, classpath...)
 	} else {
-		bootClasspath = strings.Join(flags.bootClasspath.FormTurbineClasspath("--bootclasspath "), " ")
+		deps = append(deps, flags.bootClasspath...)
+		if len(flags.bootClasspath) == 0 && ctx.Device() {
+			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
+			// ensure turbine does not fall back to the default bootclasspath.
+			bootClasspath = `--bootclasspath ""`
+		} else {
+			bootClasspath = strings.Join(flags.bootClasspath.FormTurbineClasspath("--bootclasspath "), " ")
+		}
 	}
 
+	deps = append(deps, classpath...)
+	deps = append(deps, flags.processorPath...)
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        turbine,
 		Description: "turbine",
@@ -316,9 +328,9 @@
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
 			"srcJars":       strings.Join(srcJars.Strings(), " "),
-			"classpath":     strings.Join(flags.classpath.FormTurbineClasspath("--classpath "), " "),
+			"classpath":     strings.Join(classpath.FormTurbineClasspath("--classpath "), " "),
 			"outDir":        android.PathForModuleOut(ctx, "turbine", "classes").String(),
-			"javaVersion":   flags.javaVersion,
+			"javaVersion":   flags.javaVersion.String(),
 		},
 	})
 }
@@ -339,11 +351,14 @@
 
 	deps = append(deps, srcJars...)
 
+	classpath := flags.classpath
+
 	var bootClasspath string
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		var systemModuleDeps android.Paths
 		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
 		deps = append(deps, systemModuleDeps...)
+		classpath = append(flags.java9Classpath, classpath...)
 	} else {
 		deps = append(deps, flags.bootClasspath...)
 		if len(flags.bootClasspath) == 0 && ctx.Device() {
@@ -355,7 +370,7 @@
 		}
 	}
 
-	deps = append(deps, flags.classpath...)
+	deps = append(deps, classpath...)
 	deps = append(deps, flags.processorPath...)
 
 	processor := "-proc:none"
@@ -381,14 +396,14 @@
 		Args: map[string]string{
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
-			"classpath":     flags.classpath.FormJavaClassPath("-classpath"),
+			"classpath":     classpath.FormJavaClassPath("-classpath"),
 			"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
 			"processor":     processor,
 			"srcJars":       strings.Join(srcJars.Strings(), " "),
 			"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(),
 			"outDir":        android.PathForModuleOut(ctx, intermediatesDir, outDir).String(),
 			"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(),
-			"javaVersion":   flags.javaVersion,
+			"javaVersion":   flags.javaVersion.String(),
 		},
 	})
 }
@@ -550,9 +565,9 @@
 	deps android.Paths
 }
 
-// Returns a --system argument in the form javac expects with -source 1.9.  If forceEmpty is true,
-// returns --system=none if the list is empty to ensure javac does not fall back to the default
-// system modules.
+// Returns a --system argument in the form javac expects with -source 1.9 and the list of files to
+// depend on.  If forceEmpty is true, returns --system=none if the list is empty to ensure javac
+// does not fall back to the default system modules.
 func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) {
 	if x != nil {
 		return "--system=" + x.dir.String(), x.deps
@@ -562,3 +577,16 @@
 		return "", nil
 	}
 }
+
+// Returns a --system argument in the form turbine expects with -source 1.9 and the list of files to
+// depend on.  If forceEmpty is true, returns --bootclasspath "" if the list is empty to ensure turbine
+// does not fall back to the default bootclasspath.
+func (x *systemModules) FormTurbineSystemModulesPath(forceEmpty bool) (string, android.Paths) {
+	if x != nil {
+		return "--system " + x.dir.String(), x.deps
+	} else if forceEmpty {
+		return `--bootclasspath ""`, nil
+	} else {
+		return "", nil
+	}
+}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 1091331..6f3b152 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -422,21 +422,16 @@
 func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
-		if sdkDep.hasStandardLibs() {
-			if sdkDep.useDefaultLibs {
-				ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
-				ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
-				if sdkDep.hasFrameworkLibs() {
-					ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
-				}
-			} else if sdkDep.useModule {
-				ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-				ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
+		if sdkDep.useDefaultLibs {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
+			ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
+			if sdkDep.hasFrameworkLibs() {
+				ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
 			}
-		} else if sdkDep.systemModules != "" {
-			// Add the system modules to both the system modules and bootclasspath.
+		} else if sdkDep.useModule {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 			ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.systemModules)
+			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
 		}
 	}
 
@@ -511,7 +506,8 @@
 
 	sdkDep := decodeSdkDep(ctx, sdkContext(j))
 	if sdkDep.invalidVersion {
-		ctx.AddMissingDependencies(sdkDep.modules)
+		ctx.AddMissingDependencies(sdkDep.bootclasspath)
+		ctx.AddMissingDependencies(sdkDep.java9Classpath)
 	} else if sdkDep.useFiles {
 		deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...)
 	}
@@ -544,6 +540,13 @@
 			default:
 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
+		case java9LibTag:
+			switch dep := module.(type) {
+			case Dependency:
+				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...)
+			default:
+				ctx.ModuleErrorf("depends on non-java module %q", otherName)
+			}
 		case systemModulesTag:
 			if deps.systemModules != nil {
 				panic("Found two system module dependencies")
@@ -665,7 +668,7 @@
 	cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList,
 		deps.systemModules, deps.classpath, j.sourcepaths)
 
-	cmd.FlagWithArg("-source ", javaVersion).
+	cmd.FlagWithArg("-source ", javaVersion.String()).
 		Flag("-J-Xmx1024m").
 		Flag("-XDignore.symbol.file").
 		Flag("-Xdoclint:none")
@@ -1432,12 +1435,12 @@
 	}
 }
 
-func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion string, srcs android.Paths,
+func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
 	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
 	cmd := rule.Command().BuiltTool(ctx, "metalava").
 		Flag(config.JavacVmFlags).
 		FlagWithArg("-encoding ", "UTF-8").
-		FlagWithArg("-source ", javaVersion).
+		FlagWithArg("-source ", javaVersion.String()).
 		FlagWithRspFileInputList("@", srcs).
 		FlagWithInput("@", srcJarList)
 
diff --git a/java/java.go b/java/java.go
index 9ed7621..947aa8c 100644
--- a/java/java.go
+++ b/java/java.go
@@ -140,10 +140,10 @@
 	Use_tools_jar *bool
 
 	Openjdk9 struct {
-		// List of source files that should only be used when passing -source 1.9
+		// List of source files that should only be used when passing -source 1.9 or higher
 		Srcs []string `android:"path"`
 
-		// List of javac flags that should only be used when passing -source 1.9
+		// List of javac flags that should only be used when passing -source 1.9 or higher
 		Javacflags []string
 	}
 
@@ -433,6 +433,7 @@
 var (
 	staticLibTag          = dependencyTag{name: "staticlib"}
 	libTag                = dependencyTag{name: "javalib"}
+	java9LibTag           = dependencyTag{name: "java9lib"}
 	pluginTag             = dependencyTag{name: "plugin"}
 	bootClasspathTag      = dependencyTag{name: "bootclasspath"}
 	systemModulesTag      = dependencyTag{name: "system modules"}
@@ -461,12 +462,16 @@
 type sdkDep struct {
 	useModule, useFiles, useDefaultLibs, invalidVersion bool
 
-	modules []string
+	// The modules that will be added to the bootclasspath when targeting 1.8 or lower
+	bootclasspath []string
 
 	// The default system modules to use. Will be an empty string if no system
 	// modules are to be used.
 	systemModules string
 
+	// The modules that will be added ot the classpath when targeting 1.9 or higher
+	java9Classpath []string
+
 	frameworkResModule string
 
 	jars android.Paths
@@ -524,26 +529,22 @@
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
-		if sdkDep.hasStandardLibs() {
-			if sdkDep.useDefaultLibs {
-				ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
-				ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
-				if sdkDep.hasFrameworkLibs() {
-					ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
-				}
-			} else if sdkDep.useModule {
-				ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-				ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
-				if j.deviceProperties.EffectiveOptimizeEnabled() {
-					ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
-					ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
-				}
+		if sdkDep.useDefaultLibs {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
+			ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
+			if sdkDep.hasFrameworkLibs() {
+				ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
 			}
-		} else if sdkDep.systemModules != "" {
-			// Add the system modules to both the system modules and bootclasspath.
+		} else if sdkDep.useModule {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 			ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.systemModules)
+			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+			if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
+				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
+				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
+			}
 		}
+
 		if ctx.ModuleName() == "android_stubs_current" ||
 			ctx.ModuleName() == "android_system_stubs_current" ||
 			ctx.ModuleName() == "android_test_stubs_current" {
@@ -635,6 +636,7 @@
 
 type deps struct {
 	classpath          classpath
+	java9Classpath     classpath
 	bootClasspath      classpath
 	processorPath      classpath
 	processorClasses   []string
@@ -744,7 +746,8 @@
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
 		if sdkDep.invalidVersion {
-			ctx.AddMissingDependencies(sdkDep.modules)
+			ctx.AddMissingDependencies(sdkDep.bootclasspath)
+			ctx.AddMissingDependencies(sdkDep.java9Classpath)
 		} else if sdkDep.useFiles {
 			// sdkDep.jar is actually equivalent to turbine header.jar.
 			deps.classpath = append(deps.classpath, sdkDep.jars...)
@@ -792,6 +795,8 @@
 				// sdk lib names from dependencies are re-exported
 				j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
+			case java9LibTag:
+				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...)
 			case staticLibTag:
 				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
 				deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
@@ -865,8 +870,7 @@
 	return deps
 }
 
-func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) string {
-	var ret string
+func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) javaVersion {
 	v := sdkContext.sdkVersion()
 	// For PDK builds, use the latest SDK version instead of "current"
 	if ctx.Config().IsPdkBuild() &&
@@ -884,41 +888,65 @@
 		ctx.PropertyErrorf("sdk_version", "%s", err)
 	}
 	if javaVersion != "" {
-		ret = normalizeJavaVersion(ctx, javaVersion)
+		return normalizeJavaVersion(ctx, javaVersion)
 	} else if ctx.Device() && sdk <= 23 {
-		ret = "1.7"
+		return JAVA_VERSION_7
 	} else if ctx.Device() && sdk <= 29 {
-		ret = "1.8"
-	} else if ctx.Device() &&
-		sdkContext.sdkVersion() != "" &&
-		sdkContext.sdkVersion() != "none" &&
-		sdkContext.sdkVersion() != "core_platform" &&
-		sdk == android.FutureApiLevel {
-		// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
-		ret = "1.8"
+		return JAVA_VERSION_8
+	} else if ctx.Device() && ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+		// TODO(b/142896162): once we have prebuilt system modules we can use 1.9 for unbundled builds
+		return JAVA_VERSION_8
 	} else {
-		ret = "1.9"
+		return JAVA_VERSION_9
 	}
-
-	return ret
 }
 
-func normalizeJavaVersion(ctx android.ModuleContext, javaVersion string) string {
+type javaVersion int
+
+const (
+	JAVA_VERSION_UNSUPPORTED = 0
+	JAVA_VERSION_6           = 6
+	JAVA_VERSION_7           = 7
+	JAVA_VERSION_8           = 8
+	JAVA_VERSION_9           = 9
+)
+
+func (v javaVersion) String() string {
+	switch v {
+	case JAVA_VERSION_6:
+		return "1.6"
+	case JAVA_VERSION_7:
+		return "1.7"
+	case JAVA_VERSION_8:
+		return "1.8"
+	case JAVA_VERSION_9:
+		return "1.9"
+	default:
+		return "unsupported"
+	}
+}
+
+// Returns true if javac targeting this version uses system modules instead of a bootclasspath.
+func (v javaVersion) usesJavaModules() bool {
+	return v >= 9
+}
+
+func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) javaVersion {
 	switch javaVersion {
 	case "1.6", "6":
-		return "1.6"
+		return JAVA_VERSION_6
 	case "1.7", "7":
-		return "1.7"
+		return JAVA_VERSION_7
 	case "1.8", "8":
-		return "1.8"
+		return JAVA_VERSION_8
 	case "1.9", "9":
-		return "1.9"
+		return JAVA_VERSION_9
 	case "10", "11":
 		ctx.PropertyErrorf("java_version", "Java language levels above 9 are not supported")
-		return "unsupported"
+		return JAVA_VERSION_UNSUPPORTED
 	default:
 		ctx.PropertyErrorf("java_version", "Unrecognized Java language level")
-		return "unrecognized"
+		return JAVA_VERSION_UNSUPPORTED
 	}
 }
 
@@ -931,7 +959,7 @@
 
 	// javac flags.
 	javacFlags := j.properties.Javacflags
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
 	}
 	if ctx.Config().MinimizeJavaDebugInfo() {
@@ -959,13 +987,13 @@
 	// classpath
 	flags.bootClasspath = append(flags.bootClasspath, deps.bootClasspath...)
 	flags.classpath = append(flags.classpath, deps.classpath...)
+	flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
 	flags.processorPath = append(flags.processorPath, deps.processorPath...)
 
 	flags.processor = strings.Join(deps.processorClasses, ",")
 
-	if len(flags.bootClasspath) == 0 && ctx.Host() && flags.javaVersion != "1.9" &&
-		decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() &&
-		inList(flags.javaVersion, []string{"1.6", "1.7", "1.8"}) {
+	if len(flags.bootClasspath) == 0 && ctx.Host() && !flags.javaVersion.usesJavaModules() &&
+		decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() {
 		// Give host-side tools a version of OpenJDK's standard libraries
 		// close to what they're targeting. As of Dec 2017, AOSP is only
 		// bundling OpenJDK 8 and 9, so nothing < 8 is available.
@@ -989,7 +1017,7 @@
 		}
 	}
 
-	if j.properties.Patch_module != nil && flags.javaVersion == "1.9" {
+	if j.properties.Patch_module != nil && flags.javaVersion.usesJavaModules() {
 		// Manually specify build directory in case it is not under the repo root.
 		// (javac doesn't seem to expand into symbolc links when searching for patch-module targets, so
 		// just adding a symlink under the root doesn't help.)
@@ -1022,7 +1050,7 @@
 	deps := j.collectDeps(ctx)
 	flags := j.collectBuilderFlags(ctx, deps)
 
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
 	}
 	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
diff --git a/java/java_test.go b/java/java_test.go
index 3767d1b..a6ae503 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -148,9 +148,9 @@
 		"prebuilts/sdk/17/public/android.jar":         nil,
 		"prebuilts/sdk/17/public/framework.aidl":      nil,
 		"prebuilts/sdk/17/system/android.jar":         nil,
-		"prebuilts/sdk/25/public/android.jar":         nil,
-		"prebuilts/sdk/25/public/framework.aidl":      nil,
-		"prebuilts/sdk/25/system/android.jar":         nil,
+		"prebuilts/sdk/29/public/android.jar":         nil,
+		"prebuilts/sdk/29/public/framework.aidl":      nil,
+		"prebuilts/sdk/29/system/android.jar":         nil,
 		"prebuilts/sdk/current/core/android.jar":      nil,
 		"prebuilts/sdk/current/public/android.jar":    nil,
 		"prebuilts/sdk/current/public/framework.aidl": nil,
diff --git a/java/kotlin.go b/java/kotlin.go
index 8306907..f8ae229 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -141,8 +141,8 @@
 	}
 
 	encodedJavacFlags := kaptEncodeFlags([][2]string{
-		{"-source", flags.javaVersion},
-		{"-target", flags.javaVersion},
+		{"-source", flags.javaVersion.String()},
+		{"-target", flags.javaVersion.String()},
 	})
 
 	kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
diff --git a/java/proto.go b/java/proto.go
index e013bb4..4d735eb 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -108,10 +108,10 @@
 		case "nano":
 			flags.proto.OutTypeFlag = "--javanano_out"
 			typeToPlugin = "javanano"
-		case "lite":
+		case "lite", "":
 			flags.proto.OutTypeFlag = "--java_out"
 			flags.proto.OutParams = append(flags.proto.OutParams, "lite")
-		case "full", "":
+		case "full":
 			flags.proto.OutTypeFlag = "--java_out"
 		default:
 			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
diff --git a/java/sdk.go b/java/sdk.go
index c6a9a73..6f0f432 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -122,7 +122,7 @@
 		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
 			return sdkDep{
 				invalidVersion: true,
-				modules:        []string{fmt.Sprintf("sdk_%s_%s_android", api, v)},
+				bootclasspath:  []string{fmt.Sprintf("sdk_%s_%s_android", api, v)},
 			}
 		}
 
@@ -144,20 +144,14 @@
 	}
 
 	toModule := func(m, r string, aidl android.Path) sdkDep {
-		ret := sdkDep{
+		return sdkDep{
 			useModule:          true,
-			modules:            []string{m, config.DefaultLambdaStubsLibrary},
-			systemModules:      m + "_system_modules",
+			bootclasspath:      []string{m, config.DefaultLambdaStubsLibrary},
+			systemModules:      "core-current-stubs-system-modules",
+			java9Classpath:     []string{m},
 			frameworkResModule: r,
 			aidl:               android.OptionalPathForPath(aidl),
 		}
-
-		if m == "core.current.stubs" {
-			ret.systemModules = "core-current-stubs-system-modules"
-			// core_current does not include framework classes.
-			ret.noFrameworksLibs = true
-		}
-		return ret
 	}
 
 	// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
@@ -192,13 +186,16 @@
 			ctx.PropertyErrorf("sdk_version",
 				`system_modules is required to be set to a non-empty value when sdk_version is "none", did you mean sdk_version: "core_platform"?`)
 		} else if systemModules == "none" {
-			// Normalize no system modules to an empty string.
-			systemModules = ""
+			return sdkDep{
+				noStandardLibs: true,
+			}
 		}
 
 		return sdkDep{
+			useModule:      true,
 			noStandardLibs: true,
 			systemModules:  systemModules,
+			bootclasspath:  []string{systemModules},
 		}
 	case "core_platform":
 		return sdkDep{
diff --git a/java/sdk_test.go b/java/sdk_test.go
index fd47d81..525c898 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -28,174 +28,188 @@
 
 func TestClasspath(t *testing.T) {
 	var classpathTestcases = []struct {
-		name          string
-		unbundled     bool
-		pdk           bool
-		moduleType    string
-		host          android.OsClass
-		properties    string
-		bootclasspath []string
-		system        string
-		classpath     []string
-		aidl          string
+		name       string
+		unbundled  bool
+		pdk        bool
+		moduleType string
+		host       android.OsClass
+		properties string
+
+		// for java 8
+		bootclasspath  []string
+		java8classpath []string
+
+		// for java 9
+		system         string
+		java9classpath []string
+
+		forces8 bool // if set, javac will always be called with java 8 arguments
+
+		aidl string
 	}{
 		{
-			name:          "default",
-			bootclasspath: config.DefaultBootclasspathLibraries,
-			system:        config.DefaultSystemModules,
-			classpath:     config.DefaultLibraries,
-			aidl:          "-Iframework/aidl",
+			name:           "default",
+			bootclasspath:  config.DefaultBootclasspathLibraries,
+			system:         config.DefaultSystemModules,
+			java8classpath: config.DefaultLibraries,
+			java9classpath: config.DefaultLibraries,
+			aidl:           "-Iframework/aidl",
 		},
 		{
-			name:          `sdk_version:"core_platform"`,
-			properties:    `sdk_version:"core_platform"`,
-			bootclasspath: config.DefaultBootclasspathLibraries,
-			system:        config.DefaultSystemModules,
-			classpath:     []string{},
-			aidl:          "",
+			name:           `sdk_version:"core_platform"`,
+			properties:     `sdk_version:"core_platform"`,
+			bootclasspath:  config.DefaultBootclasspathLibraries,
+			system:         config.DefaultSystemModules,
+			java8classpath: []string{},
+			aidl:           "",
 		},
 		{
-			name:          "blank sdk version",
-			properties:    `sdk_version: "",`,
-			bootclasspath: config.DefaultBootclasspathLibraries,
-			system:        config.DefaultSystemModules,
-			classpath:     config.DefaultLibraries,
-			aidl:          "-Iframework/aidl",
+			name:           "blank sdk version",
+			properties:     `sdk_version: "",`,
+			bootclasspath:  config.DefaultBootclasspathLibraries,
+			system:         config.DefaultSystemModules,
+			java8classpath: config.DefaultLibraries,
+			java9classpath: config.DefaultLibraries,
+			aidl:           "-Iframework/aidl",
 		},
 		{
 
-			name:          "sdk v25",
-			properties:    `sdk_version: "25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "sdk v29",
+			properties:     `sdk_version: "29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
 
-			name:          "current",
-			properties:    `sdk_version: "current",`,
-			bootclasspath: []string{"android_stubs_current", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			aidl:          "-p" + buildDir + "/framework.aidl",
+			name:           "current",
+			properties:     `sdk_version: "current",`,
+			bootclasspath:  []string{"android_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
 		},
 		{
 
-			name:          "system_current",
-			properties:    `sdk_version: "system_current",`,
-			bootclasspath: []string{"android_system_stubs_current", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			aidl:          "-p" + buildDir + "/framework.aidl",
+			name:           "system_current",
+			properties:     `sdk_version: "system_current",`,
+			bootclasspath:  []string{"android_system_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_system_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
 		},
 		{
 
-			name:          "system_25",
-			properties:    `sdk_version: "system_25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "system_29",
+			properties:     `sdk_version: "system_29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
 
-			name:          "test_current",
-			properties:    `sdk_version: "test_current",`,
-			bootclasspath: []string{"android_test_stubs_current", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			aidl:          "-p" + buildDir + "/framework.aidl",
+			name:           "test_current",
+			properties:     `sdk_version: "test_current",`,
+			bootclasspath:  []string{"android_test_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_test_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
 		},
 		{
 
-			name:          "core_current",
-			properties:    `sdk_version: "core_current",`,
-			bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+			name:           "core_current",
+			properties:     `sdk_version: "core_current",`,
+			bootclasspath:  []string{"core.current.stubs", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"core.current.stubs"},
 		},
 		{
 
-			name:          "nostdlib",
-			properties:    `sdk_version: "none", system_modules: "none"`,
-			system:        "none",
-			bootclasspath: []string{`""`},
-			classpath:     []string{},
+			name:           "nostdlib",
+			properties:     `sdk_version: "none", system_modules: "none"`,
+			system:         "none",
+			bootclasspath:  []string{`""`},
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "nostdlib system_modules",
-			properties:    `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
-			system:        "core-platform-api-stubs-system-modules",
-			bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"},
-			classpath:     []string{},
+			name:           "nostdlib system_modules",
+			properties:     `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
+			system:         "core-platform-api-stubs-system-modules",
+			bootclasspath:  []string{"core-platform-api-stubs-system-modules-lib"},
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "host default",
-			moduleType:    "java_library_host",
-			properties:    ``,
-			host:          android.Host,
-			bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
-			classpath:     []string{},
+			name:           "host default",
+			moduleType:     "java_library_host",
+			properties:     ``,
+			host:           android.Host,
+			bootclasspath:  []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "host supported default",
-			host:          android.Host,
-			properties:    `host_supported: true,`,
-			classpath:     []string{},
-			bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
+			name:           "host supported default",
+			host:           android.Host,
+			properties:     `host_supported: true,`,
+			java8classpath: []string{},
+			bootclasspath:  []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
 		},
 		{
-			name:       "host supported nostdlib",
-			host:       android.Host,
-			properties: `host_supported: true, sdk_version: "none", system_modules: "none"`,
-			classpath:  []string{},
+			name:           "host supported nostdlib",
+			host:           android.Host,
+			properties:     `host_supported: true, sdk_version: "none", system_modules: "none"`,
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "unbundled sdk v25",
-			unbundled:     true,
-			properties:    `sdk_version: "25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "unbundled sdk v29",
+			unbundled:      true,
+			properties:     `sdk_version: "29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
 
-			name:          "unbundled current",
-			unbundled:     true,
-			properties:    `sdk_version: "current",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/current/public/framework.aidl",
+			name:           "unbundled current",
+			unbundled:      true,
+			properties:     `sdk_version: "current",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/current/public/framework.aidl",
 		},
 
 		{
-			name:          "pdk default",
-			pdk:           true,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "pdk default",
+			pdk:            true,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
-			name:          "pdk current",
-			pdk:           true,
-			properties:    `sdk_version: "current",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "pdk current",
+			pdk:            true,
+			properties:     `sdk_version: "current",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
-			name:          "pdk 25",
-			pdk:           true,
-			properties:    `sdk_version: "25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "pdk 29",
+			pdk:            true,
+			properties:     `sdk_version: "29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 	}
 
@@ -235,7 +249,8 @@
 			}
 
 			bootclasspath := convertModulesToPaths(testcase.bootclasspath)
-			classpath := convertModulesToPaths(testcase.classpath)
+			java8classpath := convertModulesToPaths(testcase.java8classpath)
+			java9classpath := convertModulesToPaths(testcase.java9classpath)
 
 			bc := ""
 			var bcDeps []string
@@ -246,18 +261,20 @@
 				}
 			}
 
-			c := ""
-			if len(classpath) > 0 {
-				c = "-classpath " + strings.Join(classpath, ":")
+			j8c := ""
+			if len(java8classpath) > 0 {
+				j8c = "-classpath " + strings.Join(java8classpath, ":")
+			}
+
+			j9c := ""
+			if len(java9classpath) > 0 {
+				j9c = "-classpath " + strings.Join(java9classpath, ":")
 			}
 
 			system := ""
 			var systemDeps []string
 			if testcase.system == "none" {
 				system = "--system=none"
-			} else if testcase.system == "bootclasspath" {
-				system = bc
-				systemDeps = bcDeps
 			} else if testcase.system != "" {
 				system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system")
 				// The module-relative parts of these paths are hardcoded in system_modules.go:
@@ -280,7 +297,7 @@
 
 				got := javac.Args["bootClasspath"]
 				expected := ""
-				if isJava8 {
+				if isJava8 || testcase.forces8 {
 					expected = bc
 					deps = append(deps, bcDeps...)
 				} else {
@@ -291,11 +308,17 @@
 					t.Errorf("bootclasspath expected %q != got %q", expected, got)
 				}
 
-				got = javac.Args["classpath"]
-				if got != c {
-					t.Errorf("classpath expected %q != got %q", c, got)
+				if isJava8 || testcase.forces8 {
+					expected = j8c
+					deps = append(deps, java8classpath...)
+				} else {
+					expected = j9c
+					deps = append(deps, java9classpath...)
 				}
-				deps = append(deps, classpath...)
+				got = javac.Args["classpath"]
+				if got != expected {
+					t.Errorf("classpath expected %q != got %q", expected, got)
+				}
 
 				if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
 					t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
@@ -366,8 +389,23 @@
 				checkClasspath(t, ctx, true /* isJava8 */)
 			})
 
-			// TODO(b/142896162): Add a with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9, when that all works.
+			// Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9
+			t.Run("REL + Java language level 9", func(t *testing.T) {
+				config := testConfig(nil)
+				config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL")
+				config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true)
+
+				if testcase.unbundled {
+					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+				}
+				if testcase.pdk {
+					config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+				}
+				ctx := testContext(bp, nil)
+				run(t, ctx, config)
+
+				checkClasspath(t, ctx, false /* isJava8 */)
+			})
 		})
 	}
-
 }
diff --git a/rust/androidmk.go b/rust/androidmk.go
index a6208db..f933cfb 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -92,7 +92,12 @@
 		ret.Class = "RLIB_LIBRARIES"
 	} else if library.dylib() {
 		ret.Class = "DYLIB_LIBRARIES"
+	} else if library.static() {
+		ret.Class = "STATIC_LIBRARIES"
+	} else if library.shared() {
+		ret.Class = "SHARED_LIBRARIES"
 	}
+
 	ret.DistFile = library.distFile
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		if !library.rlib() {
diff --git a/rust/builder.go b/rust/builder.go
index 104313f..2a7643d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -53,6 +53,14 @@
 	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "dylib", includeDirs)
 }
 
+func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "staticlib", includeDirs)
+}
+
+func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "cdylib", includeDirs)
+}
+
 func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
 	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "proc-macro", includeDirs)
 }
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
index 328bca3..616d88b 100644
--- a/rust/config/toolchain.go
+++ b/rust/config/toolchain.go
@@ -95,7 +95,7 @@
 	return ".rlib"
 }
 func (toolchainBase) DylibSuffix() string {
-	return ".so"
+	return ".dylib.so"
 }
 
 func (toolchainBase) ProcMacroSuffix() string {
diff --git a/rust/library.go b/rust/library.go
index c831727..273a3ce 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -25,8 +25,10 @@
 	android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
 	android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
 	android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
-
-	//TODO: Add support for generating standard shared/static libraries.
+	android.RegisterModuleType("rust_library_shared", RustLibrarySharedFactory)
+	android.RegisterModuleType("rust_library_static", RustLibraryStaticFactory)
+	android.RegisterModuleType("rust_library_host_shared", RustLibrarySharedHostFactory)
+	android.RegisterModuleType("rust_library_host_static", RustLibraryStaticHostFactory)
 }
 
 type VariantLibraryProperties struct {
@@ -34,25 +36,36 @@
 }
 
 type LibraryCompilerProperties struct {
-	Rlib  VariantLibraryProperties `android:"arch_variant"`
-	Dylib VariantLibraryProperties `android:"arch_variant"`
+	Rlib   VariantLibraryProperties `android:"arch_variant"`
+	Dylib  VariantLibraryProperties `android:"arch_variant"`
+	Shared VariantLibraryProperties `android:"arch_variant"`
+	Static VariantLibraryProperties `android:"arch_variant"`
 
 	// path to the source file that is the main entry point of the program (e.g. src/lib.rs)
 	Srcs []string `android:"path,arch_variant"`
+
+	// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
+	Include_dirs []string `android:"path,arch_variant"`
 }
 
 type LibraryMutatedProperties struct {
-	VariantName string `blueprint:"mutated"`
-
 	// Build a dylib variant
 	BuildDylib bool `blueprint:"mutated"`
 	// Build an rlib variant
 	BuildRlib bool `blueprint:"mutated"`
+	// Build a shared library variant
+	BuildShared bool `blueprint:"mutated"`
+	// Build a static library variant
+	BuildStatic bool `blueprint:"mutated"`
 
 	// This variant is a dylib
 	VariantIsDylib bool `blueprint:"mutated"`
 	// This variant is an rlib
 	VariantIsRlib bool `blueprint:"mutated"`
+	// This variant is a shared library
+	VariantIsShared bool `blueprint:"mutated"`
+	// This variant is a static library
+	VariantIsStatic bool `blueprint:"mutated"`
 }
 
 type libraryDecorator struct {
@@ -67,14 +80,26 @@
 type libraryInterface interface {
 	rlib() bool
 	dylib() bool
+	static() bool
+	shared() bool
 
 	// Returns true if the build options for the module have selected a particular build type
 	buildRlib() bool
 	buildDylib() bool
+	buildShared() bool
+	buildStatic() bool
 
 	// Sets a particular variant type
 	setRlib()
 	setDylib()
+	setShared()
+	setStatic()
+
+	// Build a specific library variant
+	BuildOnlyRlib()
+	BuildOnlyDylib()
+	BuildOnlyStatic()
+	BuildOnlyShared()
 }
 
 func (library *libraryDecorator) exportedDirs() []string {
@@ -101,6 +126,14 @@
 	return library.MutatedProperties.VariantIsDylib
 }
 
+func (library *libraryDecorator) shared() bool {
+	return library.MutatedProperties.VariantIsShared
+}
+
+func (library *libraryDecorator) static() bool {
+	return library.MutatedProperties.VariantIsStatic
+}
+
 func (library *libraryDecorator) buildRlib() bool {
 	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
 }
@@ -109,17 +142,44 @@
 	return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
 }
 
+func (library *libraryDecorator) buildShared() bool {
+	return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true)
+}
+
+func (library *libraryDecorator) buildStatic() bool {
+	return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true)
+}
+
 func (library *libraryDecorator) setRlib() {
 	library.MutatedProperties.VariantIsRlib = true
 	library.MutatedProperties.VariantIsDylib = false
+	library.MutatedProperties.VariantIsStatic = false
+	library.MutatedProperties.VariantIsShared = false
 }
 
 func (library *libraryDecorator) setDylib() {
 	library.MutatedProperties.VariantIsRlib = false
 	library.MutatedProperties.VariantIsDylib = true
+	library.MutatedProperties.VariantIsStatic = false
+	library.MutatedProperties.VariantIsShared = false
+}
+
+func (library *libraryDecorator) setShared() {
+	library.MutatedProperties.VariantIsStatic = false
+	library.MutatedProperties.VariantIsShared = true
+	library.MutatedProperties.VariantIsRlib = false
+	library.MutatedProperties.VariantIsDylib = false
+}
+
+func (library *libraryDecorator) setStatic() {
+	library.MutatedProperties.VariantIsStatic = true
+	library.MutatedProperties.VariantIsShared = false
+	library.MutatedProperties.VariantIsRlib = false
+	library.MutatedProperties.VariantIsDylib = false
 }
 
 var _ compiler = (*libraryDecorator)(nil)
+var _ libraryInterface = (*libraryDecorator)(nil)
 
 // rust_library produces all variants.
 func RustLibraryFactory() android.Module {
@@ -141,6 +201,20 @@
 	return module.Init()
 }
 
+// rust_library_shared produces a shared library.
+func RustLibrarySharedFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyShared()
+	return module.Init()
+}
+
+// rust_library_static produces a static library.
+func RustLibraryStaticFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyStatic()
+	return module.Init()
+}
+
 // rust_library_host produces all variants.
 func RustLibraryHostFactory() android.Module {
 	module, _ := NewRustLibrary(android.HostSupported)
@@ -161,12 +235,44 @@
 	return module.Init()
 }
 
+// rust_library_static_host produces a static library.
+func RustLibraryStaticHostFactory() android.Module {
+	module, library := NewRustLibrary(android.HostSupported)
+	library.BuildOnlyStatic()
+	return module.Init()
+}
+
+// rust_library_shared_host produces an shared library.
+func RustLibrarySharedHostFactory() android.Module {
+	module, library := NewRustLibrary(android.HostSupported)
+	library.BuildOnlyShared()
+	return module.Init()
+}
+
 func (library *libraryDecorator) BuildOnlyDylib() {
 	library.MutatedProperties.BuildRlib = false
+	library.MutatedProperties.BuildShared = false
+	library.MutatedProperties.BuildStatic = false
+
 }
 
 func (library *libraryDecorator) BuildOnlyRlib() {
 	library.MutatedProperties.BuildDylib = false
+	library.MutatedProperties.BuildShared = false
+	library.MutatedProperties.BuildStatic = false
+}
+
+func (library *libraryDecorator) BuildOnlyStatic() {
+	library.MutatedProperties.BuildShared = false
+	library.MutatedProperties.BuildRlib = false
+	library.MutatedProperties.BuildDylib = false
+
+}
+
+func (library *libraryDecorator) BuildOnlyShared() {
+	library.MutatedProperties.BuildStatic = false
+	library.MutatedProperties.BuildRlib = false
+	library.MutatedProperties.BuildDylib = false
 }
 
 func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
@@ -174,8 +280,10 @@
 
 	library := &libraryDecorator{
 		MutatedProperties: LibraryMutatedProperties{
-			BuildDylib: true,
-			BuildRlib:  true,
+			BuildDylib:  true,
+			BuildRlib:   true,
+			BuildShared: true,
+			BuildStatic: true,
 		},
 		baseCompiler: NewBaseCompiler("lib", "lib64"),
 	}
@@ -194,7 +302,7 @@
 func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
 	deps = library.baseCompiler.compilerDeps(ctx, deps)
 
-	if ctx.toolchain().Bionic() && library.dylib() {
+	if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
 		deps = library.baseCompiler.bionicDeps(ctx, deps)
 	}
 
@@ -208,6 +316,13 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 
+	if library.dylib() || library.shared() {
+		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
+		// https://github.com/rust-lang/rust/issues/19680
+		// https://github.com/rust-lang/rust/issues/34909
+		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
+	}
+
 	if library.rlib() {
 		fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
@@ -217,16 +332,23 @@
 		fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
-		// https://github.com/rust-lang/rust/issues/19680
-		// https://github.com/rust-lang/rust/issues/34909
-		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
-
 		TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	} else if library.static() {
+		fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
+		outputFile = android.PathForModuleOut(ctx, fileName)
+
+		TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	} else if library.shared() {
+		fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+		outputFile = android.PathForModuleOut(ctx, fileName)
+
+		TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	}
 
-	library.reexportDirs(deps.linkDirs...)
-	library.reexportDepFlags(deps.depFlags...)
+	if library.rlib() || library.dylib() {
+		library.reexportDirs(deps.linkDirs...)
+		library.reexportDepFlags(deps.depFlags...)
+	}
 	library.unstrippedOutputFile = outputFile
 
 	return outputFile
@@ -236,19 +358,25 @@
 	if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
 		switch library := m.compiler.(type) {
 		case libraryInterface:
-			if library.buildRlib() && library.buildDylib() {
-				modules := mctx.CreateLocalVariations("rlib", "dylib")
-				rlib := modules[0].(*Module)
-				dylib := modules[1].(*Module)
 
-				rlib.compiler.(libraryInterface).setRlib()
-				dylib.compiler.(libraryInterface).setDylib()
-			} else if library.buildRlib() {
-				modules := mctx.CreateLocalVariations("rlib")
-				modules[0].(*Module).compiler.(libraryInterface).setRlib()
-			} else if library.buildDylib() {
-				modules := mctx.CreateLocalVariations("dylib")
-				modules[0].(*Module).compiler.(libraryInterface).setDylib()
+			// We only build the rust library variants here. This assumes that
+			// LinkageMutator runs first and there's an empty variant
+			// if rust variants are required.
+			if !library.static() && !library.shared() {
+				if library.buildRlib() && library.buildDylib() {
+					modules := mctx.CreateLocalVariations("rlib", "dylib")
+					rlib := modules[0].(*Module)
+					dylib := modules[1].(*Module)
+
+					rlib.compiler.(libraryInterface).setRlib()
+					dylib.compiler.(libraryInterface).setDylib()
+				} else if library.buildRlib() {
+					modules := mctx.CreateLocalVariations("rlib")
+					modules[0].(*Module).compiler.(libraryInterface).setRlib()
+				} else if library.buildDylib() {
+					modules := mctx.CreateLocalVariations("dylib")
+					modules[0].(*Module).compiler.(libraryInterface).setDylib()
+				}
 			}
 		}
 	}
diff --git a/rust/library_test.go b/rust/library_test.go
index bf8643e..66bcd20 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -29,19 +29,37 @@
 			crate_name: "foo",
 		}`)
 
-	// Test both variants are being built.
+	// Test all variants are being built.
 	libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+	libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Output("libfoo.a")
+	libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
+
+	rlibCrateType := "rlib"
+	dylibCrateType := "dylib"
+	sharedCrateType := "cdylib"
+	staticCrateType := "static"
 
 	// Test crate type for rlib is correct.
-	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type=rlib") {
-		t.Errorf("missing crate-type for libfoo rlib, rustcFlags: %#v", libfooRlib.Args["rustcFlags"])
+	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"])
 	}
 
 	// Test crate type for dylib is correct.
-	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type=dylib") {
-		t.Errorf("missing crate-type for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"])
 	}
+
+	// Test crate type for C static libraries is correct.
+	if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
+	}
+
+	// Test crate type for C shared libraries is correct.
+	if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
+		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
+	}
+
 }
 
 // Test that dylibs are not statically linking the standard library.
@@ -53,7 +71,7 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
 
 	if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
 		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
diff --git a/rust/rust.go b/rust/rust.go
index 707de4b..ce81b91 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -15,6 +15,7 @@
 package rust
 
 import (
+	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -74,6 +75,85 @@
 	outputFile       android.OptionalPath
 }
 
+func (mod *Module) BuildStubs() bool {
+	return false
+}
+
+func (mod *Module) HasStubsVariants() bool {
+	return false
+}
+
+func (mod *Module) SelectedStl() string {
+	return ""
+}
+
+func (mod *Module) ApiLevel() string {
+	panic(fmt.Errorf("Called ApiLevel on Rust module %q; stubs libraries are not yet supported.", mod.BaseModuleName()))
+}
+
+func (mod *Module) Static() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.static()
+		}
+	}
+	panic(fmt.Errorf("Static called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) Shared() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.static()
+		}
+	}
+	panic(fmt.Errorf("Shared called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) Toc() android.OptionalPath {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(libraryInterface); ok {
+			return android.OptionalPath{}
+		}
+	}
+	panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) OnlyInRecovery() bool {
+	return false
+}
+
+func (mod *Module) UseVndk() bool {
+	return false
+}
+
+func (mod *Module) MustUseVendorVariant() bool {
+	return false
+}
+
+func (mod *Module) IsVndk() bool {
+	return false
+}
+
+func (mod *Module) HasVendorVariant() bool {
+	return false
+}
+
+func (mod *Module) SdkVersion() string {
+	return ""
+}
+
+func (mod *Module) ToolchainLibrary() bool {
+	return false
+}
+
+func (mod *Module) NdkPrebuiltStl() bool {
+	return false
+}
+
+func (mod *Module) StubDecorator() bool {
+	return false
+}
+
 type Deps struct {
 	Dylibs     []string
 	Rlibs      []string
@@ -150,6 +230,121 @@
 	return strings.Replace(mod.BaseModuleName(), "-", "_", -1)
 }
 
+func (mod *Module) CcLibrary() bool {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(*libraryDecorator); ok {
+			return true
+		}
+	}
+	return false
+}
+
+func (mod *Module) CcLibraryInterface() bool {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(libraryInterface); ok {
+			return true
+		}
+	}
+	return false
+}
+
+func (mod *Module) IncludeDirs(ctx android.BaseModuleContext) android.Paths {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(*libraryDecorator); ok {
+			return android.PathsForSource(ctx, library.Properties.Include_dirs)
+		}
+	}
+	panic(fmt.Errorf("IncludeDirs called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) SetStatic() {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			library.setStatic()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetStatic called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) SetShared() {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			library.setShared()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetShared called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) SetBuildStubs() {
+	panic("SetBuildStubs not yet implemented for rust modules")
+}
+
+func (mod *Module) SetStubsVersions(string) {
+	panic("SetStubsVersions not yet implemented for rust modules")
+}
+
+func (mod *Module) BuildStaticVariant() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.buildStatic()
+		}
+	}
+	panic(fmt.Errorf("BuildStaticVariant called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) BuildSharedVariant() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.buildShared()
+		}
+	}
+	panic(fmt.Errorf("BuildSharedVariant called on non-library module: %q", mod.BaseModuleName()))
+}
+
+// Rust module deps don't have a link order (?)
+func (mod *Module) SetDepsInLinkOrder([]android.Path) {}
+
+func (mod *Module) GetDepsInLinkOrder() []android.Path {
+	return []android.Path{}
+}
+
+func (mod *Module) GetStaticVariant() cc.LinkableInterface {
+	return nil
+}
+
+func (mod *Module) Module() android.Module {
+	return mod
+}
+
+func (mod *Module) StubsVersions() []string {
+	// For now, Rust has no stubs versions.
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(*libraryDecorator); ok {
+			return []string{}
+		}
+	}
+	panic(fmt.Errorf("StubsVersions called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) OutputFile() android.OptionalPath {
+	return mod.outputFile
+}
+
+func (mod *Module) InRecovery() bool {
+	// For now, Rust has no notion of the recovery image
+	return false
+}
+func (mod *Module) HasStaticVariant() bool {
+	if mod.GetStaticVariant() != nil {
+		return true
+	}
+	return false
+}
+
+var _ cc.LinkableInterface = (*Module)(nil)
+
 func (mod *Module) Init() android.Module {
 	mod.AddProperties(&mod.Properties)
 
@@ -311,13 +506,12 @@
 	directRlibDeps := []*Module{}
 	directDylibDeps := []*Module{}
 	directProcMacroDeps := []*Module{}
-	directSharedLibDeps := []*(cc.Module){}
-	directStaticLibDeps := []*(cc.Module){}
+	directSharedLibDeps := [](cc.LinkableInterface){}
+	directStaticLibDeps := [](cc.LinkableInterface){}
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
-
 		if rustDep, ok := dep.(*Module); ok {
 			//Handle Rust Modules
 
@@ -365,16 +559,19 @@
 				}
 			}
 
-		} else if ccDep, ok := dep.(*cc.Module); ok {
-			//Handle C dependencies
+		}
 
-			if ccDep.Target().Os != ctx.Os() {
-				ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
-				return
-			}
-			if ccDep.Target().Arch.ArchType != ctx.Arch().ArchType {
-				ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
-				return
+		if ccDep, ok := dep.(cc.LinkableInterface); ok {
+			//Handle C dependencies
+			if _, ok := ccDep.(*Module); !ok {
+				if ccDep.Module().Target().Os != ctx.Os() {
+					ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
+					return
+				}
+				if ccDep.Module().Target().Arch.ArchType != ctx.Arch().ArchType {
+					ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
+					return
+				}
 			}
 
 			linkFile := ccDep.OutputFile()
@@ -387,25 +584,25 @@
 			exportDep := false
 
 			switch depTag {
-			case cc.StaticDepTag():
+			case cc.StaticDepTag:
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
-			case cc.SharedDepTag():
+			case cc.SharedDepTag:
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
 				directSharedLibDeps = append(directSharedLibDeps, ccDep)
 				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
 				exportDep = true
-			case cc.CrtBeginDepTag():
+			case cc.CrtBeginDepTag:
 				depPaths.CrtBegin = linkFile
-			case cc.CrtEndDepTag():
+			case cc.CrtEndDepTag:
 				depPaths.CrtEnd = linkFile
 			}
 
 			// Make sure these dependencies are propagated
-			if lib, ok := mod.compiler.(*libraryDecorator); ok && (exportDep || lib.rlib()) {
+			if lib, ok := mod.compiler.(*libraryDecorator); ok && exportDep {
 				lib.linkDirs = append(lib.linkDirs, linkPath)
 				lib.depFlags = append(lib.depFlags, "-l"+libName)
 			} else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
@@ -457,8 +654,8 @@
 }
 func libNameFromFilePath(filepath android.Path) string {
 	libName := strings.Split(filepath.Base(), filepath.Ext())[0]
-	if strings.Contains(libName, "lib") {
-		libName = strings.Split(libName, "lib")[1]
+	if strings.HasPrefix(libName, "lib") {
+		libName = libName[3:]
 	}
 	return libName
 }
@@ -472,23 +669,37 @@
 	ctx.ctx = ctx
 
 	deps := mod.deps(ctx)
-
-	actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, deps.Rlibs...)
-	actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "dylib"}}, dylibDepTag, deps.Dylibs...)
-
-	ccDepVariations := []blueprint.Variation{}
-	ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "version", Variation: ""})
+	commonDepVariations := []blueprint.Variation{}
+	commonDepVariations = append(commonDepVariations,
+		blueprint.Variation{Mutator: "version", Variation: ""})
 	if !mod.Host() {
-		ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "image", Variation: "core"})
+		commonDepVariations = append(commonDepVariations,
+			blueprint.Variation{Mutator: "image", Variation: "core"})
 	}
-	actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...)
-	actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), cc.StaticDepTag(), deps.StaticLibs...)
+
+	actx.AddVariationDependencies(
+		append(commonDepVariations, []blueprint.Variation{
+			{Mutator: "rust_libraries", Variation: "rlib"},
+			{Mutator: "link", Variation: ""}}...),
+		rlibDepTag, deps.Rlibs...)
+	actx.AddVariationDependencies(
+		append(commonDepVariations, []blueprint.Variation{
+			{Mutator: "rust_libraries", Variation: "dylib"},
+			{Mutator: "link", Variation: ""}}...),
+		dylibDepTag, deps.Dylibs...)
+
+	actx.AddVariationDependencies(append(commonDepVariations,
+		blueprint.Variation{Mutator: "link", Variation: "shared"}),
+		cc.SharedDepTag, deps.SharedLibs...)
+	actx.AddVariationDependencies(append(commonDepVariations,
+		blueprint.Variation{Mutator: "link", Variation: "static"}),
+		cc.StaticDepTag, deps.StaticLibs...)
 
 	if deps.CrtBegin != "" {
-		actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin)
+		actx.AddVariationDependencies(commonDepVariations, cc.CrtBeginDepTag, deps.CrtBegin)
 	}
 	if deps.CrtEnd != "" {
-		actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd)
+		actx.AddVariationDependencies(commonDepVariations, cc.CrtEndDepTag, deps.CrtEnd)
 	}
 
 	// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 0c8d355..eb04e72 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -101,12 +101,20 @@
 
 // Test that we can extract the lib name from a lib path.
 func TestLibNameFromFilePath(t *testing.T) {
-	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
-	libName := libNameFromFilePath(barPath)
-	expectedResult := "bar"
+	libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+	libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
 
-	if libName != expectedResult {
-		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+	libBarName := libNameFromFilePath(libBarPath)
+	libLibName := libNameFromFilePath(libLibPath)
+
+	expectedResult := "bar"
+	if libBarName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
+	}
+
+	expectedResult = "lib.dylib"
+	if libLibName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath)
 	}
 }
 
@@ -140,12 +148,20 @@
 // Test to make sure dependencies are being picked up correctly.
 func TestDepsTracking(t *testing.T) {
 	ctx := testRust(t, `
+		rust_library_host_static {
+			name: "libstatic",
+			srcs: ["foo.rs"],
+		}
+		rust_library_host_shared {
+			name: "libshared",
+			srcs: ["foo.rs"],
+		}
 		rust_library_host_dylib {
-			name: "libfoo",
+			name: "libdylib",
 			srcs: ["foo.rs"],
 		}
 		rust_library_host_rlib {
-			name: "libbar",
+			name: "librlib",
 			srcs: ["foo.rs"],
 		}
 		rust_proc_macro {
@@ -154,20 +170,22 @@
 		}
 		rust_binary_host {
 			name: "fizz-buzz",
-			dylibs: ["libfoo"],
-			rlibs: ["libbar"],
+			dylibs: ["libdylib"],
+			rlibs: ["librlib"],
 			proc_macros: ["libpm"],
+			static_libs: ["libstatic"],
+			shared_libs: ["libshared"],
 			srcs: ["foo.rs"],
 		}
 	`)
 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
-	if !android.InList("libfoo", module.Properties.AndroidMkDylibs) {
+	if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
 		t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
 	}
 
-	if !android.InList("libbar", module.Properties.AndroidMkRlibs) {
+	if !android.InList("librlib", module.Properties.AndroidMkRlibs) {
 		t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
 	}
 
@@ -175,6 +193,13 @@
 		t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
 	}
 
+	if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) {
+		t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)")
+	}
+
+	if !android.InList("libstatic", module.Properties.AndroidMkStaticLibs) {
+		t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
+	}
 }
 
 // Test to make sure proc_macros use host variants when building device modules.
diff --git a/rust/testing.go b/rust/testing.go
index 92347f1..cd63084 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -174,18 +174,23 @@
 	ctx.RegisterModuleType("rust_library_host_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibHostFactory))
 	ctx.RegisterModuleType("rust_library_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibFactory))
 	ctx.RegisterModuleType("rust_library_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibFactory))
+	ctx.RegisterModuleType("rust_library_shared", android.ModuleFactoryAdaptor(RustLibrarySharedFactory))
+	ctx.RegisterModuleType("rust_library_static", android.ModuleFactoryAdaptor(RustLibraryStaticFactory))
+	ctx.RegisterModuleType("rust_library_host_shared", android.ModuleFactoryAdaptor(RustLibrarySharedHostFactory))
+	ctx.RegisterModuleType("rust_library_host_static", android.ModuleFactoryAdaptor(RustLibraryStaticHostFactory))
 	ctx.RegisterModuleType("rust_proc_macro", android.ModuleFactoryAdaptor(ProcMacroFactory))
 	ctx.RegisterModuleType("rust_prebuilt_dylib", android.ModuleFactoryAdaptor(PrebuiltDylibFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
-
+		// cc mutators
 		ctx.BottomUp("image", cc.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
-	})
 
+		// rust mutators
+		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+	})
 	bp = bp + GatherRequiredDepsForTest()
 
 	mockFS := map[string][]byte{