Merge "Prohibit dependencies outside of uses_sdks"
diff --git a/android/androidmk.go b/android/androidmk.go
index 9071347..b66fd18 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -199,19 +199,19 @@
 	switch amod.Os().Class {
 	case Host:
 		// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
-		if archStr != "common" {
+		if amod.Arch().ArchType != Common {
 			a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
 		}
 		host = true
 	case HostCross:
 		// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
-		if archStr != "common" {
+		if amod.Arch().ArchType != Common {
 			a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
 		}
 		host = true
 	case Device:
 		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
-		if archStr != "common" {
+		if amod.Arch().ArchType != Common {
 			if amod.Target().NativeBridge {
 				hostArchStr := amod.Target().NativeBridgeHostArchName
 				if hostArchStr != "" {
diff --git a/android/arch.go b/android/arch.go
index 348b064..0519e76 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -22,9 +22,12 @@
 	"strconv"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
+const COMMON_VARIANT = "common"
+
 var (
 	archTypeList []ArchType
 
@@ -36,7 +39,7 @@
 	X86_64 = newArch("x86_64", "lib64")
 
 	Common = ArchType{
-		Name: "common",
+		Name: COMMON_VARIANT,
 	}
 )
 
@@ -702,11 +705,82 @@
 }
 
 func (target Target) String() string {
-	variant := ""
+	return target.OsVariation() + "_" + target.ArchVariation()
+}
+
+func (target Target) OsVariation() string {
+	return target.Os.String()
+}
+
+func (target Target) ArchVariation() string {
+	var variation string
 	if target.NativeBridge {
-		variant = "native_bridge_"
+		variation = "native_bridge_"
 	}
-	return target.Os.String() + "_" + variant + target.Arch.String()
+	variation += target.Arch.String()
+
+	return variation
+}
+
+func (target Target) Variations() []blueprint.Variation {
+	return []blueprint.Variation{
+		{Mutator: "os", Variation: target.OsVariation()},
+		{Mutator: "arch", Variation: target.ArchVariation()},
+	}
+}
+
+func osMutator(mctx BottomUpMutatorContext) {
+	var module Module
+	var ok bool
+	if module, ok = mctx.Module().(Module); !ok {
+		return
+	}
+
+	base := module.base()
+
+	if !base.ArchSpecific() {
+		return
+	}
+
+	osClasses := base.OsClassSupported()
+
+	var moduleOSList []OsType
+
+	for _, os := range osTypeList {
+		supportedClass := false
+		for _, osClass := range osClasses {
+			if os.Class == osClass {
+				supportedClass = true
+			}
+		}
+		if !supportedClass {
+			continue
+		}
+
+		if len(mctx.Config().Targets[os]) == 0 {
+			continue
+		}
+
+		moduleOSList = append(moduleOSList, os)
+	}
+
+	if len(moduleOSList) == 0 {
+		base.commonProperties.Enabled = boolPtr(false)
+		return
+	}
+
+	osNames := make([]string, len(moduleOSList))
+
+	for i, os := range moduleOSList {
+		osNames[i] = os.String()
+	}
+
+	modules := mctx.CreateVariations(osNames...)
+	for i, m := range modules {
+		m.(Module).base().commonProperties.CompileOS = moduleOSList[i]
+		m.(Module).base().setOSProperties(mctx)
+	}
+
 }
 
 // archMutator splits a module into a variant for each Target requested by the module.  Target selection
@@ -746,84 +820,63 @@
 		return
 	}
 
-	var moduleTargets []Target
-	moduleMultiTargets := make(map[int][]Target)
-	primaryModules := make(map[int]bool)
-	osClasses := base.OsClassSupported()
+	os := base.commonProperties.CompileOS
+	osTargets := mctx.Config().Targets[os]
 
-	for _, os := range osTypeList {
-		supportedClass := false
-		for _, osClass := range osClasses {
-			if os.Class == osClass {
-				supportedClass = true
+	// Filter NativeBridge targets unless they are explicitly supported
+	if os == Android && !Bool(base.commonProperties.Native_bridge_supported) {
+		var targets []Target
+		for _, t := range osTargets {
+			if !t.NativeBridge {
+				targets = append(targets, t)
 			}
 		}
-		if !supportedClass {
-			continue
-		}
 
-		osTargets := mctx.Config().Targets[os]
-		if len(osTargets) == 0 {
-			continue
-		}
+		osTargets = targets
+	}
 
-		// Filter NativeBridge targets unless they are explicitly supported
-		if os == Android && !Bool(base.commonProperties.Native_bridge_supported) {
-			var targets []Target
-			for _, t := range osTargets {
-				if !t.NativeBridge {
-					targets = append(targets, t)
-				}
-			}
+	// only the primary arch in the recovery partition
+	if os == Android && module.InstallInRecovery() {
+		osTargets = []Target{osTargets[0]}
+	}
 
-			osTargets = targets
-		}
+	prefer32 := false
+	if base.prefer32 != nil {
+		prefer32 = base.prefer32(mctx, base, os.Class)
+	}
 
-		// only the primary arch in the recovery partition
-		if os == Android && module.InstallInRecovery() {
-			osTargets = []Target{osTargets[0]}
-		}
+	multilib, extraMultilib := decodeMultilib(base, os.Class)
+	targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
+	if err != nil {
+		mctx.ModuleErrorf("%s", err.Error())
+	}
 
-		prefer32 := false
-		if base.prefer32 != nil {
-			prefer32 = base.prefer32(mctx, base, os.Class)
-		}
-
-		multilib, extraMultilib := decodeMultilib(base, os.Class)
-		targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
+	var multiTargets []Target
+	if extraMultilib != "" {
+		multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
 		if err != nil {
 			mctx.ModuleErrorf("%s", err.Error())
 		}
-
-		var multiTargets []Target
-		if extraMultilib != "" {
-			multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
-			if err != nil {
-				mctx.ModuleErrorf("%s", err.Error())
-			}
-		}
-
-		if len(targets) > 0 {
-			primaryModules[len(moduleTargets)] = true
-			moduleMultiTargets[len(moduleTargets)] = multiTargets
-			moduleTargets = append(moduleTargets, targets...)
-		}
 	}
 
-	if len(moduleTargets) == 0 {
+	if len(targets) == 0 {
 		base.commonProperties.Enabled = boolPtr(false)
 		return
 	}
 
-	targetNames := make([]string, len(moduleTargets))
+	targetNames := make([]string, len(targets))
 
-	for i, target := range moduleTargets {
-		targetNames[i] = target.String()
+	for i, target := range targets {
+		targetNames[i] = target.ArchVariation()
 	}
 
 	modules := mctx.CreateVariations(targetNames...)
 	for i, m := range modules {
-		m.(Module).base().SetTarget(moduleTargets[i], moduleMultiTargets[i], primaryModules[i])
+		m.(Module).base().commonProperties.CompileTarget = targets[i]
+		m.(Module).base().commonProperties.CompileMultiTargets = multiTargets
+		if i == 0 {
+			m.(Module).base().commonProperties.CompilePrimary = true
+		}
 		m.(Module).base().setArchProperties(mctx)
 	}
 }
@@ -1050,6 +1103,100 @@
 	return ret
 }
 
+// Rewrite the module's properties structs to contain os-specific values.
+func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
+	os := m.commonProperties.CompileOS
+
+	for i := range m.generalProperties {
+		genProps := m.generalProperties[i]
+		if m.archProperties[i] == nil {
+			continue
+		}
+		for _, archProperties := range m.archProperties[i] {
+			archPropValues := reflect.ValueOf(archProperties).Elem()
+
+			targetProp := archPropValues.FieldByName("Target")
+
+			// Handle host-specific properties in the form:
+			// target: {
+			//     host: {
+			//         key: value,
+			//     },
+			// },
+			if os.Class == Host || os.Class == HostCross {
+				field := "Host"
+				prefix := "target.host"
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+			}
+
+			// Handle target OS generalities of the form:
+			// target: {
+			//     bionic: {
+			//         key: value,
+			//     },
+			// }
+			if os.Linux() {
+				field := "Linux"
+				prefix := "target.linux"
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+			}
+
+			if os.Bionic() {
+				field := "Bionic"
+				prefix := "target.bionic"
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+			}
+
+			// Handle target OS properties in the form:
+			// target: {
+			//     linux_glibc: {
+			//         key: value,
+			//     },
+			//     not_windows: {
+			//         key: value,
+			//     },
+			//     android {
+			//         key: value,
+			//     },
+			// },
+			field := os.Field
+			prefix := "target." + os.Name
+			m.appendProperties(ctx, genProps, targetProp, field, prefix)
+
+			if (os.Class == Host || os.Class == HostCross) && os != Windows {
+				field := "Not_windows"
+				prefix := "target.not_windows"
+				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+			}
+
+			// Handle 64-bit device properties in the form:
+			// target {
+			//     android64 {
+			//         key: value,
+			//     },
+			//     android32 {
+			//         key: value,
+			//     },
+			// },
+			// WARNING: this is probably not what you want to use in your blueprints file, it selects
+			// options for all targets on a device that supports 64-bit binaries, not just the targets
+			// that are being compiled for 64-bit.  Its expected use case is binaries like linker and
+			// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
+			if os.Class == Device {
+				if ctx.Config().Android64() {
+					field := "Android64"
+					prefix := "target.android64"
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				} else {
+					field := "Android32"
+					prefix := "target.android32"
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				}
+			}
+		}
+	}
+}
+
 // Rewrite the module's properties structs to contain arch-specific values.
 func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
 	arch := m.Arch()
@@ -1067,9 +1214,6 @@
 			multilibProp := archPropValues.FieldByName("Multilib")
 			targetProp := archPropValues.FieldByName("Target")
 
-			var field string
-			var prefix string
-
 			// Handle arch-specific properties in the form:
 			// arch: {
 			//     arm64: {
@@ -1134,68 +1278,32 @@
 				m.appendProperties(ctx, genProps, multilibProp, field, prefix)
 			}
 
-			// Handle host-specific properties in the form:
+			// Handle combined OS-feature and arch specific properties in the form:
 			// target: {
-			//     host: {
-			//         key: value,
-			//     },
-			// },
-			if os.Class == Host || os.Class == HostCross {
-				field = "Host"
-				prefix = "target.host"
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
-			}
-
-			// Handle target OS generalities of the form:
-			// target: {
-			//     bionic: {
-			//         key: value,
-			//     },
 			//     bionic_x86: {
 			//         key: value,
 			//     },
 			// }
-			if os.Linux() {
-				field = "Linux"
-				prefix = "target.linux"
+			if os.Linux() && arch.ArchType != Common {
+				field := "Linux_" + arch.ArchType.Name
+				prefix := "target.linux_" + arch.ArchType.Name
 				m.appendProperties(ctx, genProps, targetProp, field, prefix)
-
-				if arch.ArchType != Common {
-					field = "Linux_" + arch.ArchType.Name
-					prefix = "target.linux_" + arch.ArchType.Name
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
-				}
 			}
 
-			if os.Bionic() {
-				field = "Bionic"
-				prefix = "target.bionic"
+			if os.Bionic() && arch.ArchType != Common {
+				field := "Bionic_" + t.Name
+				prefix := "target.bionic_" + t.Name
 				m.appendProperties(ctx, genProps, targetProp, field, prefix)
-
-				if arch.ArchType != Common {
-					field = "Bionic_" + t.Name
-					prefix = "target.bionic_" + t.Name
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
-				}
 			}
 
-			// Handle target OS properties in the form:
+			// Handle combined OS and arch specific properties in the form:
 			// target: {
-			//     linux_glibc: {
-			//         key: value,
-			//     },
-			//     not_windows: {
-			//         key: value,
-			//     },
 			//     linux_glibc_x86: {
 			//         key: value,
 			//     },
 			//     linux_glibc_arm: {
 			//         key: value,
 			//     },
-			//     android {
-			//         key: value,
-			//     },
 			//     android_arm {
 			//         key: value,
 			//     },
@@ -1203,46 +1311,23 @@
 			//         key: value,
 			//     },
 			// },
-			field = os.Field
-			prefix = "target." + os.Name
-			m.appendProperties(ctx, genProps, targetProp, field, prefix)
-
 			if arch.ArchType != Common {
-				field = os.Field + "_" + t.Name
-				prefix = "target." + os.Name + "_" + t.Name
+				field := os.Field + "_" + t.Name
+				prefix := "target." + os.Name + "_" + t.Name
 				m.appendProperties(ctx, genProps, targetProp, field, prefix)
 			}
 
-			if (os.Class == Host || os.Class == HostCross) && os != Windows {
-				field := "Not_windows"
-				prefix := "target.not_windows"
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
-			}
-
-			// Handle 64-bit device properties in the form:
+			// Handle arm on x86 properties in the form:
 			// target {
-			//     android64 {
+			//     arm_on_x86 {
 			//         key: value,
 			//     },
-			//     android32 {
+			//     arm_on_x86_64 {
 			//         key: value,
 			//     },
 			// },
-			// WARNING: this is probably not what you want to use in your blueprints file, it selects
-			// options for all targets on a device that supports 64-bit binaries, not just the targets
-			// that are being compiled for 64-bit.  Its expected use case is binaries like linker and
-			// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
+			// TODO(ccross): is this still necessary with native bridge?
 			if os.Class == Device {
-				if ctx.Config().Android64() {
-					field := "Android64"
-					prefix := "target.android64"
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
-				} else {
-					field := "Android32"
-					prefix := "target.android32"
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
-				}
-
 				if (arch.ArchType == X86 && (hasArmAbi(arch) ||
 					hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
 					(arch.ArchType == Arm &&
diff --git a/android/arch_test.go b/android/arch_test.go
index 11edb4f..52a6684 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"reflect"
+	"runtime"
 	"testing"
 
 	"github.com/google/blueprint/proptools"
@@ -232,3 +233,139 @@
 		})
 	}
 }
+
+type archTestModule struct {
+	ModuleBase
+	props struct {
+		Deps []string
+	}
+}
+
+func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
+}
+
+func archTestModuleFactory() Module {
+	m := &archTestModule{}
+	m.AddProperties(&m.props)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth)
+	return m
+}
+
+func TestArchMutator(t *testing.T) {
+	var buildOSVariants []string
+	var buildOS32Variants []string
+	switch runtime.GOOS {
+	case "linux":
+		buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"}
+		buildOS32Variants = []string{"linux_glibc_x86"}
+	case "darwin":
+		buildOSVariants = []string{"darwin_x86_64"}
+		buildOS32Variants = nil
+	}
+
+	bp := `
+		module {
+			name: "foo",
+		}
+
+		module {
+			name: "bar",
+			host_supported: true,
+		}
+
+		module {
+			name: "baz",
+			device_supported: false,
+		}
+
+		module {
+			name: "qux",
+			host_supported: true,
+			compile_multilib: "32",
+		}
+	`
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+	}
+
+	testCases := []struct {
+		name        string
+		config      func(Config)
+		fooVariants []string
+		barVariants []string
+		bazVariants []string
+		quxVariants []string
+	}{
+		{
+			name:        "normal",
+			config:      nil,
+			fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
+			barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
+			bazVariants: nil,
+			quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"),
+		},
+		{
+			name: "host-only",
+			config: func(config Config) {
+				config.BuildOSTarget = Target{}
+				config.BuildOSCommonTarget = Target{}
+				config.Targets[Android] = nil
+			},
+			fooVariants: nil,
+			barVariants: buildOSVariants,
+			bazVariants: nil,
+			quxVariants: buildOS32Variants,
+		},
+	}
+
+	enabledVariants := func(ctx *TestContext, name string) []string {
+		var ret []string
+		variants := ctx.ModuleVariantsForTests(name)
+		for _, variant := range variants {
+			m := ctx.ModuleForTests(name, variant)
+			if m.Module().Enabled() {
+				ret = append(ret, variant)
+			}
+		}
+		return ret
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			ctx := NewTestArchContext()
+			ctx.RegisterModuleType("module", ModuleFactoryAdaptor(archTestModuleFactory))
+			ctx.MockFileSystem(mockFS)
+			ctx.Register()
+			config := TestArchConfig(buildDir, nil)
+			if tt.config != nil {
+				tt.config(config)
+			}
+
+			_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+			FailIfErrored(t, errs)
+			_, errs = ctx.PrepareBuildActions(config)
+			FailIfErrored(t, errs)
+
+			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
+			}
+		})
+	}
+}
diff --git a/android/config.go b/android/config.go
index 26c4e6e..e208dcd 100644
--- a/android/config.go
+++ b/android/config.go
@@ -89,9 +89,10 @@
 	ConfigFileName           string
 	ProductVariablesFileName string
 
-	Targets              map[OsType][]Target
-	BuildOsVariant       string
-	BuildOsCommonVariant string
+	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
+	AndroidCommonTarget Target // the Target for common modules for the Android device
 
 	// multilibConflicts for an ArchType is true if there is earlier configured device architecture with the same
 	// multilib value.
@@ -289,8 +290,9 @@
 		config.Targets[BuildOs] = config.Targets[BuildOs][:1]
 	}
 
-	config.BuildOsVariant = config.Targets[BuildOs][0].String()
-	config.BuildOsCommonVariant = getCommonTargets(config.Targets[BuildOs])[0].String()
+	config.BuildOSTarget = config.Targets[BuildOs][0]
+	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
+	config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
 	config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
 	config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
 	config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
@@ -374,8 +376,11 @@
 	}
 
 	config.Targets = targets
