From fc12d2f494dfa92503e799e2ff0fadc2a14703db Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Fri, 27 Oct 2023 20:06:32 +0000 Subject: [PATCH] Special-case java_sdk_library in source vs prebuilt selection If a java_sdk_library is listed in `contents`, then restrict the source vs prebuilt selection superseding to only the internal stub libraries. Defer the source vs prebuilt selection mechanism of the top-level library to the existing mechanisms for now. This is necessary because this top-level library acts as a hook for - hiddenapi: boot jars are deapxed from the prebuilt apex - dexpreopt: system server jars are deapexed from the prebuilt apex and installed via required If `next` uses `framework-foo` and `service-foo` as the top-level library instead of the prebuilt equivalents, then the bootjars installed in out/soong/dexpreopt_x86_64/apex_bootjars will come from source. And the *.odex files of the system server jars will come from source. Bug: 308174768 Test: Added a java_sdk_library unit test to assert that the new mechanism supersedes the `prefer` flag Change-Id: Ib43198a3b547c58b54f1f0966e95584215096d32 --- android/prebuilt.go | 42 ++++++++++++- java/sdk_library_test.go | 131 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 2 deletions(-) diff --git a/android/prebuilt.go b/android/prebuilt.go index edd014a8c..91c0aa182 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -510,6 +510,42 @@ func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) { } } +// A wrapper around PrebuiltSelectionInfoMap.IsSelected with special handling for java_sdk_library +// java_sdk_library is a macro that creates +// 1. top-level impl library +// 2. stub libraries (suffixed with .stubs...) +// +// java_sdk_library_import is a macro that creates +// 1. top-level "impl" library +// 2. stub libraries (suffixed with .stubs...) +// +// the impl of java_sdk_library_import is a "hook" for hiddenapi and dexpreopt processing. It does not have an impl jar, but acts as a shim +// to provide the jar deapxed from the prebuilt apex +// +// isSelected uses `all_apex_contributions` to supersede source vs prebuilts selection of the stub libraries. It does not supersede the +// selection of the top-level "impl" library so that this hook can work +// +// TODO (b/308174306) - Fix this when we need to support multiple prebuilts in main +func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool { + if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil { + sln := proptools.String(sdkLibrary.SdkLibraryName()) + // This is the top-level library + // Do not supersede the existing prebuilts vs source selection mechanisms + if sln == m.base().BaseModuleName() { + return false + } + + // Stub library created by java_sdk_library_import + if p := GetEmbeddedPrebuilt(m); p != nil { + return psi.IsSelected(sln, PrebuiltNameFromSource(sln)) + } + + // Stub library created by java_sdk_library + return psi.IsSelected(sln, sln) + } + return psi.IsSelected(m.base().BaseModuleName(), m.Name()) +} + // usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt // will be used if it is marked "prefer" or if the source module is disabled. func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool { @@ -520,14 +556,16 @@ func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt M psi = ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap) } }) + // If the source module is explicitly listed in the metadata module, use that - if source != nil && psi.IsSelected(source.base().BaseModuleName(), source.Name()) { + if source != nil && isSelected(psi, source) { return false } // If the prebuilt module is explicitly listed in the metadata module, use that - if psi.IsSelected(prebuilt.base().BaseModuleName(), prebuilt.Name()) { + if isSelected(psi, prebuilt) { return true } + // If the baseModuleName could not be found in the metadata module, // fall back to the existing source vs prebuilt selection. // TODO: Drop the fallback mechanisms diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 21f0bab37..82f8a4d50 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -1068,6 +1068,137 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) { }) } +// If a module is listed in `mainline_module_contributions, it should be used +// It will supersede any other source vs prebuilt selection mechanism like `prefer` attribute +func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) { + bp := ` + apex_contributions { + name: "my_mainline_module_contributions", + api_domain: "my_mainline_module", + contents: [ + // legacy mechanism prefers the prebuilt + // mainline_module_contributions supersedes this since source is listed explicitly + "sdklib.prebuilt_preferred_using_legacy_flags", + + // legacy mechanism prefers the source + // mainline_module_contributions supersedes this since prebuilt is listed explicitly + "prebuilt_sdklib.source_preferred_using_legacy_flags", + ], + } + all_apex_contributions { + name: "all_apex_contributions", + } + java_sdk_library { + name: "sdklib.prebuilt_preferred_using_legacy_flags", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + system: { + enabled: true, + } + } + java_sdk_library_import { + name: "sdklib.prebuilt_preferred_using_legacy_flags", + prefer: true, // prebuilt is preferred using legacy mechanism + public: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + system: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + } + java_sdk_library { + name: "sdklib.source_preferred_using_legacy_flags", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + system: { + enabled: true, + } + } + java_sdk_library_import { + name: "sdklib.source_preferred_using_legacy_flags", + prefer: false, // source is preferred using legacy mechanism + public: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + system: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + } + + // rdeps + java_library { + name: "public", + srcs: ["a.java"], + libs: [ + // this should get source since source is listed in my_mainline_module_contributions + "sdklib.prebuilt_preferred_using_legacy_flags.stubs", + "sdklib.prebuilt_preferred_using_legacy_flags.stubs.system", + + // this should get prebuilt since source is listed in my_mainline_module_contributions + "sdklib.source_preferred_using_legacy_flags.stubs", + "sdklib.source_preferred_using_legacy_flags.stubs.system", + + ], + } + ` + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("sdklib.source_preferred_using_legacy_flags", "sdklib.prebuilt_preferred_using_legacy_flags"), + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + android.RegisterApexContributionsBuildComponents(ctx) + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions", + } + }), + ).RunTestWithBp(t, bp) + + // Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions + public := result.ModuleForTests("public", "android_common") + rule := public.Output("javac/public.jar") + inputs := rule.Implicits.Strings() + expectedInputs := []string{ + // source + "out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.jar", + "out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system.jar", + + // prebuilt + "out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.jar", + "out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs.system/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.system.jar", + } + for _, expected := range expectedInputs { + if !android.InList(expected, inputs) { + t.Errorf("expected %q to contain %q", inputs, expected) + } + } +} + func TestJavaSdkLibraryEnforce(t *testing.T) { partitionToBpOption := func(partition string) string { switch partition {