Merge changes I0dcc9c7b,I9bc40642

* changes:
  Move cc.imageMutator into the android package
  Make CreateVariations return []android.Module
diff --git a/Android.bp b/Android.bp
index 7259255..0ca11d3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,6 +51,7 @@
         "android/expand.go",
         "android/filegroup.go",
         "android/hooks.go",
+        "android/image.go",
         "android/makevars.go",
         "android/module.go",
         "android/mutator.go",
diff --git a/android/apex.go b/android/apex.go
index 5118a0a..44387cd 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -17,8 +17,6 @@
 import (
 	"sort"
 	"sync"
-
-	"github.com/google/blueprint"
 )
 
 // ApexModule is the interface that a module type is expected to implement if
@@ -69,7 +67,7 @@
 
 	// Mutate this module into one or more variants each of which is built
 	// for an APEX marked via BuildForApex().
-	CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module
+	CreateApexVariations(mctx BottomUpMutatorContext) []Module
 
 	// Sets the name of the apex variant of this module. Called inside
 	// CreateApexVariations.
@@ -176,7 +174,7 @@
 	}
 }
 
-func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
+func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
 	if len(m.apexVariations) > 0 {
 		m.checkApexAvailableProperty(mctx)
 		sort.Strings(m.apexVariations)
diff --git a/android/image.go b/android/image.go
new file mode 100644
index 0000000..5ec1b16
--- /dev/null
+++ b/android/image.go
@@ -0,0 +1,83 @@
+// Copyright 2019 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 android
+
+// ImageInterface is implemented by modules that need to be split by the ImageMutator.
+type ImageInterface interface {
+	// ImageMutatorBegin is called before any other method in the ImageInterface.
+	ImageMutatorBegin(ctx BaseModuleContext)
+
+	// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
+	CoreVariantNeeded(ctx BaseModuleContext) bool
+
+	// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
+	// recovery partition).
+	RecoveryVariantNeeded(ctx BaseModuleContext) bool
+
+	// ExtraImageVariations should return a list of the additional variations needed for the module.  After the
+	// variants are created the SetImageVariation method will be called on each newly created variant with the
+	// its variation.
+	ExtraImageVariations(ctx BaseModuleContext) []string
+
+	// SetImageVariation will be passed a newly created recovery variant of the module.  ModuleBase implements
+	// SetImageVariation, most module types will not need to override it, and those that do must call the
+	// overridden method.  Implementors of SetImageVariation must be careful to modify the module argument
+	// and not the receiver.
+	SetImageVariation(ctx BaseModuleContext, variation string, module Module)
+}
+
+const (
+	// CoreVariation is the variant used for framework-private libraries, or
+	// SDK libraries. (which framework-private libraries can use), which
+	// will be installed to the system image.
+	CoreVariation string = "core"
+
+	// RecoveryVariation means a module to be installed to recovery image.
+	RecoveryVariation string = "recovery"
+)
+
+// ImageMutator creates variants for modules that implement the ImageInterface that
+// allow them to build differently for each partition (recovery, core, vendor, etc.).
+func ImageMutator(ctx BottomUpMutatorContext) {
+	if ctx.Os() != Android {
+		return
+	}
+
+	if m, ok := ctx.Module().(ImageInterface); ok {
+		m.ImageMutatorBegin(ctx)
+
+		var variations []string
+
+		if m.CoreVariantNeeded(ctx) {
+			variations = append(variations, CoreVariation)
+		}
+		if m.RecoveryVariantNeeded(ctx) {
+			variations = append(variations, RecoveryVariation)
+		}
+
+		extraVariations := m.ExtraImageVariations(ctx)
+		variations = append(variations, extraVariations...)
+
+		if len(variations) == 0 {
+			return
+		}
+
+		mod := ctx.CreateVariations(variations...)
+		for i, v := range variations {
+			mod[i].base().setImageVariation(v)
+			m.SetImageVariation(ctx, v, mod[i])
+		}
+	}
+}
diff --git a/android/module.go b/android/module.go
index 891babc..5b2f9d3 100644
--- a/android/module.go
+++ b/android/module.go
@@ -431,6 +431,9 @@
 	DebugName       string   `blueprint:"mutated"`
 	DebugMutators   []string `blueprint:"mutated"`
 	DebugVariations []string `blueprint:"mutated"`
+
+	// set by ImageMutator
+	ImageVariation string `blueprint:"mutated"`
 }
 
 type hostAndDeviceProperties struct {
@@ -865,6 +868,21 @@
 	return m.noticeFile
 }
 