-	config.BuildOsVariant = targets[BuildOs][0].String()
-	config.BuildOsCommonVariant = getCommonTargets(targets[BuildOs])[0].String()
+	config.BuildOSTarget = config.Targets[BuildOs][0]
+	config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
+	if len(config.Targets[Android]) > 0 {
+		config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+	}
 
 	if err := config.fromEnv(); err != nil {
 		return Config{}, err
@@ -386,13 +391,14 @@
 
 func (c *config) fromEnv() error {
 	switch c.Getenv("EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9") {
-	case "":
-		// Nothing, this is the default
-	case "true":
-		// Use -source 9 -target 9
+	case "", "true":
+		// Use -source 9 -target 9. This is the default.
 		c.targetOpenJDK9 = true
+	case "false":
+		// Use -source 8 -target 8. This is the legacy behaviour.
+		c.targetOpenJDK9 = false
 	default:
-		return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "" or "true"`)
+		return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "", "true", or "false"`)
 	}
 
 	return nil
diff --git a/android/module.go b/android/module.go
index 5d1a609..70b602b 100644
--- a/android/module.go
+++ b/android/module.go
@@ -417,6 +417,7 @@
 	} `android:"arch_variant"`
 
 	// Set by TargetMutator
+	CompileOS           OsType   `blueprint:"mutated"`
 	CompileTarget       Target   `blueprint:"mutated"`
 	CompileMultiTargets []Target `blueprint:"mutated"`
 	CompilePrimary      bool     `blueprint:"mutated"`
