Merge "spelling/grammar fix"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 7ce0d9b..8cd52cb 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -1427,4 +1427,20 @@
 	// It is implicit that all modules in ProdMixedBuildsEnabledList will
 	// also be built - do not add them to this list.
 	StagingMixedBuildsEnabledList = []string{}
+
+	// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
+	ProdDclaMixedBuildsEnabledList = []string{}
+
+	// These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
+	StagingDclaMixedBuildsEnabledList = []string{
+		"libbase",
+		"libc++",
+		"libcrypto",
+		"libcutils",
+	}
+
+	// TODO(b/269342245): Enable the rest of the DCLA libs
+	// "libssl",
+	// "libstagefright_flacdec",
+	// "libutils",
 )
diff --git a/android/bazel.go b/android/bazel.go
index 52f50c5..b600758 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -352,11 +352,13 @@
 // metrics reporting.
 func MixedBuildsEnabled(ctx BaseModuleContext) bool {
 	module := ctx.Module()
+	apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
+	withinApex := !apexInfo.IsForPlatform()
 	mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
 		ctx.Os() != Windows && // Windows toolchains are not currently supported.
 		module.Enabled() &&
 		convertedToBazel(ctx, module) &&
-		ctx.Config().BazelContext.IsModuleNameAllowed(module.Name())
+		ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
 	ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
 	return mixedBuildEnabled
 }
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 0880ad5..3a459f1 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -109,12 +109,29 @@
 
 // Portion of cquery map key to describe target configuration.
 type configKey struct {
-	arch   string
-	osType OsType
+	arch    string
+	osType  OsType
+	apexKey ApexConfigKey
+}
+
+type ApexConfigKey struct {
+	WithinApex     bool
+	ApexSdkVersion string
+}
+
+func (c ApexConfigKey) String() string {
+	return fmt.Sprintf("%s_%s", withinApexToString(c.WithinApex), c.ApexSdkVersion)
+}
+
+func withinApexToString(withinApex bool) string {
+	if withinApex {
+		return "within_apex"
+	}
+	return ""
 }
 
 func (c configKey) String() string {
-	return fmt.Sprintf("%s::%s", c.arch, c.osType)
+	return fmt.Sprintf("%s::%s::%s", c.arch, c.osType, c.apexKey)
 }
 
 // Map key to describe bazel cquery requests.
@@ -182,7 +199,7 @@
 	// Note that this only implies "bazel mixed build" allowlisting. The caller
 	// should independently verify the module is eligible for Bazel handling
 	// (for example, that it is MixedBuildBuildable).
-	IsModuleNameAllowed(moduleName string) bool
+	IsModuleNameAllowed(moduleName string, withinApex bool) bool
 
 	// Returns the bazel output base (the root directory for all bazel intermediate outputs).
 	OutputBase() string
@@ -235,6 +252,8 @@
 	bazelDisabledModules map[string]bool
 	// Per-module allowlist to opt modules in to bazel handling.
 	bazelEnabledModules map[string]bool
+	// DCLA modules are enabled when used in apex.
+	bazelDclaEnabledModules map[string]bool
 	// If true, modules are bazel-enabled by default, unless present in bazelDisabledModules.
 	modulesDefaultToBazel bool
 
@@ -258,10 +277,16 @@
 	LabelToPythonBinary map[string]string
 	LabelToApexInfo     map[string]cquery.ApexInfo
 	LabelToCcBinary     map[string]cquery.CcUnstrippedInfo
+
+	BazelRequests map[string]bool
 }
 
-func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
-	panic("unimplemented")
+func (m MockBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
+	key := BuildMockBazelContextRequestKey(label, requestType, cfgKey.arch, cfgKey.osType, cfgKey.apexKey)
+	if m.BazelRequests == nil {
+		m.BazelRequests = make(map[string]bool)
+	}
+	m.BazelRequests[key] = true
 }
 
 func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
@@ -272,10 +297,14 @@
 	return result, nil
 }
 
-func (m MockBazelContext) GetCcInfo(label string, _ configKey) (cquery.CcInfo, error) {
+func (m MockBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
 	result, ok := m.LabelToCcInfo[label]
 	if !ok {
-		return cquery.CcInfo{}, fmt.Errorf("no target with label %q in LabelToCcInfo", label)
+		key := BuildMockBazelContextResultKey(label, cfgKey.arch, cfgKey.osType, cfgKey.apexKey)
+		result, ok = m.LabelToCcInfo[key]
+		if !ok {
+			return cquery.CcInfo{}, fmt.Errorf("no target with label %q in LabelToCcInfo", label)
+		}
 	}
 	return result, nil
 }
@@ -308,7 +337,7 @@
 	panic("unimplemented")
 }
 