+func (m *ModuleBase) setImageVariation(variant string) {
+	m.commonProperties.ImageVariation = variant
+}
+
+func (m *ModuleBase) ImageVariation() blueprint.Variation {
+	return blueprint.Variation{
+		Mutator:   "image",
+		Variation: m.base().commonProperties.ImageVariation,
+	}
+}
+
+func (m *ModuleBase) InRecovery() bool {
+	return m.base().commonProperties.ImageVariation == RecoveryVariation
+}
+
 func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
 	allInstalledFiles := Paths{}
 	allCheckbuildFiles := Paths{}
diff --git a/android/mutator.go b/android/mutator.go
index df68726..0d253eb 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -143,8 +143,8 @@
 
 	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
 	AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
-	CreateVariations(...string) []blueprint.Module
-	CreateLocalVariations(...string) []blueprint.Module
+	CreateVariations(...string) []Module
+	CreateLocalVariations(...string) []Module
 	SetDependencyVariation(string)
 	SetDefaultDependencyVariation(*string)
 	AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
@@ -285,28 +285,32 @@
 	b.bp.AddReverseDependency(module, tag, name)
 }
 
-func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []blueprint.Module {
+func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []Module {
 	modules := b.bp.CreateVariations(variations...)
 
+	aModules := make([]Module, len(modules))
 	for i := range variations {
-		base := modules[i].(Module).base()
+		aModules[i] = modules[i].(Module)
+		base := aModules[i].base()
 		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
 		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
 	}
 
-	return modules
+	return aModules
 }
 
-func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []blueprint.Module {
+func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []Module {
 	modules := b.bp.CreateLocalVariations(variations...)
 
+	aModules := make([]Module, len(modules))
 	for i := range variations {
-		base := modules[i].(Module).base()
+		aModules[i] = modules[i].(Module)
+		base := aModules[i].base()
 		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
 		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
 	}
 
-	return modules
+	return aModules
 }
 
 func (b *bottomUpMutatorContext) SetDependencyVariation(variation string) {
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 6c80370..2701185 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -25,10 +25,6 @@
 	RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
 	RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
 	RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
-
-	PreDepsMutators(func(ctx RegisterMutatorsContext) {
-		ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
-	})
 }
 
 type prebuiltEtcProperties struct {
@@ -48,8 +44,6 @@
 	// Make this module available when building for recovery.
 	Recovery_available *bool
 
-	InRecovery bool `blueprint:"mutated"`
-
 	// Whether this module is directly installable to one of the partitions. Default: true.
 	Installable *bool
 }
@@ -76,7 +70,7 @@
 }
 
 func (p *PrebuiltEtc) inRecovery() bool {
-	return p.properties.InRecovery || p.ModuleBase.InstallInRecovery()
+	return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
 }
 
 func (p *PrebuiltEtc) onlyInRecovery() bool {
@@ -87,6 +81,25 @@
 	return p.inRecovery()
 }
 
+var _ ImageInterface = (*PrebuiltEtc)(nil)
+
+func (p *PrebuiltEtc) ImageMutatorBegin(ctx BaseModuleContext) {}
+
+func (p *PrebuiltEtc) CoreVariantNeeded(ctx BaseModuleContext) bool {
+	return !p.ModuleBase.InstallInRecovery()
+}
+
+func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx BaseModuleContext) bool {
+	return Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
+}
+
+func (p *PrebuiltEtc) ExtraImageVariations(ctx BaseModuleContext) []string {
+	return nil
+}
+
+func (p *PrebuiltEtc) SetImageVariation(ctx BaseModuleContext, variation string, module Module) {
+}
+
 func (p *PrebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
 	if p.properties.Src == nil {
 		ctx.PropertyErrorf("src", "missing prebuilt source file")
@@ -222,49 +235,6 @@
 	return module
 }
 
-const (
-	// coreMode is the variant for modules to be installed to system.
-	coreMode = "core"
-
-	// recoveryMode means a module to be installed to recovery image.
-	recoveryMode = "recovery"
-)
-
-// prebuiltEtcMutator creates the needed variants to install the module to
-// system or recovery.
-func prebuiltEtcMutator(mctx BottomUpMutatorContext) {
-	m, ok := mctx.Module().(*PrebuiltEtc)
-	if !ok || m.Host() {
-		return
-	}
-
-	var coreVariantNeeded bool = true
-	var recoveryVariantNeeded bool = false
-	if Bool(m.properties.Recovery_available) {
-		recoveryVariantNeeded = true
-	}
-
-	if m.ModuleBase.InstallInRecovery() {
-		recoveryVariantNeeded = true
-		coreVariantNeeded = false
-	}
-
-	var variants []string
-	if coreVariantNeeded {
-		variants = append(variants, coreMode)
-	}
-	if recoveryVariantNeeded {
-		variants = append(variants, recoveryMode)
-	}
-	mod := mctx.CreateVariations(variants...)
-	for i, v := range variants {
-		if v == recoveryMode {
-			m := mod[i].(*PrebuiltEtc)
-			m.properties.InRecovery = true
-		}
-	}
-}
-
 // prebuilt_font installs a font in <partition>/fonts directory.
 func PrebuiltFontFactory() Module {
 	module := &PrebuiltEtc{}
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index 100e73d..3855dac 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -30,7 +30,7 @@
 	ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
 	ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
 	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-		ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
+		ctx.BottomUp("prebuilt_etc", ImageMutator).Parallel()
 	})
 	ctx.Register()
 	mockFiles := map[string][]byte{
diff --git a/apex/apex.go b/apex/apex.go
index d7f6d53..4c5e06b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -716,12 +716,12 @@
 
 func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
 	if a.vndkApex {
-		return "vendor." + a.vndkVersion(config)
+		return cc.VendorVariationPrefix + a.vndkVersion(config)
 	}
 	if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) {
-		return "vendor." + config.PlatformVndkVersion()
+		return cc.VendorVariationPrefix + config.PlatformVndkVersion()
 	} else {
-		return "core"
+		return android.CoreVariation
 	}
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b239d39..51cb74e 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -140,7 +140,7 @@
 		ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
 	})
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("image", android.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
 		ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
diff --git a/cc/cc.go b/cc/cc.go
index aa656da..f306a00 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -37,7 +37,7 @@
 
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("vndk", VndkMutator).Parallel()
-		ctx.BottomUp("image", ImageMutator).Parallel()
+		ctx.BottomUp("image", android.ImageMutator).Parallel()
 		ctx.BottomUp("link", LinkageMutator).Parallel()
 		ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
 		ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
@@ -218,7 +218,10 @@
 	// Make this module available when building for recovery
 	Recovery_available *bool
 
-	InRecovery bool `blueprint:"mutated"`
+	// Set by ImageMutator
+	CoreVariantNeeded     bool     `blueprint:"mutated"`
+	RecoveryVariantNeeded bool     `blueprint:"mutated"`
+	VendorVariants        []string `blueprint:"mutated"`
 
 	// Allows this module to use non-APEX version of libraries. Useful
 	// for building binaries that are started before APEXes are activated.
@@ -826,7 +829,7 @@
 }
 
 func (c *Module) InRecovery() bool {
-	return c.Properties.InRecovery || c.ModuleBase.InstallInRecovery()
+	return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery()
 }
 
 func (c *Module) OnlyInRecovery() bool {
@@ -1588,8 +1591,7 @@
 			depTag = headerExportDepTag
 		}
 		if buildStubs {
-			actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
-				blueprint.Variation{Mutator: "image", Variation: c.imageVariation()}),
+			actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
 				depTag, lib)
 		} else {
 			actx.AddVariationDependencies(nil, depTag, lib)
@@ -1727,14 +1729,8 @@
 
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		if vndkdep.isVndkExt() {
-			var baseModuleMode string
-			if actx.DeviceConfig().VndkVersion() == "" {
-				baseModuleMode = coreMode
-			} else {
-				baseModuleMode = c.imageVariation()
-			}
 			actx.AddVariationDependencies([]blueprint.Variation{
-				{Mutator: "image", Variation: baseModuleMode},
+				c.ImageVariation(),
 				{Mutator: "link", Variation: "shared"},
 			}, vndkExtDepTag, vndkdep.getVndkExtendsModuleName())
 		}
@@ -2389,15 +2385,6 @@
 	return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid()
 }
 