@@ -719,12 +720,6 @@
 	}
 }
 
-func (m *ModuleBase) SetTarget(target Target, multiTargets []Target, primary bool) {
-	m.commonProperties.CompileTarget = target
-	m.commonProperties.CompileMultiTargets = multiTargets
-	m.commonProperties.CompilePrimary = primary
-}
-
 func (m *ModuleBase) Target() Target {
 	return m.commonProperties.CompileTarget
 }
diff --git a/android/mutator.go b/android/mutator.go
index 88ac521..4a5338f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -86,6 +86,7 @@
 }
 
 func registerArchMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("os", osMutator).Parallel()
 	ctx.BottomUp("arch", archMutator).Parallel()
 	ctx.TopDown("arch_hooks", archHookMutator).Parallel()
 }
diff --git a/android/proto.go b/android/proto.go
index c8ade45..b712258 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -52,9 +52,8 @@
 	}
 
 	if plugin := String(p.Proto.Plugin); plugin != "" {
-		ctx.AddFarVariationDependencies([]blueprint.Variation{
-			{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
-		}, ProtoPluginDepTag, "protoc-gen-"+plugin)
+		ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(),
+			ProtoPluginDepTag, "protoc-gen-"+plugin)
 	}
 }
 
diff --git a/apex/apex.go b/apex/apex.go
index 3c32004..e14d82d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -182,7 +182,10 @@
 	android.RegisterModuleType("apex_defaults", defaultsFactory)
 	android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
 
-	android.PreDepsMutators(RegisterPreDepsMutators)
+	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
+		ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
+	})
 	android.PostDepsMutators(RegisterPostDepsMutators)
 
 	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
@@ -192,11 +195,6 @@
 	})
 }
 
-func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
-	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
-}
-
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
 	ctx.TopDown("apex_deps", apexDepsMutator)
 	ctx.BottomUp("apex", apexMutator).Parallel()
@@ -209,39 +207,44 @@
 	vndkApexListMutex sync.Mutex
 )
 
