Merge "Remove bp2build deps mutator"
diff --git a/android/arch.go b/android/arch.go
index cc70eee..583793e 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -15,13 +15,14 @@
 package android
 
 import (
-	"android/soong/bazel"
 	"encoding"
 	"fmt"
 	"reflect"
 	"runtime"
 	"strings"
 
+	"android/soong/bazel"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
@@ -290,28 +291,6 @@
 	return NoOsType
 }
 
-// BuildOs returns the OsType for the OS that the build is running on.
-var BuildOs = func() OsType {
-	switch runtime.GOOS {
-	case "linux":
-		return Linux
-	case "darwin":
-		return Darwin
-	default:
-		panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
-	}
-}()
-
-// BuildArch returns the ArchType for the CPU that the build is running on.
-var BuildArch = func() ArchType {
-	switch runtime.GOARCH {
-	case "amd64":
-		return X86_64
-	default:
-		panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
-	}
-}()
-
 var (
 	// osTypeList contains a list of all the supported OsTypes, including ones not supported
 	// by the current build host or the target device.
@@ -336,8 +315,6 @@
 	// Android is the OS for target devices that run all of Android, including the Linux kernel
 	// and the Bionic libc runtime.
 	Android = newOsType("android", Device, false, Arm, Arm64, X86, X86_64)
-	// Fuchsia is the OS for target devices that run Fuchsia.
-	Fuchsia = newOsType("fuchsia", Device, false, Arm64, X86_64)
 
 	// CommonOS is a pseudo OSType for a common OS variant, which is OsType agnostic and which
 	// has dependencies on all the OS variants.
@@ -1397,6 +1374,31 @@
 	}
 }
 
