diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go index 7ce0d9b62..8cd52cb83 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -1427,4 +1427,20 @@ var ( // 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 52f50c5c7..b60075840 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -352,11 +352,13 @@ func GetBp2BuildAllowList() Bp2BuildConversionAllowlist { // 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 0880ad5b7..3a459f181 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -109,12 +109,29 @@ type cqueryRequest interface { // 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 @@ type BazelContext interface { // 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 @@ type mixedBuildBazelContext struct { 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 @@ type MockBazelContext struct { 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 @@ func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, e 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 @@ func (m MockBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error { panic("unimplemented") } -func (m MockBazelContext) IsModuleNameAllowed(_ string) bool { +func (m MockBazelContext) IsModuleNameAllowed(_ string, _ bool) bool { return true } @@ -324,6 +353,26 @@ func (m MockBazelContext) AqueryDepsets() []bazel.AqueryDepset { 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 @@ func (m noopBazelContext) OutputBase() string { return "" } -func (n noopBazelContext) IsModuleNameAllowed(_ string) bool { +func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool { return false } @@ -442,14 +491,15 @@ func (m noopBazelContext) AqueryDepsets() []bazel.AqueryDepset { 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 @@ func NewBazelContext(c *config) (BazelContext, error) { 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 @@ func (p *bazelPaths) BazelMetricsDir() string { 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 @@ func (context *mixedBuildBazelContext) mainBzlFileContents() []byte { ##################################################### # 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 @@ def _passthrough_rule_impl(ctx): 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 @@ phony_root(name = "phonyroot", 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 @@ config_node(name = "%s", 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 @@ def get_arch(target): # 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 @@ def get_arch(target): if not platform_name.startswith("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}"): fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_', 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_' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_', 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 @@ func (context *mixedBuildBazelContext) runCquery(config Config, ctx invokeBazelC 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 @@ func getConfigString(key cqueryKey) string { // 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 GetConfigKey(ctx BaseModuleContext) configKey { } } +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 4a4ecb57f..c67d7fb66 100644 --- a/android/bazel_handler_test.go +++ b/android/bazel_handler_test.go @@ -24,20 +24,37 @@ func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler { } 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 TestCoverageFlagsAfterInvokeBazel(t *testing.T) { 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 TestBazelRequestsSorted(t *testing.T) { } } +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 d21d146f4..7d929bc4e 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -232,7 +232,7 @@ func (fg *fileGroup) QueueBazelCall(ctx BaseModuleContext) { 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 @@ func (fg *fileGroup) ProcessBazelQueryResponse(ctx ModuleContext) { 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/cc/binary.go b/cc/binary.go index 532b42a4c..496c610c2 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -577,12 +577,12 @@ var _ BazelHandler = (*ccBinaryBazelHandler)(nil) 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 c81160d55..5bb13ffff 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -1905,10 +1905,29 @@ func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { } // 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 checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { } } +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 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { 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 62adfd3ae..0d03b73e9 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -28,6 +28,10 @@ import ( "android/soong/bazel/cquery" ) +func init() { + registerTestMutators(android.InitRegistrationContext) +} + func TestMain(m *testing.M) { os.Exit(m.Run()) } @@ -41,6 +45,36 @@ var prepareForCcTest = android.GroupFixturePreparers( }), ) +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 TestCcBuildBrokenClangCFlags(t *testing.T) { }) } } + +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 f33f37efc..61e3a9344 100644 --- a/cc/library.go +++ b/cc/library.go @@ -910,12 +910,12 @@ func (handler *ccLibraryBazelHandler) generateSharedBazelBuildActions(ctx androi 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 32ea1d4be..1dee72679 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -59,12 +59,12 @@ var _ BazelHandler = (*libraryHeaderBazelHandler)(nil) 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 11ce7939c..ef4446746 100644 --- a/cc/object.go +++ b/cc/object.go @@ -54,12 +54,12 @@ var _ BazelHandler = (*objectBazelHandler)(nil) 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 03a600a85..bb517eadb 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -761,12 +761,12 @@ var _ BazelHandler = (*prebuiltBinaryBazelHandler)(nil) 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