-func vndkApexList(config android.Config) map[string]string {
+func vndkApexList(config android.Config) map[string]*apexBundle {
 	return config.Once(vndkApexListKey, func() interface{} {
-		return map[string]string{}
-	}).(map[string]string)
+		return map[string]*apexBundle{}
+	}).(map[string]*apexBundle)
 }
 
-func apexVndkMutator(mctx android.TopDownMutatorContext) {
+// apexVndkGatherMutator gathers "apex_vndk" modules and puts them in a map with vndk_version as a key.
+func apexVndkGatherMutator(mctx android.TopDownMutatorContext) {
 	if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex {
 		if ab.IsNativeBridgeSupported() {
 			mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
 		}
 
-		vndkVersion := ab.vndkVersion(mctx.DeviceConfig())
-		// Ensure VNDK APEX mount point is formatted as com.android.vndk.v###
-		ab.properties.Apex_name = proptools.StringPtr("com.android.vndk.v" + vndkVersion)
+		vndkVersion := proptools.String(ab.vndkProperties.Vndk_version)
 
-		// vndk_version should be unique
 		vndkApexListMutex.Lock()
 		defer vndkApexListMutex.Unlock()
 		vndkApexList := vndkApexList(mctx.Config())
 		if other, ok := vndkApexList[vndkVersion]; ok {
-			mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other)
+			mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other.BaseModuleName())
 		}
-		vndkApexList[vndkVersion] = mctx.ModuleName()
+		vndkApexList[vndkVersion] = ab
 	}
 }
 
-func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) {
-		vndkVersion := m.VndkVersion()
+// apexVndkAddDepsMutator adds (reverse) dependencies from vndk libs to apex_vndk modules.
+// It filters only libs with matching targets.
+func apexVndkAddDepsMutator(mctx android.BottomUpMutatorContext) {
+	if cc, ok := mctx.Module().(*cc.Module); ok && cc.IsVndkOnSystem() {
 		vndkApexList := vndkApexList(mctx.Config())
-		if vndkApex, ok := vndkApexList[vndkVersion]; ok {
-			mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApex)
+		if ab, ok := vndkApexList[cc.VndkVersion()]; ok {
+			targetArch := cc.Target().String()
+			for _, target := range ab.MultiTargets() {
+				if target.String() == targetArch {
+					mctx.AddReverseDependency(mctx.Module(), sharedLibTag, ab.Name())
+					break
+				}
+			}
 		}
 	}
 }
@@ -616,28 +619,25 @@
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
 	native_shared_libs []string, binaries []string, tests []string,
-	arch string, imageVariation string) {
+	target android.Target, imageVariation string) {
 	// Use *FarVariation* to be able to depend on modules having
 	// conflicting variations with this module. This is required since
 	// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
 	// for native shared libs.
-	ctx.AddFarVariationDependencies([]blueprint.Variation{
-		{Mutator: "arch", Variation: arch},
+	ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 		{Mutator: "image", Variation: imageVariation},
 		{Mutator: "link", Variation: "shared"},
 		{Mutator: "version", Variation: ""}, // "" is the non-stub variant
-	}, sharedLibTag, native_shared_libs...)
+	}...), sharedLibTag, native_shared_libs...)
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{
-		{Mutator: "arch", Variation: arch},
-		{Mutator: "image", Variation: imageVariation},
-	}, executableTag, binaries...)
+	ctx.AddFarVariationDependencies(append(target.Variations(),
+		blueprint.Variation{Mutator: "image", Variation: imageVariation}),
+		executableTag, binaries...)
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{
-		{Mutator: "arch", Variation: arch},
+	ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 		{Mutator: "image", Variation: imageVariation},
 		{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
-	}, testTag, tests...)
+	}...), testTag, tests...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -654,6 +654,7 @@
 }
 
 func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
+
 	targets := ctx.MultiTargets()
 	config := ctx.DeviceConfig()
 
@@ -668,49 +669,45 @@
 	for i, target := range targets {
 		// When multilib.* is omitted for native_shared_libs, it implies
 		// multilib.both.
-		ctx.AddFarVariationDependencies([]blueprint.Variation{
-			{Mutator: "arch", Variation: target.String()},
+		ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 			{Mutator: "image", Variation: a.getImageVariation(config)},
 			{Mutator: "link", Variation: "shared"},
-		}, sharedLibTag, a.properties.Native_shared_libs...)
+		}...), sharedLibTag, a.properties.Native_shared_libs...)
 
 		// When multilib.* is omitted for tests, it implies
 		// multilib.both.
-		ctx.AddFarVariationDependencies([]blueprint.Variation{
-			{Mutator: "arch", Variation: target.String()},
+		ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 			{Mutator: "image", Variation: a.getImageVariation(config)},
 			{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
-		}, testTag, a.properties.Tests...)
+		}...), testTag, a.properties.Tests...)
 
 		// Add native modules targetting both ABIs
 		addDependenciesForNativeModules(ctx,
 			a.properties.Multilib.Both.Native_shared_libs,
 			a.properties.Multilib.Both.Binaries,
 			a.properties.Multilib.Both.Tests,
-			target.String(),
+			target,
 			a.getImageVariation(config))
 
 		isPrimaryAbi := i == 0
 		if isPrimaryAbi {
 			// When multilib.* is omitted for binaries, it implies
 			// multilib.first.
-			ctx.AddFarVariationDependencies([]blueprint.Variation{
-				{Mutator: "arch", Variation: target.String()},
-				{Mutator: "image", Variation: a.getImageVariation(config)},
-			}, executableTag, a.properties.Binaries...)
+			ctx.AddFarVariationDependencies(append(target.Variations(),
+				blueprint.Variation{Mutator: "image", Variation: a.getImageVariation(config)}),
+				executableTag, a.properties.Binaries...)
 
 			// Add native modules targetting the first ABI
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.First.Native_shared_libs,
 				a.properties.Multilib.First.Binaries,
 				a.properties.Multilib.First.Tests,
-				target.String(),
+				target,
 				a.getImageVariation(config))
 
 			// When multilib.* is omitted for prebuilts, it implies multilib.first.
-			ctx.AddFarVariationDependencies([]blueprint.Variation{
-				{Mutator: "arch", Variation: target.String()},
-			}, prebuiltTag, a.properties.Prebuilts...)
+			ctx.AddFarVariationDependencies(target.Variations(),
+				prebuiltTag, a.properties.Prebuilts...)
 		}
 
 		switch target.Arch.ArchType.Multilib {
@@ -720,14 +717,14 @@
 				a.properties.Multilib.Lib32.Native_shared_libs,
 				a.properties.Multilib.Lib32.Binaries,
 				a.properties.Multilib.Lib32.Tests,
-				target.String(),
+				target,
 				a.getImageVariation(config))
 
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.Prefer32.Native_shared_libs,
 				a.properties.Multilib.Prefer32.Binaries,
 				a.properties.Multilib.Prefer32.Tests,
-				target.String(),
+				target,
 				a.getImageVariation(config))
 		case "lib64":
 			// Add native modules targetting 64-bit ABI
