From e43124023ce73f600bf0925a14095131d8f9037d Mon Sep 17 00:00:00 2001 From: Yu Liu Date: Wed, 18 Jan 2023 09:15:31 -0800 Subject: [PATCH] Support DCLA Bug: 240424572 Test: Manual tests: 1. m --dev-mode-staging com.android.adbd com.android.media.swcodec. 2. verify the DCLA libs from the two apexes have the same size and sha1sum, and also match the libs in bazel-out. 3. empty the DCLA libs list in allowlist.go and repeat step 1 4. repeat step 2 and verify the opposite result 5. build git_master: mainline_modules_bundles-userdebug in ABTD with the cl, then follow go/build-sideload-dcla-locally to download the adbd and swcodec aab files, run the DCLA trimming workflow locally, and verify the symlinks in the two trimmed apexes are identical and also match the lib path in the DCLA apex that was created by the workflow. Change-Id: Ib2f8a29126a54829c0e10eba17b256a79930fd70 --- android/allowlists/allowlists.go | 16 +++ android/bazel.go | 4 +- android/bazel_handler.go | 208 +++++++++++++++++++++++++------ android/bazel_handler_test.go | 95 +++++++++++--- android/filegroup.go | 4 +- cc/binary.go | 4 +- cc/cc.go | 57 ++++++--- cc/cc_test.go | 87 +++++++++++++ cc/library.go | 4 +- cc/library_headers.go | 4 +- cc/object.go | 4 +- cc/prebuilt.go | 4 +- 12 files changed, 411 insertions(+), 80 deletions(-) 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