Add the ability to select on arch

Bug: 323382414
Test: go test
Change-Id: I0d4cf391a1a625c5160456db1f4f7fa424c2141e
diff --git a/android/arch.go b/android/arch.go
index 4fe4345..9e79e31 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -693,6 +693,7 @@
 	m.base().commonProperties.CompileTarget = target
 	m.base().commonProperties.CompileMultiTargets = multiTargets
 	m.base().commonProperties.CompilePrimary = primaryTarget
+	m.base().commonProperties.ArchReady = true
 }
 
 // decodeMultilib returns the appropriate compile_multilib property for the module, or the default
diff --git a/android/arch_module_context.go b/android/arch_module_context.go
index 3cf4b41..a3a03af 100644
--- a/android/arch_module_context.go
+++ b/android/arch_module_context.go
@@ -35,6 +35,7 @@
 type archModuleContext struct {
 	// TODO: these should eventually go through a (possibly cached) provider like any other configuration instead
 	//  of being special cased.
+	ready         bool
 	os            OsType
 	target        Target
 	targetPrimary bool
@@ -42,6 +43,13 @@
 	primaryArch   bool
 }
 
+// ArchReady returns true if the arch mutator has run on the module. Before this returns
+// true, the module essentially doesn't have an arch and cannot make decisions based on
+// architecture.
+func (a *archModuleContext) ArchReady() bool {
+	return a.ready
+}
+
 func (a *archModuleContext) Target() Target {
 	return a.target
 }
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 9be3fad..3367b06 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -599,7 +599,14 @@
 		}
 		return "", false
 	case parser.SelectTypeVariant:
-		m.ModuleErrorf("TODO(b/323382414): Variants are not yet supported in selects")
+		if condition == "arch" {
+			if !m.ArchReady() {
+				m.ModuleErrorf("A select on arch was attempted before the arch mutator ran")
+				return "", false
+			}
+			return m.Arch().ArchType.Name, true
+		}
+		m.ModuleErrorf("Unknown variant " + condition)
 		return "", false
 	default:
 		panic("Should be unreachable")
diff --git a/android/module.go b/android/module.go
index cce4fa6..c0597fa 100644
--- a/android/module.go
+++ b/android/module.go
@@ -433,6 +433,10 @@
 	// Set by osMutator
 	CompileOS OsType `blueprint:"mutated"`
 
+	// Set to true after the arch mutator has run on this module and set CompileTarget,
+	// CompileMultiTargets, and CompilePrimary
+	ArchReady bool `blueprint:"mutated"`
+
 	// The Target of artifacts that this module variant is responsible for creating.
 	//
 	// Set by archMutator
@@ -1749,6 +1753,7 @@
 	}
 
 	return archModuleContext{
+		ready:         m.commonProperties.ArchReady,
 		os:            m.commonProperties.CompileOS,
 		target:        m.commonProperties.CompileTarget,
 		targetPrimary: m.commonProperties.CompilePrimary,
diff --git a/android/selects_test.go b/android/selects_test.go
index aa9c521..b4e226f 100644
--- a/android/selects_test.go
+++ b/android/selects_test.go
@@ -231,11 +231,30 @@
 				my_string: proptools.StringPtr("c.cpp"),
 			},
 		},
+		{
+			name: "Select on variant",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(variant("arch"), {
+					"x86": "my_x86",
+					"x86_64": "my_x86_64",
+					"arm": "my_arm",
+					"arm64": "my_arm64",
+					_: "my_default",
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("my_arm64"),
+			},
+		},
 	}
 
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			fixtures := GroupFixturePreparers(
+				PrepareForTestWithArchMutator,
 				FixtureRegisterWithContext(func(ctx RegistrationContext) {
 					ctx.RegisterModuleType("my_module_type", newSelectsMockModule)
 				}),
@@ -249,8 +268,8 @@
 			result := fixtures.RunTestWithBp(t, tc.bp)
 
 			if tc.expectedError == "" {
-				m := result.ModuleForTests("foo", "")
-				p, _ := OtherModuleProvider[selectsTestProvider](result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
+				m := result.ModuleForTests("foo", "android_arm64_armv8-a")
+				p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
 				if !reflect.DeepEqual(p, tc.provider) {
 					t.Errorf("Expected:\n  %q\ngot:\n  %q", tc.provider.String(), p.String())
 				}
@@ -310,7 +329,7 @@
 func newSelectsMockModule() Module {
 	m := &selectsMockModule{}
 	m.AddProperties(&m.properties)
-	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibFirst)
 	InitDefaultableModule(m)
 	return m
 }