@@ -735,7 +732,7 @@
 				a.properties.Multilib.Lib64.Native_shared_libs,
 				a.properties.Multilib.Lib64.Binaries,
 				a.properties.Multilib.Lib64.Tests,
-				target.String(),
+				target,
 				a.getImageVariation(config))
 
 			if !has32BitTarget {
@@ -743,7 +740,7 @@
 					a.properties.Multilib.Prefer32.Native_shared_libs,
 					a.properties.Multilib.Prefer32.Binaries,
 					a.properties.Multilib.Prefer32.Tests,
-					target.String(),
+					target,
 					a.getImageVariation(config))
 			}
 
@@ -752,7 +749,7 @@
 					if sanitizer == "hwaddress" {
 						addDependenciesForNativeModules(ctx,
 							[]string{"libclang_rt.hwasan-aarch64-android"},
-							nil, nil, target.String(), a.getImageVariation(config))
+							nil, nil, target, a.getImageVariation(config))
 						break
 					}
 				}
@@ -761,13 +758,11 @@
 
 	}
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{
-		{Mutator: "arch", Variation: "android_common"},
-	}, javaLibTag, a.properties.Java_libs...)
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		javaLibTag, a.properties.Java_libs...)
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{
-		{Mutator: "arch", Variation: "android_common"},
-	}, androidAppTag, a.properties.Apps...)
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		androidAppTag, a.properties.Apps...)
 
 	if String(a.properties.Key) == "" {
 		ctx.ModuleErrorf("key is missing")
@@ -829,9 +824,6 @@
 }
 
 func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
-	if a.vndkApex {
-		return "vendor." + a.vndkVersion(config)
-	}
 	if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) {
 		return "vendor." + config.PlatformVndkVersion()
 	} else {
@@ -1248,7 +1240,7 @@
 	// prepend the name of this APEX to the module names. These names will be the names of
 	// modules that will be defined if the APEX is flattened.
 	for i := range filesInfo {
-		filesInfo[i].moduleName = filesInfo[i].moduleName + "." + ctx.ModuleName()
+		filesInfo[i].moduleName = ctx.ModuleName() + "." + filesInfo[i].moduleName
 	}
 
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
@@ -1574,7 +1566,7 @@
 	if a.installable() {
 		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
 		// with other ordinary files.
-		a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, "apex_manifest.json." + ctx.ModuleName(), ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
 
 		// rename to apex_pubkey
 		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
@@ -1583,7 +1575,7 @@
 			Input:  a.public_key_file,
 			Output: copiedPubkey,
 		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, "apex_pubkey." + ctx.ModuleName(), ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, ctx.ModuleName() + ".apex_pubkey", ".", etc, nil, nil})
 
 		if ctx.Config().FlattenApex() {
 			apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
@@ -1668,17 +1660,17 @@
 			host := false
 			switch fi.module.Target().Os.Class {
 			case android.Host:
-				if archStr != "common" {
+				if fi.module.Target().Arch.ArchType != android.Common {
 					fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
 				}
 				host = true
 			case android.HostCross:
-				if archStr != "common" {
+				if fi.module.Target().Arch.ArchType != android.Common {
 					fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
 				}
 				host = true
 			case android.Device:
-				if archStr != "common" {
+				if fi.module.Target().Arch.ArchType != android.Common {
 					fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
 				}
 			}
@@ -1823,18 +1815,19 @@
 		}{
 			proptools.StringPtr("both"),
 		})
+
+		vndkVersion := proptools.StringDefault(bundle.vndkProperties.Vndk_version, "current")
+		if vndkVersion == "current" {
+			vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
+			bundle.vndkProperties.Vndk_version = proptools.StringPtr(vndkVersion)
+		}
+
+		// Ensure VNDK APEX mount point is formatted as com.android.vndk.v###
+		bundle.properties.Apex_name = proptools.StringPtr("com.android.vndk.v" + vndkVersion)
 	})
 	return bundle
 }
 
-func (a *apexBundle) vndkVersion(config android.DeviceConfig) string {
-	vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
-	if vndkVersion == "current" {
-		vndkVersion = config.PlatformVndkVersion()
-	}
-	return vndkVersion
-}
-
 //
 // Defaults
 //
diff --git a/apex/apex_test.go b/apex/apex_test.go
index a420c14..d1cd969 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -18,7 +18,6 @@
 	"io/ioutil"
 	"os"
 	"reflect"
-	"sort"
 	"strings"
 	"testing"
 
@@ -86,10 +85,6 @@
 	}
 }
 
-func withBinder32bit(fs map[string][]byte, config android.Config) {
-	config.TestProductVariables.Binder32bit = proptools.BoolPtr(true)
-}
-
 func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
 	config := android.TestArchConfig(buildDir, nil)
 	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
@@ -137,10 +132,13 @@
 		ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+		ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator)
+		ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator)
 	})
-	ctx.PreDepsMutators(RegisterPreDepsMutators)
-	ctx.PostDepsMutators(RegisterPostDepsMutators)
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("apex_deps", apexDepsMutator)
+		ctx.BottomUp("apex", apexMutator)
+		ctx.BottomUp("apex_uses", apexUsesMutator)
 		ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
 		ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
 	})
@@ -1209,22 +1207,16 @@
 	mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex")
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
 
 	// APEX variant has __ANDROID_APEX__=<apexname> defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_myapex").Rule("cc").Args["cFlags"]
 	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex")
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex")
-	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
 
 	// APEX variant has __ANDROID_APEX__=<apexname> defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_otherapex").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex")
 	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
-	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
 }
 
 func TestHeaderLibsDependency(t *testing.T) {
@@ -1275,74 +1267,6 @@
 	ensureContains(t, cFlags, "-Imy_include")
 }
 
