Merge changes from topic "stub-impl-per-api-domain"

* changes:
  Special case platform variant of bootstrap libs
  Select stub/impl per apex variant
  For test apexes, base_apex_name is the api domain
  Broaden the granularity of config_setting from apex_name to api_domain
  Print default val if all vals in axis match default val
diff --git a/apex/apex.go b/apex/apex.go
index 6a64ad6..33ed111 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -3700,6 +3700,8 @@
 	commonAttrs := android.CommonAttributes{}
 	if a.testApex {
 		commonAttrs.Testonly = proptools.BoolPtr(true)
+		// Set the api_domain of the test apex
+		attrs.Base_apex_name = proptools.StringPtr(cc.GetApiDomain(a.Name()))
 	}
 
 	return attrs, props, commonAttrs
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 8f4f965..d042fe8 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -69,8 +69,8 @@
 
 	productVariableBazelPackage = "//build/bazel/product_variables"
 
-	AndroidAndInApex  = "android-in_apex"
-	AndroidAndNonApex = "android-non_apex"
+	AndroidAndInApex = "android-in_apex"
+	AndroidPlatform  = "system"
 
 	InApex  = "in_apex"
 	NonApex = "non_apex"
@@ -202,7 +202,7 @@
 
 	osAndInApexMap = map[string]string{
 		AndroidAndInApex:           "//build/bazel/rules/apex:android-in_apex",
-		AndroidAndNonApex:          "//build/bazel/rules/apex:android-non_apex",
+		AndroidPlatform:            "//build/bazel/rules/apex:system",
 		osDarwin:                   "//build/bazel/platforms/os:darwin",
 		osLinux:                    "//build/bazel/platforms/os:linux_glibc",
 		osLinuxMusl:                "//build/bazel/platforms/os:linux_musl",
diff --git a/bazel/properties.go b/bazel/properties.go
index 77db1c4..e22f4db 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -1434,4 +1434,6 @@
 type ConfigSettingAttributes struct {
 	// Each key in Flag_values is a label to a custom string_setting
 	Flag_values StringMapAttribute
+	// Each element in Constraint_values is a label to a constraint_value
+	Constraint_values LabelListAttribute
 }
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 1cc3f22..390cabe 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -1475,10 +1475,11 @@
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "test_com.android.apogee", AttrNameToString{
-				"file_contexts": `"file_contexts_file"`,
-				"manifest":      `"apex_manifest.json"`,
-				"testonly":      `True`,
-				"tests":         `[":cc_test_1"]`,
+				"file_contexts":  `"file_contexts_file"`,
+				"base_apex_name": `"com.android.apogee"`,
+				"manifest":       `"apex_manifest.json"`,
+				"testonly":       `True`,
+				"tests":          `[":cc_test_1"]`,
 			}),
 		}})
 }
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 1b64055..e127fd5 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -21,6 +21,7 @@
 
 	"android/soong/android"
 	"android/soong/android/allowlists"
+	"android/soong/bazel"
 	"android/soong/python"
 )
 
@@ -1931,3 +1932,17 @@
 		Description:          "Generating API contribution Bazel targets for custom module",
 	})
 }
+
+// If values of all keys in an axis are equal to //conditions:default, drop the axis and print the common value
+func TestPrettyPrintSelectMapEqualValues(t *testing.T) {
+	lla := bazel.LabelListAttribute{
+		Value: bazel.LabelList{},
+	}
+	libFooImplLabel := bazel.Label{
+		Label: ":libfoo.impl",
+	}
+	lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList([]bazel.Label{libFooImplLabel}))
+	lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{libFooImplLabel}))
+	actual, _ := prettyPrintAttribute(lla, 0)
+	android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual)
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 776129f..1b681ef 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -3042,7 +3042,8 @@
 }`,
 		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
 			"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
+        "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:barlib"],
+        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:barlib"],
         "//conditions:default": [":barlib"],
     })`,
 			"local_includes": `["."]`,
@@ -3096,7 +3097,11 @@
         "//build/bazel/platforms/os:linux_glibc": [":quxlib"],
         "//build/bazel/platforms/os:linux_musl": [":quxlib"],
         "//build/bazel/platforms/os:windows": [":quxlib"],