-func (c *Module) imageVariation() string {
-	if c.UseVndk() {
-		return vendorMode + "." + c.Properties.VndkVersion
-	} else if c.InRecovery() {
-		return recoveryMode
-	}
-	return coreMode
-}
-
 func (c *Module) IDEInfo(dpInfo *android.IdeInfo) {
 	outputFiles, err := c.OutputFiles("")
 	if err != nil {
@@ -2481,15 +2468,9 @@
 }
 
 const (
-	// coreMode is the variant used for framework-private libraries, or
-	// SDK libraries. (which framework-private libraries can use)
-	coreMode = "core"
-
-	// vendorMode is the variant prefix used for /vendor code that compiles
+	// VendorVariationPrefix is the variant prefix used for /vendor code that compiles
 	// against the VNDK.
-	vendorMode = "vendor"
-
-	recoveryMode = "recovery"
+	VendorVariationPrefix = "vendor."
 )
 
 func squashVendorSrcs(m *Module) {
@@ -2512,74 +2493,9 @@
 	}
 }
 
-func ImageMutator(mctx android.BottomUpMutatorContext) {
-	if mctx.Os() != android.Android {
-		return
-	}
+var _ android.ImageInterface = (*Module)(nil)
 
-	if g, ok := mctx.Module().(*genrule.Module); ok {
-		if props, ok := g.Extra.(*GenruleExtraProperties); ok {
-			var coreVariantNeeded bool = false
-			var vendorVariantNeeded bool = false
-			var recoveryVariantNeeded bool = false
-			if mctx.DeviceConfig().VndkVersion() == "" {
-				coreVariantNeeded = true
-			} else if Bool(props.Vendor_available) {
-				coreVariantNeeded = true
-				vendorVariantNeeded = true
-			} else if mctx.SocSpecific() || mctx.DeviceSpecific() {
-				vendorVariantNeeded = true
-			} else {
-				coreVariantNeeded = true
-			}
-			if Bool(props.Recovery_available) {
-				recoveryVariantNeeded = true
-			}
-
-			if recoveryVariantNeeded {
-				primaryArch := mctx.Config().DevicePrimaryArchType()
-				moduleArch := g.Target().Arch.ArchType
-				if moduleArch != primaryArch {
-					recoveryVariantNeeded = false
-				}
-			}
-
-			var variants []string
-			if coreVariantNeeded {
-				variants = append(variants, coreMode)
-			}
-			if vendorVariantNeeded {
-				variants = append(variants, vendorMode+"."+mctx.DeviceConfig().PlatformVndkVersion())
-				if vndkVersion := mctx.DeviceConfig().VndkVersion(); vndkVersion != "current" {
-					variants = append(variants, vendorMode+"."+vndkVersion)
-				}
-			}
-			if recoveryVariantNeeded {
-				variants = append(variants, recoveryMode)
-			}
-			mod := mctx.CreateVariations(variants...)
-			for i, v := range variants {
-				if v == recoveryMode {
-					m := mod[i].(*genrule.Module)
-					m.Extra.(*GenruleExtraProperties).InRecovery = true
-				}
-			}
-		}
-	}
-
-	//TODO When LinkableInterface supports VNDK, this should be mctx.Module().(LinkableInterface)
-	m, ok := mctx.Module().(*Module)
-	if !ok {
-		if linkable, ok := mctx.Module().(LinkableInterface); ok {
-			variations := []string{coreMode}
-			if linkable.InRecovery() {
-				variations = append(variations, recoveryMode)
-			}
-			mctx.CreateVariations(variations...)
-		}
-		return
-	}
-
+func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
 	// Sanity check
 	vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
 	productSpecific := mctx.ProductSpecific()
@@ -2587,7 +2503,6 @@
 	if m.VendorProperties.Vendor_available != nil && vendorSpecific {
 		mctx.PropertyErrorf("vendor_available",
 			"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
-		return
 	}
 
 	if vndkdep := m.vndkdep; vndkdep != nil {
@@ -2595,38 +2510,32 @@
 			if productSpecific {
 				mctx.PropertyErrorf("product_specific",
 					"product_specific must not be true when `vndk: {enabled: true}`")
-				return
 			}
 			if vendorSpecific {
 				if !vndkdep.isVndkExt() {
 					mctx.PropertyErrorf("vndk",
 						"must set `extends: \"...\"` to vndk extension")
-					return
 				}
 			} else {
 				if vndkdep.isVndkExt() {
 					mctx.PropertyErrorf("vndk",
 						"must set `vendor: true` to set `extends: %q`",
 						m.getVndkExtendsModuleName())
-					return
 				}
 				if m.VendorProperties.Vendor_available == nil {
 					mctx.PropertyErrorf("vndk",
 						"vendor_available must be set to either true or false when `vndk: {enabled: true}`")
-					return
 				}
 			}
 		} else {
 			if vndkdep.isVndkSp() {
 				mctx.PropertyErrorf("vndk",
 					"must set `enabled: true` to set `support_system_process: true`")
-				return
 			}
 			if vndkdep.isVndkExt() {
 				mctx.PropertyErrorf("vndk",
 					"must set `enabled: true` to set `extends: %q`",
 					m.getVndkExtendsModuleName())
-				return
 			}
 		}
 	}
@@ -2705,28 +2614,34 @@
 		}
 	}
 