-func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName string, files []string) {
-	t.Helper()
-	apexRule := ctx.ModuleForTests(moduleName, "android_common_"+moduleName).Rule("apexRule")
-	copyCmds := apexRule.Args["copy_commands"]
-	imageApexDir := "/image.apex/"
-	dstFiles := []string{}
-	for _, cmd := range strings.Split(copyCmds, "&&") {
-		cmd = strings.TrimSpace(cmd)
-		if cmd == "" {
-			continue
-		}
-		terms := strings.Split(cmd, " ")
-		switch terms[0] {
-		case "mkdir":
-		case "cp":
-			if len(terms) != 3 {
-				t.Fatal("copyCmds contains invalid cp command", cmd)
-			}
-			dst := terms[2]
-			index := strings.Index(dst, imageApexDir)
-			if index == -1 {
-				t.Fatal("copyCmds should copy a file to image.apex/", cmd)
-			}
-			dstFile := dst[index+len(imageApexDir):]
-			dstFiles = append(dstFiles, dstFile)
-		default:
-			t.Fatalf("copyCmds should contain mkdir/cp commands only: %q", cmd)
-		}
-	}
-	sort.Strings(dstFiles)
-	sort.Strings(files)
-	missing := []string{}
-	surplus := []string{}
-	i := 0
-	j := 0
-	for i < len(dstFiles) && j < len(files) {
-		if dstFiles[i] == files[j] {
-			i++
-			j++
-		} else if dstFiles[i] < files[j] {
-			surplus = append(surplus, dstFiles[i])
-			i++
-		} else {
-			missing = append(missing, files[j])
-			j++
-		}
-	}
-	if i < len(dstFiles) {
-		surplus = append(surplus, dstFiles[i:]...)
-	}
-	if j < len(files) {
-		missing = append(missing, files[j:]...)
-	}
-
-	failed := false
-	if len(surplus) > 0 {
-		t.Log("surplus files", surplus)
-		failed = true
-	}
-	if len(missing) > 0 {
-		t.Log("missing files", missing)
-		failed = true
-	}
-	if failed {
-		t.Fail()
-	}
-}
-
 func TestVndkApexCurrent(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
@@ -1381,12 +1305,12 @@
 		}
 	`)
 
-	ensureExactContents(t, ctx, "myapex", []string{
-		"lib/libvndk.so",
-		"lib/libvndksp.so",
-		"lib64/libvndk.so",
-		"lib64/libvndksp.so",
-	})
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+	ensureContains(t, copyCmds, "image.apex/lib/libvndk.so")
+	ensureContains(t, copyCmds, "image.apex/lib/libvndksp.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libvndk.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libvndksp.so")
 }
 
 func TestVndkApexWithPrebuilt(t *testing.T) {
@@ -1404,8 +1328,8 @@
 		}
 
 		cc_prebuilt_library_shared {
-			name: "libvndk",
-			srcs: ["libvndk.so"],
+			name: "libvndkshared",
+			srcs: ["libvndkshared.so"],
 			vendor_available: true,
 			vndk: {
 				enabled: true,
@@ -1413,33 +1337,13 @@
 			system_shared_libs: [],
 			stl: "none",
 		}
-
-		cc_prebuilt_library_shared {
-			name: "libvndk.arm",
-			srcs: ["libvndk.arm.so"],
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-			},
-			enabled: false,
-			arch: {
-				arm: {
-					enabled: true,
-				},
-			},
-			system_shared_libs: [],
-			stl: "none",
-		}
 	`, withFiles(map[string][]byte{
-		"libvndk.so":     nil,
-		"libvndk.arm.so": nil,
+		"libvndkshared.so": nil,
 	}))
 
-	ensureExactContents(t, ctx, "myapex", []string{
-		"lib/libvndk.so",
-		"lib/libvndk.arm.so",
-		"lib64/libvndk.so",
-	})
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+	ensureContains(t, copyCmds, "image.apex/lib/libvndkshared.so")
 }
 
 func TestVndkApexVersion(t *testing.T) {
@@ -1457,22 +1361,15 @@
 			private_key: "testkey.pem",
 		}
 
-		vndk_prebuilt_shared {
-			name: "libvndk27",
-			version: "27",
+		cc_library {
+			name: "libvndk",
+			srcs: ["mylib.cpp"],
 			vendor_available: true,
 			vndk: {
 				enabled: true,
 			},
-			target_arch: "arm64",
-			arch: {
-				arm: {
-					srcs: ["libvndk27_arm.so"],
-				},
-				arm64: {
-					srcs: ["libvndk27_arm64.so"],
-				},
-			},
+			system_shared_libs: [],
+			stl: "none",
 		}
 
 		vndk_prebuilt_shared {
@@ -1482,27 +1379,18 @@
 			vndk: {
 				enabled: true,
 			},
-			target_arch: "x86_64",
-			arch: {
-				x86: {
-					srcs: ["libvndk27_x86.so"],
-				},
-				x86_64: {
-					srcs: ["libvndk27_x86_64.so"],
-				},
-			},
-	}
+			target_arch: "arm64",
+			srcs: ["libvndk27.so"],
+		}
 	`, withFiles(map[string][]byte{
-		"libvndk27_arm.so":    nil,
-		"libvndk27_arm64.so":  nil,
-		"libvndk27_x86.so":    nil,
-		"libvndk27_x86_64.so": nil,
+		"libvndk27.so": nil,
 	}))
 
-	ensureExactContents(t, ctx, "myapex_v27", []string{
-		"lib/libvndk27_arm.so",
-		"lib64/libvndk27_arm64.so",
-	})
+	apexRule := ctx.ModuleForTests("myapex_v27", "android_common_myapex_v27").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+	ensureContains(t, copyCmds, "image.apex/lib/libvndk27.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libvndk27.so")
+	ensureNotContains(t, copyCmds, "image.apex/lib/libvndk.so")
 }
 
 func TestVndkApexErrorWithDuplicateVersion(t *testing.T) {
@@ -1617,10 +1505,14 @@
 		},
 	}))
 
-	ensureExactContents(t, ctx, "myapex", []string{
-		"lib/libvndk.so",
-		"lib64/libvndk.so",
-	})
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+	ensureContains(t, copyCmds, "image.apex/lib/libvndk.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libvndk.so")
+
+	// apex
+	ensureNotContains(t, copyCmds, "image.apex/lib/x86/libvndk.so")
+	ensureNotContains(t, copyCmds, "image.apex/lib64/x86_64/libvndk.so")
 }
 
 func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) {
@@ -1653,70 +1545,6 @@
 	`)
 }
 
-func TestVndkApexWithBinder32(t *testing.T) {
-	ctx, _ := testApex(t,
-		`
-		apex_vndk {
-			name: "myapex_v27",
-			key: "myapex.key",
-			file_contexts: "myapex",
-			vndk_version: "27",
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		vndk_prebuilt_shared {
-			name: "libvndk27",
-			version: "27",
-			target_arch: "arm",
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-			},
-			arch: {
-				arm: {
-					srcs: ["libvndk27.so"],
-				}
-			},
-		}
-
-		vndk_prebuilt_shared {
-			name: "libvndk27",
-			version: "27",
-			target_arch: "arm",
-			binder32bit: true,
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-			},
-			arch: {
-				arm: {
-					srcs: ["libvndk27binder32.so"],
-				}
-			},
-		}
-		`,
-		withFiles(map[string][]byte{
-			"libvndk27.so":         nil,
-			"libvndk27binder32.so": nil,
-		}),
-		withBinder32bit,
-		withTargets(map[android.OsType][]android.Target{
-			android.Android: []android.Target{
-				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
-			},
-		}),
-	)
-
-	ensureExactContents(t, ctx, "myapex_v27", []string{
-		"lib/libvndk27binder32.so",
-	})
-}
-
 func TestDependenciesInApexManifest(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -2227,12 +2055,12 @@
 	var builder strings.Builder
 	data.Custom(&builder, name, prefix, "", data)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_MODULE := mytest.myapex\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := mytest1.myapex\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := mytest2.myapex\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := mytest3.myapex\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.json.myapex\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := apex_pubkey.myapex\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest1\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest2\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest3\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_manifest.json\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_pubkey\n")
 	ensureContains(t, androidMk, "LOCAL_MODULE := myapex\n")
 }
 