-        "//build/bazel/rules/apex:android-in_apex": [
+        "//build/bazel/rules/apex:foo": [
+            "@api_surfaces//module-libapi/current:barlib",
+            "@api_surfaces//module-libapi/current:quxlib",
+        ],
+        "//build/bazel/rules/apex:system": [
             "@api_surfaces//module-libapi/current:barlib",
             "@api_surfaces//module-libapi/current:quxlib",
         ],
@@ -4139,44 +4144,34 @@
 	name: "barlib",
 	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
 	bazel_module: { bp2build_available: false },
+	apex_available: ["//apex_available:platform",],
 }
 cc_library {
 	name: "bazlib",
 	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
 	bazel_module: { bp2build_available: false },
+	apex_available: ["//apex_available:platform",],
 }
 cc_library {
     name: "foo",
 	  shared_libs: ["barlib", "bazlib"],
     export_shared_lib_headers: ["bazlib"],
     apex_available: [
-        "apex_available:platform",
+        "//apex_available:platform",
     ],
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
-        "//conditions:default": [":barlib"],
-    })`,
-				"dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
-        "//conditions:default": [":bazlib"],
-    })`,
-				"local_includes": `["."]`,
-				"tags":           `["apex_available=apex_available:platform"]`,
+				"implementation_dynamic_deps": `[":barlib"]`,
+				"dynamic_deps":                `[":bazlib"]`,
+				"local_includes":              `["."]`,
+				"tags":                        `["apex_available=//apex_available:platform"]`,
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
-        "//conditions:default": [":barlib"],
-    })`,
-				"dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
-        "//conditions:default": [":bazlib"],
-    })`,
-				"local_includes": `["."]`,
-				"tags":           `["apex_available=apex_available:platform"]`,
+				"implementation_dynamic_deps": `[":barlib"]`,
+				"dynamic_deps":                `[":bazlib"]`,
+				"local_includes":              `["."]`,
+				"tags":                        `["apex_available=//apex_available:platform"]`,
 			}),
 		},
 	})
@@ -4473,11 +4468,12 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTargetNoRestrictions(
 				"config_setting",
-				"android-in_myapex",
+				"myapex",
 				AttrNameToString{
 					"flag_values": `{
-        "//build/bazel/rules/apex:apex_name": "myapex",
+        "//build/bazel/rules/apex:api_domain": "myapex",
     }`,
+					"constraint_values": `["//build/bazel/platforms/os:android"]`,
 				},
 			),
 		},
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 47dff8a..2ee9c99 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -609,7 +609,8 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
+        "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"],
+        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
         "//conditions:default": [":a"],
     })`,
 				"tags": `["apex_available=apex_b"]`,
@@ -618,6 +619,64 @@
 	})
 }
 
+// Tests that library in apexfoo links against stubs of platform_lib and otherapex_lib
+func TestCcLibrarySharedStubs_UseStubsFromMultipleApiDomains(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_shared stubs",
+		ModuleTypeUnderTest:        "cc_library_shared",
+		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+		Blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+	name: "libplatform_stable",
+	stubs: { symbol_file: "libplatform_stable.map.txt", versions: ["28", "29", "current"] },
+	apex_available: ["//apex_available:platform"],
+	bazel_module: { bp2build_available: false },
+	include_build_directory: false,
+}
+cc_library_shared {
+	name: "libapexfoo_stable",
+	stubs: { symbol_file: "libapexfoo_stable.map.txt", versions: ["28", "29", "current"] },
+	apex_available: ["apexfoo"],
+	bazel_module: { bp2build_available: false },
+	include_build_directory: false,
+}
+cc_library_shared {
+	name: "libutils",
+	shared_libs: ["libplatform_stable", "libapexfoo_stable",],
+	apex_available: ["//apex_available:platform", "apexfoo", "apexbar"],
+	include_build_directory: false,
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_shared", "libutils", AttrNameToString{
+				"implementation_dynamic_deps": `select({
+        "//build/bazel/rules/apex:apexbar": [
+            "@api_surfaces//module-libapi/current:libplatform_stable",
+            "@api_surfaces//module-libapi/current:libapexfoo_stable",
+        ],
+        "//build/bazel/rules/apex:apexfoo": [
+            "@api_surfaces//module-libapi/current:libplatform_stable",
+            ":libapexfoo_stable",
+        ],
+        "//build/bazel/rules/apex:system": [
+            "@api_surfaces//module-libapi/current:libplatform_stable",
+            "@api_surfaces//module-libapi/current:libapexfoo_stable",
+        ],
+        "//conditions:default": [
+            ":libplatform_stable",
+            ":libapexfoo_stable",
+        ],
+    })`,
+				"tags": `[
+        "apex_available=//apex_available:platform",
+        "apex_available=apexfoo",
+        "apex_available=apexbar",
+    ]`,
+			}),
+		},
+	})
+}
+
 func TestCcLibrarySharedStubs_IgnorePlatformAvailable(t *testing.T) {
 	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
 		Description:                "cc_library_shared stubs",
@@ -641,7 +700,8 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
+        "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"],
+        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
         "//conditions:default": [":a"],
     })`,
 				"tags": `[
@@ -653,6 +713,34 @@
 	})
 }
 
+func TestCcLibraryDoesNotDropStubDepIfNoVariationAcrossAxis(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library depeends on impl for all configurations",
+		ModuleTypeUnderTest:        "cc_library_shared",
+		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+		Blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+	name: "a",
+	stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
+	bazel_module: { bp2build_available: false },
+	apex_available: ["//apex_available:platform"],
+}
+cc_library_shared {
+	name: "b",
+	shared_libs: [":a"],
+	include_build_directory: false,
+	apex_available: ["//apex_available:platform"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
+				"implementation_dynamic_deps": `[":a"]`,
+				"tags":                        `["apex_available=//apex_available:platform"]`,
+			}),
+		},
+	})
+}
+
 func TestCcLibrarySharedStubs_MultipleApexAvailable(t *testing.T) {
 	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
 		ModuleTypeUnderTest:        "cc_library_shared",
@@ -682,7 +770,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
+        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
         "//conditions:default": [":a"],
     })`,
 				"tags": `[
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 9488014..2705aaf 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1504,6 +1504,7 @@
         versions: ["current"],
     },
     bazel_module: { bp2build_available: false },
+    apex_available: ["com.android.runtime"],
 }
 
 cc_library_static {
@@ -1561,7 +1562,8 @@
 			}),
 			MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:libm"],
+        "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:libm"],
+        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:libm"],
         "//conditions:default": [":libm"],
     })`,
 				"system_dynamic_deps": `[]`,
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 8e17103..3d9f0a2 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -279,6 +279,10 @@
 	}
 
 	if len(selects) == 0 {
+		// If there is a default value, and there are no selects for this axis, print that without any selects.
+		if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists {
+			return prettyPrint(val, indent, emitZeroValues)
+		}
 		// No conditions (or all values are empty lists), so no need for a map.
 		return "", nil
 	}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 3bb00ad..cf5f74d 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -1194,16 +1194,34 @@
 }
 
 var (
-	apexConfigSettingKey  = android.NewOnceKey("apexConfigSetting")
-	apexConfigSettingLock sync.Mutex
+	apiDomainConfigSettingKey  = android.NewOnceKey("apiDomainConfigSettingKey")
+	apiDomainConfigSettingLock sync.Mutex
 )
 
-func getApexConfigSettingMap(config android.Config) *map[string]bool {
-	return config.Once(apexConfigSettingKey, func() interface{} {
+func getApiDomainConfigSettingMap(config android.Config) *map[string]bool {
+	return config.Once(apiDomainConfigSettingKey, func() interface{} {
 		return &map[string]bool{}
 	}).(*map[string]bool)
 }
 
+var (
+	testApexNameToApiDomain = map[string]string{
+		"test_broken_com.android.art": "com.android.art",
+	}
+)
+
+// GetApiDomain returns the canonical name of the apex. This is synonymous to the apex_name definition.
+// https://cs.android.com/android/_/android/platform/build/soong/+/e3f0281b8897da1fe23b2f4f3a05f1dc87bcc902:apex/prebuilt.go;l=81-83;drc=2dc7244af985a6ad701b22f1271e606cabba527f;bpv=1;bpt=0
+// For test apexes, it uses a naming convention heuristic to determine the api domain.
+// TODO (b/281548611): Move this build/soong/android
+func GetApiDomain(apexName string) string {
+	if apiDomain, exists := testApexNameToApiDomain[apexName]; exists {
+		return apiDomain
+	}
+	// Remove `test_` prefix
+	return strings.TrimPrefix(apexName, "test_")
+}
+
 // Create a config setting for this apex in build/bazel/rules/apex
 // The use case for this is stub/impl selection in cc libraries
 // Long term, these config_setting(s) should be colocated with the respective apex definitions.
@@ -1215,23 +1233,32 @@
 		// These correspond to android-non_apex and android-in_apex
 		return
 	}
-	apexConfigSettingLock.Lock()
-	defer apexConfigSettingLock.Unlock()
+	apiDomainConfigSettingLock.Lock()
+	defer apiDomainConfigSettingLock.Unlock()
 
 	// Return if a config_setting has already been created
-	acsm := getApexConfigSettingMap(ctx.Config())
-	if _, exists := (*acsm)[apexName]; exists {
+	apiDomain := GetApiDomain(apexName)
+	acsm := getApiDomainConfigSettingMap(ctx.Config())
+	if _, exists := (*acsm)[apiDomain]; exists {
 		return
 	}
-	(*acsm)[apexName] = true
+	(*acsm)[apiDomain] = true
 
 	csa := bazel.ConfigSettingAttributes{
 		Flag_values: bazel.StringMapAttribute{
-			"//build/bazel/rules/apex:apex_name": apexName,
+			"//build/bazel/rules/apex:api_domain": apiDomain,
 		},
+		// Constraint this to android
+		Constraint_values: bazel.MakeLabelListAttribute(
+			bazel.MakeLabelList(
+				[]bazel.Label{
+					bazel.Label{Label: "//build/bazel/platforms/os:android"},
+				},
+			),
+		),
 	}
 	ca := android.CommonAttributes{
-		Name: "android-in_" + apexName,
+		Name: apiDomain,
 	}
 	ctx.CreateBazelConfigSetting(
 		csa,
@@ -1242,66 +1269,111 @@
 
 func inApexConfigSetting(apexAvailable string) string {
 	if apexAvailable == android.AvailableToPlatform {
-		return bazel.AndroidAndNonApex
+		return bazel.AndroidPlatform
 	}
 	if apexAvailable == android.AvailableToAnyApex {
 		return bazel.AndroidAndInApex
 	}
-	return "//build/bazel/rules/apex:android-in_" + apexAvailable
+	apiDomain := GetApiDomain(apexAvailable)
+	return "//build/bazel/rules/apex:" + apiDomain
+}
+
+// Inputs to stub vs impl selection.
+type stubSelectionInfo struct {
+	// Label of the implementation library (e.g. //bionic/libc:libc)
+	impl bazel.Label
+	// Axis containing the implementation library
+	axis bazel.ConfigurationAxis
+	// Axis key containing the implementation library
+	config string
+	// API domain of the apex
+	// For test apexes (test_com.android.foo), this will be the source apex (com.android.foo)
+	apiDomain string
+	// List of dep labels
+	dynamicDeps *bazel.LabelListAttribute
+	// Boolean value for determining if the dep is in the same api domain
+	// If false, the label will be rewritten to to the stub label
+	sameApiDomain bool
+}
+
+func useStubOrImplInApexWithName(ssi stubSelectionInfo) {
+	lib := ssi.impl
+	if !ssi.sameApiDomain {
+		lib = bazel.Label{
+			Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(lib.OriginalModuleName, ":"),
+		}
+	}
+	// Create a select statement specific to this apex
+	inApexSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain))
+	(&inApexSelectValue).Append(bazel.MakeLabelList([]bazel.Label{lib}))
+	ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain), bazel.FirstUniqueBazelLabelList(inApexSelectValue))
+	// Delete the library from the common config for this apex
+	implDynamicDeps := ssi.dynamicDeps.SelectValue(ssi.axis, ssi.config)
+	implDynamicDeps = bazel.SubtractBazelLabelList(implDynamicDeps, bazel.MakeLabelList([]bazel.Label{ssi.impl}))
+	ssi.dynamicDeps.SetSelectValue(ssi.axis, ssi.config, implDynamicDeps)
+	if ssi.axis == bazel.NoConfigAxis {
+		// Set defaults. Defaults (i.e. host) should use impl and not stubs.
+		defaultSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
+		(&defaultSelectValue).Append(bazel.MakeLabelList([]bazel.Label{ssi.impl}))
+		ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
+	}
 }
 
 func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
 	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
 
