Merge "Add dependency to list of asset files"
diff --git a/android/apex.go b/android/apex.go
index a4ff0f9..4a71b40 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -257,7 +257,7 @@
 	canHaveApexVariants bool
 
 	apexInfos     []ApexInfo
-	apexInfosLock sync.Mutex // protects apexInfos during parallel apexDepsMutator
+	apexInfosLock sync.Mutex // protects apexInfos during parallel apexInfoMutator
 }
 
 // Initializes ApexModuleBase struct. Not calling this (even when inheriting from ApexModuleBase)
@@ -442,7 +442,7 @@
 	} else {
 		apexInfos = base.apexInfos
 	}
-	// base.apexInfos is only needed to propagate the list of apexes from apexDepsMutator to
+	// base.apexInfos is only needed to propagate the list of apexes from apexInfoMutator to
 	// apexMutator. It is no longer accurate after mergeApexVariations, and won't be copied to
 	// all but the first created variant. Clear it so it doesn't accidentally get used later.
 	base.apexInfos = nil
diff --git a/android/module.go b/android/module.go
index f805acd..429f311 100644
--- a/android/module.go
+++ b/android/module.go
@@ -340,10 +340,51 @@
 	ExpandSource(srcFile, prop string) Path
 	ExpandOptionalSource(srcFile *string, prop string) OptionalPath
 
+	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies.  The file is marked executable after copying.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
 	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+
+	// InstallFile creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
 	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+
+	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
+	// directory.
+	//
+	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
 	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
+
+	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
+	// in the installPath directory.
+	//
+	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
 	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
+
+	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
+	// the rule to copy the file.  This is useful to define how a module would be packaged
+	// without installing it into the global installation directories.
+	//
+	// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
+
 	CheckbuildFile(srcPath Path)
 
 	InstallInData() bool
@@ -2430,6 +2471,22 @@
 	return m.installFile(installPath, name, srcPath, deps, true)
 }
 
+func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
+	fullInstallPath := installPath.Join(m, name)
+	return m.packageFile(fullInstallPath, srcPath, false)
+}
+
+func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
+	spec := PackagingSpec{
+		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+		srcPath:          srcPath,
+		symlinkTarget:    "",
+		executable:       executable,
+	}
+	m.packagingSpecs = append(m.packagingSpecs, spec)
+	return spec
+}
+
 func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, executable bool) InstallPath {
 
 	fullInstallPath := installPath.Join(m, name)
@@ -2466,12 +2523,7 @@
 		m.installFiles = append(m.installFiles, fullInstallPath)
 	}
 
-	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
-		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
-		srcPath:          srcPath,
-		symlinkTarget:    "",
-		executable:       executable,
-	})
+	m.packageFile(fullInstallPath, srcPath, executable)
 
 	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 	return fullInstallPath
@@ -2683,7 +2735,11 @@
 	}
 }
 
+// Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to
+// specify that they can be used as a tool by a genrule module.
 type HostToolProvider interface {
+	// HostToolPath returns the path to the host tool for the module if it is one, or an invalid
+	// OptionalPath.
 	HostToolPath() OptionalPath
 }
 
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index e2555e4..b00dc2f 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -57,7 +57,7 @@
 
 func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) {
 	sourcePath := t.prebuilt.SingleSourcePath(ctx)
-	installedPath := PathForModuleOut(ctx, t.ModuleBase.Name())
+	installedPath := PathForModuleOut(ctx, t.BaseModuleName())
 	deps := PathsForModuleSrc(ctx, t.properties.Deps)
 
 	var fromPath = sourcePath.String()
@@ -75,6 +75,12 @@
 		},
 	})
 
+	packagingDir := PathForModuleInstall(ctx, t.BaseModuleName())
+	ctx.PackageFile(packagingDir, sourcePath.String(), sourcePath)
+	for _, dep := range deps {
+		ctx.PackageFile(packagingDir, dep.String(), dep)
+	}
+
 	t.toolPath = OptionalPathForPath(installedPath)
 }
 
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 6c76ad3f..e7f8b7f 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -425,6 +425,15 @@
 				for _, dist := range data.Entries.GetDistForGoals(a) {
 					fmt.Fprintf(w, dist)
 				}
+
+				if a.coverageOutputPath.String() != "" {
+					goal := "apps_only"
+					distFile := a.coverageOutputPath.String()
+					fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
+						" $(call dist-for-goals,%s,%s:ndk_apis_usedby_apex/$(notdir %s))\n"+
+						"endif",
+						goal, distFile, distFile)
+				}
 			}
 		}}
 }
diff --git a/apex/apex.go b/apex/apex.go
index dae0f26..2a81b9b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -55,7 +55,7 @@
 }
 
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.TopDown("apex_deps", apexDepsMutator).Parallel()
+	ctx.TopDown("apex_info", apexInfoMutator).Parallel()
 	ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
 	ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
 	ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
@@ -491,12 +491,12 @@
 // 1) DepsMutator: from the properties like native_shared_libs, java_libs, etc., modules are added
 // to the (direct) dependencies of this APEX bundle.
 //
-// 2) apexDepsMutator: this is a post-deps mutator, so runs after DepsMutator. Its goal is to
+// 2) apexInfoMutator: this is a post-deps mutator, so runs after DepsMutator. Its goal is to
 // collect modules that are direct and transitive dependencies of each APEX bundle. The collected
 // modules are marked as being included in the APEX via BuildForApex().
 //