-func (m MockBazelContext) IsModuleNameAllowed(_ string) bool {
+func (m MockBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
 	return true
 }
 
@@ -324,6 +353,26 @@
 
 var _ BazelContext = MockBazelContext{}
 
+func BuildMockBazelContextRequestKey(label string, request cqueryRequest, arch string, osType OsType, apexKey ApexConfigKey) string {
+	cfgKey := configKey{
+		arch:    arch,
+		osType:  osType,
+		apexKey: apexKey,
+	}
+
+	return strings.Join([]string{label, request.Name(), cfgKey.String()}, "_")
+}
+
+func BuildMockBazelContextResultKey(label string, arch string, osType OsType, apexKey ApexConfigKey) string {
+	cfgKey := configKey{
+		arch:    arch,
+		osType:  osType,
+		apexKey: apexKey,
+	}
+
+	return strings.Join([]string{label, cfgKey.String()}, "_")
+}
+
 func (bazelCtx *mixedBuildBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
 	key := makeCqueryKey(label, requestType, cfgKey)
 	bazelCtx.requestMutex.Lock()
@@ -430,7 +479,7 @@
 	return ""
 }
 
-func (n noopBazelContext) IsModuleNameAllowed(_ string) bool {
+func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
 	return false
 }
 
@@ -442,14 +491,15 @@
 	return []bazel.AqueryDepset{}
 }
 
+func addToStringSet(set map[string]bool, items []string) {
+	for _, item := range items {
+		set[item] = true
+	}
+}
+
 func GetBazelEnabledAndDisabledModules(buildMode SoongBuildMode, forceEnabled map[string]struct{}) (map[string]bool, map[string]bool) {
 	disabledModules := map[string]bool{}
 	enabledModules := map[string]bool{}
-	addToStringSet := func(set map[string]bool, items []string) {
-		for _, item := range items {
-			set[item] = true
-		}
-	}
 
 	switch buildMode {
 	case BazelProdMode:
@@ -537,15 +587,24 @@
 	if c.HasDeviceProduct() {
 		targetProduct = c.DeviceProduct()
 	}
-
+	dclaMixedBuildsEnabledList := []string{}
+	if c.BuildMode == BazelProdMode {
+		dclaMixedBuildsEnabledList = allowlists.ProdDclaMixedBuildsEnabledList
+	} else if c.BuildMode == BazelStagingMode {
+		dclaMixedBuildsEnabledList = append(allowlists.ProdDclaMixedBuildsEnabledList,
+			allowlists.StagingDclaMixedBuildsEnabledList...)
+	}
+	dclaEnabledModules := map[string]bool{}
+	addToStringSet(dclaEnabledModules, dclaMixedBuildsEnabledList)
 	return &mixedBuildBazelContext{
-		bazelRunner:           &builtinBazelRunner{},
-		paths:                 &paths,
-		modulesDefaultToBazel: c.BuildMode == BazelDevMode,
-		bazelEnabledModules:   enabledModules,
-		bazelDisabledModules:  disabledModules,
-		targetProduct:         targetProduct,
-		targetBuildVariant:    targetBuildVariant,
+		bazelRunner:             &builtinBazelRunner{},
+		paths:                   &paths,
+		modulesDefaultToBazel:   c.BuildMode == BazelDevMode,
+		bazelEnabledModules:     enabledModules,
+		bazelDisabledModules:    disabledModules,
+		bazelDclaEnabledModules: dclaEnabledModules,
+		targetProduct:           targetProduct,
+		targetBuildVariant:      targetBuildVariant,
 	}, nil
 }
 
@@ -553,13 +612,17 @@
 	return p.metricsDir
 }
 
-func (context *mixedBuildBazelContext) IsModuleNameAllowed(moduleName string) bool {
+func (context *mixedBuildBazelContext) IsModuleNameAllowed(moduleName string, withinApex bool) bool {
 	if context.bazelDisabledModules[moduleName] {
 		return false
 	}
 	if context.bazelEnabledModules[moduleName] {
 		return true
 	}
+	if withinApex && context.bazelDclaEnabledModules[moduleName] {
+		return true
+	}
+
 	return context.modulesDefaultToBazel
 }
 
@@ -696,21 +759,37 @@
 #####################################################
 # This file is generated by soong_build. Do not edit.
 #####################################################
-
 def _config_node_transition_impl(settings, attr):
     if attr.os == "android" and attr.arch == "target":
         target = "{PRODUCT}-{VARIANT}"
     else:
         target = "{PRODUCT}-{VARIANT}_%s_%s" % (attr.os, attr.arch)
-    return {
+    apex_name = ""
+    if attr.within_apex:
+        # //build/bazel/rules/apex:apex_name has to be set to a non_empty value,
+        # otherwise //build/bazel/rules/apex:non_apex will be true and the
+        # "-D__ANDROID_APEX__" compiler flag will be missing. Apex_name is used
+        # in some validation on bazel side which don't really apply in mixed
+        # build because soong will do the work, so we just set it to a fixed
+        # value here.
+        apex_name = "dcla_apex"
+    outputs = {
         "//command_line_option:platforms": "@soong_injection//product_config_platforms/products/{PRODUCT}-{VARIANT}:%s" % target,
+        "@//build/bazel/rules/apex:within_apex": attr.within_apex,
+        "@//build/bazel/rules/apex:min_sdk_version": attr.apex_sdk_version,
+        "@//build/bazel/rules/apex:apex_name": apex_name,
     }
 
+    return outputs
+
 _config_node_transition = transition(
     implementation = _config_node_transition_impl,
     inputs = [],
     outputs = [
         "//command_line_option:platforms",
+        "@//build/bazel/rules/apex:within_apex",
+        "@//build/bazel/rules/apex:min_sdk_version",
+        "@//build/bazel/rules/apex:apex_name",
     ],
 )
 
@@ -720,9 +799,11 @@
 config_node = rule(
     implementation = _passthrough_rule_impl,
     attrs = {
-        "arch" : attr.string(mandatory = True),
-        "os"   : attr.string(mandatory = True),
-        "deps" : attr.label_list(cfg = _config_node_transition, allow_files = True),
+        "arch"    : attr.string(mandatory = True),
+        "os"      : attr.string(mandatory = True),
+        "within_apex" : attr.bool(default = False),
+        "apex_sdk_version" : attr.string(mandatory = True),
+        "deps"    : attr.label_list(cfg = _config_node_transition, allow_files = True),
         "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"),
     },
 )
@@ -781,6 +862,8 @@
 config_node(name = "%s",
     arch = "%s",
     os = "%s",
+    within_apex = %s,
+    apex_sdk_version = "%s",
     deps = [%s],
     testonly = True, # Unblocks testonly deps.
 )
@@ -807,15 +890,28 @@
 	for _, configString := range sortedConfigs {
 		labels := labelsByConfig[configString]
 		configTokens := strings.Split(configString, "|")
-		if len(configTokens) != 2 {
+		if len(configTokens) < 2 {
 			panic(fmt.Errorf("Unexpected config string format: %s", configString))
 		}
 		archString := configTokens[0]
 		osString := configTokens[1]
+		withinApex := "False"
+		apexSdkVerString := ""
 		targetString := fmt.Sprintf("%s_%s", osString, archString)
+		if len(configTokens) > 2 {
+			targetString += "_" + configTokens[2]
+			if configTokens[2] == withinApexToString(true) {
+				withinApex = "True"
+			}
+		}
+		if len(configTokens) > 3 {
+			targetString += "_" + configTokens[3]
+			apexSdkVerString = configTokens[3]
+		}
 		allLabels = append(allLabels, fmt.Sprintf("\":%s\"", targetString))
 		labelsString := strings.Join(labels, ",\n            ")
-		configNodesSection += fmt.Sprintf(configNodeFormatString, targetString, archString, osString, labelsString)
+		configNodesSection += fmt.Sprintf(configNodeFormatString, targetString, archString, osString, withinApex, apexSdkVerString,
+			labelsString)
 	}
 
 	return []byte(fmt.Sprintf(formatString, configNodesSection, strings.Join(allLabels, ",\n            ")))
@@ -911,6 +1007,7 @@
   # Soong treats filegroups, but it may not be the case with manually-written
   # filegroup BUILD targets.
   buildoptions = build_options(target)
+
   if buildoptions == None:
     # File targets do not have buildoptions. File targets aren't associated with
     #  any specific platform architecture in mixed builds, so use the host.
@@ -927,15 +1024,26 @@
   if not platform_name.startswith("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}"):
     fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
   platform_name = platform_name.removeprefix("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}").removeprefix("_")
+  config_key = ""
   if not platform_name:
-    return "target|android"
+    config_key = "target|android"
   elif platform_name.startswith("android_"):
-    return platform_name.removeprefix("android_") + "|android"
+    config_key = platform_name.removeprefix("android_") + "|android"
   elif platform_name.startswith("linux_"):
-    return platform_name.removeprefix("linux_") + "|linux"
+    config_key = platform_name.removeprefix("linux_") + "|linux"
   else:
     fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
 
+  within_apex = buildoptions.get("//build/bazel/rules/apex:within_apex")
+  apex_sdk_version = buildoptions.get("//build/bazel/rules/apex:min_sdk_version")
+
+  if within_apex:
+    config_key += "|within_apex"
+  if apex_sdk_version != None and len(apex_sdk_version) > 0:
+    config_key += "|" + apex_sdk_version
+
+  return config_key
+
 def format(target):
   id_string = str(target.label) + "|" + get_arch(target)
 
@@ -1044,8 +1152,12 @@
 		return err
 	}
 
-	cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
-		"--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
+	extraFlags := []string{"--output=starlark", "--starlark:file=" + absolutePath(cqueryFileRelpath)}
+	if Bool(config.productVariables.ClangCoverage) {
+		extraFlags = append(extraFlags, "--collect_code_coverage")
+	}
+
+	cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
 	cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag, eventHandler)
 	if cqueryErr != nil {
 		return cqueryErr
@@ -1325,7 +1437,16 @@
 		// Use host OS, which is currently hardcoded to be linux.
 		osName = "linux"
 	}