diff --git a/cc/androidmk.go b/cc/androidmk.go
index f6b26d2..f1d329f 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -93,11 +93,6 @@
 					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
 					if c.isVndk() && !c.static() {
 						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.vndkVersion())
-						// VNDK libraries available to vendor are not installed because
-						// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
-						if !c.isVndkExt() {
-							fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-						}
 					}
 				}
 			},
diff --git a/cc/cc.go b/cc/cc.go
index ef8906a..806a6ed 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -488,6 +488,15 @@
 	return ""
 }
 
+// IsVndkOnSystem returns true if a module is supposed to be a vndk library provided by system to vendor
+func (c *Module) IsVndkOnSystem() bool {
+	if linker, ok := c.linker.(libraryInterface); ok {
+		return linker.shared() && c.isVndk() && c.useVndk() && !c.isVndkExt()
+	}
+
+	return false
+}
+
 func (c *Module) VndkVersion() string {
 	return c.vndkVersion()
 }
@@ -1380,10 +1389,9 @@
 			depTag = headerExportDepTag
 		}
 		if buildStubs {
-			actx.AddFarVariationDependencies([]blueprint.Variation{
-				{Mutator: "arch", Variation: ctx.Target().String()},
-				{Mutator: "image", Variation: c.imageVariation()},
-			}, depTag, lib)
+			actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+				blueprint.Variation{Mutator: "image", Variation: c.imageVariation()}),
+				depTag, lib)
 		} else {
 			actx.AddVariationDependencies(nil, depTag, lib)
 		}
@@ -1925,7 +1933,11 @@
 
 		if ptr != nil {
 			if !linkFile.Valid() {
-				ctx.ModuleErrorf("module %q missing output file", depName)
+				if !ctx.Config().AllowMissingDependencies() {
+					ctx.ModuleErrorf("module %q missing output file", depName)
+				} else {
+					ctx.AddMissingDependencies([]string{depName})
+				}
 				return
 			}
 			*ptr = append(*ptr, linkFile.Path())
diff --git a/cc/compiler.go b/cc/compiler.go
index 438dee7..ffb6ad2 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -320,9 +320,7 @@
 	}
 
 	if ctx.apexName() != "" {
-		// TODO(b/142582178): remove the value for __ANDROID_APEX__
 		flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_APEX__="+ctx.apexName())
-		flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__")
 	}
 
 	instructionSet := String(compiler.Properties.Instruction_set)
@@ -530,12 +528,6 @@
 	return false
 }
 
-// makeDefineString transforms a name of an APEX module into a value to be used as value for C define
-// For example, com.android.foo => COM_ANDROID_FOO
-func makeDefineString(name string) string {
-	return strings.ReplaceAll(strings.ToUpper(name), ".", "_")
-}
-
 var gnuToCReplacer = strings.NewReplacer("gnu", "c")
 
 func ndkPathDeps(ctx ModuleContext) android.Paths {
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index d7d8955..3e8abac 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -65,6 +65,7 @@
 	"android.hardware.neuralnetworks@1.0",
 	"android.hardware.neuralnetworks@1.1",
 	"android.hardware.neuralnetworks@1.2",
+	"android.hardware.neuralnetworks@1.3",
 	"android.hardware.nfc@1.0",
 	"android.hardware.nfc@1.1",
 	"android.hardware.nfc@1.2",
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 1009f46..5172fc8 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -884,18 +884,16 @@
 			// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
 			if c.staticBinary() {
 				// static executable gets static runtime libs
-				mctx.AddFarVariationDependencies([]blueprint.Variation{
+				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "static"},
 					{Mutator: "image", Variation: c.imageVariation()},
-					{Mutator: "arch", Variation: mctx.Target().String()},
-				}, staticDepTag, runtimeLibrary)
+				}...), staticDepTag, runtimeLibrary)
 			} else if !c.static() && !c.header() {
 				// dynamic executable and shared libs get shared runtime libs
-				mctx.AddFarVariationDependencies([]blueprint.Variation{
+				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "shared"},
 					{Mutator: "image", Variation: c.imageVariation()},
-					{Mutator: "arch", Variation: mctx.Target().String()},
-				}, earlySharedDepTag, runtimeLibrary)
+				}...), earlySharedDepTag, runtimeLibrary)
 			}
 			// static lib does not have dependency to the runtime library. The
 			// dependency will be added to the executables or shared libs using
diff --git a/cc/vndk.go b/cc/vndk.go
index 2c1856e..14bbf11 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -307,31 +307,6 @@
 	}
 }
 
-func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
-	if !m.Enabled() {
-		return false
-	}
-
-	if m.Target().NativeBridge == android.NativeBridgeEnabled {
-		return false
-	}
-
-	// prebuilt vndk modules should match with device
-	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
-	// When b/142675459 is landed, remove following check
-	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.matchesWithDevice(mctx.DeviceConfig()) {
-		return false
-	}
-
-	if lib, ok := m.linker.(libraryInterface); ok {
-		useCoreVariant := m.vndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
-			mctx.DeviceConfig().VndkUseCoreVariant() &&
-			!inList(m.BaseModuleName(), config.VndkMustUseVendorVariantList)
-		return lib.shared() && m.useVndk() && m.isVndk() && !m.isVndkExt() && !useCoreVariant
-	}
-	return false
-}
-
 // gather list of vndk-core, vndk-sp, and ll-ndk libs
 func VndkMutator(mctx android.BottomUpMutatorContext) {
 	m, ok := mctx.Module().(*Module)
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 8ed0afb..2cebb6d 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -130,7 +130,13 @@
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
-	if !p.matchesWithDevice(ctx.DeviceConfig()) {
+	arches := ctx.DeviceConfig().Arches()
+	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
+		ctx.Module().SkipInstall()
+		return nil
+	}
+
+	if ctx.DeviceConfig().BinderBitness() != p.binderBit() {
 		ctx.Module().SkipInstall()
 		return nil
 	}
@@ -147,20 +153,6 @@
 	return nil
 }
 
-func (p *vndkPrebuiltLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
-	arches := config.Arches()
-	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
-		return false
-	}
-	if config.BinderBitness() != p.binderBit() {
-		return false
-	}
-	if len(p.properties.Srcs) == 0 {
-		return false
-	}
-	return true
-}
-
 func (p *vndkPrebuiltLibraryDecorator) nativeCoverage() bool {
 	return false
 }
diff --git a/genrule/genrule.go b/genrule/genrule.go
index c21df4c..a7c5d65 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -172,9 +172,7 @@
 			if m := android.SrcIsModule(tool); m != "" {
 				tool = m
 			}
-			ctx.AddFarVariationDependencies([]blueprint.Variation{
-				{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
-			}, tag, tool)
+			ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), tag, tool)
 		}
 	}
 }
