Add command line flag for extra bazel-built modules

Test: m libcore --bazel-mode-staging --bazel-force-enabled-modules=libcore and find out/bazel/ -name libcore*

Change-Id: I065696d06ce07e05300a41e133867a6e7a891b5e
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index cf74b9c..122495f 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -387,6 +387,10 @@
 		for _, enabledProdModule := range allowlists.ProdMixedBuildsEnabledList {
 			enabledModules[enabledProdModule] = true
 		}
+
+		for enabledAdHocModule := range c.BazelModulesForceEnabledByFlag() {
+			enabledModules[enabledAdHocModule] = true
+		}
 	case BazelStagingMode:
 		modulesDefaultToBazel = false
 		// Staging mode includes all prod modules plus all staging modules.
@@ -396,6 +400,10 @@
 		for _, enabledStagingMode := range allowlists.StagingMixedBuildsEnabledList {
 			enabledModules[enabledStagingMode] = true
 		}
+
+		for enabledAdHocModule := range c.BazelModulesForceEnabledByFlag() {
+			enabledModules[enabledAdHocModule] = true
+		}
 	case BazelDevMode:
 		modulesDefaultToBazel = true
 
diff --git a/android/config.go b/android/config.go
index f430b72..4a64b5b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -227,6 +227,11 @@
 	mixedBuildsLock           sync.Mutex
 	mixedBuildEnabledModules  map[string]struct{}
 	mixedBuildDisabledModules map[string]struct{}
+
+	// These are modules to be built with Bazel beyond the allowlisted/build-mode
+	// specified modules. They are passed via the command-line flag
+	// "--bazel-force-enabled-modules"
+	bazelForceEnabledModules map[string]struct{}
 }
 
 type deviceConfig struct {
@@ -399,7 +404,8 @@
 
 // NewConfig creates a new Config object. The srcDir argument specifies the path
 // to the root source directory. It also loads the config file, if found.
-func NewConfig(moduleListFile string, buildMode SoongBuildMode, runGoTests bool, outDir, soongOutDir string, availableEnv map[string]string) (Config, error) {
+func NewConfig(moduleListFile string, buildMode SoongBuildMode, runGoTests bool, outDir, soongOutDir string, availableEnv map[string]string,
+	bazelForceEnabledModules []string) (Config, error) {
 	// Make a config with default options.
 	config := &config{
 		ProductVariablesFileName: filepath.Join(soongOutDir, productVariablesFileName),
@@ -415,6 +421,7 @@
 		fs:                        pathtools.NewOsFs(absSrcDir),
 		mixedBuildDisabledModules: make(map[string]struct{}),
 		mixedBuildEnabledModules:  make(map[string]struct{}),
+		bazelForceEnabledModules:  make(map[string]struct{}),
 	}
 
 	config.deviceConfig = &deviceConfig{
@@ -500,6 +507,10 @@
 	config.BazelContext, err = NewBazelContext(config)
 	config.Bp2buildPackageConfig = GetBp2BuildAllowList()
 
+	for _, module := range bazelForceEnabledModules {
+		config.bazelForceEnabledModules[module] = struct{}{}
+	}
+
 	return Config{config}, err
 }
 
@@ -1158,6 +1169,10 @@
 	return String(c.productVariables.PrebuiltHiddenApiDir)
 }
 
+func (c *config) BazelModulesForceEnabledByFlag() map[string]struct{} {
+	return c.bazelForceEnabledModules
+}
+
 func (c *deviceConfig) Arches() []Arch {
 	var arches []Arch
 	for _, target := range c.config.Targets[Android] {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 029bbb4..e7323dd 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -89,6 +89,7 @@
 	flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
 	flag.StringVar(&symlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
 	flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
+	flag.StringVar(&cmdlineArgs.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
 	flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
 	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
 	flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
@@ -118,6 +119,10 @@
 
 func newConfig(availableEnv map[string]string) android.Config {
 	var buildMode android.SoongBuildMode
+	var bazelForceEnabledModules []string
+	if len(cmdlineArgs.BazelForceEnabledModules) > 0 {
+		bazelForceEnabledModules = strings.Split(cmdlineArgs.BazelForceEnabledModules, ",")
+	}
 
 	if symlinkForestMarker != "" {
 		buildMode = android.SymlinkForest
@@ -141,7 +146,7 @@
 		buildMode = android.AnalysisNoBazel
 	}
 
-	configuration, err := android.NewConfig(cmdlineArgs.ModuleListFile, buildMode, runGoTests, outDir, soongOutDir, availableEnv)
+	configuration, err := android.NewConfig(cmdlineArgs.ModuleListFile, buildMode, runGoTests, outDir, soongOutDir, availableEnv, bazelForceEnabledModules)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
 		os.Exit(1)
diff --git a/ui/build/config.go b/ui/build/config.go
index b3c4405..7651a0f 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -109,6 +109,8 @@
 	emptyNinjaFile bool
 
 	metricsUploader string
+
+	bazelForceEnabledModules string
 }
 
 const srcDirFileCheck = "build/soong/root.bp"
@@ -238,7 +240,7 @@
 }
 
 func defaultBazelProdMode(cfg *configImpl) bool {
-	// Envirnoment flag to disable Bazel for users which experience
+	// Environment flag to disable Bazel for users which experience
 	// broken bazel-handled builds, or significant performance regressions.
 	if cfg.IsBazelMixedBuildForceDisabled() {
 		return false
@@ -747,6 +749,8 @@
 			buildCmd = strings.TrimPrefix(buildCmd, "\"")
 			buildCmd = strings.TrimSuffix(buildCmd, "\"")
 			ctx.Metrics.SetBuildCommand([]string{buildCmd})
+		} else if strings.HasPrefix(arg, "--bazel-force-enabled-modules=") {
+			c.bazelForceEnabledModules = strings.TrimPrefix(arg, "--bazel-force-enabled-modules=")
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -1494,6 +1498,10 @@
 	return c.Environment().IsEnvTrue("BUILD_BROKEN_DISABLE_BAZEL")
 }
 
+func (c *configImpl) BazelModulesForceEnabledByFlag() string {
+	return c.bazelForceEnabledModules
+}
+
 func GetMetricsUploader(topDir string, env *Environment) string {
 	if p, ok := env.Get("METRICS_UPLOADER"); ok {
 		metricsUploader := filepath.Join(topDir, p)
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 837f0a4..de3179a 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -273,6 +273,10 @@
 	if config.bazelStagingMode {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-staging")
 	}
+	if len(config.bazelForceEnabledModules) > 0 {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-force-enabled-modules="+config.bazelForceEnabledModules)
+	}
+
 	queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
 	// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
 	// The final workspace will be generated in out/soong/api_bp2build