+// determineBuildOS stores the OS and architecture used for host targets used during the build into
+// config based on the runtime OS and architecture determined by Go.
+func determineBuildOS(config *config) {
+	config.BuildOS = func() OsType {
+		switch runtime.GOOS {
+		case "linux":
+			return Linux
+		case "darwin":
+			return Darwin
+		default:
+			panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
+		}
+	}()
+
+	config.BuildArch = func() ArchType {
+		switch runtime.GOARCH {
+		case "amd64":
+			return X86_64
+		default:
+			panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
+		}
+	}()
+
+}
+
 // Convert the arch product variables into a list of targets for each OsType.
 func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) {
 	variables := config.productVariables
@@ -1430,9 +1432,9 @@
 		hostCross := false
 		if os.Class == Host {
 			var osSupported bool
-			if os == BuildOs {
+			if os == config.BuildOS {
 				osSupported = true
-			} else if BuildOs.Linux() && os.Linux() {
+			} else if config.BuildOS.Linux() && os.Linux() {
 				// LinuxBionic and Linux are compatible
 				osSupported = true
 			} else {
@@ -1470,11 +1472,11 @@
 	}
 
 	// The primary host target, which must always exist.
-	addTarget(BuildOs, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
+	addTarget(config.BuildOS, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 
 	// An optional secondary host target.
 	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
-		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
+		addTarget(config.BuildOS, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 	}
 
 	// Optional cross-compiled host targets, generally Windows.
@@ -1499,13 +1501,8 @@
 
 	// Optional device targets
 	if variables.DeviceArch != nil && *variables.DeviceArch != "" {
-		var target = Android
-		if Bool(variables.Fuchsia) {
-			target = Fuchsia
-		}
-
 		// The primary device target.
-		addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant,
+		addTarget(Android, *variables.DeviceArch, variables.DeviceArchVariant,
 			variables.DeviceCpuVariant, variables.DeviceAbi, NativeBridgeDisabled, nil, nil)
 
 		// An optional secondary device target.
diff --git a/android/arch_test.go b/android/arch_test.go
index 3aa4779..2a2fd45 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -473,3 +473,164 @@
 		})
 	}
 }
+
+type testArchPropertiesModule struct {
+	ModuleBase
+	properties struct {
+		A []string `android:"arch_variant"`
+	}
+}
+
+func (testArchPropertiesModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+func TestArchProperties(t *testing.T) {
+	bp := `
+		module {
+			name: "foo",
+			a: ["root"],
+			arch: {
+				arm: {
+					a:  ["arm"],
+					armv7_a_neon: { a: ["armv7_a_neon"] },
+				},
+				arm64: {
+					a:  ["arm64"],
+					armv8_a: { a: ["armv8_a"] },
+				},
+				x86: { a:  ["x86"] },
+				x86_64: { a:  ["x86_64"] },
+			},
+			multilib: {
+				lib32: { a:  ["lib32"] },
+				lib64: { a:  ["lib64"] },
+			},
+			target: {
+				bionic: { a:  ["bionic"] },
+				host: { a: ["host"] },
+				android: { a:  ["android"] },
+				linux_bionic: { a:  ["linux_bionic"] },
+				linux: { a:  ["linux"] },
+				linux_glibc: { a:  ["linux_glibc"] },
+				windows: { a:  ["windows"], enabled: true },
+				darwin: { a:  ["darwin"] },
+				not_windows: { a:  ["not_windows"] },
+				android32: { a:  ["android32"] },
+				android64: { a:  ["android64"] },
+				android_arm: { a:  ["android_arm"] },
+				android_arm64: { a:  ["android_arm64"] },
+				linux_x86: { a:  ["linux_x86"] },
+				linux_x86_64: { a:  ["linux_x86_64"] },
+				linux_glibc_x86: { a:  ["linux_glibc_x86"] },
+				linux_glibc_x86_64: { a:  ["linux_glibc_x86_64"] },
+				darwin_x86_64: { a:  ["darwin_x86_64"] },
+				windows_x86: { a:  ["windows_x86"] },
+				windows_x86_64: { a:  ["windows_x86_64"] },
+			},
+		}
+	`
+
+	type result struct {
+		module   string
+		variant  string
+		property []string
+	}
+
+	testCases := []struct {
+		name     string
+		goOS     string
+		preparer FixturePreparer
+		results  []result
+	}{
+		{
+			name: "default",
+			results: []result{
+				{
+					module:   "foo",
+					variant:  "android_arm64_armv8-a",
+					property: []string{"root", "linux", "bionic", "android", "android64", "arm64", "armv8_a", "lib64", "android_arm64"},
+				},
+				{
+					module:   "foo",
+					variant:  "android_arm_armv7-a-neon",
+					property: []string{"root", "linux", "bionic", "android", "android64", "arm", "armv7_a_neon", "lib32", "android_arm"},
+				},
+			},
+		},
+		{
+			name: "linux",
+			goOS: "linux",
+			results: []result{
+				{
+					module:   "foo",
+					variant:  "linux_glibc_x86_64",
+					property: []string{"root", "host", "linux", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"},
+				},
+				{
+					module:   "foo",
+					variant:  "linux_glibc_x86",
+					property: []string{"root", "host", "linux", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"},
+				},
+			},
+		},
+		{
+			name: "windows",
+			goOS: "linux",
+			preparer: FixtureModifyConfig(func(config Config) {
+				config.Targets[Windows] = []Target{
+					{Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true},
+					{Windows, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", true},
+				}
+			}),
+			results: []result{
+				{
+					module:   "foo",
+					variant:  "windows_x86_64",
+					property: []string{"root", "host", "windows", "x86_64", "lib64", "windows_x86_64"},
+				},
+				{
+					module:   "foo",
+					variant:  "windows_x86",
+					property: []string{"root", "host", "windows", "x86", "lib32", "windows_x86"},
+				},
+			},
+		},
+		{
+			name: "darwin",
+			goOS: "darwin",
+			results: []result{
+				{
+					module:   "foo",
+					variant:  "darwin_x86_64",
+					property: []string{"root", "host", "darwin", "not_windows", "x86_64", "lib64", "darwin_x86_64"},
+				},
+			},
+		},
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.goOS != "" && tt.goOS != runtime.GOOS {
+				t.Skipf("test requires runtime.GOOS==%s, got %s", tt.goOS, runtime.GOOS)
+			}
+			result := GroupFixturePreparers(
+				PrepareForTestWithArchMutator,
+				OptionalFixturePreparer(tt.preparer),
+				FixtureRegisterWithContext(func(ctx RegistrationContext) {
+					ctx.RegisterModuleType("module", func() Module {
+						module := &testArchPropertiesModule{}
+						module.AddProperties(&module.properties)
+						InitAndroidArchModule(module, HostAndDeviceDefault, MultilibBoth)
+						return module
+					})
+				}),
+			).RunTestWithBp(t, bp)
+
+			for _, want := range tt.results {
+				t.Run(want.module+"_"+want.variant, func(t *testing.T) {
+					got := result.ModuleForTests(want.module, want.variant).Module().(*testArchPropertiesModule).properties.A
+					AssertArrayString(t, "arch mutator property", want.property, got)
+				})
+			}
+		})
+	}
+}
diff --git a/android/bazel.go b/android/bazel.go
index 46212dc..d40e650 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -140,6 +140,7 @@
 
 		"prebuilts/sdk":/* recursive = */ false,
 		"prebuilts/sdk/tools":/* recursive = */ false,
+		"packages/apps/Music":/* recursive = */ false,
 	}
 
 	// Configure modules in these directories to enable bp2build_available: true or false by default.
diff --git a/android/config.go b/android/config.go
index 396b1a6..871986c 100644
--- a/android/config.go
+++ b/android/config.go
@@ -108,6 +108,12 @@
 
 	ProductVariablesFileName string
 
+	// BuildOS stores the OsType for the OS that the build is running on.
+	BuildOS OsType
+
+	// BuildArch stores the ArchType for the CPU that the build is running on.
+	BuildArch ArchType
+
 	Targets                  map[OsType][]Target
 	BuildOSTarget            Target // the Target for tools run on the build machine
 	BuildOSCommonTarget      Target // the Target for common (java) tools run on the build machine
@@ -326,41 +332,28 @@
 	return Config{config}
 }
 
-func fuchsiaTargets() map[OsType][]Target {
-	return map[OsType][]Target{
-		Fuchsia: {
-			{Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
-		},
-		BuildOs: {
-			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
-		},
-	}
-}
-
-var PrepareForTestSetDeviceToFuchsia = FixtureModifyConfig(func(config Config) {
-	config.Targets = fuchsiaTargets()
-})
-
 func modifyTestConfigToSupportArchMutator(testConfig Config) {
 	config := testConfig.config
 
+	determineBuildOS(config)
+
 	config.Targets = map[OsType][]Target{
 		Android: []Target{
 			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
 			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
 		},
-		BuildOs: []Target{
-			{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
-			{BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
+		config.BuildOS: []Target{
+			{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
+			{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
 		},
 	}
 
 	if runtime.GOOS == "darwin" {
-		config.Targets[BuildOs] = config.Targets[BuildOs][:1]
+		config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
 	}
 
-	config.BuildOSTarget = config.Targets[BuildOs][0]
-	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
+	config.BuildOSTarget = config.Targets[config.BuildOS][0]
+	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
 	config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
 	config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
 	config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
@@ -439,6 +432,8 @@
 		config.katiEnabled = true
 	}
 
+	determineBuildOS(config)
+
 	// Sets up the map of target OSes to the finer grained compilation targets
 	// that are configured from the product variables.
 	targets, err := decodeTargetProductVariables(config)
@@ -476,8 +471,8 @@
 	config.Targets = targets
 
 	// Compilation targets for host tools.
-	config.BuildOSTarget = config.Targets[BuildOs][0]
-	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
+	config.BuildOSTarget = config.Targets[config.BuildOS][0]
+	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
 
 	// Compilation targets for Android.
 	if len(config.Targets[Android]) > 0 {
@@ -837,10 +832,6 @@
 	return Bool(c.productVariables.Skip_boot_jars_check)
 }
 
-func (c *config) Fuchsia() bool {
-	return Bool(c.productVariables.Fuchsia)
-}
-
 func (c *config) MinimizeJavaDebugInfo() bool {
 	return Bool(c.productVariables.MinimizeJavaDebugInfo) && !Bool(c.productVariables.Eng)
 }
diff --git a/android/module.go b/android/module.go
index 4dd5800..5f34e62 100644
--- a/android/module.go
+++ b/android/module.go
@@ -327,7 +327,6 @@
 	Host() bool
 	Device() bool
 	Darwin() bool
-	Fuchsia() bool
 	Windows() bool
 	Debug() bool
 	PrimaryArch() bool
@@ -415,6 +414,7 @@
 	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
+	InstallInVendor() bool
 	InstallBypassMake() bool
 	InstallForceOS() (*OsType, *ArchType)
 
@@ -473,6 +473,7 @@
 	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
+	InstallInVendor() bool
 	InstallBypassMake() bool
 	InstallForceOS() (*OsType, *ArchType)
 	HideFromMake()
@@ -1581,6 +1582,10 @@
 	return Bool(m.commonProperties.Recovery)
 }
 
+func (m *ModuleBase) InstallInVendor() bool {
+	return Bool(m.commonProperties.Vendor)
+}
+
 func (m *ModuleBase) InstallInRoot() bool {
 	return false
 }
@@ -2582,10 +2587,6 @@
 	return b.os == Darwin
 }
 
-func (b *baseModuleContext) Fuchsia() bool {
-	return b.os == Fuchsia
-}
-
 func (b *baseModuleContext) Windows() bool {
 	return b.os == Windows
 }
@@ -2664,6 +2665,10 @@
 	return m.module.InstallForceOS()
 }
 
+func (m *moduleContext) InstallInVendor() bool {
+	return m.module.InstallInVendor()
+}
+
 func (m *moduleContext) skipInstall() bool {
 	if m.module.base().commonProperties.SkipInstall {
 		return true
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index 516d042..e5edf91 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -86,7 +86,7 @@
 
 func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) {
 	if makeVar := String(t.properties.Export_to_make_var); makeVar != "" {
-		if t.Target().Os != BuildOs {
+		if t.Target().Os != ctx.Config().BuildOS {
 			return
 		}
 		ctx.StrictRaw(makeVar, t.toolPath.String())
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index dcd77ea..a1f8e63 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -21,360 +21,362 @@
 	"github.com/google/blueprint"
 )
 
-var prebuiltsTests = []struct {
-	name      string
-	replaceBp bool // modules is added to default bp boilerplate if false.
-	modules   string
-	prebuilt  []OsType
-	preparer  FixturePreparer
-}{
-	{
-		name: "no prebuilt",
-		modules: `
-			source {
-				name: "bar",
-			}`,
-		prebuilt: nil,
-	},
-	{
-		name: "no source prebuilt not preferred",
-		modules: `
-			prebuilt {
-				name: "bar",
-				prefer: false,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name: "no source prebuilt preferred",
-		modules: `
-			prebuilt {
-				name: "bar",
-				prefer: true,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name: "prebuilt not preferred",
-		modules: `
-			source {
-				name: "bar",
-			}
+func TestPrebuilts(t *testing.T) {
+	buildOS := TestArchConfig(t.TempDir(), nil, "", nil).BuildOS
 
-			prebuilt {
-				name: "bar",
-				prefer: false,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: nil,
-	},
-	{
-		name: "prebuilt preferred",
-		modules: `
-			source {
-				name: "bar",
-			}
+	var prebuiltsTests = []struct {
+		name      string
+		replaceBp bool // modules is added to default bp boilerplate if false.
+		modules   string
+		prebuilt  []OsType
+		preparer  FixturePreparer
+	}{
+		{
+			name: "no prebuilt",
+			modules: `
+				source {
+					name: "bar",
+				}`,
+			prebuilt: nil,
+		},
+		{
+			name: "no source prebuilt not preferred",
+			modules: `
+				prebuilt {
+					name: "bar",
+					prefer: false,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "no source prebuilt preferred",
+			modules: `
+				prebuilt {
+					name: "bar",
+					prefer: true,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "prebuilt not preferred",
+			modules: `
+				source {
+					name: "bar",
+				}
 
-			prebuilt {
-				name: "bar",
-				prefer: true,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name: "prebuilt no file not preferred",
-		modules: `
-			source {
-				name: "bar",
-			}
+				prebuilt {
+					name: "bar",
+					prefer: false,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: nil,
+		},
+		{
+			name: "prebuilt preferred",
+			modules: `
+				source {
+					name: "bar",
+				}
 
-			prebuilt {
-				name: "bar",
-				prefer: false,
-			}`,
-		prebuilt: nil,
-	},
-	{
-		name: "prebuilt no file preferred",
-		modules: `
-			source {
-				name: "bar",
-			}
+				prebuilt {
+					name: "bar",
+					prefer: true,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "prebuilt no file not preferred",
+			modules: `
+				source {
+					name: "bar",
+				}
 
-			prebuilt {
-				name: "bar",
-				prefer: true,
-			}`,
-		prebuilt: nil,
-	},
-	{
-		name: "prebuilt file from filegroup preferred",
-		modules: `
-			filegroup {
-				name: "fg",
-				srcs: ["prebuilt_file"],
-			}
-			prebuilt {
-				name: "bar",
-				prefer: true,
-				srcs: [":fg"],
-			}`,
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name: "prebuilt module for device only",
-		modules: `
-			source {
-				name: "bar",
-			}
+				prebuilt {
+					name: "bar",
+					prefer: false,
+				}`,
+			prebuilt: nil,
+		},
+		{
+			name: "prebuilt no file preferred",
+			modules: `
+				source {
+					name: "bar",
+				}
 
-			prebuilt {
-				name: "bar",
-				host_supported: false,
-				prefer: true,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: []OsType{Android},
-	},
-	{
-		name: "prebuilt file for host only",
-		modules: `
-			source {
-				name: "bar",
-			}
+				prebuilt {
+					name: "bar",
+					prefer: true,
+				}`,
+			prebuilt: nil,
+		},
+		{
+			name: "prebuilt file from filegroup preferred",
+			modules: `
+				filegroup {
+					name: "fg",
+					srcs: ["prebuilt_file"],
+				}
+				prebuilt {
+					name: "bar",
+					prefer: true,
+					srcs: [":fg"],
+				}`,
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "prebuilt module for device only",
+			modules: `
+				source {
+					name: "bar",
+				}
 
-			prebuilt {
-				name: "bar",
-				prefer: true,
-				target: {
-					host: {
-						srcs: ["prebuilt_file"],
-					},
-				},
-			}`,
-		prebuilt: []OsType{BuildOs},
-	},
-	{
-		name: "prebuilt override not preferred",
-		modules: `
-			source {
-				name: "baz",
-			}
+				prebuilt {
+					name: "bar",
+					host_supported: false,
+					prefer: true,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: []OsType{Android},
+		},
+		{
+			name: "prebuilt file for host only",
+			modules: `
+				source {
+					name: "bar",
+				}
 
-			override_source {
-				name: "bar",
-				base: "baz",
-			}
-
-			prebuilt {
-				name: "bar",
-				prefer: false,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: nil,
-	},
-	{
-		name: "prebuilt override preferred",
-		modules: `
-			source {
-				name: "baz",
-			}
-
-			override_source {
-				name: "bar",
-				base: "baz",
-			}
-
-			prebuilt {
-				name: "bar",
-				prefer: true,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name:      "prebuilt including default-disabled OS",
-		replaceBp: true,
-		modules: `
-			source {
-				name: "foo",
-				deps: [":bar"],
-				target: {
-					windows: {
-						enabled: true,
-					},
-				},
-			}
-
-			source {
-				name: "bar",
-				target: {
-					windows: {
-						enabled: true,
-					},
-				},
-			}
-
-			prebuilt {
-				name: "bar",
-				prefer: true,
-				srcs: ["prebuilt_file"],
-				target: {
-					windows: {
-						enabled: true,
-					},
-				},
-			}`,
-		prebuilt: []OsType{Android, BuildOs, Windows},
-	},
-	{
-		name:      "fall back to source for default-disabled OS",
-		replaceBp: true,
-		modules: `
-			source {
-				name: "foo",
-				deps: [":bar"],
-				target: {
-					windows: {
-						enabled: true,
-					},
-				},
-			}
-
-			source {
-				name: "bar",
-				target: {
-					windows: {
-						enabled: true,
-					},
-				},
-			}
-
-			prebuilt {
-				name: "bar",
-				prefer: true,
-				srcs: ["prebuilt_file"],
-			}`,
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name:      "prebuilt properties customizable",
-		replaceBp: true,
-		modules: `
-			source {
-				name: "foo",
-				deps: [":bar"],
-			}
-
-			soong_config_module_type {
-				name: "prebuilt_with_config",
-				module_type: "prebuilt",
-				config_namespace: "any_namespace",
-				bool_variables: ["bool_var"],
-				properties: ["prefer"],
-			}
-
-			prebuilt_with_config {
-				name: "bar",
-				prefer: true,
-				srcs: ["prebuilt_file"],
-				soong_config_variables: {
-					bool_var: {
-						prefer: false,
-						conditions_default: {
-							prefer: true,
+				prebuilt {
+					name: "bar",
+					prefer: true,
+					target: {
+						host: {
+							srcs: ["prebuilt_file"],
 						},
 					},
-				},
-			}`,
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name: "prebuilt use_source_config_var={acme, use_source} - no var specified",
-		modules: `
-			source {
-				name: "bar",
-			}
+				}`,
+			prebuilt: []OsType{buildOS},
+		},
+		{
+			name: "prebuilt override not preferred",
+			modules: `
+				source {
+					name: "baz",
+				}
 
-			prebuilt {
-				name: "bar",
-				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-				srcs: ["prebuilt_file"],
-			}`,
-		// When use_source_env is specified then it will use the prebuilt by default if the environment
-		// variable is not set.
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=false",
-		modules: `
-			source {
-				name: "bar",
-			}
+				override_source {
+					name: "bar",
+					base: "baz",
+				}
 
-			prebuilt {
-				name: "bar",
-				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-				srcs: ["prebuilt_file"],
-			}`,
-		preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
-			variables.VendorVars = map[string]map[string]string{
-				"acme": {
-					"use_source": "false",
-				},
-			}
-		}),
-		// Setting the environment variable named in use_source_env to false will cause the prebuilt to
-		// be used.
-		prebuilt: []OsType{Android, BuildOs},
-	},
-	{
-		name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true",
-		modules: `
-			source {
-				name: "bar",
-			}
+				prebuilt {
+					name: "bar",
+					prefer: false,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: nil,
+		},
+		{
+			name: "prebuilt override preferred",
+			modules: `
+				source {
+					name: "baz",
+				}
 
-			prebuilt {
-				name: "bar",
-				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-				srcs: ["prebuilt_file"],
-			}`,
-		preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
-			variables.VendorVars = map[string]map[string]string{
-				"acme": {
-					"use_source": "true",
-				},
-			}
-		}),
-		// Setting the environment variable named in use_source_env to true will cause the source to be
-		// used.
-		prebuilt: nil,
-	},
-	{
-		name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true, no source",
-		modules: `
-			prebuilt {
-				name: "bar",
-				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-				srcs: ["prebuilt_file"],
-			}`,
-		preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
-			variables.VendorVars = map[string]map[string]string{
-				"acme": {
-					"use_source": "true",
-				},
-			}
-		}),
-		// Although the environment variable says to use source there is no source available.
-		prebuilt: []OsType{Android, BuildOs},
-	},
-}
+				override_source {
+					name: "bar",
+					base: "baz",
+				}
 
-func TestPrebuilts(t *testing.T) {
+				prebuilt {
+					name: "bar",
+					prefer: true,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name:      "prebuilt including default-disabled OS",
+			replaceBp: true,
+			modules: `
+				source {
+					name: "foo",
+					deps: [":bar"],
+					target: {
+						windows: {
+							enabled: true,
+						},
+					},
+				}
+
+				source {
+					name: "bar",
+					target: {
+						windows: {
+							enabled: true,
+						},
+					},
+				}
+
+				prebuilt {
+					name: "bar",
+					prefer: true,
+					srcs: ["prebuilt_file"],
+					target: {
+						windows: {
+							enabled: true,
+						},
+					},
+				}`,
+			prebuilt: []OsType{Android, buildOS, Windows},
+		},
+		{
+			name:      "fall back to source for default-disabled OS",
+			replaceBp: true,
+			modules: `
+				source {
+					name: "foo",
+					deps: [":bar"],
+					target: {
+						windows: {
+							enabled: true,
+						},
+					},
+				}
+
+				source {
+					name: "bar",
+					target: {
+						windows: {
+							enabled: true,
+						},
+					},
+				}
+
+				prebuilt {
+					name: "bar",
+					prefer: true,
+					srcs: ["prebuilt_file"],
+				}`,
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name:      "prebuilt properties customizable",
+			replaceBp: true,
+			modules: `
+				source {
+					name: "foo",
+					deps: [":bar"],
+				}
+
+				soong_config_module_type {
+					name: "prebuilt_with_config",
+					module_type: "prebuilt",
+					config_namespace: "any_namespace",
+					bool_variables: ["bool_var"],
+					properties: ["prefer"],
+				}
+
+				prebuilt_with_config {
+					name: "bar",
+					prefer: true,
+					srcs: ["prebuilt_file"],
+					soong_config_variables: {
+						bool_var: {
+							prefer: false,
+							conditions_default: {
+								prefer: true,
+							},
+						},
+					},
+				}`,
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "prebuilt use_source_config_var={acme, use_source} - no var specified",
+			modules: `
+				source {
+					name: "bar",
+				}
+
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}`,
+			// When use_source_env is specified then it will use the prebuilt by default if the environment
+			// variable is not set.
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=false",
+			modules: `
+				source {
+					name: "bar",
+				}
+
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}`,
+			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "false",
+					},
+				}
+			}),
+			// Setting the environment variable named in use_source_env to false will cause the prebuilt to
+			// be used.
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true",
+			modules: `
+				source {
+					name: "bar",
+				}
+
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}`,
+			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "true",
+					},
+				}
+			}),
+			// Setting the environment variable named in use_source_env to true will cause the source to be
+			// used.
+			prebuilt: nil,
+		},
+		{
+			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true, no source",
+			modules: `
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}`,
+			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "true",
+					},
+				}
+			}),
+			// Although the environment variable says to use source there is no source available.
+			prebuilt: []OsType{Android, buildOS},
+		},
+	}
+
 	fs := MockFS{
 		"prebuilt_file": nil,
 		"source_file":   nil,
diff --git a/android/test_suites.go b/android/test_suites.go
index 6b7b909..22f6cf2 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -60,7 +60,7 @@
 	for _, module := range SortedStringKeys(files) {
 		installedPaths = append(installedPaths, files[module]...)
 	}
-	testCasesDir := pathForInstall(ctx, BuildOs, X86, "testcases", false).ToMakePath()
+	testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases", false).ToMakePath()
 
 	outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip")
 	rule := NewRuleBuilder(pctx, ctx)
diff --git a/android/variable.go b/android/variable.go
index bbb9868..d0a23aa 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -299,8 +299,6 @@
 
 	Override_rs_driver *string `json:",omitempty"`
 
-	Fuchsia *bool `json:",omitempty"`
-
 	DeviceKernelHeaders []string `json:",omitempty"`
 
 	ExtraVndkVersions []string `json:",omitempty"`
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 35f194d..3277bd0 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -29,7 +29,6 @@
 	// OsType names in arch.go
 	osAndroid     = "android"
 	osDarwin      = "darwin"
-	osFuchsia     = "fuchsia"
 	osLinux       = "linux_glibc"
 	osLinuxBionic = "linux_bionic"
 	osWindows     = "windows"
@@ -40,8 +39,6 @@
 	osArchAndroidX86        = "android_x86"
 	osArchAndroidX86_64     = "android_x86_64"
 	osArchDarwinX86_64      = "darwin_x86_64"
-	osArchFuchsiaArm64      = "fuchsia_arm64"
-	osArchFuchsiaX86_64     = "fuchsia_x86_64"
 	osArchLinuxX86          = "linux_glibc_x86"
 	osArchLinuxX86_64       = "linux_glibc_x86_64"
 	osArchLinuxBionicArm64  = "linux_bionic_arm64"
@@ -84,7 +81,6 @@
 	platformOsMap = map[string]string{
 		osAndroid:         "//build/bazel/platforms/os:android",
 		osDarwin:          "//build/bazel/platforms/os:darwin",
-		osFuchsia:         "//build/bazel/platforms/os:fuchsia",
 		osLinux:           "//build/bazel/platforms/os:linux",
 		osLinuxBionic:     "//build/bazel/platforms/os:linux_bionic",
 		osWindows:         "//build/bazel/platforms/os:windows",
@@ -102,8 +98,6 @@
 		osArchAndroidX86:        "//build/bazel/platforms/os_arch:android_x86",
 		osArchAndroidX86_64:     "//build/bazel/platforms/os_arch:android_x86_64",
 		osArchDarwinX86_64:      "//build/bazel/platforms/os_arch:darwin_x86_64",
-		osArchFuchsiaArm64:      "//build/bazel/platforms/os_arch:fuchsia_arm64",
-		osArchFuchsiaX86_64:     "//build/bazel/platforms/os_arch:fuchsia_x86_64",
 		osArchLinuxX86:          "//build/bazel/platforms/os_arch:linux_glibc_x86",
 		osArchLinuxX86_64:       "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
 		osArchLinuxBionicArm64:  "//build/bazel/platforms/os_arch:linux_bionic_arm64",
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index d1fd6af..712d0bd 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -185,7 +185,6 @@
 cc_library_headers { name: "android-lib" }
 cc_library_headers { name: "base-lib" }
 cc_library_headers { name: "darwin-lib" }
-cc_library_headers { name: "fuchsia-lib" }
 cc_library_headers { name: "linux-lib" }
 cc_library_headers { name: "linux_bionic-lib" }
 cc_library_headers { name: "windows-lib" }
@@ -195,7 +194,6 @@
     target: {
         android: { header_libs: ["android-lib"] },
         darwin: { header_libs: ["darwin-lib"] },
-        fuchsia: { header_libs: ["fuchsia-lib"] },
         linux_bionic: { header_libs: ["linux_bionic-lib"] },
         linux_glibc: { header_libs: ["linux-lib"] },
         windows: { header_libs: ["windows-lib"] },
@@ -229,19 +227,12 @@
     implementation_deps = [":base-lib"] + select({
         "//build/bazel/platforms/os:android": [":android-lib"],
         "//build/bazel/platforms/os:darwin": [":darwin-lib"],
-        "//build/bazel/platforms/os:fuchsia": [":fuchsia-lib"],
         "//build/bazel/platforms/os:linux": [":linux-lib"],
         "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
         "//build/bazel/platforms/os:windows": [":windows-lib"],
         "//conditions:default": [],
     }),
 )`, `cc_library_headers(
-    name = "fuchsia-lib",
-    copts = [
-        "-I.",
-        "-I$(BINDIR)/.",
-    ],
-)`, `cc_library_headers(
     name = "linux-lib",
     copts = [
         "-I.",
diff --git a/cc/Android.bp b/cc/Android.bp
index 4b750ff..164d32b 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -14,6 +14,7 @@
         "soong-cc-config",
         "soong-etc",
         "soong-genrule",
+        "soong-snapshot",
         "soong-tradefed",
     ],
     srcs: [
diff --git a/cc/binary.go b/cc/binary.go
index c177a08..c6d61ab 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -215,7 +215,7 @@
 			if binary.Properties.Static_executable == nil && ctx.Config().HostStaticBinaries() {
 				binary.Properties.Static_executable = BoolPtr(true)
 			}
-		} else if !ctx.Fuchsia() {
+		} else {
 			// Static executables are not supported on Darwin or Windows
 			binary.Properties.Static_executable = nil
 		}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 0a3acb9..dd51fe8 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -152,71 +152,6 @@
 	).RunTest(t)
 }
 
-func TestFuchsiaDeps(t *testing.T) {
-	t.Helper()
-
-	bp := `
-		cc_library {
-			name: "libTest",
-			srcs: ["foo.c"],
-			target: {
-				fuchsia: {
-					srcs: ["bar.c"],
-				},
-			},
-		}`
-
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-		PrepareForTestOnFuchsia,
-	).RunTestWithBp(t, bp)
-
-	rt := false
-	fb := false
-
-	ld := result.ModuleForTests("libTest", "fuchsia_arm64_shared").Rule("ld")
-	implicits := ld.Implicits
-	for _, lib := range implicits {
-		if strings.Contains(lib.Rel(), "libcompiler_rt") {
-			rt = true
-		}
-
-		if strings.Contains(lib.Rel(), "libbioniccompat") {
-			fb = true
-		}
-	}
-
-	if !rt || !fb {
-		t.Errorf("fuchsia libs must link libcompiler_rt and libbioniccompat")
-	}
-}
-
-func TestFuchsiaTargetDecl(t *testing.T) {
-	t.Helper()
-
-	bp := `
-		cc_library {
-			name: "libTest",
-			srcs: ["foo.c"],
-			target: {
-				fuchsia: {
-					srcs: ["bar.c"],
-				},
-			},
-		}`
-
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-		PrepareForTestOnFuchsia,
-	).RunTestWithBp(t, bp)
-	ld := result.ModuleForTests("libTest", "fuchsia_arm64_shared").Rule("ld")
-	var objs []string
-	for _, o := range ld.Inputs {
-		objs = append(objs, o.Base())
-	}
-	android.AssertArrayString(t, "libTest inputs", []string{"foo.o", "bar.o"}, objs)
-}
-
 func TestVendorSrc(t *testing.T) {
 	ctx := testCc(t, `
 		cc_library {
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index c1d4f17..3e8ee48 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -21,10 +21,8 @@
 
         "arm_device.go",
         "arm64_device.go",
-        "arm64_fuchsia_device.go",
         "x86_device.go",
         "x86_64_device.go",
-        "x86_64_fuchsia_device.go",
 
         "x86_darwin_host.go",
         "x86_linux_host.go",
diff --git a/cc/config/arm64_fuchsia_device.go b/cc/config/arm64_fuchsia_device.go
deleted file mode 100644
index 5ab27a0..0000000
--- a/cc/config/arm64_fuchsia_device.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// 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 config
-
-import (
-	"android/soong/android"
-)
-
-var fuchsiaArm64SysRoot string = "prebuilts/fuchsia_sdk/arch/arm64/sysroot"
-var fuchsiaArm64PrebuiltLibsRoot string = "fuchsia/prebuilt_libs/"
-
-type toolchainFuchsiaArm64 struct {
-	toolchain64Bit
-	toolchainFuchsia
-}
-
-func (t *toolchainFuchsiaArm64) Name() string {
-	return "arm64"
-}
-
-func (t *toolchainFuchsiaArm64) GccRoot() string {
-	return "${config.Arm64GccRoot}"
-}
-
-func (t *toolchainFuchsiaArm64) GccTriple() string {
-	return "aarch64-linux-android"
-}
-
-func (t *toolchainFuchsiaArm64) GccVersion() string {
-	return arm64GccVersion
-}
-
-func (t *toolchainFuchsiaArm64) IncludeFlags() string {
-	return ""
-}
-
-func (t *toolchainFuchsiaArm64) ClangTriple() string {
-	return "arm64-fuchsia-android"
-}
-
-func (t *toolchainFuchsiaArm64) Cppflags() string {
-	return "-Wno-error=deprecated-declarations"
-}
-
-func (t *toolchainFuchsiaArm64) Ldflags() string {
-	return "--target=arm64-fuchsia --sysroot=" + fuchsiaArm64SysRoot + " -L" + fuchsiaArm64PrebuiltLibsRoot + "/aarch64-fuchsia/lib " + "-Lprebuilts/fuchsia_sdk/arch/arm64/dist/"
-}
-
-func (t *toolchainFuchsiaArm64) Lldflags() string {
-	return "--target=arm64-fuchsia --sysroot=" + fuchsiaArm64SysRoot + " -L" + fuchsiaArm64PrebuiltLibsRoot + "/aarch64-fuchsia/lib " + "-Lprebuilts/fuchsia_sdk/arch/arm64/dist/"
-}
-
-func (t *toolchainFuchsiaArm64) Cflags() string {
-	return "--target=arm64-fuchsia --sysroot=" + fuchsiaArm64SysRoot + " -I" + fuchsiaArm64SysRoot + "/include"
-}
-
-func (t *toolchainFuchsiaArm64) ToolchainCflags() string {
-	return "-march=armv8-a"
-}
-
-var toolchainArm64FuchsiaSingleton Toolchain = &toolchainFuchsiaArm64{}
-
-func arm64FuchsiaToolchainFactory(arch android.Arch) Toolchain {
-	return toolchainArm64FuchsiaSingleton
-}
-
-func init() {
-	registerToolchainFactory(android.Fuchsia, android.Arm64, arm64FuchsiaToolchainFactory)
-}
diff --git a/cc/config/global.go b/cc/config/global.go
index dfbe6c4..55e0d79 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -15,6 +15,7 @@
 package config
 
 import (
+	"runtime"
 	"strings"
 
 	"android/soong/android"
@@ -282,7 +283,7 @@
 var pctx = android.NewPackageContext("android/soong/cc/config")
 
 func init() {
-	if android.BuildOs == android.Linux {
+	if runtime.GOOS == "linux" {
 		commonGlobalCflags = append(commonGlobalCflags, "-fdebug-prefix-map=/proc/self/cwd=")
 	}
 
diff --git a/cc/config/x86_64_fuchsia_device.go b/cc/config/x86_64_fuchsia_device.go
deleted file mode 100644
index 86558a6..0000000
--- a/cc/config/x86_64_fuchsia_device.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// 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 config
-
-import (
-	"android/soong/android"
-)
-
-var fuchsiaSysRoot string = "prebuilts/fuchsia_sdk/arch/x64/sysroot"
-var fuchsiaPrebuiltLibsRoot string = "fuchsia/prebuilt_libs"
-
-type toolchainFuchsia struct {
-	cFlags, ldFlags string
-}
-
-type toolchainFuchsiaX8664 struct {
-	toolchain64Bit
-	toolchainFuchsia
-}
-
-func (t *toolchainFuchsiaX8664) Name() string {
-	return "x86_64"
-}
-
-func (t *toolchainFuchsiaX8664) GccRoot() string {
-	return "${config.X86_64GccRoot}"
-}
-
-func (t *toolchainFuchsiaX8664) GccTriple() string {
-	return "x86_64-linux-android"
-}
-
-func (t *toolchainFuchsiaX8664) GccVersion() string {
-	return x86_64GccVersion
-}
-
-func (t *toolchainFuchsiaX8664) IncludeFlags() string {
-	return ""
-}
-
-func (t *toolchainFuchsiaX8664) ClangTriple() string {
-	return "x86_64-fuchsia-android"
-}
-
-func (t *toolchainFuchsiaX8664) Cppflags() string {
-	return "-Wno-error=deprecated-declarations"
-}
-
-func (t *toolchainFuchsiaX8664) Ldflags() string {
-	return "--target=x86_64-fuchsia --sysroot=" + fuchsiaSysRoot + " -L" + fuchsiaPrebuiltLibsRoot + "/x86_64-fuchsia/lib " + "-Lprebuilts/fuchsia_sdk/arch/x64/dist/"
-
-}
-
-func (t *toolchainFuchsiaX8664) Lldflags() string {
-	return "--target=x86_64-fuchsia --sysroot=" + fuchsiaSysRoot + " -L" + fuchsiaPrebuiltLibsRoot + "/x86_64-fuchsia/lib " + "-Lprebuilts/fuchsia_sdk/arch/x64/dist/"
-}
-
-func (t *toolchainFuchsiaX8664) Cflags() string {
-	return "--target=x86_64-fuchsia --sysroot=" + fuchsiaSysRoot + " -I" + fuchsiaSysRoot + "/include"
-}
-
-func (t *toolchainFuchsiaX8664) YasmFlags() string {
-	return "-f elf64 -m amd64"
-}
-
-func (t *toolchainFuchsiaX8664) ToolchainCflags() string {
-	return "-mssse3"
-}
-
-var toolchainFuchsiaSingleton Toolchain = &toolchainFuchsiaX8664{}
-
-func fuchsiaToolchainFactory(arch android.Arch) Toolchain {
-	return toolchainFuchsiaSingleton
-}
-
-func init() {
-	registerToolchainFactory(android.Fuchsia, android.X86_64, fuchsiaToolchainFactory)
-}
diff --git a/cc/genrule.go b/cc/genrule.go
index b0efc6c..0ca901e 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/genrule"
+	"android/soong/snapshot"
 )
 
 func init() {
@@ -84,7 +85,7 @@
 	// is not needed.
 	recoverySnapshotVersion := ctx.DeviceConfig().RecoverySnapshotVersion()
 	if recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" &&
-		!isRecoveryProprietaryModule(ctx) {
+		!snapshot.IsRecoveryProprietaryModule(ctx) {
 		return false
 	} else {
 		return Bool(g.Recovery_available)
@@ -103,7 +104,7 @@
 		// If not, we assume modules under proprietary paths are compatible for
 		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is
 		// PLATFORM_VNDK_VERSION.
-		if vndkVersion == "current" || !IsVendorProprietaryModule(ctx) {
+		if vndkVersion == "current" || !snapshot.IsVendorProprietaryModule(ctx) {
 			variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
 		} else {
 			variants = append(variants, VendorVariationPrefix+vndkVersion)
diff --git a/cc/image.go b/cc/image.go
index 15ec1c8..3a0857b 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -22,6 +22,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/snapshot"
 )
 
 var _ android.ImageInterface = (*Module)(nil)
@@ -496,7 +497,7 @@
 		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
 		// PLATFORM_VNDK_VERSION.
 		if m.HasVendorVariant() {
-			if IsVendorProprietaryModule(mctx) {
+			if snapshot.IsVendorProprietaryModule(mctx) {
 				vendorVariants = append(vendorVariants, boardVndkVersion)
 			} else {
 				vendorVariants = append(vendorVariants, platformVndkVersion)
@@ -525,7 +526,7 @@
 				platformVndkVersion,
 				boardVndkVersion,
 			)
-		} else if IsVendorProprietaryModule(mctx) {
+		} else if snapshot.IsVendorProprietaryModule(mctx) {
 			vendorVariants = append(vendorVariants, boardVndkVersion)
 		} else {
 			vendorVariants = append(vendorVariants, platformVndkVersion)
@@ -582,7 +583,7 @@
 	if !m.KernelHeadersDecorator() &&
 		!m.IsSnapshotPrebuilt() &&
 		usingRecoverySnapshot &&
-		!isRecoveryProprietaryModule(mctx) {
+		!snapshot.IsRecoveryProprietaryModule(mctx) {
 		recoveryVariantNeeded = false
 	}
 
diff --git a/cc/linkable.go b/cc/linkable.go
index 6232efb..b510508 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -3,6 +3,7 @@
 import (
 	"android/soong/android"
 	"android/soong/bazel/cquery"
+	"android/soong/snapshot"
 
 	"github.com/google/blueprint"
 )
@@ -71,15 +72,12 @@
 
 // Snapshottable defines those functions necessary for handling module snapshots.
 type Snapshottable interface {
+	snapshot.VendorSnapshotModuleInterface
+	snapshot.RecoverySnapshotModuleInterface
+
 	// SnapshotHeaders returns a list of header paths provided by this module.
 	SnapshotHeaders() android.Paths
 
-	// ExcludeFromVendorSnapshot returns true if this module should be otherwise excluded from the vendor snapshot.
-	ExcludeFromVendorSnapshot() bool
-
-	// ExcludeFromRecoverySnapshot returns true if this module should be otherwise excluded from the recovery snapshot.
-	ExcludeFromRecoverySnapshot() bool
-
 	// SnapshotLibrary returns true if this module is a snapshot library.
 	IsSnapshotLibrary() bool
 
diff --git a/cc/linker.go b/cc/linker.go
index a712391..82449a6 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -15,9 +15,10 @@
 package cc
 
 import (
+	"fmt"
+
 	"android/soong/android"
 	"android/soong/cc/config"
-	"fmt"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -244,8 +245,7 @@
 	if linker.Properties.System_shared_libs != nil && linker.Properties.Default_shared_libs != nil {
 		ctx.PropertyErrorf("system_shared_libs", "cannot be specified if default_shared_libs is also specified")
 	}
-	if ctx.toolchain().Bionic() && linker.Properties.System_shared_libs != nil {
-		// system_shared_libs is only honored when building against bionic.
+	if linker.Properties.System_shared_libs != nil {
 		return linker.Properties.System_shared_libs
 	}
 	return linker.Properties.Default_shared_libs
@@ -389,18 +389,6 @@
 
 	deps.LateSharedLibs = append(deps.LateSharedLibs, deps.SystemSharedLibs...)
 
-	if ctx.Fuchsia() {
-		if ctx.ModuleName() != "libbioniccompat" &&
-			ctx.ModuleName() != "libcompiler_rt-extras" &&
-			ctx.ModuleName() != "libcompiler_rt" {
-			deps.StaticLibs = append(deps.StaticLibs, "libbioniccompat")
-		}
-		if ctx.ModuleName() != "libcompiler_rt" && ctx.ModuleName() != "libcompiler_rt-extras" {
-			deps.LateStaticLibs = append(deps.LateStaticLibs, "libcompiler_rt")
-		}
-
-	}
-
 	if ctx.Windows() {
 		deps.LateStaticLibs = append(deps.LateStaticLibs, "libwinpthread")
 	}
@@ -484,7 +472,7 @@
 		flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Ldflags())
 	}
 
-	if !ctx.toolchain().Bionic() && !ctx.Fuchsia() {
+	if !ctx.toolchain().Bionic() {
 		CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs)
 
 		flags.Local.LdFlags = append(flags.Local.LdFlags, linker.Properties.Host_ldlibs...)
@@ -503,10 +491,6 @@
 		}
 	}
 
-	if ctx.Fuchsia() {
-		flags.Global.LdFlags = append(flags.Global.LdFlags, "-lfdio", "-lzircon")
-	}
-
 	if ctx.toolchain().LibclangRuntimeLibraryArch() != "" {
 		flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--exclude-libs="+config.BuiltinsRuntimeLibrary(ctx.toolchain())+".a")
 	}
diff --git a/cc/makevars.go b/cc/makevars.go
index 393170a..8d7a163 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -165,7 +165,7 @@
 	sort.Strings(ndkKnownLibs)
 	ctx.Strict("NDK_KNOWN_LIBS", strings.Join(ndkKnownLibs, " "))
 
-	hostTargets := ctx.Config().Targets[android.BuildOs]
+	hostTargets := ctx.Config().Targets[ctx.Config().BuildOS]
 	makeVarsToolchain(ctx, "", hostTargets[0])
 	if len(hostTargets) > 1 {
 		makeVarsToolchain(ctx, "2ND_", hostTargets[1])
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index a458380..63e8261 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -150,12 +150,6 @@
 	if !ctx.Module().Enabled() {
 		return nil
 	}
-	if ctx.Os() != android.Android {
-		// These modules are always android.DeviceEnabled only, but
-		// those include Fuchsia devices, which we don't support.
-		ctx.Module().Disable()
-		return nil
-	}
 	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
 		ctx.Module().Disable()
 		return nil
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index fa6dd87..c8f8103 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"runtime"
 	"testing"
 
 	"android/soong/android"
@@ -271,8 +272,8 @@
 }
 
 func TestPrebuiltSymlinkedHostBinary(t *testing.T) {
-	if android.BuildOs != android.Linux {
-		t.Skipf("Skipping host prebuilt testing that is only supported on %s not %s", android.Linux, android.BuildOs)
+	if runtime.GOOS != "linux" {
+		t.Skipf("Skipping host prebuilt testing that is only supported on linux not %s", runtime.GOOS)
 	}
 
 	ctx := testPrebuilt(t, `
diff --git a/cc/proto_test.go b/cc/proto_test.go
index b9c89c7..abcb273 100644
--- a/cc/proto_test.go
+++ b/cc/proto_test.go
@@ -51,7 +51,7 @@
 			},
 		}`)
 
-		buildOS := android.BuildOs.String()
+		buildOS := ctx.Config().BuildOS.String()
 
 		proto := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Output("proto/a.pb.cc")
 		foobar := ctx.ModuleForTests("protoc-gen-foobar", buildOS+"_x86_64")
diff --git a/cc/sabi.go b/cc/sabi.go
index 5fd6f5d..e62ca66 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -101,10 +101,6 @@
 // Called from sabiDepsMutator to check whether ABI dumps should be created for this module.
 // ctx should be wrapping a native library type module.
 func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool {
-	if ctx.Fuchsia() {
-		return false
-	}
-
 	// Only generate ABI dump for device modules.
 	if !ctx.Device() {
 		return false
diff --git a/cc/sanitize.go b/cc/sanitize.go
index defe8fd..3911f48 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -25,6 +25,7 @@
 
 	"android/soong/android"
 	"android/soong/cc/config"
+	"android/soong/snapshot"
 )
 
 var (
@@ -265,7 +266,6 @@
 }
 
 type SanitizeProperties struct {
-	// Sanitizers are not supported for Fuchsia.
 	Sanitize          SanitizeUserProps `android:"arch_variant"`
 	SanitizerEnabled  bool              `blueprint:"mutated"`
 	SanitizeDep       bool              `blueprint:"mutated"`
@@ -305,11 +305,6 @@
 		s.Never = BoolPtr(true)
 	}
 
-	// Sanitizers do not work on Fuchsia yet.
-	if ctx.Fuchsia() {
-		s.Never = BoolPtr(true)
-	}
-
 	// Never always wins.
 	if Bool(s.Never) {
 		return
@@ -907,7 +902,7 @@
 // as vendor snapshot. Such modules must create both cfi and non-cfi variants,
 // except for ones which explicitly disable cfi.
 func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
-	if IsVendorProprietaryModule(mctx) {
+	if snapshot.IsVendorProprietaryModule(mctx) {
 		return false
 	}
 
diff --git a/cc/sdk.go b/cc/sdk.go
index 69ad311..a83e5ad 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -76,7 +76,7 @@
 			}
 			ctx.AliasVariation("")
 		}
-	case *snapshot:
+	case *snapshotModule:
 		ctx.CreateVariations("")
 	}
 }
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 4f031ff..9672c0f 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -18,57 +18,17 @@
 // snapshot mutators and snapshot information maps which are also defined in this file.
 
 import (
-	"path/filepath"
 	"strings"
 
 	"android/soong/android"
+	"android/soong/snapshot"
 
 	"github.com/google/blueprint"
 )
 
-// Defines the specifics of different images to which the snapshot process is applicable, e.g.,
-// vendor, recovery, ramdisk.
+// This interface overrides snapshot.SnapshotImage to implement cc module specific functions
 type SnapshotImage interface {
-	// Returns true if a snapshot should be generated for this image.
-	shouldGenerateSnapshot(ctx android.SingletonContext) bool
-
-	// 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 LinkableInterface) func() bool
-
-	// Returns true if the module is private and must not be included in the
-	// snapshot. For example VNDK-private modules must return true for the
-	// vendor snapshots. But false for the recovery snapshots.
-	private(m LinkableInterface) 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, deviceConfig) returns true, then the module in dir
-	// will be built from sources.
-	isProprietaryPath(dir string, deviceConfig android.DeviceConfig) 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 LinkableInterface) bool
-
-	// Returns true if the build is using a snapshot for this image.
-	isUsingSnapshot(cfg android.DeviceConfig) bool
-
-	// Returns a version of which the snapshot should be used in this target.
-	// This will only be meaningful when isUsingSnapshot is true.
-	targetSnapshotVersion(cfg android.DeviceConfig) string
-
-	// Whether to exclude a given module from the directed snapshot or not.
-	// If the makefile variable DIRECTED_{IMAGE}_SNAPSHOT is true, directed snapshot is turned on,
-	// and only modules listed in {IMAGE}_SNAPSHOT_MODULES will be captured.
-	excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool
+	snapshot.SnapshotImage
 
 	// The image variant name for this snapshot image.
 	// For example, recovery snapshot image will return "recovery", and vendor snapshot image will
@@ -80,110 +40,12 @@
 	moduleNameSuffix() string
 }
 
-type vendorSnapshotImage struct{}
-type recoverySnapshotImage struct{}
-
-type directoryMap map[string]bool
-
-var (
-	// Modules under following directories are ignored. They are OEM's and vendor's
-	// proprietary modules(device/, kernel/, vendor/, and hardware/).
-	defaultDirectoryExcludedMap = directoryMap{
-		"device":   true,
-		"hardware": true,
-		"kernel":   true,
-		"vendor":   true,
-	}
-
-	// Modules under following directories are included as they are in AOSP,
-	// although hardware/ and kernel/ are normally for vendor's own.
-	defaultDirectoryIncludedMap = directoryMap{
-		"kernel/configs":              true,
-		"kernel/prebuilts":            true,
-		"kernel/tests":                true,
-		"hardware/interfaces":         true,
-		"hardware/libhardware":        true,
-		"hardware/libhardware_legacy": true,
-		"hardware/ril":                true,
-	}
-)
-
-func (vendorSnapshotImage) Init(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
-	ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory)
-	ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
-	ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
-	ctx.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
-	ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
-	ctx.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory)
-
-	ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
+type vendorSnapshotImage struct {
+	*snapshot.VendorSnapshotImage
 }
 
-func (vendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
-	ctx.RegisterModuleType(name, factory)
-}
-
-func (vendorSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
-	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a snapshot.
-	return ctx.DeviceConfig().VndkVersion() == "current"
-}
-
-func (vendorSnapshotImage) inImage(m LinkableInterface) func() bool {
-	return m.InVendor
-}
-
-func (vendorSnapshotImage) private(m LinkableInterface) bool {
-	return m.IsVndkPrivate()
-}
-
-func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool {
-	if dir == "." || dir == "/" {
-		return false
-	}
-	if includedMap[dir] {
-		return false
-	} else if excludedMap[dir] {
-		return true
-	} else if defaultDirectoryIncludedMap[dir] {
-		return false
-	} else if defaultDirectoryExcludedMap[dir] {
-		return true
-	} else {
-		return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap)
-	}
-}
-
-func (vendorSnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap())
-}
-
-// vendor snapshot includes static/header libraries with vndk: {enabled: true}.
-func (vendorSnapshotImage) includeVndk() bool {
-	return true
-}
-
-func (vendorSnapshotImage) excludeFromSnapshot(m LinkableInterface) bool {
-	return m.ExcludeFromVendorSnapshot()
-}
-
-func (vendorSnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool {
-	vndkVersion := cfg.VndkVersion()
-	return vndkVersion != "current" && vndkVersion != ""
-}
-
-func (vendorSnapshotImage) targetSnapshotVersion(cfg android.DeviceConfig) string {
-	return cfg.VndkVersion()
-}
-
-// returns true iff a given module SHOULD BE EXCLUDED, false if included
-func (vendorSnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
-	// If we're using full snapshot, not directed snapshot, capture every module
-	if !cfg.DirectedVendorSnapshot() {
-		return false
-	}
-	// Else, checks if name is in VENDOR_SNAPSHOT_MODULES.
-	return !cfg.VendorSnapshotModules()[name]
+type recoverySnapshotImage struct {
+	*snapshot.RecoverySnapshotImage
 }
 
 func (vendorSnapshotImage) imageVariantName(cfg android.DeviceConfig) string {
@@ -194,62 +56,6 @@
 	return VendorSuffix
 }
 
-func (recoverySnapshotImage) init(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
-	ctx.RegisterModuleType("recovery_snapshot", recoverySnapshotFactory)
-	ctx.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory)
-	ctx.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory)
-	ctx.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory)
-	ctx.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory)
-	ctx.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory)
-}
-
-func (recoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
-	// RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a
-	// snapshot.
-	return ctx.DeviceConfig().RecoverySnapshotVersion() == "current"
-}
-
-func (recoverySnapshotImage) inImage(m LinkableInterface) func() bool {
-	return m.InRecovery
-}
-
-// recovery snapshot does not have private libraries.
-func (recoverySnapshotImage) private(m LinkableInterface) bool {
-	return false
-}
-
-func (recoverySnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap())
-}
-
-// recovery snapshot does NOT treat vndk specially.
-func (recoverySnapshotImage) includeVndk() bool {
-	return false
-}
-
-func (recoverySnapshotImage) excludeFromSnapshot(m LinkableInterface) bool {
-	return m.ExcludeFromRecoverySnapshot()
-}
-
-func (recoverySnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool {
-	recoverySnapshotVersion := cfg.RecoverySnapshotVersion()
-	return recoverySnapshotVersion != "current" && recoverySnapshotVersion != ""
-}
-
-func (recoverySnapshotImage) targetSnapshotVersion(cfg android.DeviceConfig) string {
-	return cfg.RecoverySnapshotVersion()
-}
-
-func (recoverySnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
-	// If we're using full snapshot, not directed snapshot, capture every module
-	if !cfg.DirectedRecoverySnapshot() {
-		return false
-	}
-	// Else, checks if name is in RECOVERY_SNAPSHOT_MODULES.
-	return !cfg.RecoverySnapshotModules()[name]
-}
-
 func (recoverySnapshotImage) imageVariantName(cfg android.DeviceConfig) string {
 	return android.RecoveryVariation
 }
@@ -258,12 +64,31 @@
 	return recoverySuffix
 }
 
-var VendorSnapshotImageSingleton vendorSnapshotImage
-var recoverySnapshotImageSingleton recoverySnapshotImage
+// Override existing vendor and recovery snapshot for cc module specific extra functions
+var VendorSnapshotImageSingleton vendorSnapshotImage = vendorSnapshotImage{&snapshot.VendorSnapshotImageSingleton}
+var recoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton}
+
+func RegisterVendorSnapshotModules(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory)
+	ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
+	ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
+	ctx.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
+	ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
+	ctx.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory)
+}
+
+func RegisterRecoverySnapshotModules(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("recovery_snapshot", recoverySnapshotFactory)
+	ctx.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory)
+	ctx.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory)
+	ctx.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory)
+	ctx.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory)
+	ctx.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory)
+}
 
 func init() {
-	VendorSnapshotImageSingleton.Init(android.InitRegistrationContext)
-	recoverySnapshotImageSingleton.init(android.InitRegistrationContext)
+	RegisterVendorSnapshotModules(android.InitRegistrationContext)
+	RegisterRecoverySnapshotModules(android.InitRegistrationContext)
 	android.RegisterMakeVarsProvider(pctx, snapshotMakeVarsProvider)
 }
 
@@ -285,8 +110,7 @@
 	Binaries    []string `android:"arch_variant"`
 	Objects     []string `android:"arch_variant"`
 }
-
-type snapshot struct {
+type snapshotModule struct {
 	android.ModuleBase
 
 	properties SnapshotProperties
@@ -296,41 +120,41 @@
 	image SnapshotImage
 }
 
-func (s *snapshot) ImageMutatorBegin(ctx android.BaseModuleContext) {
+func (s *snapshotModule) ImageMutatorBegin(ctx android.BaseModuleContext) {
 	cfg := ctx.DeviceConfig()
-	if !s.image.isUsingSnapshot(cfg) || s.image.targetSnapshotVersion(cfg) != s.baseSnapshot.Version() {
+	if !s.image.IsUsingSnapshot(cfg) || s.image.TargetSnapshotVersion(cfg) != s.baseSnapshot.Version() {
 		s.Disable()
 	}
 }
 
-func (s *snapshot) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *snapshotModule) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
 	return false
 }
 
-func (s *snapshot) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *snapshotModule) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
 	return false
 }
 
-func (s *snapshot) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *snapshotModule) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
 	return false
 }
 
-func (s *snapshot) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *snapshotModule) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
 	return false
 }
 
-func (s *snapshot) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+func (s *snapshotModule) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return false
 }
 
-func (s *snapshot) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+func (s *snapshotModule) ExtraImageVariations(ctx android.BaseModuleContext) []string {
 	return []string{s.image.imageVariantName(ctx.DeviceConfig())}
 }
 
-func (s *snapshot) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+func (s *snapshotModule) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
 }
 
-func (s *snapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (s *snapshotModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// Nothing, the snapshot module is only used to forward dependency information in DepsMutator.
 }
 
@@ -342,7 +166,7 @@
 	return moduleSuffix + versionSuffix
 }
 
-func (s *snapshot) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (s *snapshotModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	collectSnapshotMap := func(names []string, snapshotSuffix, moduleSuffix string) map[string]string {
 		snapshotMap := make(map[string]string)
 		for _, name := range names {
@@ -382,12 +206,12 @@
 
 var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps")
 
-var _ android.ImageInterface = (*snapshot)(nil)
+var _ android.ImageInterface = (*snapshotModule)(nil)
 
 func snapshotMakeVarsProvider(ctx android.MakeVarsContext) {
 	snapshotSet := map[string]struct{}{}
 	ctx.VisitAllModules(func(m android.Module) {
-		if s, ok := m.(*snapshot); ok {
+		if s, ok := m.(*snapshotModule); ok {
 			if _, ok := snapshotSet[s.Name()]; ok {
 				// arch variant generates duplicated modules
 				// skip this as we only need to know the path of the module.
@@ -411,13 +235,13 @@
 }
 
 func snapshotFactory(image SnapshotImage) android.Module {
-	snapshot := &snapshot{}
-	snapshot.image = image
-	snapshot.AddProperties(
-		&snapshot.properties,
-		&snapshot.baseSnapshot.baseProperties)
-	android.InitAndroidArchModule(snapshot, android.DeviceSupported, android.MultilibBoth)
-	return snapshot
+	snapshotModule := &snapshotModule{}
+	snapshotModule.image = image
+	snapshotModule.AddProperties(
+		&snapshotModule.properties,
+		&snapshotModule.baseSnapshot.baseProperties)
+	android.InitAndroidArchModule(snapshotModule, android.DeviceSupported, android.MultilibBoth)
+	return snapshotModule
 }
 
 type BaseSnapshotDecoratorProperties struct {
@@ -449,7 +273,7 @@
 // will be seen as "libbase.vendor_static.30.arm64" by Soong.
 type BaseSnapshotDecorator struct {
 	baseProperties BaseSnapshotDecoratorProperties
-	image          SnapshotImage
+	Image          SnapshotImage
 }
 
 func (p *BaseSnapshotDecorator) Name(name string) string {
@@ -489,7 +313,7 @@
 		Variation: android.CoreVariation})
 
 	if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) {
-		p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix()
+		p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix()
 		return
 	}
 
@@ -498,14 +322,14 @@
 		Variation: ProductVariationPrefix + ctx.DeviceConfig().PlatformVndkVersion()})
 
 	if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) {
-		p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix()
+		p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix()
 		return
 	}
 
 	images := []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton}
 
 	for _, image := range images {
-		if p.image == image {
+		if p.Image == image {
 			continue
 		}
 		variations = append(ctx.Target().Variations(), blueprint.Variation{
@@ -518,7 +342,7 @@
 					image.moduleNameSuffix()+variant,
 					p.Version(),
 					ctx.DeviceConfig().Arches()[0].ArchType.String())) {
-			p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix()
+			p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix()
 			return
 		}
 	}
@@ -529,7 +353,7 @@
 // Call this with a module suffix after creating a snapshot module, such as
 // vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc.
 func (p *BaseSnapshotDecorator) Init(m LinkableInterface, image SnapshotImage, moduleSuffix string) {
-	p.image = image
+	p.Image = image
 	p.baseProperties.ModuleSuffix = image.moduleNameSuffix() + moduleSuffix
 	m.AddProperties(&p.baseProperties)
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index b0538be..24abcce 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -114,7 +114,7 @@
 	}
 
 	for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} {
-		if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) {
+		if isSnapshotAware(ctx.DeviceConfig(), m, image.IsProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) {
 			return true
 		}
 	}
diff --git a/cc/stl.go b/cc/stl.go
index 06dc840..0f2a878 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -15,8 +15,9 @@
 package cc
 
 import (
-	"android/soong/android"
 	"fmt"
+
+	"android/soong/android"
 )
 
 func getNdkStlFamily(m LinkableInterface) string {
@@ -92,26 +93,6 @@
 				ctx.ModuleErrorf("stl: %q is not a supported STL for windows", s)
 				return ""
 			}
-		} else if ctx.Fuchsia() {
-			switch s {
-			case "c++_static":
-				return "libc++_static"
-			case "c++_shared":
-				return "libc++"
-			case "libc++", "libc++_static":
-				return s
-			case "none":
-				return ""
-			case "":
-				if ctx.static() {
-					return "libc++_static"
-				} else {
-					return "libc++"
-				}
-			default:
-				ctx.ModuleErrorf("stl: %q is not a supported STL on Fuchsia", s)
-				return ""
-			}
 		} else {
 			switch s {
 			case "libc++", "libc++_static":
diff --git a/cc/testing.go b/cc/testing.go
index b9d84f6..19513e3 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -20,6 +20,7 @@
 
 	"android/soong/android"
 	"android/soong/genrule"
+	"android/soong/snapshot"
 )
 
 func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
@@ -44,9 +45,6 @@
 
 	supportLinuxBionic := false
 	for _, os := range oses {
-		if os == android.Fuchsia {
-			ret += withFuchsiaModules()
-		}
 		if os == android.Windows {
 			ret += withWindowsModules()
 		}
@@ -471,19 +469,6 @@
 		`
 }
 
-func withFuchsiaModules() string {
-	return `
-		cc_library {
-			name: "libbioniccompat",
-			stl: "none",
-		}
-		cc_library {
-			name: "libcompiler_rt",
-			stl: "none",
-		}
-		`
-}
-
 func withLinuxBionic() string {
 	return `
 				cc_binary {
@@ -625,21 +610,15 @@
 	android.FixtureOverrideTextFile(linuxBionicDefaultsPath, withLinuxBionic()),
 )
 
-// The preparer to include if running a cc related test for fuchsia.
-var PrepareForTestOnFuchsia = android.GroupFixturePreparers(
-	// Place the default cc test modules for fuschia in a location that will not conflict with default
-	// test modules defined by other packages.
-	android.FixtureAddTextFile("defaults/cc/fuschia/Android.bp", withFuchsiaModules()),
-	android.PrepareForTestSetDeviceToFuchsia,
-)
-
 // This adds some additional modules and singletons which might negatively impact the performance
 // of tests so they are not included in the PrepareForIntegrationTestWithCc.
 var PrepareForTestWithCcIncludeVndk = android.GroupFixturePreparers(
 	PrepareForIntegrationTestWithCc,
 	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-		VendorSnapshotImageSingleton.Init(ctx)
-		recoverySnapshotImageSingleton.init(ctx)
+		snapshot.VendorSnapshotImageSingleton.Init(ctx)
+		snapshot.RecoverySnapshotImageSingleton.Init(ctx)
+		RegisterVendorSnapshotModules(ctx)
+		RegisterRecoverySnapshotModules(ctx)
 		ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 	}),
 )
@@ -663,14 +642,7 @@
 		mockFS[k] = v
 	}
 
-	var config android.Config
-	if os == android.Fuchsia {
-		panic("Fuchsia not supported use test fixture instead")
-	} else {
-		config = android.TestArchConfig(buildDir, env, bp, mockFS)
-	}
-
-	return config
+	return android.TestArchConfig(buildDir, env, bp, mockFS)
 }
 
 // CreateTestContext is the legacy way of creating a TestContext for testing cc modules.
@@ -687,8 +659,10 @@
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
 
-	VendorSnapshotImageSingleton.Init(ctx)
-	recoverySnapshotImageSingleton.init(ctx)
+	snapshot.VendorSnapshotImageSingleton.Init(ctx)
+	snapshot.RecoverySnapshotImageSingleton.Init(ctx)
+	RegisterVendorSnapshotModules(ctx)
+	RegisterRecoverySnapshotModules(ctx)
 	ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 	RegisterVndkLibraryTxtTypes(ctx)
 
diff --git a/cc/util.go b/cc/util.go
index 1220d84..9bba876 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -21,6 +21,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/snapshot"
 )
 
 // Efficiently converts a list of include directories to a single string
@@ -126,20 +127,6 @@
 		"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{
@@ -151,12 +138,6 @@
 	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}
@@ -172,5 +153,5 @@
 		txtBuilder.WriteString(" ")
 		txtBuilder.WriteString(m[k])
 	}
-	return writeStringToFileRule(ctx, txtBuilder.String(), path)
+	return snapshot.WriteStringToFileRule(ctx, txtBuilder.String(), path)
 }
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 003b7c9..ba4d79f 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -13,141 +13,46 @@
 // 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"
 
 	"android/soong/android"
+	"android/soong/snapshot"
 )
 
-var vendorSnapshotSingleton = snapshotSingleton{
-	"vendor",
-	"SOONG_VENDOR_SNAPSHOT_ZIP",
-	android.OptionalPath{},
-	true,
-	VendorSnapshotImageSingleton,
-	false, /* fake */
-}
+// This file defines how to capture cc modules into snapshot package.
 
-var vendorFakeSnapshotSingleton = snapshotSingleton{
-	"vendor",
-	"SOONG_VENDOR_FAKE_SNAPSHOT_ZIP",
-	android.OptionalPath{},
-	true,
-	VendorSnapshotImageSingleton,
-	true, /* fake */
-}
-
-var recoverySnapshotSingleton = snapshotSingleton{
-	"recovery",
-	"SOONG_RECOVERY_SNAPSHOT_ZIP",
-	android.OptionalPath{},
-	false,
-	recoverySnapshotImageSingleton,
-	false, /* fake */
-}
-
-func VendorSnapshotSingleton() android.Singleton {
-	return &vendorSnapshotSingleton
-}
-
-func VendorFakeSnapshotSingleton() android.Singleton {
-	return &vendorFakeSnapshotSingleton
-}
-
-func RecoverySnapshotSingleton() android.Singleton {
-	return &recoverySnapshotSingleton
-}
-
-type snapshotSingleton struct {
-	// Name, e.g., "vendor", "recovery", "ramdisk".
-	name string
-
-	// Make variable that points to the snapshot file, e.g.,
-	// "SOONG_RECOVERY_SNAPSHOT_ZIP".
-	makeVar string
-
-	// Path to the snapshot zip file.
-	snapshotZipFile android.OptionalPath
-
-	// Whether the image supports VNDK extension modules.
-	supportsVndkExt bool
-
-	// Implementation of the image interface specific to the image
-	// associated with this snapshot (e.g., specific to the vendor image,
-	// recovery image, etc.).
-	image SnapshotImage
-
-	// Whether this singleton is for fake snapshot or not.
-	// Fake snapshot is a snapshot whose prebuilt binaries and headers are empty.
-	// It is much faster to generate, and can be used to inspect dependencies.
-	fake bool
-}
-
-// Determine if a dir under source tree is an SoC-owned proprietary directory based
-// on vendor snapshot configuration
-// Examples: device/, vendor/
-func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return VendorSnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig)
-}
-
-// Determine if a dir under source tree is an SoC-owned proprietary directory based
-// on recovery snapshot configuration
-// Examples: device/, vendor/
-func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return RecoverySnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig)
-}
-
-func IsVendorProprietaryModule(ctx android.BaseModuleContext) bool {
-	// Any module in a vendor proprietary path is a vendor proprietary
-	// module.
-	if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
+// Checks if the target image would contain VNDK
+func includeVndk(image snapshot.SnapshotImage) bool {
+	if image.ImageName() == snapshot.VendorSnapshotImageName {
 		return true
 	}
 
-	// However if the module is not in a vendor proprietary path, it may
-	// 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().(LinkableInterface); ok {
-		if c.ExcludeFromVendorSnapshot() {
-			return true
-		}
-	}
-
 	return false
 }
 
-func isRecoveryProprietaryModule(ctx android.BaseModuleContext) bool {
-
-	// Any module in a recovery proprietary path is a recovery proprietary
-	// module.
-	if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
+// Check if the module is VNDK private
+func isPrivate(image snapshot.SnapshotImage, m LinkableInterface) bool {
+	if image.ImageName() == snapshot.VendorSnapshotImageName && m.IsVndkPrivate() {
 		return true
 	}
 
-	// However if the module is not in a recovery proprietary path, it may
-	// still be a recovery proprietary module. This happens for cc modules
-	// that are excluded from the recovery snapshot, and it means that the
-	// vendor has assumed control of the framework-provided module.
+	return false
+}
 
-	if c, ok := ctx.Module().(LinkableInterface); ok {
-		if c.ExcludeFromRecoverySnapshot() {
-			return true
-		}
+// Checks if target image supports VNDK Ext
+func supportsVndkExt(image snapshot.SnapshotImage) bool {
+	if image.ImageName() == snapshot.VendorSnapshotImageName {
+		return true
 	}
 
 	return false
 }
 
 // Determines if the module is a candidate for snapshot.
-func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image SnapshotImage) bool {
+func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshot.SnapshotImage) bool {
 	if !m.Enabled() || m.HiddenFromMake() {
 		return false
 	}
@@ -158,12 +63,12 @@
 	}
 	// skip proprietary modules, but (for the vendor snapshot only)
 	// include all VNDK (static)
-	if inProprietaryPath && (!image.includeVndk() || !m.IsVndk()) {
+	if inProprietaryPath && (!includeVndk(image) || !m.IsVndk()) {
 		return false
 	}
 	// If the module would be included based on its path, check to see if
 	// the module is marked to be excluded. If so, skip it.
-	if image.excludeFromSnapshot(m) {
+	if image.ExcludeFromSnapshot(m) {
 		return false
 	}
 	if m.Target().Os.Class != android.Device {
@@ -173,7 +78,7 @@
 		return false
 	}
 	// the module must be installed in target image
-	if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.inImage(m)() {
+	if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.InImage(m)() {
 		return false
 	}
 	// skip kernel_headers which always depend on vendor
@@ -203,13 +108,13 @@
 			}
 		}
 		if sanitizable.Static() {
-			return sanitizable.OutputFile().Valid() && !image.private(m)
+			return sanitizable.OutputFile().Valid() && !isPrivate(image, m)
 		}
 		if sanitizable.Shared() || sanitizable.Rlib() {
 			if !sanitizable.OutputFile().Valid() {
 				return false
 			}
-			if image.includeVndk() {
+			if includeVndk(image) {
 				if !sanitizable.IsVndk() {
 					return true
 				}
@@ -256,15 +161,9 @@
 	VintfFragments []string `json:",omitempty"`
 }
 
-func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	if !c.image.shouldGenerateSnapshot(ctx) {
-		return
-	}
-
-	var snapshotOutputs android.Paths
-
+var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths {
 	/*
-		Vendor snapshot zipped artifacts directory structure:
+		Vendor snapshot zipped artifacts directory structure for cc modules:
 		{SNAPSHOT_ARCH}/
 			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
 				shared/
@@ -296,13 +195,7 @@
 				(header files of same directory structure with source tree)
 	*/
 
-	snapshotDir := c.name + "-snapshot"
-	if c.fake {
-		// If this is a fake snapshot singleton, place all files under fake/ subdirectory to avoid
-		// collision with real snapshot files
-		snapshotDir = filepath.Join("fake", snapshotDir)
-	}
-	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+	var snapshotOutputs android.Paths
 
 	includeDir := filepath.Join(snapshotArchDir, "include")
 	configsDir := filepath.Join(snapshotArchDir, "configs")
@@ -317,9 +210,9 @@
 		if fake {
 			// All prebuilt binaries and headers are installed by copyFile function. This makes a fake
 			// snapshot just touch prebuilts and headers, rather than installing real files.
-			return writeStringToFileRule(ctx, "", out)
+			return snapshot.WriteStringToFileRule(ctx, "", out)
 		} else {
-			return copyFileRule(ctx, path, out)
+			return snapshot.CopyFileRule(pctx, ctx, path, out)
 		}
 	}
 
@@ -337,7 +230,7 @@
 
 		// Common properties among snapshots.
 		prop.ModuleName = ctx.ModuleName(m)
-		if c.supportsVndkExt && m.IsVndkExt() {
+		if supportsVndkExt(s.Image) && m.IsVndkExt() {
 			// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
 			if m.IsVndkSp() {
 				prop.RelativeInstallPath = "vndk-sp"
@@ -457,7 +350,7 @@
 			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
 			return nil
 		}
-		ret = append(ret, writeStringToFileRule(ctx, string(j), propOut))
+		ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
 
 		return ret
 	}
@@ -469,10 +362,10 @@
 		}
 
 		moduleDir := ctx.ModuleDir(module)
-		inProprietaryPath := c.image.isProprietaryPath(moduleDir, ctx.DeviceConfig())
+		inProprietaryPath := s.Image.IsProprietaryPath(moduleDir, ctx.DeviceConfig())
 		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
 
-		if c.image.excludeFromSnapshot(m) {
+		if s.Image.ExcludeFromSnapshot(m) {
 			if inProprietaryPath {
 				// Error: exclude_from_vendor_snapshot applies
 				// to framework-path modules only.
@@ -481,7 +374,7 @@
 			}
 		}
 
-		if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, c.image) {
+		if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, s.Image) {
 			return
 		}
 
@@ -489,8 +382,8 @@
 		// list, we will still include the module as if it was a fake module.
 		// The reason is that soong needs all the dependencies to be present, even
 		// if they are not using during the build.
-		installAsFake := c.fake
-		if c.image.excludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
+		installAsFake := s.Fake
+		if s.Image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
 			installAsFake = true
 		}
 
@@ -514,47 +407,12 @@
 
 	// install all headers after removing duplicates
 	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), c.fake))
+		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), s.Fake))
 	}
 
-	// All artifacts are ready. Sort them to normalize ninja and then zip.
-	sort.Slice(snapshotOutputs, func(i, j int) bool {
-		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
-	})
-
-	zipPath := android.PathForOutput(
-		ctx,
-		snapshotDir,
-		c.name+"-"+ctx.Config().DeviceName()+".zip")
-	zipRule := android.NewRuleBuilder(pctx, ctx)
-
-	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
-	snapshotOutputList := android.PathForOutput(
-		ctx,
-		snapshotDir,
-		c.name+"-"+ctx.Config().DeviceName()+"_list")
-	rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp")
-	zipRule.Command().
-		Text("tr").
-		FlagWithArg("-d ", "\\'").
-		FlagWithRspFileInputList("< ", rspFile, snapshotOutputs).
-		FlagWithOutput("> ", snapshotOutputList)
-
-	zipRule.Temporary(snapshotOutputList)
-
-	zipRule.Command().
-		BuiltTool("soong_zip").
-		FlagWithOutput("-o ", zipPath).
-		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
-		FlagWithInput("-l ", snapshotOutputList)
-
-	zipRule.Build(zipPath.String(), c.name+" snapshot "+zipPath.String())
-	zipRule.DeleteTemporaryFiles()
-	c.snapshotZipFile = android.OptionalPathForPath(zipPath)
+	return snapshotOutputs
 }
 
-func (c *snapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
-	ctx.Strict(
-		c.makeVar,
-		c.snapshotZipFile.String())
+func init() {
+	snapshot.RegisterSnapshotAction(ccSnapshotAction)
 }
diff --git a/cc/vndk.go b/cc/vndk.go
index 499d428..1ae79de 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -25,6 +25,7 @@
 	"android/soong/android"
 	"android/soong/cc/config"
 	"android/soong/etc"
+	"android/soong/snapshot"
 
 	"github.com/google/blueprint"
 )
@@ -698,7 +699,7 @@
 
 		libPath := m.outputFile.Path()
 		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
-		ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut))
+		ret = append(ret, snapshot.CopyFileRule(pctx, ctx, libPath, snapshotLibOut))
 
 		if ctx.Config().VndkSnapshotBuildArtifacts() {
 			prop := struct {
@@ -720,7 +721,7 @@
 				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
 				return nil, false
 			}
-			ret = append(ret, writeStringToFileRule(ctx, string(j), propOut))
+			ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
 		}
 		return ret, true
 	}
@@ -778,8 +779,8 @@
 
 	// install all headers after removing duplicates
 	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, copyFileRule(
-			ctx, header, filepath.Join(includeDir, header.String())))
+		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
+			pctx, ctx, header, filepath.Join(includeDir, header.String())))
 	}
 
 	// install *.libraries.txt except vndkcorevariant.libraries.txt
@@ -788,8 +789,8 @@
 		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
 			return
 		}
-		snapshotOutputs = append(snapshotOutputs, copyFileRule(
-			ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
+		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
+			pctx, ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
 	})
 
 	/*
diff --git a/etc/Android.bp b/etc/Android.bp
index cab7389..06a2fa1 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -9,6 +9,7 @@
         "blueprint",
         "soong",
         "soong-android",
+        "soong-snapshot",
     ],
     srcs: [
         "prebuilt_etc.go",
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 4dd383d..4107916 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -28,12 +28,15 @@
 // various `prebuilt_*` mutators.
 
 import (
+	"encoding/json"
 	"fmt"
+	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/snapshot"
 )
 
 var pctx = android.NewPackageContext("android/soong/etc")
@@ -43,6 +46,7 @@
 func init() {
 	pctx.Import("android/soong/android")
 	RegisterPrebuiltEtcBuildComponents(android.InitRegistrationContext)
+	snapshot.RegisterSnapshotAction(generatePrebuiltSnapshot)
 }
 
 func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) {
@@ -128,6 +132,9 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 
+	snapshot.VendorSnapshotModuleInterface
+	snapshot.RecoverySnapshotModuleInterface
+
 	properties       prebuiltEtcProperties
 	subdirProperties prebuiltSubdirProperties
 
@@ -183,7 +190,7 @@
 	return p.inDebugRamdisk()
 }
 
-func (p *PrebuiltEtc) inRecovery() bool {
+func (p *PrebuiltEtc) InRecovery() bool {
 	return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
 }
 
@@ -192,7 +199,7 @@
 }
 
 func (p *PrebuiltEtc) InstallInRecovery() bool {
-	return p.inRecovery()
+	return p.InRecovery()
 }
 
 var _ android.ImageInterface = (*PrebuiltEtc)(nil)
@@ -271,6 +278,18 @@
 	return p.properties.Installable == nil || proptools.Bool(p.properties.Installable)
 }
 
+func (p *PrebuiltEtc) InVendor() bool {
+	return p.ModuleBase.InstallInVendor()
+}
+
+func (p *PrebuiltEtc) ExcludeFromVendorSnapshot() bool {
+	return false
+}
+
+func (p *PrebuiltEtc) ExcludeFromRecoverySnapshot() bool {
+	return false
+}
+
 func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if p.properties.Src == nil {
 		ctx.PropertyErrorf("src", "missing prebuilt source file")
@@ -344,7 +363,7 @@
 	if p.inDebugRamdisk() && !p.onlyInDebugRamdisk() {
 		nameSuffix = ".debug_ramdisk"
 	}
-	if p.inRecovery() && !p.onlyInRecovery() {
+	if p.InRecovery() && !p.onlyInRecovery() {
 		nameSuffix = ".recovery"
 	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
@@ -494,3 +513,137 @@
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	return module
 }
+
+// Flags to be included in the snapshot
+type snapshotJsonFlags struct {
+	ModuleName          string `json:",omitempty"`
+	Filename            string `json:",omitempty"`
+	RelativeInstallPath string `json:",omitempty"`
+}
+
+// Copy file into the snapshot
+func copyFile(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath {
+	if fake {
+		// Create empty file instead for the fake snapshot
+		return snapshot.WriteStringToFileRule(ctx, "", out)
+	} else {
+		return snapshot.CopyFileRule(pctx, ctx, path, out)
+	}
+}
+
+// Check if the module is target of the snapshot
+func isSnapshotAware(ctx android.SingletonContext, m *PrebuiltEtc, image snapshot.SnapshotImage) bool {
+	if !m.Enabled() {
+		return false
+	}
+
+	// Skip if the module is not included in the image
+	if !image.InImage(m)() {
+		return false
+	}
+
+	// When android/prebuilt.go selects between source and prebuilt, it sets
+	// HideFromMake on the other one to avoid duplicate install rules in make.
+	if m.IsHideFromMake() {
+		return false
+	}
+
+	// There are some prebuilt_etc module with multiple definition of same name.
+	// Check if the target would be included from the build
+	if !m.ExportedToMake() {
+		return false
+	}
+
+	// Skip if the module is in the predefined path list to skip
+	if image.IsProprietaryPath(ctx.ModuleDir(m), ctx.DeviceConfig()) {
+		return false
+	}
+
+	// Skip if the module should be excluded
+	if image.ExcludeFromSnapshot(m) || image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
+		return false
+	}
+
+	// Skip from other exceptional cases
+	if m.Target().Os.Class != android.Device {
+		return false
+	}
+	if m.Target().NativeBridge == android.NativeBridgeEnabled {
+		return false
+	}
+
+	return true
+}
+
+func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths {
+	/*
+		Snapshot zipped artifacts directory structure for etc modules:
+		{SNAPSHOT_ARCH}/
+			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
+				etc/
+					(prebuilt etc files)
+			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
+				etc/
+					(prebuilt etc files)
+			NOTICE_FILES/
+				(notice files)
+	*/
+	var snapshotOutputs android.Paths
+	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+	installedNotices := make(map[string]bool)
+
+	ctx.VisitAllModules(func(module android.Module) {
+		m, ok := module.(*PrebuiltEtc)
+		if !ok {
+			return
+		}
+
+		if !isSnapshotAware(ctx, m, s.Image) {
+			return
+		}
+
+		targetArch := "arch-" + m.Target().Arch.ArchType.String()
+
+		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "etc", m.BaseModuleName())
+		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, m.OutputFile(), snapshotLibOut, s.Fake))
+
+		prop := snapshotJsonFlags{}
+		propOut := snapshotLibOut + ".json"
+		prop.ModuleName = m.BaseModuleName()
+		if m.subdirProperties.Relative_install_path != nil {
+			prop.RelativeInstallPath = *m.subdirProperties.Relative_install_path
+		}
+
+		if m.properties.Filename != nil {
+			prop.Filename = *m.properties.Filename
+		}
+
+		j, err := json.Marshal(prop)
+		if err != nil {
+			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
+			return
+		}
+		snapshotOutputs = append(snapshotOutputs, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
+
+		if len(m.EffectiveLicenseFiles()) > 0 {
+			noticeName := ctx.ModuleName(m) + ".txt"
+			noticeOut := filepath.Join(noticeDir, noticeName)
+			// skip already copied notice file
+			if !installedNotices[noticeOut] {
+				installedNotices[noticeOut] = true
+
+				noticeOutPath := android.PathForOutput(ctx, noticeOut)
+				ctx.Build(pctx, android.BuildParams{
+					Rule:        android.Cat,
+					Inputs:      m.EffectiveLicenseFiles(),
+					Output:      noticeOutPath,
+					Description: "combine notices for " + noticeOut,
+				})
+				snapshotOutputs = append(snapshotOutputs, noticeOutPath)
+			}
+		}
+
+	})
+
+	return snapshotOutputs
+}
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 354f6bb..cf1f6d7 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -15,11 +15,15 @@
 package etc
 
 import (
+	"fmt"
 	"os"
 	"path/filepath"
 	"testing"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
+	"android/soong/snapshot"
 )
 
 func TestMain(m *testing.M) {
@@ -36,6 +40,18 @@
 	}),
 )
 
+var prepareForPrebuiltEtcSnapshotTest = android.GroupFixturePreparers(
+	prepareForPrebuiltEtcTest,
+	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+		snapshot.VendorSnapshotImageSingleton.Init(ctx)
+		snapshot.RecoverySnapshotImageSingleton.Init(ctx)
+	}),
+	android.FixtureModifyConfig(func(config android.Config) {
+		config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
+		config.TestProductVariables.RecoverySnapshotVersion = proptools.StringPtr("current")
+	}),
+)
+
 func TestPrebuiltEtcVariants(t *testing.T) {
 	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
@@ -172,7 +188,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := result.Config.BuildOS.String()
 	p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc)
 	if !p.Host() {
 		t.Errorf("host bit is not set for a prebuilt_etc_host module.")
@@ -226,7 +242,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := result.Config.BuildOS.String()
 	p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc)
 	expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "usr", "share", "bar")
 	android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
@@ -346,3 +362,110 @@
 		})
 	}
 }
+
+func checkIfSnapshotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) {
+	checkIfSnapshotExistAsExpected(t, result, image, moduleName, true)
+}
+
+func checkIfSnapshotNotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) {
+	checkIfSnapshotExistAsExpected(t, result, image, moduleName, false)
+}
+
+func checkIfSnapshotExistAsExpected(t *testing.T, result *android.TestResult, image string, moduleName string, expectToExist bool) {
+	snapshotSingleton := result.SingletonForTests(image + "-snapshot")
+	archType := "arm64"
+	archVariant := "armv8-a"
+	archDir := fmt.Sprintf("arch-%s", archType)
+
+	snapshotDir := fmt.Sprintf("%s-snapshot", image)
+	snapshotVariantPath := filepath.Join(snapshotDir, archType)
+	outputDir := filepath.Join(snapshotVariantPath, archDir, "etc")
+	imageVariant := ""
+	if image == "recovery" {
+		imageVariant = "recovery_"
+	}
+	mod := result.ModuleForTests(moduleName, fmt.Sprintf("android_%s%s_%s", imageVariant, archType, archVariant))
+	outputFiles := mod.OutputFiles(t, "")
+	if len(outputFiles) != 1 {
+		t.Errorf("%q must have single output\n", moduleName)
+		return
+	}
+	snapshotPath := filepath.Join(outputDir, moduleName)
+
+	if expectToExist {
+		out := snapshotSingleton.Output(snapshotPath)
+
+		if out.Input.String() != outputFiles[0].String() {
+			t.Errorf("The input of snapshot %q must be %q, but %q", "prebuilt_vendor", out.Input.String(), outputFiles[0])
+		}
+
+		snapshotJsonPath := snapshotPath + ".json"
+
+		if snapshotSingleton.MaybeOutput(snapshotJsonPath).Rule == nil {
+			t.Errorf("%q expected but not found", snapshotJsonPath)
+		}
+	} else {
+		out := snapshotSingleton.MaybeOutput(snapshotPath)
+		if out.Rule != nil {
+			t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0])
+		}
+	}
+}
+
+func TestPrebuiltTakeSnapshot(t *testing.T) {
+	var testBp = `
+	prebuilt_etc {
+		name: "prebuilt_vendor",
+		src: "foo.conf",
+		vendor: true,
+	}
+
+	prebuilt_etc {
+		name: "prebuilt_vendor_indirect",
+		src: "foo.conf",
+		vendor: true,
+	}
+
+	prebuilt_etc {
+		name: "prebuilt_recovery",
+		src: "bar.conf",
+		recovery: true,
+	}
+
+	prebuilt_etc {
+		name: "prebuilt_recovery_indirect",
+		src: "bar.conf",
+		recovery: true,
+	}
+	`
+
+	t.Run("prebuilt: vendor and recovery snapshot", func(t *testing.T) {
+		result := prepareForPrebuiltEtcSnapshotTest.RunTestWithBp(t, testBp)
+
+		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor")
+		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor_indirect")
+		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery")
+		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery_indirect")
+	})
+
+	t.Run("prebuilt: directed snapshot", func(t *testing.T) {
+		prepareForPrebuiltEtcDirectedSnapshotTest := android.GroupFixturePreparers(
+			prepareForPrebuiltEtcSnapshotTest,
+			android.FixtureModifyConfig(func(config android.Config) {
+				config.TestProductVariables.DirectedVendorSnapshot = true
+				config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
+				config.TestProductVariables.VendorSnapshotModules["prebuilt_vendor"] = true
+				config.TestProductVariables.DirectedRecoverySnapshot = true
+				config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
+				config.TestProductVariables.RecoverySnapshotModules["prebuilt_recovery"] = true
+			}),
+		)
+
+		result := prepareForPrebuiltEtcDirectedSnapshotTest.RunTestWithBp(t, testBp)
+
+		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor")
+		checkIfSnapshotNotTaken(t, result, "vendor", "prebuilt_vendor_indirect")
+		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery")
+		checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect")
+	})
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index dff9543..2c78d73 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -523,14 +523,14 @@
 }
 
 // buildBootImageVariantsForBuildOs generates rules to build the boot image variants for the
-// android.BuildOs OsType, i.e. the type of OS on which the build is being running.
+// config.BuildOS OsType, i.e. the type of OS on which the build is being running.
 //
 // The files need to be generated into their predefined location because they are used from there
 // both within Soong and outside, e.g. for ART based host side testing and also for use by some
 // cloud based tools. However, they are not needed by callers of this function and so the paths do
 // not need to be returned from this func, unlike the buildBootImageVariantsForAndroidOs func.
 func buildBootImageVariantsForBuildOs(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) {
-	buildBootImageForOsType(ctx, image, profile, android.BuildOs)
+	buildBootImageForOsType(ctx, image, profile, ctx.Config().BuildOS)
 }
 
 // buildBootImageForOsType takes a bootImageConfig, a profile file and an android.OsType
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index b13955f..1507aaf 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -32,7 +32,7 @@
 		}
 	}
 	// We may also need the images on host in order to run host-based tests.
-	for _, target := range ctx.Config().Targets[android.BuildOs] {
+	for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
 		targets = append(targets, target)
 	}
 
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index b25dece..8dc7b79 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"runtime"
 	"testing"
 
 	"android/soong/android"
@@ -173,9 +174,9 @@
 }
 
 func TestDex2oatToolDeps(t *testing.T) {
-	if android.BuildOs != android.Linux {
+	if runtime.GOOS != "linux" {
 		// The host binary paths checked below are build OS dependent.
-		t.Skipf("Unsupported build OS %s", android.BuildOs)
+		t.Skipf("Unsupported build OS %s", runtime.GOOS)
 	}
 
 	preparers := android.GroupFixturePreparers(
diff --git a/java/java_test.go b/java/java_test.go
index 0f9965d..b6780c2 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -441,7 +441,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := ctx.Config().BuildOS.String()
 
 	bar := ctx.ModuleForTests("bar", buildOS+"_common")
 	barJar := bar.Output("bar.jar").Output.String()
@@ -478,7 +478,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := ctx.Config().BuildOS.String()
 
 	foo := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
 
@@ -523,7 +523,7 @@
 	}
 
 	// check that -g is not overridden for host modules
-	buildOS := android.BuildOs.String()
+	buildOS := result.Config.BuildOS.String()
 	hostBinary := result.ModuleForTests("host_binary", buildOS+"_common")
 	hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"]
 	if strings.Contains(hostJavaFlags, "-g:source,lines") {
@@ -1371,7 +1371,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := ctx.Config().BuildOS.String()
 
 	test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
 	entries := android.AndroidMkEntriesForTest(t, ctx, test)[0]
@@ -1387,7 +1387,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := ctx.Config().BuildOS.String()
 	module := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
 	assertDeepEquals(t, "Default installable value should be true.", proptools.BoolPtr(true),
 		module.properties.Installable)
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index fd2f3ca..db30696 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -15,10 +15,11 @@
 package java
 
 import (
-	"android/soong/android"
 	"strconv"
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 func TestKotlin(t *testing.T) {
@@ -114,7 +115,7 @@
 	t.Run("", func(t *testing.T) {
 		ctx, _ := testJava(t, bp)
 
-		buildOS := android.BuildOs.String()
+		buildOS := ctx.Config().BuildOS.String()
 
 		kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
 		kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
@@ -182,7 +183,7 @@
 			android.FixtureMergeEnv(env),
 		).RunTestWithBp(t, bp)
 
-		buildOS := android.BuildOs.String()
+		buildOS := result.Config.BuildOS.String()
 
 		kapt := result.ModuleForTests("foo", "android_common").Rule("kapt")
 		javac := result.ModuleForTests("foo", "android_common").Description("javac")
diff --git a/java/plugin_test.go b/java/plugin_test.go
index c7913d3..dc29b1c 100644
--- a/java/plugin_test.go
+++ b/java/plugin_test.go
@@ -15,7 +15,6 @@
 package java
 
 import (
-	"android/soong/android"
 	"testing"
 )
 
@@ -58,7 +57,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := ctx.Config().BuildOS.String()
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
 	turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine")
@@ -98,7 +97,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := ctx.Config().BuildOS.String()
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
 	turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine")
diff --git a/java/robolectric.go b/java/robolectric.go
index a37a118..a0c9c7f 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -83,6 +83,9 @@
 
 	testConfig android.Path
 	data       android.Paths
+
+	forceOSType   android.OsType
+	forceArchType android.ArchType
 }
 
 func (r *robolectricTest) TestSuites() []string {
@@ -115,6 +118,9 @@
 }
 
 func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.forceOSType = ctx.Config().BuildOS
+	r.forceArchType = ctx.Config().BuildArch
+
 	r.testConfig = tradefed.AutoGenRobolectricTestConfig(ctx, r.testProperties.Test_config,
 		r.testProperties.Test_config_template, r.testProperties.Test_suites,
 		r.testProperties.Auto_gen_config)
@@ -345,7 +351,7 @@
 func (r *robolectricTest) InstallBypassMake() bool  { return true }
 func (r *robolectricTest) InstallInTestcases() bool { return true }
 func (r *robolectricTest) InstallForceOS() (*android.OsType, *android.ArchType) {
-	return &android.BuildOs, &android.BuildArch
+	return &r.forceOSType, &r.forceArchType
 }
 
 func robolectricRuntimesFactory() android.Module {
@@ -366,6 +372,9 @@
 	props robolectricRuntimesProperties
 
 	runtimes []android.InstallPath
+
+	forceOSType   android.OsType
+	forceArchType android.ArchType
 }
 
 func (r *robolectricRuntimes) TestSuites() []string {
@@ -385,6 +394,9 @@
 		return
 	}
 
+	r.forceOSType = ctx.Config().BuildOS
+	r.forceArchType = ctx.Config().BuildArch
+
 	files := android.PathsForModuleSrc(ctx, r.props.Jars)
 
 	androidAllDir := android.PathForModuleInstall(ctx, "android-all")
@@ -417,5 +429,5 @@
 func (r *robolectricRuntimes) InstallBypassMake() bool  { return true }
 func (r *robolectricRuntimes) InstallInTestcases() bool { return true }
 func (r *robolectricRuntimes) InstallForceOS() (*android.OsType, *android.ArchType) {
-	return &android.BuildOs, &android.BuildArch
+	return &r.forceOSType, &r.forceArchType
 }
diff --git a/java/sdk_test.go b/java/sdk_test.go
index bb595a5..6d62130 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -255,9 +255,11 @@
 				` + testcase.properties + `
 			}`
 
-			variant := "android_common"
-			if testcase.host == android.Host {
-				variant = android.BuildOs.String() + "_common"
+			variant := func(result *android.TestResult) string {
+				if testcase.host == android.Host {
+					return result.Config.BuildOS.String() + "_common"
+				}
+				return "android_common"
 			}
 
 			convertModulesToPaths := func(cp []string) []string {
@@ -312,7 +314,7 @@
 			}
 
 			checkClasspath := func(t *testing.T, result *android.TestResult, isJava8 bool) {
-				foo := result.ModuleForTests("foo", variant)
+				foo := result.ModuleForTests("foo", variant(result))
 				javac := foo.Rule("javac")
 				var deps []string
 
@@ -376,7 +378,7 @@
 				checkClasspath(t, result, true /* isJava8 */)
 
 				if testcase.host != android.Host {
-					aidl := result.ModuleForTests("foo", variant).Rule("aidl")
+					aidl := result.ModuleForTests("foo", variant(result)).Rule("aidl")
 
 					android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.")
 				}
@@ -389,7 +391,7 @@
 				checkClasspath(t, result, false /* isJava8 */)
 
 				if testcase.host != android.Host {
-					aidl := result.ModuleForTests("foo", variant).Rule("aidl")
+					aidl := result.ModuleForTests("foo", variant(result)).Rule("aidl")
 
 					android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.")
 				}
diff --git a/rust/Android.bp b/rust/Android.bp
index 11069d1..221014e 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -11,6 +11,7 @@
         "soong-bloaty",
         "soong-cc",
         "soong-rust-config",
+        "soong-snapshot",
     ],
     srcs: [
         "androidmk.go",
diff --git a/rust/binary_test.go b/rust/binary_test.go
index 86f50d3..968c0c1 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -114,6 +114,23 @@
 	}
 }
 
+// Test that the bootstrap property sets the appropriate linker
+func TestBootstrap(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary {
+			name: "foo",
+			srcs: ["foo.rs"],
+			bootstrap: true,
+		}`)
+
+	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
+
+	flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
+	if !strings.Contains(foo.Args["linkFlags"], flag) {
+		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, linkFlags: %#v", flag, foo.Args["linkFlags"])
+	}
+}
+
 func TestStaticBinaryFlags(t *testing.T) {
 	ctx := testRust(t, `
 		rust_binary {
diff --git a/rust/builder.go b/rust/builder.go
index 6db508d..523428d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -220,6 +220,15 @@
 	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
 	linkFlags = append(linkFlags, flags.LinkFlags...)
 
+	// Check if this module needs to use the bootstrap linker
+	if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
+		dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
+		if ctx.toolchain().Is64Bit() {
+			dynamicLinker += "64"
+		}
+		linkFlags = append(linkFlags, dynamicLinker)
+	}
+
 	libFlags := makeLibFlags(deps)
 
 	// Collect dependencies
diff --git a/rust/compiler.go b/rust/compiler.go
index 0b28135..df77759 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -305,7 +305,7 @@
 	if !Bool(compiler.Properties.No_stdlibs) {
 		for _, stdlib := range config.Stdlibs {
 			// If we're building for the primary arch of the build host, use the compiler's stdlibs
-			if ctx.Target().Os == android.BuildOs {
+			if ctx.Target().Os == ctx.Config().BuildOS {
 				stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
 			}
 			deps.Stdlibs = append(deps.Stdlibs, stdlib)
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 31ec3f1..f568f27 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -6,6 +6,7 @@
 	// for an example.
 	// TODO(b/160223496): enable rustfmt globally.
 	RustAllowedPaths = []string{
+		"bionic/libc",
 		"device/google/cuttlefish",
 		"external/adhd",
 		"external/crosvm",
diff --git a/rust/library.go b/rust/library.go
index 5a36bd1..8c10e29 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -21,6 +21,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/snapshot"
 )
 
 var (
@@ -645,7 +646,7 @@
 			variation := v.(*Module).ModuleBase.ImageVariation().Variation
 			if strings.HasPrefix(variation, cc.VendorVariationPrefix) &&
 				m.HasVendorVariant() &&
-				!cc.IsVendorProprietaryModule(mctx) &&
+				!snapshot.IsVendorProprietaryModule(mctx) &&
 				strings.TrimPrefix(variation, cc.VendorVariationPrefix) == mctx.DeviceConfig().VndkVersion() {
 
 				// cc.MutateImage runs before LibraryMutator, so vendor variations which are meant for rlibs only are
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index 09d30db..bdd54c5 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -176,6 +176,8 @@
 }
 
 func TestProjectJsonBindGen(t *testing.T) {
+	buildOS := android.TestConfig(t.TempDir(), nil, "", nil).BuildOS
+
 	bp := `
 	rust_library {
 		name: "libd",
@@ -214,9 +216,9 @@
 		if strings.Contains(rootModule, "libbindings1") && !strings.Contains(rootModule, "android_arm64") {
 			t.Errorf("The source path for libbindings1 does not contain android_arm64, got %v", rootModule)
 		}
-		if strings.Contains(rootModule, "libbindings2") && !strings.Contains(rootModule, android.BuildOs.String()) {
+		if strings.Contains(rootModule, "libbindings2") && !strings.Contains(rootModule, buildOS.String()) {
 			t.Errorf("The source path for libbindings2 does not contain the BuildOs, got %v; want %v",
-				rootModule, android.BuildOs.String())
+				rootModule, buildOS.String())
 		}
 		// Check that libbindings1 does not depend on itself.
 		if strings.Contains(rootModule, "libbindings1") {
diff --git a/rust/rust.go b/rust/rust.go
index 52b4094..931cb9d 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -85,6 +85,10 @@
 	VendorRamdiskVariantNeeded bool     `blueprint:"mutated"`
 	ExtraVariants              []string `blueprint:"mutated"`
 
+	// Allows this module to use non-APEX version of libraries. Useful
+	// for building binaries that are started before APEXes are activated.
+	Bootstrap *bool
+
 	// Used by vendor snapshot to record dependencies from snapshot modules.
 	SnapshotSharedLibs []string `blueprint:"mutated"`
 	SnapshotStaticLibs []string `blueprint:"mutated"`
@@ -288,7 +292,7 @@
 }
 
 func (mod *Module) Bootstrap() bool {
-	return false
+	return Bool(mod.Properties.Bootstrap)
 }
 
 func (mod *Module) MustUseVendorVariant() bool {
diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go
index 2f54973..79eaab3 100644
--- a/rust/snapshot_prebuilt.go
+++ b/rust/snapshot_prebuilt.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/cc"
+
 	"github.com/google/blueprint/proptools"
 )
 
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 8168fbf..4ef4399 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -90,6 +90,15 @@
   else:
     manifest_required, manifest_optional, tags = extract_uses_libs_xml(manifest)
 
+  # Trim namespace component. Normally Soong does that automatically when it
+  # handles module names specified in Android.bp properties. However not all
+  # <uses-library> entries in the manifest correspond to real modules: some of
+  # the optional libraries may be missing at build time. Therefor this script
+  # accepts raw module names as spelled in Android.bp/Amdroid.mk and trims the
+  # optional namespace part manually.
+  required = trim_namespace_parts(required)
+  optional = trim_namespace_parts(optional)
+
   if manifest_required == required and manifest_optional == optional:
     return None
 
@@ -118,6 +127,17 @@
   return errmsg
 
 
+MODULE_NAMESPACE = re.compile("^//[^:]+:")
+
+def trim_namespace_parts(modules):
+  """Trim the namespace part of each module, if present. Leave only the name."""
+
+  trimmed = []
+  for module in modules:
+    trimmed.append(MODULE_NAMESPACE.sub('', module))
+  return trimmed
+
+
 def extract_uses_libs_apk(badging):
   """Extract <uses-library> tags from the manifest of an APK."""
 
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
index 7159bdd..e3e8ac4 100755
--- a/scripts/manifest_check_test.py
+++ b/scripts/manifest_check_test.py
@@ -183,6 +183,15 @@
                             optional_uses_libraries=['bar'])
     self.assertTrue(matches)
 
+  def test_mixed_with_namespace(self):
+    xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
+                                      uses_library_xml('bar', required_xml(False))]))
+    apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
+                                      uses_library_apk('bar', required_apk(False))]))
+    matches = self.run_test(xml, apk, uses_libraries=['//x/y/z:foo'],
+                            optional_uses_libraries=['//x/y/z:bar'])
+    self.assertTrue(matches)
+
 
 class ExtractTargetSdkVersionTest(unittest.TestCase):
   def run_test(self, xml, apk, version):
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 97fb248..85e3d87 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -15,19 +15,21 @@
 package sdk
 
 import (
-	"android/soong/android"
 	"log"
 	"os"
+	"runtime"
 	"testing"
 
+	"android/soong/android"
+
 	"github.com/google/blueprint/proptools"
 )
 
 // Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
 func TestMain(m *testing.M) {
-	if android.BuildOs != android.Linux {
+	if runtime.GOOS != "linux" {
 		// b/145598135 - Generating host snapshots for anything other than linux is not supported.
-		log.Printf("Skipping as sdk snapshot generation is only supported on %s not %s", android.Linux, android.BuildOs)
+		log.Printf("Skipping as sdk snapshot generation is only supported on linux not %s", runtime.GOOS)
 		os.Exit(0)
 	}
 
diff --git a/sdk/update.go b/sdk/update.go
index 3ec1bfa..1cd8f13 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -22,6 +22,7 @@
 
 	"android/soong/apex"
 	"android/soong/cc"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -1774,7 +1775,7 @@
 	var osTypes []android.OsType
 	for _, osType := range android.OsTypeList() {
 		if s.DeviceSupported() {
-			if osType.Class == android.Device && osType != android.Fuchsia {
+			if osType.Class == android.Device {
 				osTypes = append(osTypes, osType)
 			}
 		}
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 20317d8..865d5f3 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -115,7 +115,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := config.BuildOS.String()
 	arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"}
 	for _, arch := range arches {
 		variant := ctx.ModuleForTests("foo", arch)
@@ -155,7 +155,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := ctx.Config().BuildOS.String()
 	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
 	if !mod.Host() {
 		t.Errorf("host bit is not set for a sh_test_host module.")
@@ -192,7 +192,7 @@
 		}
 	`)
 
-	buildOS := android.BuildOs.String()
+	buildOS := config.BuildOS.String()
 	variant := ctx.ModuleForTests("foo", buildOS+"_x86_64")
 
 	relocated := variant.Output("relocated/lib64/libbar.so")
diff --git a/snapshot/Android.bp b/snapshot/Android.bp
new file mode 100644
index 0000000..f17ac53
--- /dev/null
+++ b/snapshot/Android.bp
@@ -0,0 +1,22 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-snapshot",
+    pkgPath: "android/soong/snapshot",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "soong",
+        "soong-android",
+    ],
+    srcs: [
+        "recovery_snapshot.go",
+        "snapshot.go",
+        "snapshot_base.go",
+        "util.go",
+        "vendor_snapshot.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/snapshot/recovery_snapshot.go b/snapshot/recovery_snapshot.go
new file mode 100644
index 0000000..9b3919c
--- /dev/null
+++ b/snapshot/recovery_snapshot.go
@@ -0,0 +1,130 @@
+// Copyright 2021 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 snapshot
+
+import "android/soong/android"
+
+// Interface for modules which can be captured in the recovery snapshot.
+type RecoverySnapshotModuleInterface interface {
+	SnapshotModuleInterfaceBase
+	InRecovery() bool
+	ExcludeFromRecoverySnapshot() bool
+}
+
+var recoverySnapshotSingleton = SnapshotSingleton{
+	"recovery",                     // name
+	"SOONG_RECOVERY_SNAPSHOT_ZIP",  // makeVar
+	android.OptionalPath{},         // snapshotZipFile
+	RecoverySnapshotImageSingleton, // Image
+	false,                          // Fake
+}
+
+func RecoverySnapshotSingleton() android.Singleton {
+	return &recoverySnapshotSingleton
+}
+
+// Determine if a dir under source tree is an SoC-owned proprietary directory based
+// on recovery snapshot configuration
+// Examples: device/, vendor/
+func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return RecoverySnapshotSingleton().(*SnapshotSingleton).Image.IsProprietaryPath(dir, deviceConfig)
+}
+
+func IsRecoveryProprietaryModule(ctx android.BaseModuleContext) bool {
+
+	// Any module in a recovery proprietary path is a recovery proprietary
+	// module.
+	if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
+		return true
+	}
+
+	// However if the module is not in a recovery proprietary path, it may
+	// still be a recovery proprietary module. This happens for cc modules
+	// that are excluded from the recovery snapshot, and it means that the
+	// vendor has assumed control of the framework-provided module.
+
+	if c, ok := ctx.Module().(RecoverySnapshotModuleInterface); ok {
+		if c.ExcludeFromRecoverySnapshot() {
+			return true
+		}
+	}
+
+	return false
+}
+
+var RecoverySnapshotImageName = "recovery"
+
+type RecoverySnapshotImage struct{}
+
+func (RecoverySnapshotImage) Init(ctx android.RegistrationContext) {
+	ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
+}
+
+func (RecoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
+	// RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a
+	// snapshot.
+	return ctx.DeviceConfig().RecoverySnapshotVersion() == "current"
+}
+
+func (RecoverySnapshotImage) InImage(m SnapshotModuleInterfaceBase) func() bool {
+	r, ok := m.(RecoverySnapshotModuleInterface)
+
+	if !ok {
+		// This module does not support recovery snapshot
+		return func() bool { return false }
+	}
+	return r.InRecovery
+}
+
+func (RecoverySnapshotImage) IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap())
+}
+
+func (RecoverySnapshotImage) ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool {
+	r, ok := m.(RecoverySnapshotModuleInterface)
+
+	if !ok {
+		// This module does not support recovery snapshot
+		return true
+	}
+	return r.ExcludeFromRecoverySnapshot()
+}
+
+func (RecoverySnapshotImage) IsUsingSnapshot(cfg android.DeviceConfig) bool {
+	recoverySnapshotVersion := cfg.RecoverySnapshotVersion()
+	return recoverySnapshotVersion != "current" && recoverySnapshotVersion != ""
+}
+
+func (RecoverySnapshotImage) TargetSnapshotVersion(cfg android.DeviceConfig) string {
+	return cfg.RecoverySnapshotVersion()
+}
+
+func (RecoverySnapshotImage) ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
+	// If we're using full snapshot, not directed snapshot, capture every module
+	if !cfg.DirectedRecoverySnapshot() {
+		return false
+	}
+	// Else, checks if name is in RECOVERY_SNAPSHOT_MODULES.
+	return !cfg.RecoverySnapshotModules()[name]
+}
+
+func (RecoverySnapshotImage) ImageName() string {
+	return RecoverySnapshotImageName
+}
+
+var RecoverySnapshotImageSingleton RecoverySnapshotImage
+
+func init() {
+	RecoverySnapshotImageSingleton.Init(android.InitRegistrationContext)
+}
diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go
new file mode 100644
index 0000000..294f8b6
--- /dev/null
+++ b/snapshot/snapshot.go
@@ -0,0 +1,122 @@
+// Copyright 2021 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 snapshot
+
+import (
+	"path/filepath"
+	"sort"
+
+	"android/soong/android"
+)
+
+// This file contains singletons to capture snapshots. This singleton will generate snapshot of each target
+// image, and capturing snapshot module will be delegated to each module which implements GenerateSnapshotAction
+// function and register with RegisterSnapshotAction.
+
+var pctx = android.NewPackageContext("android/soong/snapshot")
+
+type SnapshotSingleton struct {
+	// Name, e.g., "vendor", "recovery", "ramdisk".
+	name string
+
+	// Make variable that points to the snapshot file, e.g.,
+	// "SOONG_RECOVERY_SNAPSHOT_ZIP".
+	makeVar string
+
+	// Path to the snapshot zip file.
+	snapshotZipFile android.OptionalPath
+
+	// Implementation of the image interface specific to the image
+	// associated with this snapshot (e.g., specific to the vendor image,
+	// recovery image, etc.).
+	Image SnapshotImage
+
+	// Whether this singleton is for fake snapshot or not.
+	// Fake snapshot is a snapshot whose prebuilt binaries and headers are empty.
+	// It is much faster to generate, and can be used to inspect dependencies.
+	Fake bool
+}
+
+// Interface of function to capture snapshot from each module
+type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths
+
+var snapshotActionList []GenerateSnapshotAction
+
+// Register GenerateSnapshotAction function so it can be called while generating snapshot
+func RegisterSnapshotAction(x GenerateSnapshotAction) {
+	snapshotActionList = append(snapshotActionList, x)
+}
+
+func (c *SnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	if !c.Image.shouldGenerateSnapshot(ctx) {
+		return
+	}
+
+	var snapshotOutputs android.Paths
+
+	// Snapshot zipped artifacts will be captured under {SNAPSHOT_ARCH} directory
+
+	snapshotDir := c.name + "-snapshot"
+	if c.Fake {
+		// If this is a fake snapshot singleton, place all files under fake/ subdirectory to avoid
+		// collision with real snapshot files
+		snapshotDir = filepath.Join("fake", snapshotDir)
+	}
+	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+
+	for _, f := range snapshotActionList {
+		snapshotOutputs = append(snapshotOutputs, f(*c, ctx, snapshotArchDir)...)
+	}
+
+	// All artifacts are ready. Sort them to normalize ninja and then zip.
+	sort.Slice(snapshotOutputs, func(i, j int) bool {
+		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
+	})
+
+	zipPath := android.PathForOutput(
+		ctx,
+		snapshotDir,
+		c.name+"-"+ctx.Config().DeviceName()+".zip")
+	zipRule := android.NewRuleBuilder(pctx, ctx)
+
+	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
+	snapshotOutputList := android.PathForOutput(
+		ctx,
+		snapshotDir,
+		c.name+"-"+ctx.Config().DeviceName()+"_list")
+	rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp")
+	zipRule.Command().
+		Text("tr").
+		FlagWithArg("-d ", "\\'").
+		FlagWithRspFileInputList("< ", rspFile, snapshotOutputs).
+		FlagWithOutput("> ", snapshotOutputList)
+
+	zipRule.Temporary(snapshotOutputList)
+
+	zipRule.Command().
+		BuiltTool("soong_zip").
+		FlagWithOutput("-o ", zipPath).
+		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
+		FlagWithInput("-l ", snapshotOutputList)
+
+	zipRule.Build(zipPath.String(), c.name+" snapshot "+zipPath.String())
+	zipRule.DeleteTemporaryFiles()
+	c.snapshotZipFile = android.OptionalPathForPath(zipPath)
+}
+
+func (c *SnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
+	ctx.Strict(
+		c.makeVar,
+		c.snapshotZipFile.String())
+}
diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go
new file mode 100644
index 0000000..de93f3e
--- /dev/null
+++ b/snapshot/snapshot_base.go
@@ -0,0 +1,104 @@
+// Copyright 2021 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 snapshot
+
+import (
+	"android/soong/android"
+	"path/filepath"
+)
+
+// Interface for modules which can be captured in the snapshot.
+type SnapshotModuleInterfaceBase interface{}
+
+// Defines the specifics of different images to which the snapshot process is applicable, e.g.,
+// vendor, recovery, ramdisk.
+type SnapshotImage interface {
+	// Returns true if a snapshot should be generated for this image.
+	shouldGenerateSnapshot(ctx android.SingletonContext) bool
+
+	// 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 SnapshotModuleInterfaceBase) func() 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, deviceConfig) returns true, then the module in dir
+	// will be built from sources.
+	IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) 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 SnapshotModuleInterfaceBase) bool
+
+	// Returns true if the build is using a snapshot for this image.
+	IsUsingSnapshot(cfg android.DeviceConfig) bool
+
+	// Returns a version of which the snapshot should be used in this target.
+	// This will only be meaningful when isUsingSnapshot is true.
+	TargetSnapshotVersion(cfg android.DeviceConfig) string
+
+	// Whether to exclude a given module from the directed snapshot or not.
+	// If the makefile variable DIRECTED_{IMAGE}_SNAPSHOT is true, directed snapshot is turned on,
+	// and only modules listed in {IMAGE}_SNAPSHOT_MODULES will be captured.
+	ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool
+
+	// Returns target image name
+	ImageName() string
+}
+
+type directoryMap map[string]bool
+
+var (
+	// Modules under following directories are ignored. They are OEM's and vendor's
+	// proprietary modules(device/, kernel/, vendor/, and hardware/).
+	defaultDirectoryExcludedMap = directoryMap{
+		"device":   true,
+		"hardware": true,
+		"kernel":   true,
+		"vendor":   true,
+	}
+
+	// Modules under following directories are included as they are in AOSP,
+	// although hardware/ and kernel/ are normally for vendor's own.
+	defaultDirectoryIncludedMap = directoryMap{
+		"kernel/configs":              true,
+		"kernel/prebuilts":            true,
+		"kernel/tests":                true,
+		"hardware/interfaces":         true,
+		"hardware/libhardware":        true,
+		"hardware/libhardware_legacy": true,
+		"hardware/ril":                true,
+	}
+)
+
+func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool {
+	if dir == "." || dir == "/" {
+		return false
+	}
+	if includedMap[dir] {
+		return false
+	} else if excludedMap[dir] {
+		return true
+	} else if defaultDirectoryIncludedMap[dir] {
+		return false
+	} else if defaultDirectoryExcludedMap[dir] {
+		return true
+	} else {
+		return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap)
+	}
+}
diff --git a/snapshot/util.go b/snapshot/util.go
new file mode 100644
index 0000000..2297dfc
--- /dev/null
+++ b/snapshot/util.go
@@ -0,0 +1,36 @@
+// Copyright 2021 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 snapshot
+
+import "android/soong/android"
+
+func WriteStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	android.WriteFileRule(ctx, outPath, content)
+	return outPath
+}
+
+func CopyFileRule(pctx android.PackageContext, 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
+}
diff --git a/snapshot/vendor_snapshot.go b/snapshot/vendor_snapshot.go
new file mode 100644
index 0000000..9bd26c2
--- /dev/null
+++ b/snapshot/vendor_snapshot.go
@@ -0,0 +1,147 @@
+// Copyright 2021 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 snapshot
+
+import "android/soong/android"
+
+// Interface for modules which can be captured in the vendor snapshot.
+type VendorSnapshotModuleInterface interface {
+	SnapshotModuleInterfaceBase
+	InVendor() bool
+	ExcludeFromVendorSnapshot() bool
+}
+
+var vendorSnapshotSingleton = SnapshotSingleton{
+	"vendor",                     // name
+	"SOONG_VENDOR_SNAPSHOT_ZIP",  // makeVar
+	android.OptionalPath{},       // snapshotZipFile
+	VendorSnapshotImageSingleton, // Image
+	false,                        // Fake
+}
+
+var vendorFakeSnapshotSingleton = SnapshotSingleton{
+	"vendor",                         // name
+	"SOONG_VENDOR_FAKE_SNAPSHOT_ZIP", // makeVar
+	android.OptionalPath{},           // snapshotZipFile
+	VendorSnapshotImageSingleton,     // Image
+	true,                             // Fake
+}
+
+func VendorSnapshotSingleton() android.Singleton {
+	return &vendorSnapshotSingleton
+}
+
+func VendorFakeSnapshotSingleton() android.Singleton {
+	return &vendorFakeSnapshotSingleton
+}
+
+// Determine if a dir under source tree is an SoC-owned proprietary directory based
+// on vendor snapshot configuration
+// Examples: device/, vendor/
+func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return VendorSnapshotSingleton().(*SnapshotSingleton).Image.IsProprietaryPath(dir, deviceConfig)
+}
+
+func IsVendorProprietaryModule(ctx android.BaseModuleContext) bool {
+	// Any module in a vendor proprietary path is a vendor proprietary
+	// module.
+	if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
+		return true
+	}
+
+	// However if the module is not in a vendor proprietary path, it may
+	// 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().(VendorSnapshotModuleInterface); ok {
+		if c.ExcludeFromVendorSnapshot() {
+			return true
+		}
+	}
+
+	return false
+}
+
+var VendorSnapshotImageName = "vendor"
+
+type VendorSnapshotImage struct{}
+
+func (VendorSnapshotImage) Init(ctx android.RegistrationContext) {
+	ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
+	ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
+}
+
+func (VendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
+	ctx.RegisterModuleType(name, factory)
+}
+
+func (VendorSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
+	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a snapshot.
+	return ctx.DeviceConfig().VndkVersion() == "current"
+}
+
+func (VendorSnapshotImage) InImage(m SnapshotModuleInterfaceBase) func() bool {
+	v, ok := m.(VendorSnapshotModuleInterface)
+
+	if !ok {
+		// This module does not support Vendor snapshot
+		return func() bool { return false }
+	}
+
+	return v.InVendor
+}
+
+func (VendorSnapshotImage) IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+	return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap())
+}
+
+func (VendorSnapshotImage) ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool {
+	v, ok := m.(VendorSnapshotModuleInterface)
+
+	if !ok {
+		// This module does not support Vendor snapshot
+		return true
+	}
+
+	return v.ExcludeFromVendorSnapshot()
+}
+
+func (VendorSnapshotImage) IsUsingSnapshot(cfg android.DeviceConfig) bool {
+	vndkVersion := cfg.VndkVersion()
+	return vndkVersion != "current" && vndkVersion != ""
+}
+
+func (VendorSnapshotImage) TargetSnapshotVersion(cfg android.DeviceConfig) string {
+	return cfg.VndkVersion()
+}
+
+// returns true iff a given module SHOULD BE EXCLUDED, false if included
+func (VendorSnapshotImage) ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
+	// If we're using full snapshot, not directed snapshot, capture every module
+	if !cfg.DirectedVendorSnapshot() {
+		return false
+	}
+	// Else, checks if name is in VENDOR_SNAPSHOT_MODULES.
+	return !cfg.VendorSnapshotModules()[name]
+}
+
+func (VendorSnapshotImage) ImageName() string {
+	return VendorSnapshotImageName
+}
+
+var VendorSnapshotImageSingleton VendorSnapshotImage
+
+func init() {
+	VendorSnapshotImageSingleton.Init(android.InitRegistrationContext)
+}