-	return arch + "|" + osName
+	keyString := arch + "|" + osName
+	if key.configKey.apexKey.WithinApex {
+		keyString += "|" + withinApexToString(key.configKey.apexKey.WithinApex)
+	}
+
+	if len(key.configKey.apexKey.ApexSdkVersion) > 0 {
+		keyString += "|" + key.configKey.apexKey.ApexSdkVersion
+	}
+
+	return keyString
 }
 
 func GetConfigKey(ctx BaseModuleContext) configKey {
@@ -1336,6 +1457,19 @@
 	}
 }
 
+func GetConfigKeyApexVariant(ctx BaseModuleContext, apexKey *ApexConfigKey) configKey {
+	configKey := GetConfigKey(ctx)
+
+	if apexKey != nil {
+		configKey.apexKey = ApexConfigKey{
+			WithinApex:     apexKey.WithinApex,
+			ApexSdkVersion: apexKey.ApexSdkVersion,
+		}
+	}
+
+	return configKey
+}
+
 func bazelDepsetName(contentHash string) string {
 	return fmt.Sprintf("bazel_depset_%s", contentHash)
 }
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index 4a4ecb5..c67d7fb 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -24,20 +24,37 @@
 }
 
 func TestRequestResultsAfterInvokeBazel(t *testing.T) {
-	label := "@//foo:bar"
-	cfg := configKey{"arm64_armv8-a", Android}
+	label_foo := "@//foo:foo"
+	label_bar := "@//foo:bar"
+	apexKey := ApexConfigKey{
+		WithinApex:     true,
+		ApexSdkVersion: "29",
+	}
+	cfg_foo := configKey{"arm64_armv8-a", Android, apexKey}
+	cfg_bar := configKey{arch: "arm64_armv8-a", osType: Android}
+	cmd_results := []string{
+		`@//foo:foo|arm64_armv8-a|android|within_apex|29>>out/foo/foo.txt`,
+		`@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
+	}
 	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
-		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
+		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: strings.Join(cmd_results, "\n"),
 	})
-	bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
+
+	bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
+	bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
 	err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
 	if err != nil {
 		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
 	}
-	g, err := bazelContext.GetOutputFiles(label, cfg)
+	verifyCqueryResult(t, bazelContext, label_foo, cfg_foo, "out/foo/foo.txt")
+	verifyCqueryResult(t, bazelContext, label_bar, cfg_bar, "out/foo/bar.txt")
+}
+
+func verifyCqueryResult(t *testing.T, ctx *mixedBuildBazelContext, label string, cfg configKey, result string) {
+	g, err := ctx.GetOutputFiles(label, cfg)
 	if err != nil {
 		t.Errorf("Expected cquery results after running InvokeBazel(), but got err %v", err)
-	} else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) {
+	} else if w := []string{result}; !reflect.DeepEqual(w, g) {
 		t.Errorf("Expected output %s, got %s", w, g)
 	}
 }
@@ -178,14 +195,18 @@
 func TestBazelRequestsSorted(t *testing.T) {
 	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
 
-	bazelContext.QueueBazelRequest("zzz", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
-	bazelContext.QueueBazelRequest("ccc", cquery.GetApexInfo, configKey{"arm64_armv8-a", Android})
-	bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
-	bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
-	bazelContext.QueueBazelRequest("xxx", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Linux})
-	bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
-	bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, configKey{"otherarch", Android})
-	bazelContext.QueueBazelRequest("bbb", cquery.GetOutputFiles, configKey{"otherarch", Android})
+	cfgKeyArm64Android := configKey{arch: "arm64_armv8-a", osType: Android}
+	cfgKeyArm64Linux := configKey{arch: "arm64_armv8-a", osType: Linux}
+	cfgKeyOtherAndroid := configKey{arch: "otherarch", osType: Android}
+
+	bazelContext.QueueBazelRequest("zzz", cquery.GetOutputFiles, cfgKeyArm64Android)
+	bazelContext.QueueBazelRequest("ccc", cquery.GetApexInfo, cfgKeyArm64Android)
+	bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
+	bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
+	bazelContext.QueueBazelRequest("xxx", cquery.GetOutputFiles, cfgKeyArm64Linux)
+	bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyArm64Android)
+	bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyOtherAndroid)
+	bazelContext.QueueBazelRequest("bbb", cquery.GetOutputFiles, cfgKeyOtherAndroid)
 
 	if len(bazelContext.requests) != 7 {
 		t.Error("Expected 7 request elements, but got", len(bazelContext.requests))
@@ -201,6 +222,52 @@
 	}
 }
 
+func TestIsModuleNameAllowed(t *testing.T) {
+	libDisabled := "lib_disabled"
+	libEnabled := "lib_enabled"
+	libDclaWithinApex := "lib_dcla_within_apex"
+	libDclaNonApex := "lib_dcla_non_apex"
+	libNotConverted := "lib_not_converted"
+
+	disabledModules := map[string]bool{
+		libDisabled: true,
+	}
+	enabledModules := map[string]bool{
+		libEnabled: true,
+	}
+	dclaEnabledModules := map[string]bool{
+		libDclaWithinApex: true,
+		libDclaNonApex:    true,
+	}
+
+	bazelContext := &mixedBuildBazelContext{
+		modulesDefaultToBazel:   false,
+		bazelEnabledModules:     enabledModules,
+		bazelDisabledModules:    disabledModules,
+		bazelDclaEnabledModules: dclaEnabledModules,
+	}
+
+	if bazelContext.IsModuleNameAllowed(libDisabled, true) {
+		t.Fatalf("%s shouldn't be allowed for mixed build", libDisabled)
+	}
+
+	if !bazelContext.IsModuleNameAllowed(libEnabled, true) {
+		t.Fatalf("%s should be allowed for mixed build", libEnabled)
+	}
+
+	if !bazelContext.IsModuleNameAllowed(libDclaWithinApex, true) {
+		t.Fatalf("%s should be allowed for mixed build", libDclaWithinApex)
+	}
+
+	if bazelContext.IsModuleNameAllowed(libDclaNonApex, false) {
+		t.Fatalf("%s shouldn't be allowed for mixed build", libDclaNonApex)
+	}
+
+	if bazelContext.IsModuleNameAllowed(libNotConverted, true) {
+		t.Fatalf("%s shouldn't be allowed for mixed build", libNotConverted)
+	}
+}
+
 func verifyExtraFlags(t *testing.T, config Config, expected string) string {
 	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
 
diff --git a/android/filegroup.go b/android/filegroup.go
index d21d146..7d929bc 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -232,7 +232,7 @@
 	bazelCtx.QueueBazelRequest(
 		fg.GetBazelLabel(ctx, fg),
 		cquery.GetOutputFiles,
-		configKey{Common.String(), CommonOS})
+		configKey{arch: Common.String(), osType: CommonOS})
 }
 
 func (fg *fileGroup) IsMixedBuildSupported(ctx BaseModuleContext) bool {
@@ -252,7 +252,7 @@
 		relativeRoot = filepath.Join(relativeRoot, *fg.properties.Path)
 	}
 
-	filePaths, err := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{Common.String(), CommonOS})
+	filePaths, err := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{arch: Common.String(), osType: CommonOS})
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
 		return
diff --git a/apex/apex.go b/apex/apex.go
index b77568d..9a80aa8 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -141,6 +141,9 @@
 	// Default: true.
 	Installable *bool
 
+	// Whether this APEX ignores the apex_available list defined in its dependencies.
+	Override_apex_available *bool
+
 	// If set true, VNDK libs are considered as stable libs and are not included in this APEX.
 	// Should be only used in non-system apexes (e.g. vendor: true). Default is false.
 	Use_vndk_as_stable *bool
@@ -1513,6 +1516,10 @@
 	return proptools.BoolDefault(a.properties.Platform_apis, false)
 }
 
+func (a *apexBundle) OverrideApexAvailable() bool {
+	return proptools.BoolDefault(a.properties.Override_apex_available, false)
+}
+
 // getCertString returns the name of the cert that should be used to sign this APEX. This is
 // basically from the "certificate" property, but could be overridden by the device config.
 func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
@@ -3040,6 +3047,11 @@
 		return
 	}
 
+	// Ignore availability when `override_apex_available` is true.
+	if a.OverrideApexAvailable() {
+		return
+	}
+
 	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		// As soon as the dependency graph crosses the APEX boundary, don't go further.
 		if externalDep {
diff --git a/cc/binary.go b/cc/binary.go
index 532b42a..496c610 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -577,12 +577,12 @@
 
 func (handler *ccBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
+	bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 }
 
 func (handler *ccBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKey(ctx))
+	info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
 		return
diff --git a/cc/cc.go b/cc/cc.go
index c81160d..5bb13ff 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1905,10 +1905,29 @@
 	}
 
 	// TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan)
-	ubsanEnabled := c.sanitize != nil &&
-		((c.sanitize.Properties.Sanitize.Integer_overflow != nil && *c.sanitize.Properties.Sanitize.Integer_overflow) ||
-			c.sanitize.Properties.Sanitize.Misc_undefined != nil)
-	return c.bazelHandler != nil && !ubsanEnabled
+	// Currently we can only support ubsan when minimum runtime is used.
+	return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded())
+}
+
+func isUbsanEnabled(c *Module) bool {
+	if c.sanitize == nil {
+		return false
+	}
+	sanitizeProps := &c.sanitize.Properties.SanitizeMutated
+	return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+}
+
+func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	if !apexInfo.IsForPlatform() {
+		apexKey := android.ApexConfigKey{
+			WithinApex:     true,
+			ApexSdkVersion: findApexSdkVersion(ctx, apexInfo).String(),
+		}
+		return &apexKey
+	}
+
+	return nil
 }
 
 func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
@@ -2841,6 +2860,23 @@
 	}
 }
 
+func findApexSdkVersion(ctx android.BaseModuleContext, apexInfo android.ApexInfo) android.ApiLevel {
+	// For the dependency from platform to apex, use the latest stubs
+	apexSdkVersion := android.FutureApiLevel
+	if !apexInfo.IsForPlatform() {
+		apexSdkVersion = apexInfo.MinSdkVersion
+	}
+
+	if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+		// In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+		// so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+		// (b/144430859)
+		apexSdkVersion = android.FutureApiLevel
+	}
+
+	return apexSdkVersion
+}
+
 // Convert dependencies to paths.  Returns a PathDeps containing paths
 func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
@@ -2856,19 +2892,8 @@
 		depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.GeneratedHeaders...)
 	}
 
-	// For the dependency from platform to apex, use the latest stubs
-	c.apexSdkVersion = android.FutureApiLevel
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	if !apexInfo.IsForPlatform() {
-		c.apexSdkVersion = apexInfo.MinSdkVersion
-	}
-
-	if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
-		// In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
-		// so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
-		// (b/144430859)
-		c.apexSdkVersion = android.FutureApiLevel
-	}
+	c.apexSdkVersion = findApexSdkVersion(ctx, apexInfo)
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 62adfd3..0d03b73 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -28,6 +28,10 @@
 	"android/soong/bazel/cquery"
 )
 
+func init() {
+	registerTestMutators(android.InitRegistrationContext)
+}
+
 func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
@@ -41,6 +45,36 @@
 	}),
 )
 
+var ccLibInApex = "cc_lib_in_apex"
+var apexVariationName = "apex28"
+var apexVersion = "28"
+
+func registerTestMutators(ctx android.RegistrationContext) {
+	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("apex", testApexMutator).Parallel()
+		ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
+	})
+}
+
+func mixedBuildsPrepareMutator(ctx android.BottomUpMutatorContext) {
+	if m := ctx.Module(); m.Enabled() {
+		if mixedBuildMod, ok := m.(android.MixedBuildBuildable); ok {
+			if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) {
+				mixedBuildMod.QueueBazelCall(ctx)
+			}
+		}
+	}
+}
+
+func testApexMutator(mctx android.BottomUpMutatorContext) {
+	modules := mctx.CreateVariations(apexVariationName)
+	apexInfo := android.ApexInfo{
+		ApexVariationName: apexVariationName,
+		MinSdkVersion:     android.ApiLevelForTest(apexVersion),
+	}
+	mctx.SetVariationProvider(modules[0], android.ApexInfoProvider, apexInfo)
+}
+
 // testCcWithConfig runs tests using the prepareForCcTest
 //
 // See testCc for an explanation as to how to stop using this deprecated method.
@@ -4906,3 +4940,56 @@
 		})
 	}
 }
+
+func TestDclaLibraryInApex(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "cc_lib_in_apex",
+		srcs: ["foo.cc"],
+    apex_available: ["myapex"],
+		bazel_module: { label: "//foo/bar:bar" },
+	}`
+	label := "//foo/bar:bar"
+	arch64 := "arm64_armv8-a"
+	arch32 := "arm_armv7-a-neon"
+	apexCfgKey := android.ApexConfigKey{
+		WithinApex:     true,
+		ApexSdkVersion: "28",
+	}
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureRegisterWithContext(registerTestMutators),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: "outputbase",
+				LabelToCcInfo: map[string]cquery.CcInfo{
+					android.BuildMockBazelContextResultKey(label, arch32, android.Android, apexCfgKey): cquery.CcInfo{
+						RootDynamicLibraries: []string{"foo.so"},
+					},
+					android.BuildMockBazelContextResultKey(label, arch64, android.Android, apexCfgKey): cquery.CcInfo{
+						RootDynamicLibraries: []string{"foo.so"},
+					},
+				},
+				BazelRequests: make(map[string]bool),
+			}
+		}),
+	).RunTestWithBp(t, bp)
+	ctx := result.TestContext
+
+	// Test if the bazel request is queued correctly
+	key := android.BuildMockBazelContextRequestKey(label, cquery.GetCcInfo, arch32, android.Android, apexCfgKey)
+	if !ctx.Config().BazelContext.(android.MockBazelContext).BazelRequests[key] {
+		t.Errorf("Bazel request was not queued: %s", key)
+	}
+
+	sharedFoo := ctx.ModuleForTests(ccLibInApex, "android_arm_armv7-a-neon_shared_"+apexVariationName).Module()
+	producer := sharedFoo.(android.OutputFileProducer)
+	outputFiles, err := producer.OutputFiles("")
+	if err != nil {
+		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+	}
+	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
+	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+}
diff --git a/cc/library.go b/cc/library.go
index f33f37e..61e3a93 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -910,12 +910,12 @@
 
 func (handler *ccLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx))
+	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 }
 
 func (handler *ccLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
+	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 	if err != nil {
 		ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
 		return
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 32ea1d4..1dee726 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -59,12 +59,12 @@
 
 func (handler *libraryHeaderBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx))
+	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 }
 
 func (h *libraryHeaderBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
+	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
 		return
diff --git a/cc/object.go b/cc/object.go
index 11ce793..ef44467 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -54,12 +54,12 @@
 
 func (handler *objectBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
+	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 }
 
 func (handler *objectBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	objPaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
+	objPaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
 		return
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 03a600a..bb517ea 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -761,12 +761,12 @@
 
 func (h *prebuiltBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
+	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 }
 
 func (h *prebuiltBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
+	outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
 		return