-// 3) apexMutator: this is a post-deps mutator that runs after apexDepsMutator. For each module that
-// are marked by the apexDepsMutator, apex variations are created using CreateApexVariations().
+// 3) apexMutator: this is a post-deps mutator that runs after apexInfoMutator. For each module that
+// are marked by the apexInfoMutator, apex variations are created using CreateApexVariations().
 
 type dependencyTag struct {
 	blueprint.BaseDependencyTag
@@ -530,11 +530,8 @@
 
 	if ctx.Device() {
 		binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
-		libVariations = append(libVariations,
-			blueprint.Variation{Mutator: "image", Variation: imageVariation},
-			blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant
-		rustLibVariations = append(rustLibVariations,
-			blueprint.Variation{Mutator: "image", Variation: imageVariation})
+		libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
+		rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
 	}
 
 	// Use *FarVariation* to be able to depend on modules having conflicting variations with
@@ -729,14 +726,20 @@
 	Contents *android.ApexContents
 }
 
-var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_deps")
+var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_info")
 
-// apexDepsMutator is responsible for collecting modules that need to have apex variants. They are
+// apexInfoMutator is responsible for collecting modules that need to have apex variants. They are
 // identified by doing a graph walk starting from an apexBundle. Basically, all the (direct and
 // indirect) dependencies are collected. But a few types of modules that shouldn't be included in
 // the apexBundle (e.g. stub libraries) are not collected. Note that a single module can be depended
 // on by multiple apexBundles. In that case, the module is collected for all of the apexBundles.
-func apexDepsMutator(mctx android.TopDownMutatorContext) {
+//
+// For each dependency between an apex and an ApexModule an ApexInfo object describing the apex
+// is passed to that module's BuildForApex(ApexInfo) method which collates them all in a list.
+// The apexMutator uses that list to create module variants for the apexes to which it belongs.
+// The relationship between module variants and apexes is not one-to-one as variants will be
+// shared between compatible apexes.
+func apexInfoMutator(mctx android.TopDownMutatorContext) {
 	if !mctx.Module().Enabled() {
 		return
 	}
@@ -918,7 +921,7 @@
 }
 
 // apexMutator visits each module and creates apex variations if the module was marked in the
-// previous run of apexDepsMutator.
+// previous run of apexInfoMutator.
 func apexMutator(mctx android.BottomUpMutatorContext) {
 	if !mctx.Module().Enabled() {
 		return
@@ -1530,6 +1533,9 @@
 						provideNativeLibs = append(provideNativeLibs, fi.stem())
 					}
 					return true // track transitive dependencies
+				} else if r, ok := child.(*rust.Module); ok {
+					fi := apexFileForRustLibrary(ctx, r)
+					filesInfo = append(filesInfo, fi)
 				} else {
 					propertyName := "native_shared_libs"
 					if isJniLib {
@@ -1704,6 +1710,11 @@
 
 						filesInfo = append(filesInfo, af)
 						return true // track transitive dependencies
+					} else if rm, ok := child.(*rust.Module); ok {
+						af := apexFileForRustLibrary(ctx, rm)
+						af.transitiveDep = true
+						filesInfo = append(filesInfo, af)
+						return true // track transitive dependencies
 					}
 				} else if cc.IsTestPerSrcDepTag(depTag) {
 					if cc, ok := child.(*cc.Module); ok {
@@ -1718,6 +1729,8 @@
 						filesInfo = append(filesInfo, af)
 						return true // track transitive dependencies
 					}
+				} else if cc.IsHeaderDepTag(depTag) {
+					// nothing
 				} else if java.IsJniDepTag(depTag) {
 					// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
 					return false
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 16c01ca..ab8ae16 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -362,7 +362,10 @@
 			androidManifest: ":myapex.androidmanifest",
 			key: "myapex.key",
 			binaries: ["foo.rust"],
-			native_shared_libs: ["mylib"],
+			native_shared_libs: [
+				"mylib",
+				"libfoo.ffi",
+			],
 			rust_dyn_libs: ["libfoo.dylib.rust"],
 			multilib: {
 				both: {
@@ -399,7 +402,10 @@
 		cc_library {
 			name: "mylib",
 			srcs: ["mylib.cpp"],
-			shared_libs: ["mylib2"],
+			shared_libs: [
+				"mylib2",
+				"libbar.ffi",
+			],
 			system_shared_libs: [],
 			stl: "none",
 			// TODO: remove //apex_available:platform
@@ -451,6 +457,20 @@
 			apex_available: ["myapex"],
 		}
 
+		rust_ffi_shared {
+			name: "libfoo.ffi",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			apex_available: ["myapex"],
+		}
+
+		rust_ffi_shared {
+			name: "libbar.ffi",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+			apex_available: ["myapex"],
+		}
+
 		apex {
 			name: "com.android.gki.fake",
 			binaries: ["foo"],
@@ -566,12 +586,14 @@
 	ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000")
 	ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000")
 	ensureListContains(t, ctx.ModuleVariantsForTests("foo.rust"), "android_arm64_armv8-a_apex10000")
+	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.ffi"), "android_arm64_armv8-a_shared_apex10000")
 
 	// Ensure that apex variant is created for the indirect dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
 	ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000")
 	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.rlib.rust"), "android_arm64_armv8-a_rlib_dylib-std_apex10000")
 	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000")
+	ensureListContains(t, ctx.ModuleVariantsForTests("libbar.ffi"), "android_arm64_armv8-a_shared_apex10000")
 
 	// Ensure that both direct and indirect deps are copied into apex
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -579,6 +601,8 @@
 	ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar")
 	ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar")
 	ensureContains(t, copyCmds, "image.apex/lib64/libfoo.dylib.rust.dylib.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libfoo.ffi.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libbar.ffi.so")
 	// .. but not for java libs
 	ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
 	ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
@@ -1789,6 +1813,31 @@
 			min_sdk_version: "30",
 		}
 	`)
+
+	testApexError(t, `module "libfoo.ffi".*: should support min_sdk_version\(29\)`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo.ffi"],
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		rust_ffi_shared {
+			name: "libfoo.ffi",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			apex_available: [
+				"myapex",
+			],
+			min_sdk_version: "30",
+		}
+	`)
 }
 
 func TestApexMinSdkVersion_Okay(t *testing.T) {
@@ -5642,6 +5691,13 @@
 			],
 		}
 	`
+
+	testDexpreoptWithApexes(t, bp, errmsg, transformDexpreoptConfig)
+}
+
+func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+	t.Helper()
+
 	bp += cc.GatherRequiredDepsForTest(android.Android)
 	bp += java.GatherRequiredDepsForTest()
 	bp += dexpreopt.BpToolModulesForTest()
diff --git a/cc/Android.bp b/cc/Android.bp
index 88104e2..33f3db2 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -31,6 +31,7 @@
         "sanitize.go",
         "sabi.go",
         "sdk.go",
+        "snapshot_prebuilt.go",
         "snapshot_utils.go",
         "stl.go",
         "strip.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 9b61e55..4f4b047 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -113,7 +113,7 @@
 						entries.SetString("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() {
+						if !c.IsVndkExt() {
 							entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 						}
 					}
diff --git a/cc/cc.go b/cc/cc.go
index ae75c1d..9383e39 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -409,7 +409,7 @@
 	isVndkPrivate(config android.Config) bool
 	isVndk() bool
 	isVndkSp() bool
-	isVndkExt() bool
+	IsVndkExt() bool
 	inProduct() bool
 	inVendor() bool
 	inRamdisk() bool
@@ -1035,7 +1035,7 @@
 	return isLlndkLibrary(name, config) && !isVndkPrivateLibrary(name, config)
 }
 
-func (c *Module) isVndkPrivate(config android.Config) bool {
+func (c *Module) IsVndkPrivate(config android.Config) bool {
 	// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
 	return isVndkPrivateLibrary(c.BaseModuleName(), config)
 }
@@ -1068,7 +1068,7 @@
 	return false
 }
 
-func (c *Module) isVndkExt() bool {
+func (c *Module) IsVndkExt() bool {
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		return vndkdep.isVndkExt()
 	}
@@ -1252,7 +1252,7 @@
 }
 
 func (ctx *moduleContextImpl) isVndkPrivate(config android.Config) bool {
-	return ctx.mod.isVndkPrivate(config)
+	return ctx.mod.IsVndkPrivate(config)
 }
 
 func (ctx *moduleContextImpl) isVndk() bool {
@@ -1271,8 +1271,8 @@
 	return ctx.mod.isVndkSp()
 }
 
-func (ctx *moduleContextImpl) isVndkExt() bool {
-	return ctx.mod.isVndkExt()
+func (ctx *moduleContextImpl) IsVndkExt() bool {
+	return ctx.mod.IsVndkExt()
 }
 
 func (ctx *moduleContextImpl) mustUseVendorVariant() bool {
@@ -1425,7 +1425,7 @@
 	// "current", it will append the VNDK version to the name suffix.
 	var vndkVersion string
 	var nameSuffix string
-	if c.inProduct() {
+	if c.InProduct() {
 		vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
 		nameSuffix = productSuffix
 	} else {
@@ -1459,7 +1459,7 @@
 		c.hideApexVariantFromMake = true
 	}
 
-	c.makeLinkType = c.getMakeLinkType(actx)
+	c.makeLinkType = GetMakeLinkType(actx, c)
 
 	c.Properties.SubName = ""
 
@@ -1601,7 +1601,7 @@
 
 		// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current.
 		if i, ok := c.linker.(snapshotLibraryInterface); ok && ctx.DeviceConfig().VndkVersion() == "current" {
-			if isSnapshotAware(ctx, c, apexInfo) {
+			if shouldCollectHeadersForSnapshot(ctx, c, apexInfo) {
 				i.collectHeadersForSnapshot(ctx)
 			}
 		}
@@ -1892,13 +1892,6 @@
 		}
 	}
 
-	buildStubs := false
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		if versioned.buildStubs() {
-			buildStubs = true
-		}
-	}
-
 	rewriteSnapshotLibs := func(lib string, snapshotMap *snapshotMap) string {
 		// only modules with BOARD_VNDK_VERSION uses snapshot.
 		if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
@@ -1921,7 +1914,7 @@
 
 		lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs)
 
-		if buildStubs {
+		if c.IsStubs() {
 			actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
 				depTag, lib)
 		} else {
@@ -1929,12 +1922,6 @@
 		}
 	}
 
-	if buildStubs {
-		// Stubs lib does not have dependency to other static/shared libraries.
-		// Don't proceed.
-		return
-	}
-
 	// sysprop_library has to support both C++ and Java. So sysprop_library internally creates one
 	// C++ implementation library and one Java implementation library. When a module links against
 	// sysprop_library, the C++ implementation library has to be linked. syspropImplLibraries is a
@@ -2114,7 +2101,7 @@
 		return
 	}
 
-	if from.Module().Target().Os != android.Android {
+	if from.Target().Os != android.Android {
 		// Host code is not restricted
 		return
 	}
@@ -2128,6 +2115,11 @@
 			if ccFrom.vndkdep != nil {
 				ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag)
 			}
+		} else if linkableMod, ok := to.(LinkableInterface); ok {
+			// Static libraries from other languages can be linked
+			if !linkableMod.Static() {
+				ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
+			}
 		} else {
 			ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
 		}
@@ -2254,6 +2246,11 @@
 			return false
 		}
 
+		depTag := ctx.OtherModuleDependencyTag(child)
+		if IsHeaderDepTag(depTag) {
+			return false
+		}
+
 		// Even if target lib has no vendor variant, keep checking dependency
 		// graph in case it depends on vendor_available or product_available
 		// but not double_loadable transtively.
@@ -2505,6 +2502,12 @@
 					}
 				}
 
+				// Stubs lib doesn't link to the shared lib dependencies. Don't set
+				// linkFile, depFile, and ptr.
+				if c.IsStubs() {
+					break
+				}
+
 				linkFile = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
 				depFile = sharedLibraryInfo.TableOfContents
 
@@ -2532,6 +2535,13 @@
 					}
 					return
 				}
+
+				// Stubs lib doesn't link to the static lib dependencies. Don't set
+				// linkFile, depFile, and ptr.
+				if c.IsStubs() {
+					break
+				}
+
 				staticLibraryInfo := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
 				linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
 				if libDepTag.wholeStatic {
@@ -2659,7 +2669,9 @@
 						c.Properties.AndroidMkStaticLibs, makeLibName)
 				}
 			}
-		} else {
+		} else if !c.IsStubs() {
+			// Stubs lib doesn't link to the runtime lib, object, crt, etc. dependencies.
+
 			switch depTag {
 			case runtimeDepTag:
 				c.Properties.AndroidMkRuntimeLibs = append(
@@ -2784,7 +2796,7 @@
 		return libName + vendorRamdiskSuffix
 	} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
 		return libName + recoverySuffix
-	} else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
+	} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
 		return libName + nativeBridgeSuffix
 	} else {
 		return libName
@@ -2896,22 +2908,24 @@
 	return false
 }
 
-func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
+func GetMakeLinkType(actx android.ModuleContext, c LinkableInterface) string {
 	if c.UseVndk() {
-		if lib, ok := c.linker.(*llndkStubDecorator); ok {
-			if Bool(lib.Properties.Vendor_available) {
-				return "native:vndk"
+		if ccModule, ok := c.Module().(*Module); ok {
+			// Only CC modules provide stubs at the moment.
+			if lib, ok := ccModule.linker.(*llndkStubDecorator); ok {
+				if Bool(lib.Properties.Vendor_available) {
+					return "native:vndk"
+				}
+				return "native:vndk_private"
 			}
-			return "native:vndk_private"
 		}
-		if c.IsVndk() && !c.isVndkExt() {
-			// Product_available, if defined, must have the same value with Vendor_available.
-			if Bool(c.VendorProperties.Vendor_available) {
-				return "native:vndk"
+		if c.IsVndk() && !c.IsVndkExt() {
+			if c.IsVndkPrivate(actx.Config()) {
+				return "native:vndk_private"
 			}
-			return "native:vndk_private"
+			return "native:vndk"
 		}
-		if c.inProduct() {
+		if c.InProduct() {
 			return "native:product"
 		}
 		return "native:vendor"
@@ -2921,7 +2935,7 @@
 		return "native:vendor_ramdisk"
 	} else if c.InRecovery() {
 		return "native:recovery"
-	} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
+	} else if c.Target().Os == android.Android && c.SdkVersion() != "" {
 		return "native:ndk:none:none"
 		// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
 		//family, link := getNdkStlFamilyAndLinkType(c)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index af9b943..c16cce8 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -250,8 +250,8 @@
 
 	// Check VNDK extension properties.
 	isVndkExt := extends != ""
-	if mod.isVndkExt() != isVndkExt {
-		t.Errorf("%q isVndkExt() must equal to %t", name, isVndkExt)
+	if mod.IsVndkExt() != isVndkExt {
+		t.Errorf("%q IsVndkExt() must equal to %t", name, isVndkExt)
 	}
 
 	if actualExtends := mod.getVndkExtendsModuleName(); actualExtends != extends {
@@ -4056,3 +4056,35 @@
 	}
 
 }
+
+func TestStubsLibReexportsHeaders(t *testing.T) {
+	ctx := testCc(t, `
+		cc_library_shared {
+			name: "libclient",
+			srcs: ["foo.c"],
+			shared_libs: ["libfoo#1"],
+		}
+
+		cc_library_shared {
+			name: "libfoo",
+			srcs: ["foo.c"],
+			shared_libs: ["libbar"],
+			export_shared_lib_headers: ["libbar"],
+			stubs: {
+				symbol_file: "foo.map.txt",
+				versions: ["1", "2", "3"],
+			},
+		}
+
+		cc_library_shared {
+			name: "libbar",
+			export_include_dirs: ["include/libbar"],
+			srcs: ["foo.c"],
+		}`)
+
+	cFlags := ctx.ModuleForTests("libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"]
+
+	if !strings.Contains(cFlags, "-Iinclude/libbar") {
+		t.Errorf("expected %q in cflags, got %q", "-Iinclude/libbar", cFlags)
+	}
+}
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index a548452..8a0d7bd 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -21,10 +21,10 @@
 	"android.hardware.automotive.occupant_awareness-ndk_platform",
 	"android.hardware.light-ndk_platform",
 	"android.hardware.identity-ndk_platform",
-	"android.hardware.keymint-unstable-ndk_platform",
 	"android.hardware.nfc@1.2",
 	"android.hardware.power-ndk_platform",
 	"android.hardware.rebootescrow-ndk_platform",
+	"android.hardware.security.keymint-unstable-ndk_platform",
 	"android.hardware.vibrator-ndk_platform",
 	"android.system.keystore2-unstable-ndk_platform",
 	"libbinder",
diff --git a/cc/coverage.go b/cc/coverage.go
index aa1fdf6..acf98dd 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -149,6 +149,7 @@
 
 			coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
 			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open")
 		}
 	}
 
diff --git a/cc/image.go b/cc/image.go
index 3d6769e..32325b9 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -41,7 +41,7 @@
 		return hostImageVariant
 	} else if c.inVendor() {
 		return vendorImageVariant
-	} else if c.inProduct() {
+	} else if c.InProduct() {
 		return productImageVariant
 	} else if c.InRamdisk() {
 		return ramdiskImageVariant
@@ -67,7 +67,7 @@
 func (ctx *moduleContext) ProductSpecific() bool {
 	//TODO(b/150902910): Replace HasNonSystemVariants() with HasProductVariant()
 	return ctx.ModuleContext.ProductSpecific() ||
-		(ctx.mod.HasNonSystemVariants() && ctx.mod.inProduct())
+		(ctx.mod.HasNonSystemVariants() && ctx.mod.InProduct())
 }
 
 func (ctx *moduleContext) SocSpecific() bool {
@@ -76,7 +76,7 @@
 }
 
 func (ctx *moduleContextImpl) inProduct() bool {
-	return ctx.mod.inProduct()
+	return ctx.mod.InProduct()
 }
 
 func (ctx *moduleContextImpl) inVendor() bool {
@@ -111,7 +111,7 @@
 }
 
 // Returns true if the module is "product" variant. Usually these modules are installed in /product
-func (c *Module) inProduct() bool {
+func (c *Module) InProduct() bool {
 	return c.Properties.ImageVariationPrefix == ProductVariationPrefix
 }
 
@@ -265,7 +265,7 @@
 		} else {
 			mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
 		}
-	} else if m.HasNonSystemVariants() && !m.isVndkExt() {
+	} else if m.HasNonSystemVariants() && !m.IsVndkExt() {
 		// This will be available to /system unless it is product_specific
 		// which will be handled later.
 		coreVariantNeeded = true
diff --git a/cc/library.go b/cc/library.go
index b796aaf..06b9905 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -610,13 +610,13 @@
 	}
 	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(ctx.Config()) {
 		if ctx.isVndkSp() {
-			if ctx.isVndkExt() {
+			if ctx.IsVndkExt() {
 				return "VNDK-SP-ext"
 			} else {
 				return "VNDK-SP"
 			}
 		} else {
-			if ctx.isVndkExt() {
+			if ctx.IsVndkExt() {
 				return "VNDK-ext"
 			} else {
 				return "VNDK-core"
@@ -767,7 +767,7 @@
 func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
 	name := library.getLibNameHelper(ctx.baseModuleName(), ctx.useVndk())
 
-	if ctx.isVndkExt() {
+	if ctx.IsVndkExt() {
 		// vndk-ext lib should have the same name with original lib
 		ctx.VisitDirectDepsWithTag(vndkExtDepTag, func(module android.Module) {
 			originalName := module.(*Module).outputFile.Path()
@@ -1190,7 +1190,7 @@
 			library.sAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
 				refAbiDumpFile, fileName, exportedHeaderFlags,
 				Bool(library.Properties.Header_abi_checker.Check_all_apis),
-				ctx.isLlndk(ctx.Config()), ctx.isNdk(ctx.Config()), ctx.isVndkExt())
+				ctx.isLlndk(ctx.Config()), ctx.isNdk(ctx.Config()), ctx.IsVndkExt())
 		}
 	}
 }
@@ -1320,7 +1320,7 @@
 	if library.shared() {
 		if ctx.Device() && ctx.useVndk() {
 			// set subDir for VNDK extensions
-			if ctx.isVndkExt() {
+			if ctx.IsVndkExt() {
 				if ctx.isVndkSp() {
 					library.baseInstaller.subDir = "vndk-sp"
 				} else {
@@ -1329,7 +1329,7 @@
 			}
 
 			// In some cases we want to use core variant for VNDK-Core libs
-			if ctx.isVndk() && !ctx.isVndkSp() && !ctx.isVndkExt() {
+			if ctx.isVndk() && !ctx.isVndkSp() && !ctx.IsVndkExt() {
 				mayUseCoreVariant := true
 
 				if ctx.mustUseVendorVariant() {
@@ -1350,7 +1350,7 @@
 
 			// do not install vndk libs
 			// vndk libs are packaged into VNDK APEX
-			if ctx.isVndk() && !ctx.isVndkExt() {
+			if ctx.isVndk() && !ctx.IsVndkExt() {
 				return
 			}
 		} else if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.directlyInAnyApex() {
diff --git a/cc/linkable.go b/cc/linkable.go
index ddf3950..4efe2a7 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -8,6 +8,8 @@
 
 // LinkableInterface is an interface for a type of module that is linkable in a C++ library.
 type LinkableInterface interface {
+	android.Module
+
 	Module() android.Module
 	CcLibrary() bool
 	CcLibraryInterface() bool
@@ -42,7 +44,10 @@
 	UseVndk() bool
 	MustUseVendorVariant() bool
 	IsVndk() bool
+	IsVndkExt() bool
+	IsVndkPrivate(config android.Config) bool
 	HasVendorVariant() bool
+	InProduct() bool
 
 	SdkVersion() string
 	AlwaysSdk() bool
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
new file mode 100644
index 0000000..b291bd0
--- /dev/null
+++ b/cc/snapshot_prebuilt.go
@@ -0,0 +1,844 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package cc
+
+// This file defines snapshot prebuilt modules, e.g. vendor snapshot and recovery snapshot. Such
+// snapshot modules will override original source modules with setting BOARD_VNDK_VERSION, with
+// snapshot mutators and snapshot information maps which are also defined in this file.
+
+import (
+	"strings"
+	"sync"
+
+	"android/soong/android"
+)
+
+// Defines the specifics of different images to which the snapshot process is applicable, e.g.,
+// vendor, recovery, ramdisk.
+type snapshotImage interface {
+	// Used to register callbacks with the build system.
+	init()
+
+	// Function that returns true if the module is included in this image.
+	// Using a function return instead of a value to prevent early
+	// evalution of a function that may be not be defined.
+	inImage(m *Module) func() bool
+
+	// Returns the value of the "available" property for a given module for
+	// and snapshot, e.g., "vendor_available", "recovery_available", etc.
+	// or nil if the property is not defined.
+	available(m *Module) *bool
+
+	// Returns true if a dir under source tree is an SoC-owned proprietary
+	// directory, such as device/, vendor/, etc.
+	//
+	// For a given snapshot (e.g., vendor, recovery, etc.) if
+	// isProprietaryPath(dir) returns true, then the module in dir will be
+	// built from sources.
+	isProprietaryPath(dir string) bool
+
+	// Whether to include VNDK in the snapshot for this image.
+	includeVndk() bool
+
+	// Whether a given module has been explicitly excluded from the
+	// snapshot, e.g., using the exclude_from_vendor_snapshot or
+	// exclude_from_recovery_snapshot properties.
+	excludeFromSnapshot(m *Module) bool
+}
+
+type vendorSnapshotImage struct{}
+type recoverySnapshotImage struct{}
+
+func (vendorSnapshotImage) init() {
+	android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
+	android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
+	android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
+	android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
+	android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
+	android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory)
+}
+
+func (vendorSnapshotImage) inImage(m *Module) func() bool {
+	return m.inVendor
+}
+
+func (vendorSnapshotImage) available(m *Module) *bool {
+	return m.VendorProperties.Vendor_available
+}
+
+func (vendorSnapshotImage) isProprietaryPath(dir string) bool {
+	return isVendorProprietaryPath(dir)
+}
+
+// vendor snapshot includes static/header libraries with vndk: {enabled: true}.
+func (vendorSnapshotImage) includeVndk() bool {
+	return true
+}
+
+func (vendorSnapshotImage) excludeFromSnapshot(m *Module) bool {
+	return m.ExcludeFromVendorSnapshot()
+}
+
+func (recoverySnapshotImage) init() {
+	android.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
+	android.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory)
+	android.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory)
+	android.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory)
+	android.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory)
+	android.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory)
+}
+
+func (recoverySnapshotImage) inImage(m *Module) func() bool {
+	return m.InRecovery
+}
+
+func (recoverySnapshotImage) available(m *Module) *bool {
+	return m.Properties.Recovery_available
+}
+
+func (recoverySnapshotImage) isProprietaryPath(dir string) bool {
+	return isRecoveryProprietaryPath(dir)
+}
+
+// recovery snapshot does NOT treat vndk specially.
+func (recoverySnapshotImage) includeVndk() bool {
+	return false
+}
+
+func (recoverySnapshotImage) excludeFromSnapshot(m *Module) bool {
+	return m.ExcludeFromRecoverySnapshot()
+}
+
+var vendorSnapshotImageSingleton vendorSnapshotImage
+var recoverySnapshotImageSingleton recoverySnapshotImage
+
+func init() {
+	vendorSnapshotImageSingleton.init()
+	recoverySnapshotImageSingleton.init()
+}
+
+const (
+	vendorSnapshotHeaderSuffix = ".vendor_header."
+	vendorSnapshotSharedSuffix = ".vendor_shared."
+	vendorSnapshotStaticSuffix = ".vendor_static."
+	vendorSnapshotBinarySuffix = ".vendor_binary."
+	vendorSnapshotObjectSuffix = ".vendor_object."
+)
+
+const (
+	recoverySnapshotHeaderSuffix = ".recovery_header."
+	recoverySnapshotSharedSuffix = ".recovery_shared."
+	recoverySnapshotStaticSuffix = ".recovery_static."
+	recoverySnapshotBinarySuffix = ".recovery_binary."
+	recoverySnapshotObjectSuffix = ".recovery_object."
+)
+
+var (
+	vendorSnapshotsLock         sync.Mutex
+	vendorSuffixModulesKey      = android.NewOnceKey("vendorSuffixModules")
+	vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs")
+	vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
+	vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
+	vendorSnapshotBinariesKey   = android.NewOnceKey("vendorSnapshotBinaries")
+	vendorSnapshotObjectsKey    = android.NewOnceKey("vendorSnapshotObjects")
+)
+
+// vendorSuffixModules holds names of modules whose vendor variants should have the vendor suffix.
+// This is determined by source modules, and then this will be used when exporting snapshot modules
+// to Makefile.
+//
+// For example, if libbase has "vendor_available: true", the name of core variant will be "libbase"
+// while the name of vendor variant will be "libbase.vendor". In such cases, the vendor snapshot of
+// "libbase" should be exported with the name "libbase.vendor".
+//
+// Refer to VendorSnapshotSourceMutator and makeLibName which use this.
+func vendorSuffixModules(config android.Config) map[string]bool {
+	return config.Once(vendorSuffixModulesKey, func() interface{} {
+		return make(map[string]bool)
+	}).(map[string]bool)
+}
+
+// these are vendor snapshot maps holding names of vendor snapshot modules
+func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func vendorSnapshotSharedLibs(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotSharedLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func vendorSnapshotStaticLibs(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotStaticLibsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func vendorSnapshotBinaries(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotBinariesKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+func vendorSnapshotObjects(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotObjectsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
+type baseSnapshotDecoratorProperties struct {
+	// snapshot version.
+	Version string
+
+	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
+	Target_arch string
+}
+
+// baseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot
+// version, snapshot arch, etc. It also adds a special suffix to Soong module name, so it doesn't
+// collide with source modules. e.g. the following example module,
+//
+// vendor_snapshot_static {
+//     name: "libbase",
+//     arch: "arm64",
+//     version: 30,
+//     ...
+// }
+//
+// will be seen as "libbase.vendor_static.30.arm64" by Soong.
+type baseSnapshotDecorator struct {
+	baseProperties baseSnapshotDecoratorProperties
+	moduleSuffix   string
+}
+
+func (p *baseSnapshotDecorator) Name(name string) string {
+	return name + p.NameSuffix()
+}
+
+func (p *baseSnapshotDecorator) NameSuffix() string {
+	versionSuffix := p.version()
+	if p.arch() != "" {
+		versionSuffix += "." + p.arch()
+	}
+
+	return p.moduleSuffix + versionSuffix
+}
+
+func (p *baseSnapshotDecorator) version() string {
+	return p.baseProperties.Version
+}
+
+func (p *baseSnapshotDecorator) arch() string {
+	return p.baseProperties.Target_arch
+}
+
+func (p *baseSnapshotDecorator) isSnapshotPrebuilt() bool {
+	return true
+}
+
+// Call this with a module suffix after creating a snapshot module, such as
+// vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc.
+func (p *baseSnapshotDecorator) init(m *Module, suffix string) {
+	p.moduleSuffix = suffix
+	m.AddProperties(&p.baseProperties)
+	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
+		vendorSnapshotLoadHook(ctx, p)
+	})
+}
+
+// vendorSnapshotLoadHook disables snapshots if it's not BOARD_VNDK_VERSION.
+// As vendor snapshot is only for vendor, such modules won't be used at all.
+func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *baseSnapshotDecorator) {
+	if p.version() != ctx.DeviceConfig().VndkVersion() {
+		ctx.Module().Disable()
+		return
+	}
+}
+
+//
+// Module definitions for snapshots of libraries (shared, static, header).
+//
+// Modules (vendor|recovery)_snapshot_(shared|static|header) are defined here. Shared libraries and
+// static libraries have their prebuilt library files (.so for shared, .a for static) as their src,
+// which can be installed or linked against. Also they export flags needed when linked, such as
+// include directories, c flags, sanitize dependency information, etc.
+//
+// These modules are auto-generated by development/vendor_snapshot/update.py.
+type snapshotLibraryProperties struct {
+	// Prebuilt file for each arch.
+	Src *string `android:"arch_variant"`
+
+	// list of directories that will be added to the include path (using -I).
+	Export_include_dirs []string `android:"arch_variant"`
+
+	// list of directories that will be added to the system path (using -isystem).
+	Export_system_include_dirs []string `android:"arch_variant"`
+
+	// list of flags that will be used for any module that links against this module.
+	Export_flags []string `android:"arch_variant"`
+
+	// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
+	Sanitize_ubsan_dep *bool `android:"arch_variant"`
+
+	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
+	Sanitize_minimal_dep *bool `android:"arch_variant"`
+}
+
+type snapshotSanitizer interface {
+	isSanitizerEnabled(t sanitizerType) bool
+	setSanitizerVariation(t sanitizerType, enabled bool)
+}
+
+type snapshotLibraryDecorator struct {
+	baseSnapshotDecorator
+	*libraryDecorator
+	properties          snapshotLibraryProperties
+	sanitizerProperties struct {
+		CfiEnabled bool `blueprint:"mutated"`
+
+		// Library flags for cfi variant.
+		Cfi snapshotLibraryProperties `android:"arch_variant"`
+	}
+	androidMkVendorSuffix bool
+}
+
+func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
+	return p.libraryDecorator.linkerFlags(ctx, flags)
+}
+
+func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+	arches := config.Arches()
+	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
+		return false
+	}
+	if !p.header() && p.properties.Src == nil {
+		return false
+	}
+	return true
+}
+
+// cc modules' link functions are to link compiled objects into final binaries.
+// As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are
+// done by normal library decorator, e.g. exporting flags.
+func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+	m := ctx.Module().(*Module)
+	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+	if p.header() {
+		return p.libraryDecorator.link(ctx, flags, deps, objs)
+	}
+
+	if p.sanitizerProperties.CfiEnabled {
+		p.properties = p.sanitizerProperties.Cfi
+	}
+
+	if !p.matchesWithDevice(ctx.DeviceConfig()) {
+		return nil
+	}
+
+	p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
+	p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
+	p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
+
+	in := android.PathForModuleSrc(ctx, *p.properties.Src)
+	p.unstrippedOutputFile = in
+
+	if p.shared() {
+		libName := in.Base()
+		builderFlags := flagsToBuilderFlags(flags)
+
+		// Optimize out relinking against shared libraries whose interface hasn't changed by
+		// depending on a table of contents file instead of the library itself.
+		tocFile := android.PathForModuleOut(ctx, libName+".toc")
+		p.tocFile = android.OptionalPathForPath(tocFile)
+		transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+
+		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+			SharedLibrary:           in,
+			UnstrippedSharedLibrary: p.unstrippedOutputFile,
+
+			TableOfContents: p.tocFile,
+		})
+	}
+
+	if p.static() {
+		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
+		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+			StaticLibrary: in,
+
+			TransitiveStaticLibrariesForOrdering: depSet,
+		})
+	}
+
+	p.libraryDecorator.flagExporter.setProvider(ctx)
+
+	return in
+}
+
+func (p *snapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
+	if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
+		p.baseInstaller.install(ctx, file)
+	}
+}
+
+func (p *snapshotLibraryDecorator) nativeCoverage() bool {
+	return false
+}
+
+func (p *snapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
+	switch t {
+	case cfi:
+		return p.sanitizerProperties.Cfi.Src != nil
+	default:
+		return false
+	}
+}
+
+func (p *snapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
+	if !enabled {
+		return
+	}
+	switch t {
+	case cfi:
+		p.sanitizerProperties.CfiEnabled = true
+	default:
+		return
+	}
+}
+
+func snapshotLibraryFactory(suffix string) (*Module, *snapshotLibraryDecorator) {
+	module, library := NewLibrary(android.DeviceSupported)
+
+	module.stl = nil
+	module.sanitize = nil
+	library.disableStripping()
+
+	prebuilt := &snapshotLibraryDecorator{
+		libraryDecorator: library,
+	}
+
+	prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
+	prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+	// Prevent default system libs (libc, libm, and libdl) from being linked
+	if prebuilt.baseLinker.Properties.System_shared_libs == nil {
+		prebuilt.baseLinker.Properties.System_shared_libs = []string{}
+	}
+
+	module.compiler = nil
+	module.linker = prebuilt
+	module.installer = prebuilt
+
+	prebuilt.init(module, suffix)
+	module.AddProperties(
+		&prebuilt.properties,
+		&prebuilt.sanitizerProperties,
+	)
+
+	return module, prebuilt
+}
+
+// vendor_snapshot_shared is a special prebuilt shared library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_shared
+// overrides the vendor variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func VendorSnapshotSharedFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(vendorSnapshotSharedSuffix)
+	prebuilt.libraryDecorator.BuildOnlyShared()
+	return module.Init()
+}
+
+// recovery_snapshot_shared is a special prebuilt shared library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_shared
+// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RecoverySnapshotSharedFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(recoverySnapshotSharedSuffix)
+	prebuilt.libraryDecorator.BuildOnlyShared()
+	return module.Init()
+}
+
+// vendor_snapshot_static is a special prebuilt static library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_static
+// overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func VendorSnapshotStaticFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(vendorSnapshotStaticSuffix)
+	prebuilt.libraryDecorator.BuildOnlyStatic()
+	return module.Init()
+}
+
+// recovery_snapshot_static is a special prebuilt static library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_static
+// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RecoverySnapshotStaticFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(recoverySnapshotStaticSuffix)
+	prebuilt.libraryDecorator.BuildOnlyStatic()
+	return module.Init()
+}
+
+// vendor_snapshot_header is a special header library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_header
+// overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func VendorSnapshotHeaderFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(vendorSnapshotHeaderSuffix)
+	prebuilt.libraryDecorator.HeaderOnly()
+	return module.Init()
+}
+
+// recovery_snapshot_header is a special header library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_header
+// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RecoverySnapshotHeaderFactory() android.Module {
+	module, prebuilt := snapshotLibraryFactory(recoverySnapshotHeaderSuffix)
+	prebuilt.libraryDecorator.HeaderOnly()
+	return module.Init()
+}
+
+var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+
+//
+// Module definitions for snapshots of executable binaries.
+//
+// Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable
+// binaries (e.g. toybox, sh) as their src, which can be installed.
+//
+// These modules are auto-generated by development/vendor_snapshot/update.py.
+type snapshotBinaryProperties struct {
+	// Prebuilt file for each arch.
+	Src *string `android:"arch_variant"`
+}
+
+type snapshotBinaryDecorator struct {
+	baseSnapshotDecorator
+	*binaryDecorator
+	properties            snapshotBinaryProperties
+	androidMkVendorSuffix bool
+}
+
+func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+	if config.DeviceArch() != p.arch() {
+		return false
+	}
+	if p.properties.Src == nil {
+		return false
+	}
+	return true
+}
+
+// cc modules' link functions are to link compiled objects into final binaries.
+// As snapshots are prebuilts, this just returns the prebuilt binary
+func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+	if !p.matchesWithDevice(ctx.DeviceConfig()) {
+		return nil
+	}
+
+	in := android.PathForModuleSrc(ctx, *p.properties.Src)
+	p.unstrippedOutputFile = in
+	binName := in.Base()
+
+	m := ctx.Module().(*Module)
+	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+	// use cpExecutable to make it executable
+	outputFile := android.PathForModuleOut(ctx, binName)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.CpExecutable,
+		Description: "prebuilt",
+		Output:      outputFile,
+		Input:       in,
+	})
+
+	return outputFile
+}
+
+func (p *snapshotBinaryDecorator) nativeCoverage() bool {
+	return false
+}
+
+// vendor_snapshot_binary is a special prebuilt executable binary which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_binary
+// overrides the vendor variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
+func VendorSnapshotBinaryFactory() android.Module {
+	return snapshotBinaryFactory(vendorSnapshotBinarySuffix)
+}
+
+// recovery_snapshot_binary is a special prebuilt executable binary which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary
+// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
+func RecoverySnapshotBinaryFactory() android.Module {
+	return snapshotBinaryFactory(recoverySnapshotBinarySuffix)
+}
+
+func snapshotBinaryFactory(suffix string) android.Module {
+	module, binary := NewBinary(android.DeviceSupported)
+	binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
+	binary.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+	// Prevent default system libs (libc, libm, and libdl) from being linked
+	if binary.baseLinker.Properties.System_shared_libs == nil {
+		binary.baseLinker.Properties.System_shared_libs = []string{}
+	}
+
+	prebuilt := &snapshotBinaryDecorator{
+		binaryDecorator: binary,
+	}
+
+	module.compiler = nil
+	module.sanitize = nil
+	module.stl = nil
+	module.linker = prebuilt
+
+	prebuilt.init(module, suffix)
+	module.AddProperties(&prebuilt.properties)
+	return module.Init()
+}
+
+//
+// Module definitions for snapshots of object files (*.o).
+//
+// Modules (vendor|recovery)_snapshot_object are defined here. They have their prebuilt object
+// files (*.o) as their src.
+//
+// These modules are auto-generated by development/vendor_snapshot/update.py.
+type vendorSnapshotObjectProperties struct {
+	// Prebuilt file for each arch.
+	Src *string `android:"arch_variant"`
+}
+
+type snapshotObjectLinker struct {
+	baseSnapshotDecorator
+	objectLinker
+	properties            vendorSnapshotObjectProperties
+	androidMkVendorSuffix bool
+}
+
+func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
+	if config.DeviceArch() != p.arch() {
+		return false
+	}
+	if p.properties.Src == nil {
+		return false
+	}
+	return true
+}
+
+// cc modules' link functions are to link compiled objects into final binaries.
+// As snapshots are prebuilts, this just returns the prebuilt binary
+func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+	if !p.matchesWithDevice(ctx.DeviceConfig()) {
+		return nil
+	}
+
+	m := ctx.Module().(*Module)
+	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+	return android.PathForModuleSrc(ctx, *p.properties.Src)
+}
+
+func (p *snapshotObjectLinker) nativeCoverage() bool {
+	return false
+}
+
+// vendor_snapshot_object is a special prebuilt compiled object file which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_object
+// overrides the vendor variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
+func VendorSnapshotObjectFactory() android.Module {
+	module := newObject()
+
+	prebuilt := &snapshotObjectLinker{
+		objectLinker: objectLinker{
+			baseLinker: NewBaseLinker(nil),
+		},
+	}
+	module.linker = prebuilt
+
+	prebuilt.init(module, vendorSnapshotObjectSuffix)
+	module.AddProperties(&prebuilt.properties)
+	return module.Init()
+}
+
+// recovery_snapshot_object is a special prebuilt compiled object file which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_object
+// overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
+func RecoverySnapshotObjectFactory() android.Module {
+	module := newObject()
+
+	prebuilt := &snapshotObjectLinker{
+		objectLinker: objectLinker{
+			baseLinker: NewBaseLinker(nil),
+		},
+	}
+	module.linker = prebuilt
+
+	prebuilt.init(module, recoverySnapshotObjectSuffix)
+	module.AddProperties(&prebuilt.properties)
+	return module.Init()
+}
+
+type snapshotInterface interface {
+	matchesWithDevice(config android.DeviceConfig) bool
+}
+
+var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
+var _ snapshotInterface = (*snapshotLibraryDecorator)(nil)
+var _ snapshotInterface = (*snapshotBinaryDecorator)(nil)
+var _ snapshotInterface = (*snapshotObjectLinker)(nil)
+
+//
+// Mutators that helps vendor snapshot modules override source modules.
+//
+
+// VendorSnapshotMutator gathers all snapshots for vendor, and disable all snapshots which don't
+// match with device, e.g.
+//   - snapshot version is different with BOARD_VNDK_VERSION
+//   - snapshot arch is different with device's arch (e.g. arm vs x86)
+//
+// This also handles vndk_prebuilt_shared, except for they won't be disabled in any cases, given
+// that any versions of VNDK might be packed into vndk APEX.
+//
+// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
+func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
+	vndkVersion := ctx.DeviceConfig().VndkVersion()
+	// don't need snapshot if current
+	if vndkVersion == "current" || vndkVersion == "" {
+		return
+	}
+
+	module, ok := ctx.Module().(*Module)
+	if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
+		return
+	}
+
+	if !module.isSnapshotPrebuilt() {
+		return
+	}
+
+	// isSnapshotPrebuilt ensures snapshotInterface
+	if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) {
+		// Disable unnecessary snapshot module, but do not disable
+		// vndk_prebuilt_shared because they might be packed into vndk APEX
+		if !module.IsVndk() {
+			module.Disable()
+		}
+		return
+	}
+
+	var snapshotMap *snapshotMap
+
+	if lib, ok := module.linker.(libraryInterface); ok {
+		if lib.static() {
+			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+		} else if lib.shared() {
+			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+		} else {
+			// header
+			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+		}
+	} else if _, ok := module.linker.(*snapshotBinaryDecorator); ok {
+		snapshotMap = vendorSnapshotBinaries(ctx.Config())
+	} else if _, ok := module.linker.(*snapshotObjectLinker); ok {
+		snapshotMap = vendorSnapshotObjects(ctx.Config())
+	} else {
+		return
+	}
+
+	vendorSnapshotsLock.Lock()
+	defer vendorSnapshotsLock.Unlock()
+	snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
+}
+
+// VendorSnapshotSourceMutator disables source modules which have corresponding snapshots.
+func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
+	if !ctx.Device() {
+		return
+	}
+
+	vndkVersion := ctx.DeviceConfig().VndkVersion()
+	// don't need snapshot if current
+	if vndkVersion == "current" || vndkVersion == "" {
+		return
+	}
+
+	module, ok := ctx.Module().(*Module)
+	if !ok {
+		return
+	}
+
+	// vendor suffix should be added to snapshots if the source module isn't vendor: true.
+	if !module.SocSpecific() {
+		// But we can't just check SocSpecific() since we already passed the image mutator.
+		// Check ramdisk and recovery to see if we are real "vendor: true" module.
+		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
+		vendor_ramdisk_available := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk()
+		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
+
+		if !ramdisk_available && !recovery_available && !vendor_ramdisk_available {
+			vendorSnapshotsLock.Lock()
+			defer vendorSnapshotsLock.Unlock()
+
+			vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
+		}
+	}
+
+	if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
+		// only non-snapshot modules with BOARD_VNDK_VERSION
+		return
+	}
+
+	// .. and also filter out llndk library
+	if module.isLlndk(ctx.Config()) {
+		return
+	}
+
+	var snapshotMap *snapshotMap
+
+	if lib, ok := module.linker.(libraryInterface); ok {
+		if lib.static() {
+			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+		} else if lib.shared() {
+			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+		} else {
+			// header
+			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+		}
+	} else if module.binary() {
+		snapshotMap = vendorSnapshotBinaries(ctx.Config())
+	} else if module.object() {
+		snapshotMap = vendorSnapshotObjects(ctx.Config())
+	} else {
+		return
+	}
+
+	if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
+		// Corresponding snapshot doesn't exist
+		return
+	}
+
+	// Disables source modules if corresponding snapshot exists.
+	if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
+		// But do not disable because the shared variant depends on the static variant.
+		module.SkipInstall()
+		module.Properties.HideFromMake = true
+	} else {
+		module.Disable()
+	}
+}
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index a3d52e6..e841a54 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -13,6 +13,8 @@
 // limitations under the License.
 package cc
 
+// This file contains utility types and functions for VNDK / vendor snapshot.
+
 import (
 	"android/soong/android"
 )
@@ -21,15 +23,24 @@
 	headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
 )
 
+// snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots.
 type snapshotLibraryInterface interface {
 	libraryInterface
+
+	// collectHeadersForSnapshot is called in GenerateAndroidBuildActions for snapshot aware
+	// modules (See isSnapshotAware below).
+	// This function should gather all headers needed for snapshot.
 	collectHeadersForSnapshot(ctx android.ModuleContext)
+
+	// snapshotHeaders should return collected headers by collectHeadersForSnapshot.
+	// Calling snapshotHeaders before collectHeadersForSnapshot is an error.
 	snapshotHeaders() android.Paths
 }
 
 var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
 var _ snapshotLibraryInterface = (*libraryDecorator)(nil)
 
+// snapshotMap is a helper wrapper to a map from base module name to snapshot module name.
 type snapshotMap struct {
 	snapshots map[string]string
 }
@@ -57,43 +68,14 @@
 	return snapshot, found
 }
 
-func isSnapshotAware(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool {
-	if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m, apexInfo); ok {
+// shouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot.
+// If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions.
+func shouldCollectHeadersForSnapshot(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool {
+	if _, _, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo); ok {
 		return ctx.Config().VndkSnapshotBuildArtifacts()
-	} else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) ||
-		isRecoverySnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) {
+	} else if isVendorSnapshotAware(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) ||
+		isRecoverySnapshotAware(m, isRecoveryProprietaryPath(ctx.ModuleDir()), apexInfo) {
 		return true
 	}
 	return false
 }
-
-func copyFile(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
-	outPath := android.PathForOutput(ctx, out)
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cp,
-		Input:       path,
-		Output:      outPath,
-		Description: "Cp " + out,
-		Args: map[string]string{
-			"cpFlags": "-f -L",
-		},
-	})
-	return outPath
-}
-
-func combineNotices(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
-	outPath := android.PathForOutput(ctx, out)
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cat,
-		Inputs:      paths,
-		Output:      outPath,
-		Description: "combine notices for " + out,
-	})
-	return outPath
-}
-
-func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath {
-	outPath := android.PathForOutput(ctx, out)
-	android.WriteFileRule(ctx, outPath, content)
-	return outPath
-}
diff --git a/cc/testing.go b/cc/testing.go
index 85f12b7..fc5b030 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -335,7 +335,7 @@
 			},
 			apex_available: [
 				"//apex_available:platform",
-				"myapex"
+				"//apex_available:anyapex",
 			],
 		}
 		cc_library {
diff --git a/cc/util.go b/cc/util.go
index 40374bf..1220d84 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -125,3 +125,52 @@
 	return "mkdir -p " + dir + " && " +
 		"ln -sf " + target + " " + filepath.Join(dir, linkName)
 }
+
+func copyFileRule(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cp,
+		Input:       path,
+		Output:      outPath,
+		Description: "copy " + path.String() + " -> " + out,
+		Args: map[string]string{
+			"cpFlags": "-f -L",
+		},
+	})
+	return outPath
+}
+
+func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cat,
+		Inputs:      paths,
+		Output:      outPath,
+		Description: "combine notices for " + out,
+	})
+	return outPath
+}
+
+func writeStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	android.WriteFileRule(ctx, outPath, content)
+	return outPath
+}
+
+// Dump a map to a list file as:
+//
+// {key1} {value1}
+// {key2} {value2}
+// ...
+func installMapListFileRule(ctx android.SingletonContext, m map[string]string, path string) android.OutputPath {
+	var txtBuilder strings.Builder
+	for idx, k := range android.SortedStringKeys(m) {
+		if idx > 0 {
+			txtBuilder.WriteString("\n")
+		}
+		txtBuilder.WriteString(k)
+		txtBuilder.WriteString(" ")
+		txtBuilder.WriteString(m[k])
+	}
+	return writeStringToFileRule(ctx, txtBuilder.String(), path)
+}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 3ef0b62..da37d0f 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -13,625 +13,27 @@
 // limitations under the License.
 package cc
 
+// This file contains singletons to capture vendor and recovery snapshot. They consist of prebuilt
+// modules under AOSP so older vendor and recovery can be built with a newer system in a single
+// source tree.
+
 import (
 	"encoding/json"
 	"path/filepath"
 	"sort"
 	"strings"
-	"sync"
 
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
 
-// Defines the specifics of different images to which the snapshot process is
-// applicable, e.g., vendor, recovery, ramdisk.
-type image interface {
-	// Used to register callbacks with the build system.
-	init()
-
-	// Function that returns true if the module is included in this image.
-	// Using a function return instead of a value to prevent early
-	// evalution of a function that may be not be defined.
-	inImage(m *Module) func() bool
-
-	// Returns the value of the "available" property for a given module for
-	// and snapshot, e.g., "vendor_available", "recovery_available", etc.
-	// or nil if the property is not defined.
-	available(m *Module) *bool
-
-	// Returns true if a dir under source tree is an SoC-owned proprietary
-	// directory, such as device/, vendor/, etc.
-	//
-	// For a given snapshot (e.g., vendor, recovery, etc.) if
-	// isProprietaryPath(dir) returns true, then the module in dir will be
-	// built from sources.
-	isProprietaryPath(dir string) bool
-
-	// Whether to include VNDK in the snapshot for this image.
-	includeVndk() bool
-
-	// Whether a given module has been explicitly excluded from the
-	// snapshot, e.g., using the exclude_from_vendor_snapshot or
-	// exclude_from_recovery_snapshot properties.
-	excludeFromSnapshot(m *Module) bool
-}
-
-type vendorImage struct{}
-type recoveryImage struct{}
-
-func (vendorImage) init() {
-	android.RegisterSingletonType(
-		"vendor-snapshot", VendorSnapshotSingleton)
-	android.RegisterModuleType(
-		"vendor_snapshot_shared", VendorSnapshotSharedFactory)
-	android.RegisterModuleType(
-		"vendor_snapshot_static", VendorSnapshotStaticFactory)
-	android.RegisterModuleType(
-		"vendor_snapshot_header", VendorSnapshotHeaderFactory)
-	android.RegisterModuleType(
-		"vendor_snapshot_binary", VendorSnapshotBinaryFactory)
-	android.RegisterModuleType(
-		"vendor_snapshot_object", VendorSnapshotObjectFactory)
-}
-
-func (vendorImage) inImage(m *Module) func() bool {
-	return m.inVendor
-}
-
-func (vendorImage) available(m *Module) *bool {
-	return m.VendorProperties.Vendor_available
-}
-
-func (vendorImage) isProprietaryPath(dir string) bool {
-	return isVendorProprietaryPath(dir)
-}
-
-func (vendorImage) includeVndk() bool {
-	return true
-}
-
-func (vendorImage) excludeFromSnapshot(m *Module) bool {
-	return m.ExcludeFromVendorSnapshot()
-}
-
-func (recoveryImage) init() {
-	android.RegisterSingletonType(
-		"recovery-snapshot", RecoverySnapshotSingleton)
-	android.RegisterModuleType(
-		"recovery_snapshot_shared", RecoverySnapshotSharedFactory)
-	android.RegisterModuleType(
-		"recovery_snapshot_static", RecoverySnapshotStaticFactory)
-	android.RegisterModuleType(
-		"recovery_snapshot_header", RecoverySnapshotHeaderFactory)
-	android.RegisterModuleType(
-		"recovery_snapshot_binary", RecoverySnapshotBinaryFactory)
-	android.RegisterModuleType(
-		"recovery_snapshot_object", RecoverySnapshotObjectFactory)
-}
-
-func (recoveryImage) inImage(m *Module) func() bool {
-	return m.InRecovery
-}
-
-func (recoveryImage) available(m *Module) *bool {
-	return m.Properties.Recovery_available
-}
-
-func (recoveryImage) isProprietaryPath(dir string) bool {
-	return isRecoveryProprietaryPath(dir)
-}
-
-func (recoveryImage) includeVndk() bool {
-	return false
-}
-
-func (recoveryImage) excludeFromSnapshot(m *Module) bool {
-	return m.ExcludeFromRecoverySnapshot()
-}
-
-var vendorImageSingleton vendorImage
-var recoveryImageSingleton recoveryImage
-
-const (
-	vendorSnapshotHeaderSuffix = ".vendor_header."
-	vendorSnapshotSharedSuffix = ".vendor_shared."
-	vendorSnapshotStaticSuffix = ".vendor_static."
-	vendorSnapshotBinarySuffix = ".vendor_binary."
-	vendorSnapshotObjectSuffix = ".vendor_object."
-)
-
-const (
-	recoverySnapshotHeaderSuffix = ".recovery_header."
-	recoverySnapshotSharedSuffix = ".recovery_shared."
-	recoverySnapshotStaticSuffix = ".recovery_static."
-	recoverySnapshotBinarySuffix = ".recovery_binary."
-	recoverySnapshotObjectSuffix = ".recovery_object."
-)
-
-var (
-	vendorSnapshotsLock         sync.Mutex
-	vendorSuffixModulesKey      = android.NewOnceKey("vendorSuffixModules")
-	vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs")
-	vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
-	vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
-	vendorSnapshotBinariesKey   = android.NewOnceKey("vendorSnapshotBinaries")
-	vendorSnapshotObjectsKey    = android.NewOnceKey("vendorSnapshotObjects")
-)
-
-// vendor snapshot maps hold names of vendor snapshot modules per arch
-func vendorSuffixModules(config android.Config) map[string]bool {
-	return config.Once(vendorSuffixModulesKey, func() interface{} {
-		return make(map[string]bool)
-	}).(map[string]bool)
-}
-
-func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap {
-	return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} {
-		return newSnapshotMap()
-	}).(*snapshotMap)
-}
-
-func vendorSnapshotSharedLibs(config android.Config) *snapshotMap {
-	return config.Once(vendorSnapshotSharedLibsKey, func() interface{} {
-		return newSnapshotMap()
-	}).(*snapshotMap)
-}
-
-func vendorSnapshotStaticLibs(config android.Config) *snapshotMap {
-	return config.Once(vendorSnapshotStaticLibsKey, func() interface{} {
-		return newSnapshotMap()
-	}).(*snapshotMap)
-}
-
-func vendorSnapshotBinaries(config android.Config) *snapshotMap {
-	return config.Once(vendorSnapshotBinariesKey, func() interface{} {
-		return newSnapshotMap()
-	}).(*snapshotMap)
-}
-
-func vendorSnapshotObjects(config android.Config) *snapshotMap {
-	return config.Once(vendorSnapshotObjectsKey, func() interface{} {
-		return newSnapshotMap()
-	}).(*snapshotMap)
-}
-
-type vendorSnapshotBaseProperties struct {
-	// snapshot version.
-	Version string
-
-	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
-	Target_arch string
-}
-
-// vendorSnapshotModuleBase provides common basic functions for all snapshot modules.
-type vendorSnapshotModuleBase struct {
-	baseProperties vendorSnapshotBaseProperties
-	moduleSuffix   string
-}
-
-func (p *vendorSnapshotModuleBase) Name(name string) string {
-	return name + p.NameSuffix()
-}
-
-func (p *vendorSnapshotModuleBase) NameSuffix() string {
-	versionSuffix := p.version()
-	if p.arch() != "" {
-		versionSuffix += "." + p.arch()
-	}
-
-	return p.moduleSuffix + versionSuffix
-}
-
-func (p *vendorSnapshotModuleBase) version() string {
-	return p.baseProperties.Version
-}
-
-func (p *vendorSnapshotModuleBase) arch() string {
-	return p.baseProperties.Target_arch
-}
-
-func (p *vendorSnapshotModuleBase) isSnapshotPrebuilt() bool {
-	return true
-}
-
-// Call this after creating a snapshot module with module suffix
-// such as vendorSnapshotSharedSuffix
-func (p *vendorSnapshotModuleBase) init(m *Module, suffix string) {
-	p.moduleSuffix = suffix
-	m.AddProperties(&p.baseProperties)
-	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
-		vendorSnapshotLoadHook(ctx, p)
-	})
-}
-
-func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *vendorSnapshotModuleBase) {
-	if p.version() != ctx.DeviceConfig().VndkVersion() {
-		ctx.Module().Disable()
-		return
-	}
-}
-
-type snapshotLibraryProperties struct {
-	// Prebuilt file for each arch.
-	Src *string `android:"arch_variant"`
-
-	// list of directories that will be added to the include path (using -I).
-	Export_include_dirs []string `android:"arch_variant"`
-
-	// list of directories that will be added to the system path (using -isystem).
-	Export_system_include_dirs []string `android:"arch_variant"`
-
-	// list of flags that will be used for any module that links against this module.
-	Export_flags []string `android:"arch_variant"`
-
-	// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
-	Sanitize_ubsan_dep *bool `android:"arch_variant"`
-
-	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
-	Sanitize_minimal_dep *bool `android:"arch_variant"`
-}
-
-type snapshotSanitizer interface {
-	isSanitizerEnabled(t sanitizerType) bool
-	setSanitizerVariation(t sanitizerType, enabled bool)
-}
-
-type snapshotLibraryDecorator struct {
-	vendorSnapshotModuleBase
-	*libraryDecorator
-	properties          snapshotLibraryProperties
-	sanitizerProperties struct {
-		CfiEnabled bool `blueprint:"mutated"`
-
-		// Library flags for cfi variant.
-		Cfi snapshotLibraryProperties `android:"arch_variant"`
-	}
-	androidMkVendorSuffix bool
-}
-
-func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
-	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
-	return p.libraryDecorator.linkerFlags(ctx, flags)
-}
-
-func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
-	arches := config.Arches()
-	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
-		return false
-	}
-	if !p.header() && p.properties.Src == nil {
-		return false
-	}
-	return true
-}
-
-func (p *snapshotLibraryDecorator) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objs Objects) android.Path {
-	m := ctx.Module().(*Module)
-	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
-
-	if p.header() {
-		return p.libraryDecorator.link(ctx, flags, deps, objs)
-	}
-
-	if p.sanitizerProperties.CfiEnabled {
-		p.properties = p.sanitizerProperties.Cfi
-	}
-
-	if !p.matchesWithDevice(ctx.DeviceConfig()) {
-		return nil
-	}
-
-	p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
-	p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
-	p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
-
-	in := android.PathForModuleSrc(ctx, *p.properties.Src)
-	p.unstrippedOutputFile = in
-
-	if p.shared() {
-		libName := in.Base()
-		builderFlags := flagsToBuilderFlags(flags)
-
-		// Optimize out relinking against shared libraries whose interface hasn't changed by
-		// depending on a table of contents file instead of the library itself.
-		tocFile := android.PathForModuleOut(ctx, libName+".toc")
-		p.tocFile = android.OptionalPathForPath(tocFile)
-		transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
-
-		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
-			SharedLibrary:           in,
-			UnstrippedSharedLibrary: p.unstrippedOutputFile,
-
-			TableOfContents: p.tocFile,
-		})
-	}
-
-	if p.static() {
-		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
-		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
-			StaticLibrary: in,
-
-			TransitiveStaticLibrariesForOrdering: depSet,
-		})
-	}
-
-	p.libraryDecorator.flagExporter.setProvider(ctx)
-
-	return in
-}
-
-func (p *snapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
-	if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
-		p.baseInstaller.install(ctx, file)
-	}
-}
-
-func (p *snapshotLibraryDecorator) nativeCoverage() bool {
-	return false
-}
-
-func (p *snapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
-	switch t {
-	case cfi:
-		return p.sanitizerProperties.Cfi.Src != nil
-	default:
-		return false
-	}
-}
-
-func (p *snapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
-	if !enabled {
-		return
-	}
-	switch t {
-	case cfi:
-		p.sanitizerProperties.CfiEnabled = true
-	default:
-		return
-	}
-}
-
-func snapshotLibrary(suffix string) (*Module, *snapshotLibraryDecorator) {
-	module, library := NewLibrary(android.DeviceSupported)
-
-	module.stl = nil
-	module.sanitize = nil
-	library.disableStripping()
-
-	prebuilt := &snapshotLibraryDecorator{
-		libraryDecorator: library,
-	}
-
-	prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
-	prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
-
-	// Prevent default system libs (libc, libm, and libdl) from being linked
-	if prebuilt.baseLinker.Properties.System_shared_libs == nil {
-		prebuilt.baseLinker.Properties.System_shared_libs = []string{}
-	}
-
-	module.compiler = nil
-	module.linker = prebuilt
-	module.installer = prebuilt
-
-	prebuilt.init(module, suffix)
-	module.AddProperties(
-		&prebuilt.properties,
-		&prebuilt.sanitizerProperties,
-	)
-
-	return module, prebuilt
-}
-
-func VendorSnapshotSharedFactory() android.Module {
-	module, prebuilt := snapshotLibrary(vendorSnapshotSharedSuffix)
-	prebuilt.libraryDecorator.BuildOnlyShared()
-	return module.Init()
-}
-
-func RecoverySnapshotSharedFactory() android.Module {
-	module, prebuilt := snapshotLibrary(recoverySnapshotSharedSuffix)
-	prebuilt.libraryDecorator.BuildOnlyShared()
-	return module.Init()
-}
-
-func VendorSnapshotStaticFactory() android.Module {
-	module, prebuilt := snapshotLibrary(vendorSnapshotStaticSuffix)
-	prebuilt.libraryDecorator.BuildOnlyStatic()
-	return module.Init()
-}
-
-func RecoverySnapshotStaticFactory() android.Module {
-	module, prebuilt := snapshotLibrary(recoverySnapshotStaticSuffix)
-	prebuilt.libraryDecorator.BuildOnlyStatic()
-	return module.Init()
-}
-
-func VendorSnapshotHeaderFactory() android.Module {
-	module, prebuilt := snapshotLibrary(vendorSnapshotHeaderSuffix)
-	prebuilt.libraryDecorator.HeaderOnly()
-	return module.Init()
-}
-
-func RecoverySnapshotHeaderFactory() android.Module {
-	module, prebuilt := snapshotLibrary(recoverySnapshotHeaderSuffix)
-	prebuilt.libraryDecorator.HeaderOnly()
-	return module.Init()
-}
-
-var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
-
-type snapshotBinaryProperties struct {
-	// Prebuilt file for each arch.
-	Src *string `android:"arch_variant"`
-}
-
-type snapshotBinaryDecorator struct {
-	vendorSnapshotModuleBase
-	*binaryDecorator
-	properties            snapshotBinaryProperties
-	androidMkVendorSuffix bool
-}
-
-func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
-	if config.DeviceArch() != p.arch() {
-		return false
-	}
-	if p.properties.Src == nil {
-		return false
-	}
-	return true
-}
-
-func (p *snapshotBinaryDecorator) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objs Objects) android.Path {
-	if !p.matchesWithDevice(ctx.DeviceConfig()) {
-		return nil
-	}
-
-	in := android.PathForModuleSrc(ctx, *p.properties.Src)
-	stripFlags := flagsToStripFlags(flags)
-	p.unstrippedOutputFile = in
-	binName := in.Base()
-	if p.stripper.NeedsStrip(ctx) {
-		stripped := android.PathForModuleOut(ctx, "stripped", binName)
-		p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
-		in = stripped
-	}
-
-	m := ctx.Module().(*Module)
-	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
-
-	// use cpExecutable to make it executable
-	outputFile := android.PathForModuleOut(ctx, binName)
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.CpExecutable,
-		Description: "prebuilt",
-		Output:      outputFile,
-		Input:       in,
-	})
-
-	return outputFile
-}
-
-func (p *snapshotBinaryDecorator) nativeCoverage() bool {
-	return false
-}
-
-func VendorSnapshotBinaryFactory() android.Module {
-	return snapshotBinaryFactory(vendorSnapshotBinarySuffix)
-}
-
-func RecoverySnapshotBinaryFactory() android.Module {
-	return snapshotBinaryFactory(recoverySnapshotBinarySuffix)
-}
-
-func snapshotBinaryFactory(suffix string) android.Module {
-	module, binary := NewBinary(android.DeviceSupported)
-	binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
-	binary.baseLinker.Properties.Nocrt = BoolPtr(true)
-
-	// Prevent default system libs (libc, libm, and libdl) from being linked
-	if binary.baseLinker.Properties.System_shared_libs == nil {
-		binary.baseLinker.Properties.System_shared_libs = []string{}
-	}
-
-	prebuilt := &snapshotBinaryDecorator{
-		binaryDecorator: binary,
-	}
-
-	module.compiler = nil
-	module.sanitize = nil
-	module.stl = nil
-	module.linker = prebuilt
-
-	prebuilt.init(module, suffix)
-	module.AddProperties(&prebuilt.properties)
-	return module.Init()
-}
-
-type vendorSnapshotObjectProperties struct {
-	// Prebuilt file for each arch.
-	Src *string `android:"arch_variant"`
-}
-
-type snapshotObjectLinker struct {
-	vendorSnapshotModuleBase
-	objectLinker
-	properties            vendorSnapshotObjectProperties
-	androidMkVendorSuffix bool
-}
-
-func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
-	if config.DeviceArch() != p.arch() {
-		return false
-	}
-	if p.properties.Src == nil {
-		return false
-	}
-	return true
-}
-
-func (p *snapshotObjectLinker) link(ctx ModuleContext,
-	flags Flags, deps PathDeps, objs Objects) android.Path {
-	if !p.matchesWithDevice(ctx.DeviceConfig()) {
-		return nil
-	}
-
-	m := ctx.Module().(*Module)
-	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
-
-	return android.PathForModuleSrc(ctx, *p.properties.Src)
-}
-
-func (p *snapshotObjectLinker) nativeCoverage() bool {
-	return false
-}
-
-func VendorSnapshotObjectFactory() android.Module {
-	module := newObject()
-
-	prebuilt := &snapshotObjectLinker{
-		objectLinker: objectLinker{
-			baseLinker: NewBaseLinker(nil),
-		},
-	}
-	module.linker = prebuilt
-
-	prebuilt.init(module, vendorSnapshotObjectSuffix)
-	module.AddProperties(&prebuilt.properties)
-	return module.Init()
-}
-
-func RecoverySnapshotObjectFactory() android.Module {
-	module := newObject()
-
-	prebuilt := &snapshotObjectLinker{
-		objectLinker: objectLinker{
-			baseLinker: NewBaseLinker(nil),
-		},
-	}
-	module.linker = prebuilt
-
-	prebuilt.init(module, recoverySnapshotObjectSuffix)
-	module.AddProperties(&prebuilt.properties)
-	return module.Init()
-}
-
-func init() {
-	vendorImageSingleton.init()
-	recoveryImageSingleton.init()
-}
-
 var vendorSnapshotSingleton = snapshotSingleton{
 	"vendor",
 	"SOONG_VENDOR_SNAPSHOT_ZIP",
 	android.OptionalPath{},
 	true,
-	vendorImageSingleton,
+	vendorSnapshotImageSingleton,
 }
 
 var recoverySnapshotSingleton = snapshotSingleton{
@@ -639,7 +41,7 @@
 	"SOONG_RECOVERY_SNAPSHOT_ZIP",
 	android.OptionalPath{},
 	false,
-	recoveryImageSingleton,
+	recoverySnapshotImageSingleton,
 }
 
 func VendorSnapshotSingleton() android.Singleton {
@@ -667,13 +69,12 @@
 	// Implementation of the image interface specific to the image
 	// associated with this snapshot (e.g., specific to the vendor image,
 	// recovery image, etc.).
-	image image
+	image snapshotImage
 }
 
 var (
 	// Modules under following directories are ignored. They are OEM's and vendor's
 	// proprietary modules(device/, kernel/, vendor/, and hardware/).
-	// TODO(b/65377115): Clean up these with more maintainable way
 	vendorProprietaryDirs = []string{
 		"device",
 		"kernel",
@@ -683,7 +84,6 @@
 
 	// Modules under following directories are ignored. They are OEM's and vendor's
 	// proprietary modules(device/, kernel/, vendor/, and hardware/).
-	// TODO(b/65377115): Clean up these with more maintainable way
 	recoveryProprietaryDirs = []string{
 		"bootable/recovery",
 		"device",
@@ -694,7 +94,6 @@
 
 	// Modules under following directories are included as they are in AOSP,
 	// although hardware/ and kernel/ are normally for vendor's own.
-	// TODO(b/65377115): Clean up these with more maintainable way
 	aospDirsUnderProprietary = []string{
 		"kernel/configs",
 		"kernel/prebuilts",
@@ -738,10 +137,8 @@
 }
 
 func isVendorProprietaryModule(ctx android.BaseModuleContext) bool {
-
 	// Any module in a vendor proprietary path is a vendor proprietary
 	// module.
-
 	if isVendorProprietaryPath(ctx.ModuleDir()) {
 		return true
 	}
@@ -750,7 +147,6 @@
 	// still be a vendor proprietary module. This happens for cc modules
 	// that are excluded from the vendor snapshot, and it means that the
 	// vendor has assumed control of the framework-provided module.
-
 	if c, ok := ctx.Module().(*Module); ok {
 		if c.ExcludeFromVendorSnapshot() {
 			return true
@@ -766,15 +162,21 @@
 // AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might
 // depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
 // image and newer system image altogether.
-func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool, apexInfo android.ApexInfo) bool {
-	return isSnapshotModule(m, inVendorProprietaryPath, apexInfo, vendorImageSingleton)
+func isVendorSnapshotAware(m *Module, inVendorProprietaryPath bool, apexInfo android.ApexInfo) bool {
+	return isSnapshotAware(m, inVendorProprietaryPath, apexInfo, vendorSnapshotImageSingleton)
 }
 
-func isRecoverySnapshotModule(m *Module, inRecoveryProprietaryPath bool, apexInfo android.ApexInfo) bool {
-	return isSnapshotModule(m, inRecoveryProprietaryPath, apexInfo, recoveryImageSingleton)
+// Determine if a module is going to be included in recovery snapshot or not.
+//
+// Targets of recovery snapshot are "recovery: true" or "recovery_available: true"
+// modules in AOSP. They are not guaranteed to be compatible with older recovery images.
+// So they are captured as recovery snapshot To build older recovery image.
+func isRecoverySnapshotAware(m *Module, inRecoveryProprietaryPath bool, apexInfo android.ApexInfo) bool {
+	return isSnapshotAware(m, inRecoveryProprietaryPath, apexInfo, recoverySnapshotImageSingleton)
 }
 
-func isSnapshotModule(m *Module, inProprietaryPath bool, apexInfo android.ApexInfo, image image) bool {
+// Determines if the module is a candidate for snapshot.
+func isSnapshotAware(m *Module, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshotImage) bool {
 	if !m.Enabled() || m.Properties.HideFromMake {
 		return false
 	}
@@ -799,7 +201,7 @@
 	if m.Target().NativeBridge == android.NativeBridgeEnabled {
 		return false
 	}
-	// the module must be installed in /vendor
+	// the module must be installed in target image
 	if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !image.inImage(m)() {
 		return false
 	}
@@ -817,7 +219,6 @@
 
 	// Libraries
 	if l, ok := m.linker.(snapshotLibraryInterface); ok {
-		// TODO(b/65377115): add full support for sanitizer
 		if m.sanitize != nil {
 			// scs and hwasan export both sanitized and unsanitized variants for static and header
 			// Always use unsanitized variants of them.
@@ -827,6 +228,8 @@
 				}
 			}
 			// cfi also exports both variants. But for static, we capture both.
+			// This is because cfi static libraries can't be linked from non-cfi modules,
+			// and vice versa. This isn't the case for scs and hwasan sanitizers.
 			if !l.static() && !l.shared() && m.sanitize.isSanitizerEnabled(cfi) {
 				return false
 			}
@@ -842,7 +245,7 @@
 				if !m.IsVndk() {
 					return true
 				}
-				return m.isVndkExt()
+				return m.IsVndkExt()
 			}
 		}
 		return true
@@ -856,6 +259,33 @@
 	return false
 }
 
+// This is to be saved as .json files, which is for development/vendor_snapshot/update.py.
+// These flags become Android.bp snapshot module properties.
+type snapshotJsonFlags struct {
+	ModuleName          string `json:",omitempty"`
+	RelativeInstallPath string `json:",omitempty"`
+
+	// library flags
+	ExportedDirs       []string `json:",omitempty"`
+	ExportedSystemDirs []string `json:",omitempty"`
+	ExportedFlags      []string `json:",omitempty"`
+	Sanitize           string   `json:",omitempty"`
+	SanitizeMinimalDep bool     `json:",omitempty"`
+	SanitizeUbsanDep   bool     `json:",omitempty"`
+
+	// binary flags
+	Symlinks []string `json:",omitempty"`
+
+	// dependencies
+	SharedLibs  []string `json:",omitempty"`
+	RuntimeLibs []string `json:",omitempty"`
+	Required    []string `json:",omitempty"`
+
+	// extra config files
+	InitRc         []string `json:",omitempty"`
+	VintfFragments []string `json:",omitempty"`
+}
+
 func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot.
 	if ctx.DeviceConfig().VndkVersion() != "current" {
@@ -909,6 +339,8 @@
 
 	var headers android.Paths
 
+	// installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file.
+	// For executables, init_rc and vintf_fragments files are also copied.
 	installSnapshot := func(m *Module) android.Paths {
 		targetArch := "arch-" + m.Target().Arch.ArchType.String()
 		if m.Target().Arch.ArchVariant != "" {
@@ -917,34 +349,11 @@
 
 		var ret android.Paths
 
-		prop := struct {
-			ModuleName          string `json:",omitempty"`
-			RelativeInstallPath string `json:",omitempty"`
-
-			// library flags
-			ExportedDirs       []string `json:",omitempty"`
-			ExportedSystemDirs []string `json:",omitempty"`
-			ExportedFlags      []string `json:",omitempty"`
-			Sanitize           string   `json:",omitempty"`
-			SanitizeMinimalDep bool     `json:",omitempty"`
-			SanitizeUbsanDep   bool     `json:",omitempty"`
-
-			// binary flags
-			Symlinks []string `json:",omitempty"`
-
-			// dependencies
-			SharedLibs  []string `json:",omitempty"`
-			RuntimeLibs []string `json:",omitempty"`
-			Required    []string `json:",omitempty"`
-
-			// extra config files
-			InitRc         []string `json:",omitempty"`
-			VintfFragments []string `json:",omitempty"`
-		}{}
+		prop := snapshotJsonFlags{}
 
 		// Common properties among snapshots.
 		prop.ModuleName = ctx.ModuleName(m)
-		if c.supportsVndkExt && m.isVndkExt() {
+		if c.supportsVndkExt && m.IsVndkExt() {
 			// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
 			if m.isVndkSp() {
 				prop.RelativeInstallPath = "vndk-sp"
@@ -968,7 +377,7 @@
 			out := filepath.Join(configsDir, path.Base())
 			if !installedConfigs[out] {
 				installedConfigs[out] = true
-				ret = append(ret, copyFile(ctx, path, out))
+				ret = append(ret, copyFileRule(ctx, path, out))
 			}
 		}
 
@@ -1019,7 +428,7 @@
 					prop.ModuleName += ".cfi"
 				}
 				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
-				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+				ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut))
 			} else {
 				stem = ctx.ModuleName(m)
 			}
@@ -1033,7 +442,7 @@
 			// install bin
 			binPath := m.outputFile.Path()
 			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
-			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
+			ret = append(ret, copyFileRule(ctx, binPath, snapshotBinOut))
 			propOut = snapshotBinOut + ".json"
 		} else if m.object() {
 			// object files aren't installed to the device, so their names can conflict.
@@ -1041,7 +450,7 @@
 			objPath := m.outputFile.Path()
 			snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
 				ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
-			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut))
+			ret = append(ret, copyFileRule(ctx, objPath, snapshotObjOut))
 			propOut = snapshotObjOut + ".json"
 		} else {
 			ctx.Errorf("unknown module %q in vendor snapshot", m.String())
@@ -1053,7 +462,7 @@
 			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
 			return nil
 		}
-		ret = append(ret, writeStringToFile(ctx, string(j), propOut))
+		ret = append(ret, writeStringToFileRule(ctx, string(j), propOut))
 
 		return ret
 	}
@@ -1088,11 +497,14 @@
 			}
 		}
 
-		if !isSnapshotModule(m, inProprietaryPath, apexInfo, c.image) {
+		if !isSnapshotAware(m, inProprietaryPath, apexInfo, c.image) {
 			return
 		}
 
+		// installSnapshot installs prebuilts and json flag files
 		snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
+
+		// just gather headers and notice files here, because they are to be deduplicated
 		if l, ok := m.linker.(snapshotLibraryInterface); ok {
 			headers = append(headers, l.snapshotHeaders()...)
 		}
@@ -1103,7 +515,7 @@
 			// skip already copied notice file
 			if !installedNotices[noticeOut] {
 				installedNotices[noticeOut] = true
-				snapshotOutputs = append(snapshotOutputs, combineNotices(
+				snapshotOutputs = append(snapshotOutputs, combineNoticesRule(
 					ctx, m.NoticeFiles(), noticeOut))
 			}
 		}
@@ -1111,7 +523,7 @@
 
 	// install all headers after removing duplicates
 	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, copyFile(
+		snapshotOutputs = append(snapshotOutputs, copyFileRule(
 			ctx, header, filepath.Join(includeDir, header.String())))
 	}
 
@@ -1155,141 +567,3 @@
 		c.makeVar,
 		c.snapshotZipFile.String())
 }
-
-type snapshotInterface interface {
-	matchesWithDevice(config android.DeviceConfig) bool
-}
-
-var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
-var _ snapshotInterface = (*snapshotLibraryDecorator)(nil)
-var _ snapshotInterface = (*snapshotBinaryDecorator)(nil)
-var _ snapshotInterface = (*snapshotObjectLinker)(nil)
-
-// gathers all snapshot modules for vendor, and disable unnecessary snapshots
-// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
-func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
-	vndkVersion := ctx.DeviceConfig().VndkVersion()
-	// don't need snapshot if current
-	if vndkVersion == "current" || vndkVersion == "" {
-		return
-	}
-
-	module, ok := ctx.Module().(*Module)
-	if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
-		return
-	}
-
-	if !module.isSnapshotPrebuilt() {
-		return
-	}
-
-	// isSnapshotPrebuilt ensures snapshotInterface
-	if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) {
-		// Disable unnecessary snapshot module, but do not disable
-		// vndk_prebuilt_shared because they might be packed into vndk APEX
-		if !module.IsVndk() {
-			module.Disable()
-		}
-		return
-	}
-
-	var snapshotMap *snapshotMap
-
-	if lib, ok := module.linker.(libraryInterface); ok {
-		if lib.static() {
-			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
-		} else if lib.shared() {
-			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
-		} else {
-			// header
-			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
-		}
-	} else if _, ok := module.linker.(*snapshotBinaryDecorator); ok {
-		snapshotMap = vendorSnapshotBinaries(ctx.Config())
-	} else if _, ok := module.linker.(*snapshotObjectLinker); ok {
-		snapshotMap = vendorSnapshotObjects(ctx.Config())
-	} else {
-		return
-	}
-
-	vendorSnapshotsLock.Lock()
-	defer vendorSnapshotsLock.Unlock()
-	snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
-}
-
-// Disables source modules which have snapshots
-func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
-	if !ctx.Device() {
-		return
-	}
-
-	vndkVersion := ctx.DeviceConfig().VndkVersion()
-	// don't need snapshot if current
-	if vndkVersion == "current" || vndkVersion == "" {
-		return
-	}
-
-	module, ok := ctx.Module().(*Module)
-	if !ok {
-		return
-	}
-
-	// vendor suffix should be added to snapshots if the source module isn't vendor: true.
-	if !module.SocSpecific() {
-		// But we can't just check SocSpecific() since we already passed the image mutator.
-		// Check ramdisk and recovery to see if we are real "vendor: true" module.
-		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
-		vendor_ramdisk_available := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk()
-		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
-
-		if !ramdisk_available && !recovery_available && !vendor_ramdisk_available {
-			vendorSnapshotsLock.Lock()
-			defer vendorSnapshotsLock.Unlock()
-
-			vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
-		}
-	}
-
-	if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
-		// only non-snapshot modules with BOARD_VNDK_VERSION
-		return
-	}
-
-	// .. and also filter out llndk library
-	if module.isLlndk(ctx.Config()) {
-		return
-	}
-
-	var snapshotMap *snapshotMap
-
-	if lib, ok := module.linker.(libraryInterface); ok {
-		if lib.static() {
-			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
-		} else if lib.shared() {
-			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
-		} else {
-			// header
-			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
-		}
-	} else if module.binary() {
-		snapshotMap = vendorSnapshotBinaries(ctx.Config())
-	} else if module.object() {
-		snapshotMap = vendorSnapshotObjects(ctx.Config())
-	} else {
-		return
-	}
-
-	if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
-		// Corresponding snapshot doesn't exist
-		return
-	}
-
-	// Disables source modules if corresponding snapshot exists.
-	if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
-		// But do not disable because the shared variant depends on the static variant.
-		module.SkipInstall()
-		module.Properties.HideFromMake = true
-	} else {
-		module.Disable()
-	}
-}
diff --git a/cc/vndk.go b/cc/vndk.go
index d57cdf7..1529ac5 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -389,7 +389,7 @@
 
 		useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
 			mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
-		return lib.shared() && m.inVendor() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
+		return lib.shared() && m.inVendor() && m.IsVndk() && !m.IsVndkExt() && !useCoreVariant
 	}
 	return false
 }
@@ -533,7 +533,7 @@
 	vndkSnapshotZipFile android.OptionalPath
 }
 
-func isVndkSnapshotLibrary(config android.DeviceConfig, m *Module,
+func isVndkSnapshotAware(config android.DeviceConfig, m *Module,
 	apexInfo android.ApexInfo) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
 
 	if m.Target().NativeBridge == android.NativeBridgeEnabled {
@@ -549,7 +549,7 @@
 	if !ok || !l.shared() {
 		return nil, "", false
 	}
-	if m.VndkVersion() == config.PlatformVndkVersion() && m.IsVndk() && !m.isVndkExt() {
+	if m.VndkVersion() == config.PlatformVndkVersion() && m.IsVndk() && !m.IsVndkExt() {
 		if m.isVndkSp() {
 			return l, "vndk-sp", true
 		} else {
@@ -622,6 +622,9 @@
 
 	var headers android.Paths
 
+	// installVndkSnapshotLib copies built .so file from the module.
+	// Also, if the build artifacts is on, write a json file which contains all exported flags
+	// with FlagExporterInfo.
 	installVndkSnapshotLib := func(m *Module, vndkType string) (android.Paths, bool) {
 		var ret android.Paths
 
@@ -632,7 +635,7 @@
 
 		libPath := m.outputFile.Path()
 		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
-		ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+		ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut))
 
 		if ctx.Config().VndkSnapshotBuildArtifacts() {
 			prop := struct {
@@ -654,7 +657,7 @@
 				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
 				return nil, false
 			}
-			ret = append(ret, writeStringToFile(ctx, string(j), propOut))
+			ret = append(ret, writeStringToFileRule(ctx, string(j), propOut))
 		}
 		return ret, true
 	}
@@ -667,11 +670,21 @@
 
 		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
 
-		l, vndkType, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m, apexInfo)
+		l, vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
 		if !ok {
 			return
 		}
 
+		// For all snapshot candidates, the followings are captured.
+		//   - .so files
+		//   - notice files
+		//
+		// The followings are also captured if VNDK_SNAPSHOT_BUILD_ARTIFACTS.
+		//   - .json files containing exported flags
+		//   - exported headers from collectHeadersForSnapshot()
+		//
+		// Headers are deduplicated after visiting all modules.
+
 		// install .so files for appropriate modules.
 		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
 		libs, ok := installVndkSnapshotLib(m, vndkType)
@@ -690,7 +703,7 @@
 			// skip already copied notice file
 			if _, ok := noticeBuilt[noticeName]; !ok {
 				noticeBuilt[noticeName] = true
-				snapshotOutputs = append(snapshotOutputs, combineNotices(
+				snapshotOutputs = append(snapshotOutputs, combineNoticesRule(
 					ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
 			}
 		}
@@ -702,7 +715,7 @@
 
 	// install all headers after removing duplicates
 	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, copyFile(
+		snapshotOutputs = append(snapshotOutputs, copyFileRule(
 			ctx, header, filepath.Join(includeDir, header.String())))
 	}
 
@@ -712,38 +725,18 @@
 		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
 			return
 		}
-		snapshotOutputs = append(snapshotOutputs, copyFile(
+		snapshotOutputs = append(snapshotOutputs, copyFileRule(
 			ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
 	})
 
 	/*
-		Dump a map to a list file as:
-
-		{key1} {value1}
-		{key2} {value2}
-		...
-	*/
-	installMapListFile := func(m map[string]string, path string) android.OutputPath {
-		var txtBuilder strings.Builder
-		for idx, k := range android.SortedStringKeys(m) {
-			if idx > 0 {
-				txtBuilder.WriteString("\n")
-			}
-			txtBuilder.WriteString(k)
-			txtBuilder.WriteString(" ")
-			txtBuilder.WriteString(m[k])
-		}
-		return writeStringToFile(ctx, txtBuilder.String(), path)
-	}
-
-	/*
 		module_paths.txt contains paths on which VNDK modules are defined.
 		e.g.,
 			libbase.so system/libbase
 			libc.so bionic/libc
 			...
 	*/
-	snapshotOutputs = append(snapshotOutputs, installMapListFile(modulePaths, filepath.Join(configsDir, "module_paths.txt")))
+	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, modulePaths, filepath.Join(configsDir, "module_paths.txt")))
 
 	/*
 		module_names.txt contains names as which VNDK modules are defined,
@@ -754,7 +747,7 @@
 			libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
 			...
 	*/
-	snapshotOutputs = append(snapshotOutputs, installMapListFile(moduleNames, filepath.Join(configsDir, "module_names.txt")))
+	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, moduleNames, filepath.Join(configsDir, "module_names.txt")))
 
 	// All artifacts are ready. Sort them to normalize ninja and then zip.
 	sort.Slice(snapshotOutputs, func(i, j int) bool {
@@ -764,7 +757,7 @@
 	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
 	zipRule := android.NewRuleBuilder(pctx, ctx)
 
-	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with xargs
+	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
 	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
 	zipRule.Command().
 		Text("tr").
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 0a9b156..c079e83 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -185,7 +185,11 @@
 		Status:  stat,
 	}}
 
-	config := build.NewConfig(buildCtx)
+	args := ""
+	if *alternateResultDir {
+		args = "dist"
+	}
+	config := build.NewConfig(buildCtx, args)
 	if *outDir == "" {
 		name := "multiproduct"
 		if !*incremental {
@@ -212,15 +216,10 @@
 	os.MkdirAll(logsDir, 0777)
 
 	build.SetupOutDir(buildCtx, config)
-	if *alternateResultDir {
-		distLogsDir := filepath.Join(config.DistDir(), "logs")
-		os.MkdirAll(distLogsDir, 0777)
-		log.SetOutput(filepath.Join(distLogsDir, "soong.log"))
-		trace.SetOutput(filepath.Join(distLogsDir, "build.trace"))
-	} else {
-		log.SetOutput(filepath.Join(config.OutDir(), "soong.log"))
-		trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
-	}
+
+	os.MkdirAll(config.LogsDir(), 0777)
+	log.SetOutput(filepath.Join(config.LogsDir(), "soong.log"))
+	trace.SetOutput(filepath.Join(config.LogsDir(), "build.trace"))
 
 	var jobs = *numJobs
 	if jobs < 1 {
@@ -344,7 +343,7 @@
 			FileArgs: []zip.FileArg{
 				{GlobDir: logsDir, SourcePrefixToStrip: logsDir},
 			},
-			OutputFilePath:   filepath.Join(config.DistDir(), "logs.zip"),
+			OutputFilePath:   filepath.Join(config.RealDistDir(), "logs.zip"),
 			NumParallelJobs:  runtime.NumCPU(),
 			CompressionLevel: 5,
 		}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 4ffe944..bd1d450 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -18,6 +18,7 @@
 	"context"
 	"flag"
 	"fmt"
+	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -173,13 +174,18 @@
 
 	build.SetupOutDir(buildCtx, config)
 
+	if config.UseBazel() {
+		defer populateExternalDistDir(buildCtx, config)
+	}
+
 	// Set up files to be outputted in the log directory.
 	logsDir := config.LogsDir()
 
+	// Common list of metric file definition.
 	buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
 	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
 	soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
-	defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+
 	build.PrintOutDirWarning(buildCtx, config)
 
 	os.MkdirAll(logsDir, 0777)
@@ -195,8 +201,22 @@
 	buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
 		config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
 
-	defer met.Dump(soongMetricsFile)
-	defer build.DumpRBEMetrics(buildCtx, config, rbeMetricsFile)
+	{
+		// The order of the function calls is important. The last defer function call
+		// is the first one that is executed to save the rbe metrics to a protobuf
+		// file. The soong metrics file is then next. Bazel profiles are written
+		// before the uploadMetrics is invoked. The written files are then uploaded
+		// if the uploading of the metrics is enabled.
+		files := []string{
+			buildErrorFile,           // build error strings
+			rbeMetricsFile,           // high level metrics related to remote build execution.
+			soongMetricsFile,         // high level metrics related to this build system.
+			config.BazelMetricsDir(), // directory that contains a set of bazel metrics.
+		}
+		defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, files...)
+		defer met.Dump(soongMetricsFile)
+		defer build.DumpRBEMetrics(buildCtx, config, rbeMetricsFile)
+	}
 
 	// Read the time at the starting point.
 	if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
@@ -510,3 +530,72 @@
 	// command not found
 	return nil, nil, fmt.Errorf("Command not found: %q", args)
 }
+
+// For Bazel support, this moves files and directories from e.g. out/dist/$f to DIST_DIR/$f if necessary.
+func populateExternalDistDir(ctx build.Context, config build.Config) {
+	// Make sure that internalDistDirPath and externalDistDirPath are both absolute paths, so we can compare them
+	var err error
+	var internalDistDirPath string
+	var externalDistDirPath string
+	if internalDistDirPath, err = filepath.Abs(config.DistDir()); err != nil {
+		ctx.Fatalf("Unable to find absolute path of %s: %s", internalDistDirPath, err)
+	}
+	if externalDistDirPath, err = filepath.Abs(config.RealDistDir()); err != nil {
+		ctx.Fatalf("Unable to find absolute path of %s: %s", externalDistDirPath, err)
+	}
+	if externalDistDirPath == internalDistDirPath {
+		return
+	}
+
+	// Make sure the external DIST_DIR actually exists before trying to write to it
+	if err = os.MkdirAll(externalDistDirPath, 0755); err != nil {
+		ctx.Fatalf("Unable to make directory %s: %s", externalDistDirPath, err)
+	}
+
+	ctx.Println("Populating external DIST_DIR...")
+
+	populateExternalDistDirHelper(ctx, config, internalDistDirPath, externalDistDirPath)
+}
+
+func populateExternalDistDirHelper(ctx build.Context, config build.Config, internalDistDirPath string, externalDistDirPath string) {
+	files, err := ioutil.ReadDir(internalDistDirPath)
+	if err != nil {
+		ctx.Fatalf("Can't read internal distdir %s: %s", internalDistDirPath, err)
+	}
+	for _, f := range files {
+		internalFilePath := filepath.Join(internalDistDirPath, f.Name())
+		externalFilePath := filepath.Join(externalDistDirPath, f.Name())
+
+		if f.IsDir() {
+			// Moving a directory - check if there is an existing directory to merge with
+			externalLstat, err := os.Lstat(externalFilePath)
+			if err != nil {
+				if !os.IsNotExist(err) {
+					ctx.Fatalf("Can't lstat external %s: %s", externalDistDirPath, err)
+				}
+				// Otherwise, if the error was os.IsNotExist, that's fine and we fall through to the rename at the bottom
+			} else {
+				if externalLstat.IsDir() {
+					// Existing dir - try to merge the directories?
+					populateExternalDistDirHelper(ctx, config, internalFilePath, externalFilePath)
+					continue
+				} else {
+					// Existing file being replaced with a directory. Delete the existing file...
+					if err := os.RemoveAll(externalFilePath); err != nil {
+						ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
+					}
+				}
+			}
+		} else {
+			// Moving a file (not a dir) - delete any existing file or directory
+			if err := os.RemoveAll(externalFilePath); err != nil {
+				ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
+			}
+		}
+
+		// The actual move - do a rename instead of a copy in order to save disk space.
+		if err := os.Rename(internalFilePath, externalFilePath); err != nil {
+			ctx.Fatalf("Unable to rename %s -> %s due to error %s", internalFilePath, externalFilePath, err)
+		}
+	}
+}
diff --git a/rust/Android.bp b/rust/Android.bp
index 8618207..df731db 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -15,6 +15,7 @@
         "clippy.go",
         "compiler.go",
         "coverage.go",
+        "image.go",
         "library.go",
         "prebuilt.go",
         "proc_macro.go",
@@ -33,6 +34,7 @@
         "clippy_test.go",
         "compiler_test.go",
         "coverage_test.go",
+        "image_test.go",
         "library_test.go",
         "project_json_test.go",
         "protobuf_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index c181d67..e9da6fa 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -58,6 +58,7 @@
 				entries.AddStrings("LOCAL_PROC_MACRO_LIBRARIES", mod.Properties.AndroidMkProcMacroLibs...)
 				entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...)
 				entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
+				entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType)
 			},
 		},
 	}
diff --git a/rust/builder.go b/rust/builder.go
index 6079e30..8ec2da2 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -189,6 +189,7 @@
 	implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
 	implicits = append(implicits, deps.StaticLibs...)
 	implicits = append(implicits, deps.SharedLibs...)
+	implicits = append(implicits, deps.srcProviderFiles...)
 
 	if deps.CrtBegin.Valid() {
 		implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
diff --git a/rust/image.go b/rust/image.go
new file mode 100644
index 0000000..4951d2b
--- /dev/null
+++ b/rust/image.go
@@ -0,0 +1,153 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"strings"
+
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+var _ android.ImageInterface = (*Module)(nil)
+
+func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return false
+}
+
+func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	return mod.Properties.CoreVariantNeeded
+}
+
+func (mod *Module) RamdiskVariantNeeded(android.BaseModuleContext) bool {
+	return mod.InRamdisk()
+}
+
+func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
+	return mod.InRecovery()
+}
+
+func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string {
+	return mod.Properties.ExtraVariants
+}
+
+func (ctx *moduleContext) ProductSpecific() bool {
+	return false
+}
+
+func (mod *Module) InRecovery() bool {
+	// TODO(b/165791368)
+	return false
+}
+
+func (mod *Module) OnlyInRamdisk() bool {
+	// TODO(b/165791368)
+	return false
+}
+
+func (mod *Module) OnlyInRecovery() bool {
+	// TODO(b/165791368)
+	return false
+}
+
+func (mod *Module) OnlyInVendorRamdisk() bool {
+	return false
+}
+
+// Returns true when this module is configured to have core and vendor variants.
+func (mod *Module) HasVendorVariant() bool {
+	return mod.IsVndk() || Bool(mod.VendorProperties.Vendor_available)
+}
+
+func (c *Module) VendorAvailable() bool {
+	return Bool(c.VendorProperties.Vendor_available)
+}
+
+func (c *Module) InProduct() bool {
+	return false
+}
+
+func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
+	m := module.(*Module)
+	if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
+		m.Properties.ImageVariationPrefix = cc.VendorVariationPrefix
+		m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix)
+
+		// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
+		// Hide other vendor variants to avoid collision.
+		vndkVersion := ctx.DeviceConfig().VndkVersion()
+		if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
+			m.Properties.HideFromMake = true
+			m.SkipInstall()
+		}
+	}
+}
+
+func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
+	vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+	platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
+
+	// Rust does not support installing to the product image yet.
+	if mod.VendorProperties.Product_available != nil {
+		mctx.PropertyErrorf("product_available",
+			"Rust modules do not yet support being available to the product image")
+	} else if mctx.ProductSpecific() {
+		mctx.PropertyErrorf("product_specific",
+			"Rust modules do not yet support installing to the product image.")
+	} else if mod.VendorProperties.Double_loadable != nil {
+		mctx.PropertyErrorf("double_loadable",
+			"Rust modules do not yet support double loading")
+	}
+
+	coreVariantNeeded := true
+	var vendorVariants []string
+
+	if mod.VendorProperties.Vendor_available != nil {
+		if vendorSpecific {
+			mctx.PropertyErrorf("vendor_available",
+				"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
+		}
+
+		if lib, ok := mod.compiler.(libraryInterface); ok {
+			// Explicitly disallow rust_ffi variants which produce shared libraries from setting vendor_available.
+			// Vendor variants do not produce an error for dylibs, rlibs with dylib-std linkage are disabled in the respective library
+			// mutators until support is added.
+			//
+			// We can't check shared() here because image mutator is called before the library mutator, so we need to
+			// check buildShared()
+			if lib.buildShared() {
+				mctx.PropertyErrorf("vendor_available",
+					"vendor_available can only be set for rust_ffi_static modules.")
+			} else if Bool(mod.VendorProperties.Vendor_available) == true {
+				vendorVariants = append(vendorVariants, platformVndkVersion)
+			}
+		}
+	}
+
+	if vendorSpecific {
+		if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && !lib.static()) {
+			mctx.ModuleErrorf("Rust vendor specific modules are currently only supported for rust_ffi_static modules.")
+		} else {
+			coreVariantNeeded = false
+			vendorVariants = append(vendorVariants, platformVndkVersion)
+		}
+	}
+
+	mod.Properties.CoreVariantNeeded = coreVariantNeeded
+	for _, variant := range android.FirstUniqueStrings(vendorVariants) {
+		mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, cc.VendorVariationPrefix+variant)
+	}
+
+}
diff --git a/rust/image_test.go b/rust/image_test.go
new file mode 100644
index 0000000..025b0fd
--- /dev/null
+++ b/rust/image_test.go
@@ -0,0 +1,73 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+// Test that cc_binaries can link against rust_ffi_static libraries.
+func TestVendorLinkage(t *testing.T) {
+	ctx := testRust(t, `
+			cc_binary {
+				name: "fizz_vendor",
+				static_libs: ["libfoo_vendor"],
+				soc_specific: true,
+			}
+			rust_ffi_static {
+				name: "libfoo_vendor",
+				crate_name: "foo",
+				srcs: ["foo.rs"],
+				vendor_available: true,
+			}
+		`)
+
+	vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_arm64_armv8-a").Module().(*cc.Module)
+
+	if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
+		t.Errorf("vendorBinary should have a dependency on libfoo_vendor")
+	}
+}
+
+// Test that shared libraries cannot be made vendor available until proper support is added.
+func TestForbiddenVendorLinkage(t *testing.T) {
+	testRustError(t, "vendor_available can only be set for rust_ffi_static modules", `
+		rust_ffi_shared {
+			name: "libfoo_vendor",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+			vendor_available: true,
+		}
+	`)
+	testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
+		rust_ffi {
+			name: "libfoo_vendor",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+			vendor: true,
+		}
+	`)
+	testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
+		rust_library {
+			name: "libfoo_vendor",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+			vendor: true,
+		}
+	`)
+}
diff --git a/rust/library.go b/rust/library.go
index 9d731e6..4ac52b4 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -433,6 +433,7 @@
 	if library.sourceProvider != nil {
 		// Assume the first source from the source provider is the library entry point.
 		srcPath = library.sourceProvider.Srcs()[0]
+		deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
 	} else {
 		srcPath, _ = srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
 	}
@@ -604,6 +605,11 @@
 			v.(*Module).compiler.(libraryInterface).setRlib()
 		case dylibVariation:
 			v.(*Module).compiler.(libraryInterface).setDylib()
+			if v.(*Module).ModuleBase.ImageVariation().Variation != android.CoreVariation {
+				// TODO(b/165791368)
+				// Disable dylib non-core variations until we support these.
+				v.(*Module).Disable()
+			}
 		case "source":
 			v.(*Module).compiler.(libraryInterface).setSource()
 			// The source variant does not produce any library.
@@ -640,6 +646,12 @@
 				dylib := modules[1].(*Module)
 				rlib.compiler.(libraryInterface).setRlibStd()
 				dylib.compiler.(libraryInterface).setDylibStd()
+				if dylib.ModuleBase.ImageVariation().Variation != android.CoreVariation {
+					// TODO(b/165791368)
+					// Disable rlibs that link against dylib-std on non-core variations until non-core dylib
+					// variants are properly supported.
+					dylib.Disable()
+				}
 				rlib.Properties.SubName += RlibStdlibSuffix
 				dylib.Properties.SubName += DylibStdlibSuffix
 			}
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 0e79089..4fba34f 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -46,7 +46,7 @@
 var _ SourceProvider = (*protobufDecorator)(nil)
 
 type ProtobufProperties struct {
-	// List of realtive paths to proto files that will be used to generate the source
+	// List of relative paths to proto files that will be used to generate the source
 	Protos []string `android:"path,arch_variant"`
 
 	// List of additional flags to pass to aprotoc
@@ -80,6 +80,10 @@
 
 	protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
 
+	if len(protoFiles) == 0 {
+		ctx.PropertyErrorf("protos", "at least one protobuf must be defined.")
+	}
+
 	// Add exported dependency include paths
 	for _, include := range deps.depIncludePaths {
 		protoFlags.Flags = append(protoFlags.Flags, "-I"+include.String())
@@ -91,7 +95,7 @@
 	stemFile := android.PathForModuleOut(ctx, "mod_"+stem+".rs")
 
 	// stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
-	outputs := android.WritablePaths{stemFile}
+	var outputs android.WritablePaths
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 	for _, protoFile := range protoFiles {
@@ -112,14 +116,12 @@
 		outputs = append(outputs, ruleOutputs...)
 	}
 
-	rule.Command().
-		Implicits(outputs.Paths()).
-		Text("printf '" + proto.genModFileContents(ctx, protoNames) + "' >").
-		Output(stemFile)
+	android.WriteFileRule(ctx, stemFile, proto.genModFileContents(ctx, protoNames))
 
 	rule.Build("protoc_"+ctx.ModuleName(), "protoc "+ctx.ModuleName())
 
-	proto.BaseSourceProvider.OutputFiles = outputs.Paths()
+	// stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
+	proto.BaseSourceProvider.OutputFiles = append(android.Paths{stemFile}, outputs.Paths()...)
 
 	// mod_stem.rs is the entry-point for our library modules, so this is what we return.
 	return stemFile
@@ -145,7 +147,7 @@
 			"}")
 	}
 
-	return strings.Join(lines, "\\n")
+	return strings.Join(lines, "\n")
 }
 
 func (proto *protobufDecorator) setupPlugin(ctx ModuleContext, protoFlags android.ProtoFlags, outDir android.ModuleOutPath) (android.Paths, android.ProtoFlags) {
diff --git a/rust/rust.go b/rust/rust.go
index 38caad3..3d70121 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -65,7 +65,16 @@
 	AndroidMkSharedLibs    []string
 	AndroidMkStaticLibs    []string
 
-	SubName string `blueprint:"mutated"`
+	ImageVariationPrefix string `blueprint:"mutated"`
+	VndkVersion          string `blueprint:"mutated"`
+	SubName              string `blueprint:"mutated"`
+
+	// Set by imageMutator
+	CoreVariantNeeded bool     `blueprint:"mutated"`
+	ExtraVariants     []string `blueprint:"mutated"`
+
+	// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+	Min_sdk_version *string
 
 	PreventInstall bool
 	HideFromMake   bool
@@ -76,11 +85,15 @@
 	android.DefaultableModuleBase
 	android.ApexModuleBase
 
+	VendorProperties cc.VendorProperties
+
 	Properties BaseProperties
 
 	hod      android.HostOrDeviceSupported
 	multilib android.Multilib
 
+	makeLinkType string
+
 	compiler         compiler
 	coverage         *coverage
 	clippy           *clippy
@@ -109,33 +122,6 @@
 	}
 }
 
-var _ android.ImageInterface = (*Module)(nil)
-
-func (mod *Module) ImageMutatorBegin(ctx android.BaseModuleContext) {}
-
-func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	return true
-}
-
-func (mod *Module) RamdiskVariantNeeded(android.BaseModuleContext) bool {
-	return mod.InRamdisk()
-}
-
-func (mod *Module) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool {
-	return mod.InVendorRamdisk()
-}
-
-func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
-	return mod.InRecovery()
-}
-
-func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string {
-	return nil
-}
-
-func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
-}
-
 func (mod *Module) SelectedStl() string {
 	return ""
 }
@@ -176,24 +162,18 @@
 	panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))
 }
 
-func (mod *Module) OnlyInRamdisk() bool {
-	return false
-}
-
-func (mod *Module) OnlyInVendorRamdisk() bool {
-	return false
-}
-
-func (mod *Module) OnlyInRecovery() bool {
-	return false
-}
-
 func (mod *Module) UseSdk() bool {
 	return false
 }
 
+// Returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
+// "product" and "vendor" variant modules return true for this function.
+// When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
+// "soc_specific: true" and more vendor installed modules are included here.
+// When PRODUCT_PRODUCT_VNDK_VERSION is set, product variants of "vendor_available: true" or
+// "product_specific: true" modules are included here.
 func (mod *Module) UseVndk() bool {
-	return false
+	return mod.Properties.VndkVersion != ""
 }
 
 func (mod *Module) MustUseVendorVariant() bool {
@@ -201,10 +181,15 @@
 }
 
 func (mod *Module) IsVndk() bool {
+	// TODO(b/165791368)
 	return false
 }
 
-func (mod *Module) HasVendorVariant() bool {
+func (mod *Module) IsVndkExt() bool {
+	return false
+}
+
+func (c *Module) IsVndkPrivate(config android.Config) bool {
 	return false
 }
 
@@ -260,7 +245,8 @@
 	CrtEnd   android.OptionalPath
 
 	// Paths to generated source files
-	SrcDeps android.Paths
+	SrcDeps          android.Paths
+	srcProviderFiles android.Paths
 }
 
 type RustLibraries []RustLibrary
@@ -376,6 +362,7 @@
 	module.AddProperties(props...)
 	module.AddProperties(
 		&BaseProperties{},
+		&cc.VendorProperties{},
 		&BindgenProperties{},
 		&BaseCompilerProperties{},
 		&BinaryCompilerProperties{},
@@ -472,11 +459,6 @@
 	return mod.outputFile
 }
 
-func (mod *Module) InRecovery() bool {
-	// For now, Rust has no notion of the recovery image
-	return false
-}
-
 func (mod *Module) CoverageFiles() android.Paths {
 	if mod.compiler != nil {
 		if !mod.compiler.nativeCoverage() {
@@ -496,6 +478,7 @@
 
 func (mod *Module) Init() android.Module {
 	mod.AddProperties(&mod.Properties)
+	mod.AddProperties(&mod.VendorProperties)
 
 	if mod.compiler != nil {
 		mod.AddProperties(mod.compiler.compilerProps()...)
@@ -615,6 +598,12 @@
 	}
 
 	toolchain := mod.toolchain(ctx)
+	mod.makeLinkType = cc.GetMakeLinkType(actx, mod)
+
+	// Differentiate static libraries that are vendor available
+	if mod.UseVndk() {
+		mod.Properties.SubName += ".vendor"
+	}
 
 	if !toolchain.Supported() {
 		// This toolchain's unsupported, there's nothing to do for this mod.
@@ -956,10 +945,6 @@
 
 	deps := mod.deps(ctx)
 	var commonDepVariations []blueprint.Variation
-	if !mod.Host() {
-		commonDepVariations = append(commonDepVariations,
-			blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
-	}
 
 	stdLinkage := "dylib-std"
 	if mod.compiler.stdLinkage(ctx) == RlibLinkage {
@@ -1076,7 +1061,29 @@
 
 var _ android.ApexModule = (*Module)(nil)
 
+func (mod *Module) minSdkVersion() string {
+	return String(mod.Properties.Min_sdk_version)
+}
+
 func (mod *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
+	minSdkVersion := mod.minSdkVersion()
+	if minSdkVersion == "apex_inherit" {
+		return nil
+	}
+	if minSdkVersion == "" {
+		return fmt.Errorf("min_sdk_version is not specificed")
+	}
+
+	// Not using nativeApiLevelFromUser because the context here is not
+	// necessarily a native context.
+	ver, err := android.ApiLevelFromUser(ctx, minSdkVersion)
+	if err != nil {
+		return err
+	}
+
+	if ver.GreaterThan(sdkVersion) {
+		return fmt.Errorf("newer SDK(%v)", ver)
+	}
 	return nil
 }
 
diff --git a/rust/testing.go b/rust/testing.go
index a8496d9..963a4ea 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -78,6 +78,7 @@
 			nocrt: true,
 			system_shared_libs: [],
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
+			min_sdk_version: "29",
 		}
 		cc_library {
 			name: "libprotobuf-cpp-full",
@@ -92,9 +93,11 @@
 			srcs: ["foo.rs"],
 			no_stdlibs: true,
 			host_supported: true,
+			vendor_available: true,
                         native_coverage: false,
 			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
+			min_sdk_version: "29",
 		}
 		rust_library {
 			name: "libtest",
@@ -102,9 +105,11 @@
 			srcs: ["foo.rs"],
 			no_stdlibs: true,
 			host_supported: true,
+			vendor_available: true,
                         native_coverage: false,
 			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
+			min_sdk_version: "29",
 		}
 		rust_library {
 			name: "libprotobuf",
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index d9c2266..4f2d645 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -78,7 +78,10 @@
 	bazelEnv["PACKAGE_NINJA"] = config.KatiPackageNinjaFile()
 	bazelEnv["SOONG_NINJA"] = config.SoongNinjaFile()
 
+	// NOTE: When Bazel is used, config.DistDir() is rigged to return a fake distdir under config.OutDir()
+	// This is to ensure that Bazel can actually write there. See config.go for more details.
 	bazelEnv["DIST_DIR"] = config.DistDir()
+
 	bazelEnv["SHELL"] = "/bin/bash"
 
 	// `tools/bazel` is the default entry point for executing Bazel in the AOSP
@@ -189,13 +192,14 @@
 	// currently hardcoded as ninja_build.output_root.
 	bazelNinjaBuildOutputRoot := filepath.Join(outputBasePath, "..", "out")
 
-	ctx.Println("Creating output symlinks..")
-	symlinkOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".")
+	ctx.Println("Populating output directory...")
+	populateOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".")
 }
 
 // For all files F recursively under rootPath/relativePath, creates symlinks
 // such that OutDir/F resolves to rootPath/F via symlinks.
-func symlinkOutdir(ctx Context, config Config, rootPath string, relativePath string) {
+// NOTE: For distdir paths we rename files instead of creating symlinks, so that the distdir is independent.
+func populateOutdir(ctx Context, config Config, rootPath string, relativePath string) {
 	destDir := filepath.Join(rootPath, relativePath)
 	os.MkdirAll(destDir, 0755)
 	files, err := ioutil.ReadDir(destDir)
@@ -220,7 +224,7 @@
 		if srcLstatErr == nil {
 			if srcLstatResult.IsDir() && destLstatResult.IsDir() {
 				// src and dest are both existing dirs - recurse on the dest dir contents...
-				symlinkOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
+				populateOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
 			} else {
 				// Ignore other pre-existing src files (could be pre-existing files, directories, symlinks, ...)
 				// This can arise for files which are generated under OutDir outside of soong_build, such as .bootstrap files.
@@ -231,9 +235,17 @@
 				ctx.Fatalf("Unable to Lstat src %s: %s", srcPath, srcLstatErr)
 			}
 
-			// src does not exist, so try to create a src -> dest symlink (i.e. a Soong path -> Bazel path symlink)
-			if symlinkErr := os.Symlink(destPath, srcPath); symlinkErr != nil {
-				ctx.Fatalf("Unable to create symlink %s -> %s due to error %s", srcPath, destPath, symlinkErr)
+			if strings.Contains(destDir, config.DistDir()) {
+				// We need to make a "real" file/dir instead of making a symlink (because the distdir can't have symlinks)
+				// Rename instead of copy in order to save disk space.
+				if err := os.Rename(destPath, srcPath); err != nil {
+					ctx.Fatalf("Unable to rename %s -> %s due to error %s", srcPath, destPath, err)
+				}
+			} else {
+				// src does not exist, so try to create a src -> dest symlink (i.e. a Soong path -> Bazel path symlink)
+				if err := os.Symlink(destPath, srcPath); err != nil {
+					ctx.Fatalf("Unable to create symlink %s -> %s due to error %s", srcPath, destPath, err)
+				}
 			}
 		}
 	}
diff --git a/ui/build/build.go b/ui/build/build.go
index e8f0fc4..926da31 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -302,7 +302,7 @@
 	}
 
 	subDir := filepath.Join(subDirs...)
-	destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+	destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
 
 	if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
 		ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
@@ -321,7 +321,7 @@
 	}
 
 	subDir := filepath.Join(subDirs...)
-	destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+	destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
 
 	if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
 		ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
diff --git a/ui/build/config.go b/ui/build/config.go
index 72ae3fe..ecca4de 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -65,6 +65,12 @@
 	brokenNinjaEnvVars []string
 
 	pathReplaced bool
+
+	useBazel bool
+
+	// During Bazel execution, Bazel cannot write outside OUT_DIR.
+	// So if DIST_DIR is set to an external dir (outside of OUT_DIR), we need to rig it temporarily and then migrate files at the end of the build.
+	riggedDistDirForBazel string
 }
 
 const srcDirFileCheck = "build/soong/root.bp"
@@ -221,7 +227,7 @@
 		ctx.Fatalln("Directory names containing spaces are not supported")
 	}
 
-	if distDir := ret.DistDir(); strings.ContainsRune(distDir, ' ') {
+	if distDir := ret.RealDistDir(); strings.ContainsRune(distDir, ' ') {
 		ctx.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:")
 		ctx.Println()
 		ctx.Printf("%q\n", distDir)
@@ -279,12 +285,22 @@
 	if err := os.RemoveAll(bpd); err != nil {
 		ctx.Fatalf("Unable to remove bazel profile directory %q: %v", bpd, err)
 	}
+
+	ret.useBazel = ret.environ.IsEnvTrue("USE_BAZEL")
+
 	if ret.UseBazel() {
 		if err := os.MkdirAll(bpd, 0777); err != nil {
 			ctx.Fatalf("Failed to create bazel profile directory %q: %v", bpd, err)
 		}
 	}
 
+	if ret.UseBazel() {
+		ret.riggedDistDirForBazel = filepath.Join(ret.OutDir(), "dist")
+	} else {
+		// Not rigged
+		ret.riggedDistDirForBazel = ret.distDir
+	}
+
 	c := Config{ret}
 	storeConfigMetrics(ctx, c)
 	return c
@@ -697,6 +713,14 @@
 }
 
 func (c *configImpl) DistDir() string {
+	if c.UseBazel() {
+		return c.riggedDistDirForBazel
+	} else {
+		return c.distDir
+	}
+}
+
+func (c *configImpl) RealDistDir() string {
 	return c.distDir
 }
 
@@ -863,13 +887,7 @@
 }
 
 func (c *configImpl) UseBazel() bool {
-	if v, ok := c.environ.Get("USE_BAZEL"); ok {
-		v = strings.TrimSpace(v)
-		if v != "" && v != "false" {
-			return true
-		}
-	}
-	return false
+	return c.useBazel
 }
 
 func (c *configImpl) StartRBE() bool {
@@ -886,14 +904,14 @@
 	return true
 }
 
-func (c *configImpl) logDir() string {
+func (c *configImpl) rbeLogDir() string {
 	for _, f := range []string{"RBE_log_dir", "FLAG_log_dir"} {
 		if v, ok := c.environ.Get(f); ok {
 			return v
 		}
 	}
 	if c.Dist() {
-		return filepath.Join(c.DistDir(), "logs")
+		return c.LogsDir()
 	}
 	return c.OutDir()
 }
@@ -904,7 +922,7 @@
 			return v
 		}
 	}
-	return c.logDir()
+	return c.rbeLogDir()
 }
 
 func (c *configImpl) rbeLogPath() string {
@@ -913,7 +931,7 @@
 			return v
 		}
 	}
-	return fmt.Sprintf("text://%v/reproxy_log.txt", c.logDir())
+	return fmt.Sprintf("text://%v/reproxy_log.txt", c.rbeLogDir())
 }
 
 func (c *configImpl) rbeExecRoot() string {
@@ -1128,7 +1146,8 @@
 // is <dist_dir>/logs.
 func (c *configImpl) LogsDir() string {
 	if c.Dist() {
-		return filepath.Join(c.DistDir(), "logs")
+		// Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files
+		return filepath.Join(c.RealDistDir(), "logs")
 	}
 	return c.OutDir()
 }
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 64f3d4c..d9c33f6 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -74,7 +74,7 @@
 func getRBEVars(ctx Context, config Config) map[string]string {
 	vars := map[string]string{
 		"RBE_log_path":   config.rbeLogPath(),
-		"RBE_log_dir":    config.logDir(),
+		"RBE_log_dir":    config.rbeLogDir(),
 		"RBE_re_proxy":   config.rbeReproxy(),
 		"RBE_exec_root":  config.rbeExecRoot(),
 		"RBE_output_dir": config.rbeStatsOutputDir(),
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 4f30136..55ca800 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -40,13 +40,42 @@
 	tmpDir = ioutil.TempDir
 )
 
+// pruneMetricsFiles iterates the list of paths, checking if a path exist.
+// If a path is a file, it is added to the return list. If the path is a
+// directory, a recursive call is made to add the children files of the
+// path.
+func pruneMetricsFiles(paths []string) []string {
+	var metricsFiles []string
+	for _, p := range paths {
+		fi, err := os.Stat(p)
+		// Some paths passed may not exist. For example, build errors protobuf
+		// file may not exist since the build was successful.
+		if err != nil {
+			continue
+		}
+
+		if fi.IsDir() {
+			if l, err := ioutil.ReadDir(p); err == nil {
+				files := make([]string, 0, len(l))
+				for _, fi := range l {
+					files = append(files, filepath.Join(p, fi.Name()))
+				}
+				metricsFiles = append(metricsFiles, pruneMetricsFiles(files)...)
+			}
+		} else {
+			metricsFiles = append(metricsFiles, p)
+		}
+	}
+	return metricsFiles
+}
+
 // UploadMetrics uploads a set of metrics files to a server for analysis. An
 // uploader full path is specified in ANDROID_ENABLE_METRICS_UPLOAD environment
 // variable in order to upload the set of metrics files. The metrics files are
 // first copied to a temporary directory and the uploader is then executed in
 // the background to allow the user/system to continue working. Soong communicates
 // to the uploader through the upload_proto raw protobuf file.
-func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, files ...string) {
+func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, paths ...string) {
 	ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
 	defer ctx.EndTrace()
 
@@ -56,15 +85,8 @@
 		return
 	}
 
-	// Some files passed in to this function may not exist. For example,
-	// build errors protobuf file may not exist since the build was successful.
-	var metricsFiles []string
-	for _, f := range files {
-		if _, err := os.Stat(f); err == nil {
-			metricsFiles = append(metricsFiles, f)
-		}
-	}
-
+	// Several of the files might be directories.
+	metricsFiles := pruneMetricsFiles(paths)
 	if len(metricsFiles) == 0 {
 		return
 	}
diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go
index 768b031..b740c11 100644
--- a/ui/build/upload_test.go
+++ b/ui/build/upload_test.go
@@ -19,6 +19,8 @@
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"reflect"
+	"sort"
 	"strconv"
 	"strings"
 	"testing"
@@ -27,6 +29,49 @@
 	"android/soong/ui/logger"
 )
 
+func TestPruneMetricsFiles(t *testing.T) {
+	rootDir := t.TempDir()
+
+	dirs := []string{
+		filepath.Join(rootDir, "d1"),
+		filepath.Join(rootDir, "d1", "d2"),
+		filepath.Join(rootDir, "d1", "d2", "d3"),
+	}
+
+	files := []string{
+		filepath.Join(rootDir, "d1", "f1"),
+		filepath.Join(rootDir, "d1", "d2", "f1"),
+		filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
+	}
+
+	for _, d := range dirs {
+		if err := os.MkdirAll(d, 0777); err != nil {
+			t.Fatalf("got %v, expecting nil error for making directory %q", err, d)
+		}
+	}
+
+	for _, f := range files {
+		if err := ioutil.WriteFile(f, []byte{}, 0777); err != nil {
+			t.Fatalf("got %v, expecting nil error on writing file %q", err, f)
+		}
+	}
+
+	want := []string{
+		filepath.Join(rootDir, "d1", "f1"),
+		filepath.Join(rootDir, "d1", "d2", "f1"),
+		filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
+	}
+
+	got := pruneMetricsFiles([]string{rootDir})
+
+	sort.Strings(got)
+	sort.Strings(want)
+
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("got %q, want %q after pruning metrics files", got, want)
+	}
+}
+
 func TestUploadMetrics(t *testing.T) {
 	ctx := testContext()
 	tests := []struct {