-	var variants []string
-	if coreVariantNeeded {
-		variants = append(variants, coreMode)
-	}
 	for _, variant := range android.FirstUniqueStrings(vendorVariants) {
-		variants = append(variants, vendorMode+"."+variant)
+		m.Properties.VendorVariants = append(m.Properties.VendorVariants, VendorVariationPrefix+variant)
 	}
-	if recoveryVariantNeeded {
-		variants = append(variants, recoveryMode)
-	}
-	mod := mctx.CreateVariations(variants...)
-	for i, v := range variants {
-		if strings.HasPrefix(v, vendorMode+".") {
-			m := mod[i].(*Module)
-			m.Properties.VndkVersion = strings.TrimPrefix(v, vendorMode+".")
-			squashVendorSrcs(m)
-		} else if v == recoveryMode {
-			m := mod[i].(*Module)
-			m.Properties.InRecovery = true
-			m.MakeAsPlatform()
-			squashRecoverySrcs(m)
-		}
+
+	m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded
+	m.Properties.CoreVariantNeeded = coreVariantNeeded
+}
+
+func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	return c.Properties.CoreVariantNeeded
+}
+
+func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+	return c.Properties.RecoveryVariantNeeded
+}
+
+func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+	return c.Properties.VendorVariants
+}
+
+func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
+	m := module.(*Module)
+	if variant == android.RecoveryVariation {
+		m.MakeAsPlatform()
+		squashRecoverySrcs(m)
+	} else if strings.HasPrefix(variant, VendorVariationPrefix) {
+		m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
+		squashVendorSrcs(m)
 	}
 }
 
diff --git a/cc/genrule.go b/cc/genrule.go
index e594f4b..e74dd4d 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -26,9 +26,6 @@
 type GenruleExtraProperties struct {
 	Vendor_available   *bool
 	Recovery_available *bool
-
-	// This genrule is for recovery variant
-	InRecovery bool `blueprint:"mutated"`
 }
 
 // cc_genrule is a genrule that can depend on other cc_* objects.
@@ -37,7 +34,9 @@
 func genRuleFactory() android.Module {
 	module := genrule.NewGenRule()
 
-	module.Extra = &GenruleExtraProperties{}
+	extra := &GenruleExtraProperties{}
+	module.Extra = extra
+	module.ImageInterface = extra
 	module.AddProperties(module.Extra)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibBoth)
@@ -46,3 +45,44 @@
 
 	return module
 }
+
+var _ android.ImageInterface = (*GenruleExtraProperties)(nil)
+
+func (g *GenruleExtraProperties) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	if ctx.DeviceConfig().VndkVersion() == "" {
+		return true
+	}
+
+	return Bool(g.Vendor_available) || !(ctx.SocSpecific() || ctx.DeviceSpecific())
+}
+
+func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+	if Bool(g.Recovery_available) {
+		primaryArch := ctx.Config().DevicePrimaryArchType()
+		moduleArch := ctx.Target().Arch.ArchType
+		return moduleArch == primaryArch
+	}
+	return false
+}
+
+func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+	if ctx.DeviceConfig().VndkVersion() == "" {
+		return nil
+	}
+
+	if Bool(g.Vendor_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
+		var variants []string
+		variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
+		if vndkVersion := ctx.DeviceConfig().VndkVersion(); vndkVersion != "current" {
+			variants = append(variants, VendorVariationPrefix+vndkVersion)
+		}
+		return variants
+	}
+
+	return nil
+}
+
+func (g *GenruleExtraProperties) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
diff --git a/cc/library.go b/cc/library.go
index b8c4b51..98cae3d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1359,9 +1359,11 @@
 		return
 	}
 	if genrule, ok := mctx.Module().(*genrule.Module); ok {
-		if props, ok := genrule.Extra.(*GenruleExtraProperties); ok && !props.InRecovery {
-			mctx.CreateVariations("")
-			return
+		if _, ok := genrule.Extra.(*GenruleExtraProperties); ok {
+			if !genrule.InRecovery() {
+				mctx.CreateVariations("")
+				return
+			}
 		}
 	}
 }
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 2bf051e..55bdd1c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -886,13 +886,13 @@
 				// static executable gets static runtime libs
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "static"},
-					{Mutator: "image", Variation: c.imageVariation()},
+					c.ImageVariation(),
 				}...), StaticDepTag, append([]string{runtimeLibrary}, extraStaticDeps...)...)
 			} else if !c.static() && !c.header() {
 				// dynamic executable and shared libs get shared runtime libs
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "shared"},
-					{Mutator: "image", Variation: c.imageVariation()},
+					c.ImageVariation(),
 				}...), earlySharedDepTag, runtimeLibrary)
 			}
 			// static lib does not have dependency to the runtime library. The
