Use one mutator for all bp2build conversion.

Each conversion required defining a separate mutator, which will each
operate on _all_ modules and requires each to repeat checks whether the
mutator should operator. Instead, we introduce a single mutator and
modules can define a ConvertWithBp2build to implement bp2build
conversion for that module.

Test: bp2build.sh
Bug: 183079158
Change-Id: I99d4b51f441c2903879092c5b56313d606d4338d
diff --git a/android/bazel.go b/android/bazel.go
index 0ee65ef..fd3f23e 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -39,6 +39,10 @@
 	// To opt-out a module, set bazel_module: { bp2build_available: false }
 	// To defer the default setting for the directory, do not set the value.
 	Bp2build_available *bool
+
+	// CanConvertToBazel is set via InitBazelModule to indicate that a module type can be converted to
+	// Bazel with Bp2build.
+	CanConvertToBazel bool `blueprint:"mutated"`
 }
 
 // Properties contains common module properties for Bazel migration purposes.
@@ -80,9 +84,10 @@
 	HasHandcraftedLabel() bool
 	HandcraftedLabel() string
 	GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
-	ConvertWithBp2build(ctx BazelConversionContext) bool
-	convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool
+	ShouldConvertWithBp2build(ctx BazelConversionContext) bool
+	shouldConvertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool
 	GetBazelBuildFileContents(c Config, path, name string) (string, error)
+	ConvertWithBp2build(ctx TopDownMutatorContext)
 
 	// namespacedVariableProps is a map from a soong config variable namespace
 	// (e.g. acme, android) to a map of interfaces{}, which are really
@@ -109,6 +114,7 @@
 // properties.
 func InitBazelModule(module BazelModule) {
 	module.AddProperties(module.bazelProps())
+	module.bazelProps().Bazel_module.CanConvertToBazel = true
 }
 
 // bazelProps returns the Bazel properties for the given BazelModuleBase.
@@ -147,7 +153,7 @@
 	if b.HasHandcraftedLabel() {
 		return b.HandcraftedLabel()
 	}
-	if b.ConvertWithBp2build(ctx) {
+	if b.ShouldConvertWithBp2build(ctx) {
 		return bp2buildModuleLabel(ctx, module)
 	}
 	return "" // no label for unconverted module
@@ -436,6 +442,9 @@
 
 		"acvp_modulewrapper", // disabled for android x86/x86_64
 		"CarHTMLViewer",      // depends on unconverted modules android.car-stubs, car-ui-lib
+
+		"libdexfile",  // depends on unconverted modules: dexfile_operator_srcs, libartbase, libartpalette,
+		"libdexfiled", // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette
 	}
 
 	// Per-module denylist of cc_library modules to only generate the static
@@ -530,32 +539,21 @@
 	if !ok {
 		return false
 	}
-	return b.convertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
+	return b.shouldConvertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
 }
 
-// ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build.
-func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionContext) bool {
-	return b.convertWithBp2build(ctx, ctx.Module())
+// ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build.
+func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx BazelConversionContext) bool {
+	return b.shouldConvertWithBp2build(ctx, ctx.Module())
 }
 
-func (b *BazelModuleBase) convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool {
+func (b *BazelModuleBase) shouldConvertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool {
 	if bp2buildModuleDoNotConvert[module.Name()] {
 		return false
 	}
 
-	// Ensure that the module type of this module has a bp2build converter. This
-	// prevents mixed builds from using auto-converted modules just by matching
-	// the package dir; it also has to have a bp2build mutator as well.
-	if ctx.Config().bp2buildModuleTypeConfig[ctx.OtherModuleType(module)] == false {
-		if b, ok := module.(Bazelable); ok && b.BaseModuleType() != "" {
-			// For modules with custom types from soong_config_module_types,
-			// check that their _base module type_ has a bp2build mutator.
-			if ctx.Config().bp2buildModuleTypeConfig[b.BaseModuleType()] == false {
-				return false
-			}
-		} else {
-			return false
-		}
+	if !b.bazelProps().Bazel_module.CanConvertToBazel {
+		return false
 	}
 
 	packagePath := ctx.OtherModuleDir(module)
@@ -629,3 +627,16 @@
 	}
 	return string(data[:]), nil
 }
+
+func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
+	ctx.TopDown("bp2build_conversion", convertWithBp2build).Parallel()
+}
+
+func convertWithBp2build(ctx TopDownMutatorContext) {
+	bModule, ok := ctx.Module().(Bazelable)
+	if !ok || !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
+		return
+	}
+
+	bModule.ConvertWithBp2build(ctx)
+}
diff --git a/android/config.go b/android/config.go
index 3ce59b2..5d90fd2 100644
--- a/android/config.go
+++ b/android/config.go
@@ -157,7 +157,6 @@
 
 	runningAsBp2Build              bool
 	bp2buildPackageConfig          Bp2BuildConfig
-	bp2buildModuleTypeConfig       map[string]bool
 	Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
 
 	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
@@ -353,8 +352,6 @@
 
 	config.mockFileSystem(bp, fs)
 
-	config.bp2buildModuleTypeConfig = map[string]bool{}
-
 	determineBuildOS(config)
 
 	return Config{config}
@@ -522,7 +519,6 @@
 
 	config.BazelContext, err = NewBazelContext(config)
 	config.bp2buildPackageConfig = bp2buildDefaultConfig
-	config.bp2buildModuleTypeConfig = make(map[string]bool)
 
 	return Config{config}, err
 }
diff --git a/android/defaults.go b/android/defaults.go
index d2b351d..7b3d38c 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -173,6 +173,10 @@
 func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
 }
 
+// ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are
+// *NOT* converted with bp2build
+func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {}
+
 func InitDefaultsModule(module DefaultsModule) {
 	commonProperties := &commonProperties{}
 
diff --git a/android/filegroup.go b/android/filegroup.go
index a79374d..c932ffa 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -22,7 +22,6 @@
 
 func init() {
 	RegisterModuleType("filegroup", FileGroupFactory)
-	RegisterBp2BuildMutator("filegroup", FilegroupBp2Build)
 }
 
 var PrepareForTestWithFilegroup = FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -34,12 +33,8 @@
 	Srcs bazel.LabelListAttribute
 }
 
-func FilegroupBp2Build(ctx TopDownMutatorContext) {
-	fg, ok := ctx.Module().(*fileGroup)
-	if !ok || !fg.ConvertWithBp2build(ctx) {
-		return
-	}
-
+// ConvertWithBp2build performs bp2build conversion of filegroup
+func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
 	srcs := bazel.MakeLabelListAttribute(
 		BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs))
 
diff --git a/android/mutator.go b/android/mutator.go
index bf1cf80..dbd8c04 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -16,7 +16,6 @@
 
 import (
 	"reflect"
-	"sync"
 
 	"android/soong/bazel"
 
@@ -34,12 +33,12 @@
 //   continue on to GenerateAndroidBuildActions
 
 // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
-func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators, bp2buildMutators []RegisterMutatorFunc) {
+func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
 	mctx := &registerMutatorsContext{
 		bazelConversionMode: true,
 	}
 
-	bp2buildPreArchMutators = append([]RegisterMutatorFunc{
+	bp2buildMutators := append([]RegisterMutatorFunc{
 		RegisterNamespaceMutator,
 		RegisterDefaultsPreArchMutators,
 		// TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should
@@ -47,10 +46,7 @@
 		RegisterPrebuiltsPreArchMutators,
 	},
 		preArchMutators...)
-
-	for _, f := range bp2buildPreArchMutators {
-		f(mctx)
-	}
+	bp2buildMutators = append(bp2buildMutators, registerBp2buildConversionMutator)
 
 	// Register bp2build mutators
 	for _, f := range bp2buildMutators {
@@ -216,10 +212,6 @@
 }
 
 var bp2buildPreArchMutators = []RegisterMutatorFunc{}
-var bp2buildMutators = map[string]RegisterMutatorFunc{}
-
-// See http://b/192523357
-var bp2buildLock sync.Mutex
 
 // A minimal context for Bp2build conversion
 type Bp2buildMutatorContext interface {
@@ -228,21 +220,6 @@
 	CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
 }
 
-// RegisterBp2BuildMutator registers specially crafted mutators for
-// converting Blueprint/Android modules into special modules that can
-// be code-generated into Bazel BUILD targets.
-//
-// TODO(b/178068862): bring this into TestContext.
-func RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
-	f := func(ctx RegisterMutatorsContext) {
-		ctx.TopDown(moduleType, m)
-	}
-	// Use a lock to avoid a concurrent map write if RegisterBp2BuildMutator is called in parallel
-	bp2buildLock.Lock()
-	defer bp2buildLock.Unlock()
-	bp2buildMutators[moduleType] = f
-}
-
 // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
 // into Bazel BUILD targets that should run prior to deps and conversion.
 func PreArchBp2BuildMutators(f RegisterMutatorFunc) {
diff --git a/android/register.go b/android/register.go
index 4244398..1ac4440 100644
--- a/android/register.go
+++ b/android/register.go
@@ -178,13 +178,7 @@
 		t.register(ctx)
 	}
 
-	bp2buildMutatorList := []RegisterMutatorFunc{}
-	for t, f := range bp2buildMutators {
-		ctx.config.bp2buildModuleTypeConfig[t] = true
-		bp2buildMutatorList = append(bp2buildMutatorList, f)
-	}
-
-	RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildMutatorList)
+	RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
 }
 
 // Register the pipeline of singletons, module types, and mutators for
@@ -196,15 +190,6 @@
 		t.register(ctx)
 	}
 
-	if ctx.config.BazelContext.BazelEnabled() {
-		// Hydrate the configuration of bp2build-enabled module types. This is
-		// required as a signal to identify which modules should be deferred to
-		// Bazel in mixed builds, if it is enabled.
-		for t, _ := range bp2buildMutators {
-			ctx.config.bp2buildModuleTypeConfig[t] = true
-		}
-	}
-
 	mutators := collateGloballyRegisteredMutators()
 	mutators.registerAll(ctx)
 
diff --git a/android/testing.go b/android/testing.go
index 6290d43..8daf6b7 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -208,16 +208,6 @@
 	ctx.config.bp2buildPackageConfig = config
 }
 
-// RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module
-// type to the equivalent Bazel target.
-func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
-	f := func(ctx RegisterMutatorsContext) {
-		ctx.TopDown(moduleType, m)
-	}
-	ctx.config.bp2buildModuleTypeConfig[moduleType] = true
-	ctx.bp2buildMutators = append(ctx.bp2buildMutators, f)
-}
-
 // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
 // into Bazel BUILD targets that should run prior to deps and conversion.
 func (ctx *TestContext) PreArchBp2BuildMutators(f RegisterMutatorFunc) {
@@ -459,7 +449,7 @@
 // RegisterForBazelConversion prepares a test context for bp2build conversion.
 func (ctx *TestContext) RegisterForBazelConversion() {
 	ctx.SetRunningAsBp2build()
-	RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch, ctx.bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch)
 }
 
 func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {