Soong: Add BUILD_MODULES build action in soong_ui.

There was one case that did not work:
  1) Create dir in root source tree
  2) Run "m libc"

The build would fail as it was using the mma logic. A separate
one named BUILD_MODULES was added to allow building specific
modules in any directories using the "m" command.

Bug: b/130049705
Test: unit test cases, ran "m libc" in a tmp directory inside
      of the source tree.

Change-Id: I8d23e685a673a311001ee8edd89bd73b662392dd
diff --git a/ui/build/config.go b/ui/build/config.go
index 6df9529..4a70f06 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -71,6 +71,9 @@
 	// Builds all of the modules and their dependencies of a list of specified directories. All specified
 	// directories are relative to the root directory of the source tree.
 	BUILD_MODULES_IN_DIRECTORIES
+
+	// Build a list of specified modules. If none was specified, simply build the whole source tree.
+	BUILD_MODULES
 )
 
 // checkTopDir validates that the current directory is at the root directory of the source tree.
@@ -290,6 +293,8 @@
 	var targets []string
 
 	switch action {
+	case BUILD_MODULES:
+		// No additional processing is required when building a list of specific modules or all modules.
 	case BUILD_MODULES_IN_A_DIRECTORY:
 		// If dir is the root source tree, all the modules are built of the source tree are built so
 		// no need to find the build file.
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 1ef5456..856af11 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -763,6 +763,51 @@
 	}
 }
 
+func TestGetConfigArgsBuildModules(t *testing.T) {
+	tests := []buildActionTestCase{{
+		description:     "normal execution from the root source tree directory",
+		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
+		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
+		args:            []string{"-j", "fake_module", "fake_module2"},
+		curDir:          ".",
+		tidyOnly:        "",
+		expectedArgs:    []string{"-j", "fake_module", "fake_module2"},
+		expectedEnvVars: []envVar{},
+	}, {
+		description:     "normal execution in deep directory",
+		dirsInTrees:     []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+		args:            []string{"-j", "fake_module", "fake_module2", "-k"},
+		curDir:          "1/2/3/4/5/6/7/8/9",
+		tidyOnly:        "",
+		expectedArgs:    []string{"-j", "fake_module", "fake_module2", "-k"},
+		expectedEnvVars: []envVar{},
+	}, {
+		description:     "normal execution in deep directory, no targets",
+		dirsInTrees:     []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+		args:            []string{"-j", "-k"},
+		curDir:          "1/2/3/4/5/6/7/8/9",
+		tidyOnly:        "",
+		expectedArgs:    []string{"-j", "-k"},
+		expectedEnvVars: []envVar{},
+	}, {
+		description:     "normal execution in root source tree, no args",
+		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
+		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp"},
+		args:            []string{},
+		curDir:          "1/2/3/4/5/6/7/8/9",
+		tidyOnly:        "",
+		expectedArgs:    []string{},
+		expectedEnvVars: []envVar{},
+	}}
+	for _, tt := range tests {
+		t.Run("build action BUILD_MODULES with dependencies, "+tt.description, func(t *testing.T) {
+			testGetConfigArgs(t, tt, BUILD_MODULES, true)
+		})
+	}
+}
+
 // TODO: Remove this test case once mm shell build command has been deprecated.
 func TestGetConfigArgsBuildModulesInDirecotoryNoDeps(t *testing.T) {
 	tests := []buildActionTestCase{{