diff --git a/cc/testing.go b/cc/testing.go
index 3943e72..3b10f87 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -271,7 +271,7 @@
 	ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("image", ImageMutator).Parallel()
+		ctx.BottomUp("image", android.ImageMutator).Parallel()
 		ctx.BottomUp("link", LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", VndkMutator).Parallel()
 		ctx.BottomUp("version", VersionMutator).Parallel()
diff --git a/genrule/genrule.go b/genrule/genrule.go
index a7c5d65..57ca9bc 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -118,6 +118,7 @@
 	// For other packages to make their own genrules with extra
 	// properties
 	Extra interface{}
+	android.ImageInterface
 
 	properties generatorProperties
 
@@ -532,9 +533,20 @@
 	module.AddProperties(props...)
 	module.AddProperties(&module.properties)
 
+	module.ImageInterface = noopImageInterface{}
+
 	return module
 }
 
+type noopImageInterface struct{}
+
+func (x noopImageInterface) ImageMutatorBegin(android.BaseModuleContext)                 {}
+func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool            { return false }
+func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool        { return false }
+func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
+func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
+
 // replace "out" with "__SBOX_OUT_DIR__/<the value of ${out}>"
 func pathToSandboxOut(path android.Path, genDir android.Path) string {
 	relOut, err := filepath.Rel(genDir.String(), path.String())
diff --git a/rust/rust.go b/rust/rust.go
index 096f7b6..a3266f7 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -77,6 +77,25 @@
 	outputFile       android.OptionalPath
 }
 
+var _ android.ImageInterface = (*Module)(nil)
+
+func (mod *Module) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	return true
+}
+
+func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
+	return mod.InRecovery()
+}
+
+func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string {
+	return nil
+}
+
+func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
+}
+
 func (mod *Module) BuildStubs() bool {
 	return false
 }
@@ -687,7 +706,7 @@
 		blueprint.Variation{Mutator: "version", Variation: ""})
 	if !mod.Host() {
 		commonDepVariations = append(commonDepVariations,
-			blueprint.Variation{Mutator: "image", Variation: "core"})
+			blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
 	}
 
 	actx.AddVariationDependencies(
diff --git a/rust/testing.go b/rust/testing.go
index fbded73..45dbbbd 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -185,7 +185,7 @@
 	ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		// cc mutators
-		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("image", android.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
diff --git a/sdk/sdk.go b/sdk/sdk.go
index ed2f26c..ac6fce9 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -187,7 +187,7 @@
 					version = cc.LatestStubsVersionFor(mctx.Config(), name)
 				}
 				mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-					{Mutator: "image", Variation: "core"},
+					{Mutator: "image", Variation: android.CoreVariation},
 					{Mutator: "link", Variation: "shared"},
 					{Mutator: "version", Variation: version},
 				}...), sdkMemberDepTag, name)
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 8552825..b40ec13 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -57,7 +57,7 @@
 	ctx.RegisterModuleType("llndk_library", cc.LlndkLibraryFactory)
 	ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("image", android.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
 		ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 80dcb72..5e0eb35 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -73,7 +73,7 @@
 	ctx.RegisterModuleType("llndk_library", cc.LlndkLibraryFactory)
 	ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("image", android.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()