-	depsWithStubs := []bazel.Label{}
-	for _, l := range dynamicLibs.Includes {
-		dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
-		if d, ok := dep.(*Module); ok && d.HasStubsVariants() {
-			depApexAvailable := d.ApexAvailable()
-			if !availableToSameApexes(apexAvailable, depApexAvailable) {
-				depsWithStubs = append(depsWithStubs, l)
-			}
-		}
-	}
-	if len(depsWithStubs) > 0 {
-		implDynamicDeps := bazel.SubtractBazelLabelList(dynamicLibs, bazel.MakeLabelList(depsWithStubs))
-		dynamicDeps.SetSelectValue(axis, config, implDynamicDeps)
-
-		stubLibLabels := []bazel.Label{}
-		for _, l := range depsWithStubs {
-			stubLabelInApiSurfaces := bazel.Label{
-				Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(l.OriginalModuleName, ":"),
-			}
-			stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces)
-		}
-		inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
-		nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
-		defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
-		nonApexDeps := depsWithStubs
-		if buildNonApexWithStubs {
-			nonApexDeps = stubLibLabels
-		}
-		if axis == bazel.NoConfigAxis {
-			(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
-			(&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps))
-			(&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
-		} else if config == bazel.OsAndroid {
-			(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
-			(&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
-		}
-	}
-
 	// Create a config_setting for each apex_available.
 	// This will be used to select impl of a dep if dep is available to the same apex.
 	for _, aa := range apexAvailable {
 		createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
 	}
 
+	apiDomainForSelects := []string{}
+	for _, apex := range apexAvailable {
+		apiDomainForSelects = append(apiDomainForSelects, GetApiDomain(apex))
+	}
+	// Always emit a select statement for the platform variant.
+	// This ensures that b build //foo --config=android works
+	// Soong always creates a platform variant even when the library might not be available to platform.
+	if !android.InList(android.AvailableToPlatform, apiDomainForSelects) {
+		apiDomainForSelects = append(apiDomainForSelects, android.AvailableToPlatform)
+	}
+	apiDomainForSelects = android.SortedUniqueStrings(apiDomainForSelects)
+
+	// Create a select for each apex this library could be included in.
+	for _, l := range dynamicLibs.Includes {
+		dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
+		if c, ok := dep.(*Module); !ok || !c.HasStubsVariants() {
+			continue
+		}
+		// TODO (b/280339069): Decrease the verbosity of the generated BUILD files
+		for _, apiDomain := range apiDomainForSelects {
+			var sameApiDomain bool
+			if apiDomain == android.AvailableToPlatform {
+				// Platform variants in Soong use equality of apex_available for stub/impl selection.
+				// https://cs.android.com/android/_/android/platform/build/soong/+/316b0158fe57ee7764235923e7c6f3d530da39c6:cc/cc.go;l=3393-3404;drc=176271a426496fa2688efe2b40d5c74340c63375;bpv=1;bpt=0
+				// One of the factors behind this design choice is cc_test
+				// Tests only have a platform variant, and using equality of apex_available ensures
+				// that tests of an apex library gets its implementation and not stubs.
+				// TODO (b/280343104): Discuss if we can drop this special handling for platform variants.
+				sameApiDomain = availableToSameApexes(apexAvailable, dep.(*Module).ApexAvailable())
+				if linkable, ok := ctx.Module().(LinkableInterface); ok && linkable.Bootstrap() {
+					sameApiDomain = true
+				}
+			} else {
+				sameApiDomain = android.InList(apiDomain, dep.(*Module).ApexAvailable())
+			}
+			ssi := stubSelectionInfo{
+				impl:          l,
+				axis:          axis,
+				config:        config,
+				apiDomain:     apiDomain,
+				dynamicDeps:   dynamicDeps,
+				sameApiDomain: sameApiDomain,
+			}
+			useStubOrImplInApexWithName(ssi)
+		}
+	}
 }
 
 func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
@@ -1396,7 +1468,6 @@
 		la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
 
 		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, toRemove)
-		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, toRemove)
 		stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep))
 		for _, lib := range toRemove.Includes {
 			stubLabelInApiSurfaces := bazel.Label{
@@ -1404,7 +1475,12 @@
 			}
 			stubsToRemove = append(stubsToRemove, stubLabelInApiSurfaces)
 		}
-		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove))
+		// system libraries (e.g. libc, libm, libdl) belong the com.android.runtime api domain
+		// dedupe the stubs of these libraries from the other api domains (platform, other_apexes...)
+		for _, aa := range ctx.Module().(*Module).ApexAvailable() {
+			la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, inApexConfigSetting(aa), bazel.MakeLabelList(stubsToRemove))
+		}
+		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList(stubsToRemove))
 	}
 
 	la.deps.ResolveExcludes()