diff --git a/java/app.go b/java/app.go
index e033661..6b640f1 100644
--- a/java/app.go
+++ b/java/app.go
@@ -167,10 +167,8 @@
 
 	embedJni := a.shouldEmbedJnis(ctx)
 	for _, jniTarget := range ctx.MultiTargets() {
-		variation := []blueprint.Variation{
-			{Mutator: "arch", Variation: jniTarget.String()},
-			{Mutator: "link", Variation: "shared"},
-		}
+		variation := append(jniTarget.Variations(),
+			blueprint.Variation{Mutator: "link", Variation: "shared"})
 		tag := &jniDependencyTag{
 			target: jniTarget,
 		}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 030b010..14db521 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -18,8 +18,6 @@
 	"fmt"
 	"io"
 
-	"github.com/google/blueprint"
-
 	"android/soong/android"
 )
 
@@ -83,13 +81,13 @@
 var deviceHostConverterDepTag = dependencyTag{name: "device_host_converter"}
 
 func (d *DeviceForHost) DepsMutator(ctx android.BottomUpMutatorContext) {
-	variation := []blueprint.Variation{{Mutator: "arch", Variation: "android_common"}}
-	ctx.AddFarVariationDependencies(variation, deviceHostConverterDepTag, d.properties.Libs...)
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		deviceHostConverterDepTag, d.properties.Libs...)
 }
 
 func (d *HostForDevice) DepsMutator(ctx android.BottomUpMutatorContext) {
-	variation := []blueprint.Variation{{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant}}
-	ctx.AddFarVariationDependencies(variation, deviceHostConverterDepTag, d.properties.Libs...)
+	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
+		deviceHostConverterDepTag, d.properties.Libs...)
 }
 
 func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 44aae9b..3c9a0f3 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -60,7 +60,7 @@
 	deviceImportModule := ctx.ModuleForTests("device_import_module", "android_common")
 	deviceImportCombined := deviceImportModule.Output("combined/device_import_module.jar")
 
-	hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
+	hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String())
 	hostJavac := hostModule.Output("javac/host_module.jar")
 	hostRes := hostModule.Output("res/host_module.jar")
 	combined := hostModule.Output("combined/host_module.jar")
@@ -133,11 +133,11 @@
 
 	ctx, config := testJava(t, bp)
 
-	hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
+	hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String())
 	hostJavac := hostModule.Output("javac/host_module.jar")
 	hostRes := hostModule.Output("res/host_module.jar")
 
-	hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOsCommonVariant)
+	hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOSCommonTarget.String())
 	hostImportCombined := hostImportModule.Output("combined/host_import_module.jar")
 
 	deviceModule := ctx.ModuleForTests("device_module", "android_common")
diff --git a/java/java.go b/java/java.go
index d39c0d2..0aef69e 100644
--- a/java/java.go
+++ b/java/java.go
@@ -551,9 +551,7 @@
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{
-		{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
-	}, pluginTag, j.properties.Plugins...)
+	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...)
 
 	android.ProtoDeps(ctx, &j.protoProperties)
 	if j.hasSrcExt(".proto") {
diff --git a/java/java_test.go b/java/java_test.go
index f0cb6f8..a3499cc 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1095,8 +1095,10 @@
 	`
 
 	t.Run("Java language level 8", func(t *testing.T) {
-		// Test default javac -source 1.8 -target 1.8
-		ctx, _ := testJava(t, bp)
+		// Test with legacy javac -source 1.8 -target 1.8
+		config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "false"})
+		ctx := testContext(bp, nil)
+		run(t, ctx, config)
 
 		checkPatchModuleFlag(t, ctx, "foo", "")
 		checkPatchModuleFlag(t, ctx, "bar", "")
@@ -1104,10 +1106,8 @@
 	})
 
 	t.Run("Java language level 9", func(t *testing.T) {
-		// Test again with javac -source 9 -target 9
-		config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
-		ctx := testContext(bp, nil)
-		run(t, ctx, config)
+		// Test with default javac -source 9 -target 9
+		ctx, _ := testJava(t, bp)
 
 		checkPatchModuleFlag(t, ctx, "foo", "")
 		expected := "java.base=.:" + buildDir
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 5001b47..5e0e592 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -279,9 +279,9 @@
 				}
 			}
 
+			// Test with legacy javac -source 1.8 -target 1.8
 			t.Run("Java language level 8", func(t *testing.T) {
-				// Test default javac -source 1.8 -target 1.8
-				config := testConfig(nil)
+				config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "false"})
 				if testcase.unbundled {
 					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
 				}
@@ -302,9 +302,9 @@
 				}
 			})
 
-			// Test again with javac -source 9 -target 9
+			// Test with default javac -source 9 -target 9
 			t.Run("Java language level 9", func(t *testing.T) {
-				config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
+				config := testConfig(nil)
 				if testcase.unbundled {
 					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
 				}
@@ -327,7 +327,8 @@
 
 			// Test again with PLATFORM_VERSION_CODENAME=REL
 			t.Run("REL", func(t *testing.T) {
-				config := testConfig(nil)
+				// TODO(b/115604102): This test should be rewritten with language level 9
+				config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "false"})
 				config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL")
 				config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true)
 
diff --git a/python/python.go b/python/python.go
index ad08909..1b606cb 100644
--- a/python/python.go
+++ b/python/python.go
@@ -306,22 +306,17 @@
 			if p.bootstrapper.autorun() {
 				launcherModule = "py2-launcher-autorun"
 			}
-			ctx.AddFarVariationDependencies([]blueprint.Variation{
-				{Mutator: "arch", Variation: ctx.Target().String()},
-			}, launcherTag, launcherModule)
+			ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherTag, launcherModule)
 
 			// Add py2-launcher shared lib dependencies. Ideally, these should be
 			// derived from the `shared_libs` property of "py2-launcher". However, we
 			// cannot read the property at this stage and it will be too late to add
 			// dependencies later.
-			ctx.AddFarVariationDependencies([]blueprint.Variation{
-				{Mutator: "arch", Variation: ctx.Target().String()},
-			}, launcherSharedLibTag, "libsqlite")
+			ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, "libsqlite")
 
 			if ctx.Target().Os.Bionic() {
-				ctx.AddFarVariationDependencies([]blueprint.Variation{
-					{Mutator: "arch", Variation: ctx.Target().String()},
-				}, launcherSharedLibTag, "libc", "libdl", "libm")
+				ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag,
+					"libc", "libdl", "libm")
 			}
 		}
 
diff --git a/rust/rust.go b/rust/rust.go
index 61b51e5..4f5e7fb 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -496,7 +496,7 @@
 	}
 
 	// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
-	actx.AddFarVariationDependencies([]blueprint.Variation{{Mutator: "arch", Variation: ctx.Config().BuildOsVariant}}, procMacroDepTag, deps.ProcMacros...)
+	actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
 }
 
 func (mod *Module) Name() string {
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 7668d91..d189043 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -148,11 +148,10 @@
 
 		targets := mctx.MultiTargets()
 		for _, target := range targets {
-			mctx.AddFarVariationDependencies([]blueprint.Variation{
-				{Mutator: "arch", Variation: target.String()},
+			mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 				{Mutator: "image", Variation: "core"},
 				{Mutator: "link", Variation: "shared"},
-			}, sdkMemberDepTag, m.properties.Native_shared_libs...)
+			}...), sdkMemberDepTag, m.properties.Native_shared_libs...)
 		}
 	}
 }