diff --git a/android/prebuilt.go b/android/prebuilt.go index 2896dbd53..13cda9dad 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -518,7 +518,7 @@ func hideUnflaggedModules(ctx BottomUpMutatorContext, psi PrebuiltSelectionInfoM // query all_apex_contributions to see if any module in this family has been selected for _, moduleInFamily := range allModulesInFamily { // validate that are no duplicates - if psi.IsSelected(moduleInFamily.Name()) { + if isSelected(psi, moduleInFamily) { if selectedModuleInFamily == nil { // Store this so we can validate that there are no duplicates selectedModuleInFamily = moduleInFamily @@ -598,16 +598,20 @@ func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) { 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 // TODO (b/308187268): Remove this after the apexes have been added to apex_contributions - if sln == m.base().BaseModuleName() { + if bmn, ok := m.(baseModuleName); ok && sln == bmn.BaseModuleName() { return false } // Stub library created by java_sdk_library_import - if p := GetEmbeddedPrebuilt(m); p != nil { - return psi.IsSelected(PrebuiltNameFromSource(sln)) + // java_sdk_library creates several child modules (java_import + prebuilt_stubs_sources) dynamically. + // This code block ensures that these child modules are selected if the top-level java_sdk_library_import is listed + // in the selected apex_contributions. + if javaImport, ok := m.(createdByJavaSdkLibraryName); ok && javaImport.CreatedByJavaSdkLibraryName() != nil { + return psi.IsSelected(PrebuiltNameFromSource(proptools.String(javaImport.CreatedByJavaSdkLibraryName()))) } // Stub library created by java_sdk_library @@ -616,6 +620,11 @@ func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool { return psi.IsSelected(m.Name()) } +// implemented by child modules of java_sdk_library_import +type createdByJavaSdkLibraryName interface { + CreatedByJavaSdkLibraryName() *string +} + // 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 { diff --git a/java/droidstubs.go b/java/droidstubs.go index 426754553..56ae427ac 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -1320,6 +1320,24 @@ var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil) type PrebuiltStubsSourcesProperties struct { Srcs []string `android:"path"` + + // Name of the source soong module that gets shadowed by this prebuilt + // If unspecified, follows the naming convention that the source module of + // the prebuilt is Name() without "prebuilt_" prefix + Source_module_name *string + + // Non-nil if this prebuilt stub srcs module was dynamically created by a java_sdk_library_import + // The name is the undecorated name of the java_sdk_library as it appears in the blueprint file + // (without any prebuilt_ prefix) + Created_by_java_sdk_library_name *string `blueprint:"mutated"` +} + +func (j *PrebuiltStubsSources) BaseModuleName() string { + return proptools.StringDefault(j.properties.Source_module_name, j.ModuleBase.Name()) +} + +func (j *PrebuiltStubsSources) CreatedByJavaSdkLibraryName() *string { + return j.properties.Created_by_java_sdk_library_name } type PrebuiltStubsSources struct { diff --git a/java/java.go b/java/java.go index 30a3763a1..d7d271cca 100644 --- a/java/java.go +++ b/java/java.go @@ -2097,6 +2097,11 @@ type ImportProperties struct { // If unspecified, follows the naming convention that the source module of // the prebuilt is Name() without "prebuilt_" prefix Source_module_name *string + + // Non-nil if this java_import module was dynamically created by a java_sdk_library_import + // The name is the undecorated name of the java_sdk_library as it appears in the blueprint file + // (without any prebuilt_ prefix) + Created_by_java_sdk_library_name *string `blueprint:"mutated"` } type Import struct { @@ -2182,6 +2187,10 @@ func (j *Import) Stem() string { return proptools.StringDefault(j.properties.Stem, j.BaseModuleName()) } +func (j *Import) CreatedByJavaSdkLibraryName() *string { + return j.properties.Created_by_java_sdk_library_name +} + func (a *Import) JacocoReportClassesFile() android.Path { return nil } @@ -2833,7 +2842,20 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, type JavaApiContributionImport struct { JavaApiContribution - prebuilt android.Prebuilt + prebuilt android.Prebuilt + prebuiltProperties javaApiContributionImportProperties +} + +type javaApiContributionImportProperties struct { + // Name of the source soong module that gets shadowed by this prebuilt + // If unspecified, follows the naming convention that the source module of + // the prebuilt is Name() without "prebuilt_" prefix + Source_module_name *string + + // Non-nil if this java_import module was dynamically created by a java_sdk_library_import + // The name is the undecorated name of the java_sdk_library as it appears in the blueprint file + // (without any prebuilt_ prefix) + Created_by_java_sdk_library_name *string `blueprint:"mutated"` } func ApiContributionImportFactory() android.Module { @@ -2841,7 +2863,7 @@ func ApiContributionImportFactory() android.Module { android.InitAndroidModule(module) android.InitDefaultableModule(module) android.InitPrebuiltModule(module, &[]string{""}) - module.AddProperties(&module.properties) + module.AddProperties(&module.properties, &module.prebuiltProperties) module.AddProperties(&module.sdkLibraryComponentProperties) return module } @@ -2854,6 +2876,14 @@ func (module *JavaApiContributionImport) Name() string { return module.prebuilt.Name(module.ModuleBase.Name()) } +func (j *JavaApiContributionImport) BaseModuleName() string { + return proptools.StringDefault(j.prebuiltProperties.Source_module_name, j.ModuleBase.Name()) +} + +func (j *JavaApiContributionImport) CreatedByJavaSdkLibraryName() *string { + return j.prebuiltProperties.Created_by_java_sdk_library_name +} + func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ap.JavaApiContribution.GenerateAndroidBuildActions(ctx) } diff --git a/java/sdk_library.go b/java/sdk_library.go index 49e6727eb..fbde04276 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -907,7 +907,30 @@ type commonToSdkLibraryAndImportProperties struct { type commonSdkLibraryAndImportModule interface { android.Module - BaseModuleName() string + // Returns the name of the root java_sdk_library that creates the child stub libraries + // This is the `name` as it appears in Android.bp, and not the name in Soong's build graph + // (with the prebuilt_ prefix) + // + // e.g. in the following java_sdk_library_import + // java_sdk_library_import { + // name: "framework-foo.v1", + // source_module_name: "framework-foo", + // } + // the values returned by + // 1. Name(): prebuilt_framework-foo.v1 # unique + // 2. BaseModuleName(): framework-foo # the source + // 3. RootLibraryName: framework-foo.v1 # the undecordated `name` from Android.bp + RootLibraryName() string +} + +func (m *SdkLibrary) RootLibraryName() string { + return m.BaseModuleName() +} + +func (m *SdkLibraryImport) RootLibraryName() string { + // m.BaseModuleName refers to the source of the import + // use moduleBase.Name to get the name of the module as it appears in the .bp file + return m.ModuleBase.Name() } // Common code between sdk library and sdk library import @@ -946,7 +969,7 @@ func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android return false } - namePtr := proptools.StringPtr(c.module.BaseModuleName()) + namePtr := proptools.StringPtr(c.module.RootLibraryName()) c.sdkLibraryComponentProperties.SdkLibraryName = namePtr // Only track this sdk library if this can be used as a shared library. @@ -973,51 +996,51 @@ func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.Mod // Module name of the runtime implementation library func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string { - return c.module.BaseModuleName() + ".impl" + return c.module.RootLibraryName() + ".impl" } // Module name of the XML file for the lib func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string { - return c.module.BaseModuleName() + sdkXmlFileSuffix + return c.module.RootLibraryName() + sdkXmlFileSuffix } // Name of the java_library module that compiles the stubs source. func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.BaseModuleName() + baseName := c.module.RootLibraryName() return c.namingScheme.stubsLibraryModuleName(apiScope, baseName) } // Name of the java_library module that compiles the exportable stubs source. func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.BaseModuleName() + baseName := c.module.RootLibraryName() return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName) } // Name of the droidstubs module that generates the stubs source and may also // generate/check the API. func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string { - baseName := c.module.BaseModuleName() + baseName := c.module.RootLibraryName() return c.namingScheme.stubsSourceModuleName(apiScope, baseName) } // Name of the java_api_library module that generates the from-text stubs source // and compiles to a jar file. func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.BaseModuleName() + baseName := c.module.RootLibraryName() return c.namingScheme.apiLibraryModuleName(apiScope, baseName) } // Name of the java_library module that compiles the stubs // generated from source Java files. func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.BaseModuleName() + baseName := c.module.RootLibraryName() return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName) } // Name of the java_library module that compiles the exportable stubs // generated from source Java files. func (c *commonToSdkLibraryAndImport) exportableSourceStubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.BaseModuleName() + baseName := c.module.RootLibraryName() return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName) } @@ -1067,7 +1090,7 @@ func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Pat if scope, ok := scopeByName[scopeName]; ok { paths := c.findScopePaths(scope) if paths == nil { - return nil, fmt.Errorf("%q does not provide api scope %s", c.module.BaseModuleName(), scopeName) + return nil, fmt.Errorf("%q does not provide api scope %s", c.module.RootLibraryName(), scopeName) } switch component { @@ -1103,7 +1126,7 @@ func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Pat if c.doctagPaths != nil { return c.doctagPaths, nil } else { - return nil, fmt.Errorf("no doctag_files specified on %s", c.module.BaseModuleName()) + return nil, fmt.Errorf("no doctag_files specified on %s", c.module.RootLibraryName()) } } return nil, nil @@ -1149,7 +1172,7 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android. // If a specific numeric version has been requested then use prebuilt versions of the sdk. if !sdkVersion.ApiLevel.IsPreview() { - return PrebuiltJars(ctx, c.module.BaseModuleName(), sdkVersion) + return PrebuiltJars(ctx, c.module.RootLibraryName(), sdkVersion) } paths := c.selectScopePaths(ctx, sdkVersion.Kind) @@ -1176,7 +1199,7 @@ func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleCon scopes = append(scopes, s.name) } } - ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.BaseModuleName(), scopes) + ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.RootLibraryName(), scopes) return nil } @@ -1238,7 +1261,7 @@ func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() in SdkLibraryToImplicitlyTrack *string }{} - namePtr := proptools.StringPtr(c.module.BaseModuleName()) + namePtr := proptools.StringPtr(c.module.RootLibraryName()) componentProps.SdkLibraryName = namePtr if c.sharedLibrary() { @@ -2525,6 +2548,11 @@ type sdkLibraryImportProperties struct { // If not empty, classes are restricted to the specified packages and their sub-packages. Permitted_packages []string + + // Name of the source soong module that gets shadowed by this prebuilt + // If unspecified, follows the naming convention that the source module of + // the prebuilt is Name() without "prebuilt_" prefix + Source_module_name *string } type SdkLibraryImport struct { @@ -2638,6 +2666,10 @@ func (module *SdkLibraryImport) Name() string { return module.prebuilt.Name(module.ModuleBase.Name()) } +func (module *SdkLibraryImport) BaseModuleName() string { + return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name()) +} + func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) { // If the build is configured to use prebuilts then force this to be preferred. @@ -2670,15 +2702,19 @@ func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHo func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { // Creates a java import for the jar with ".stubs" suffix props := struct { - Name *string - Sdk_version *string - Libs []string - Jars []string - Compile_dex *bool + Name *string + Source_module_name *string + Created_by_java_sdk_library_name *string + Sdk_version *string + Libs []string + Jars []string + Compile_dex *bool android.UserSuppliedPrebuiltProperties }{} props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) + props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName())) + props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) props.Sdk_version = scopeProperties.Sdk_version // Prepend any of the libs from the legacy public properties to the libs for each of the // scopes to avoid having to duplicate them in each scope. @@ -2700,12 +2736,16 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { props := struct { - Name *string - Srcs []string + Name *string + Source_module_name *string + Created_by_java_sdk_library_name *string + Srcs []string android.UserSuppliedPrebuiltProperties }{} props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope)) + props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName())) + props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) props.Srcs = scopeProperties.Stub_srcs // The stubs source is preferred if the java_sdk_library_import is preferred. @@ -2719,13 +2759,17 @@ func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.Defau api_surface := &apiScope.name props := struct { - Name *string - Api_surface *string - Api_file *string - Visibility []string + Name *string + Source_module_name *string + Created_by_java_sdk_library_name *string + Api_surface *string + Api_file *string + Visibility []string }{} props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope) + ".api.contribution") + props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution") + props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) props.Api_surface = api_surface props.Api_file = api_file props.Visibility = []string{"//visibility:override", "//visibility:public"} diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 0a113b6d5..93ef40872 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -1830,3 +1830,93 @@ func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) { inputs := rule.Implicits.Strings() android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar") } + +// test that rdep gets resolved to the correct version of a java_sdk_library (source or a specific prebuilt) +func TestMultipleSdkLibraryPrebuilts(t *testing.T) { + bp := ` + apex_contributions { + name: "my_mainline_module_contributions", + api_domain: "my_mainline_module", + contents: ["%s"], + } + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + } + java_sdk_library_import { + name: "sdklib.v1", //prebuilt + source_module_name: "sdklib", + public: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + } + java_sdk_library_import { + name: "sdklib.v2", //prebuilt + source_module_name: "sdklib", + public: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + } + // rdeps + java_library { + name: "mymodule", + srcs: ["a.java"], + libs: ["sdklib.stubs",], + } + ` + testCases := []struct { + desc string + selectedDependencyName string + expectedStubPath string + }{ + { + desc: "Source library is selected using apex_contributions", + selectedDependencyName: "sdklib", + expectedStubPath: "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar", + }, + { + desc: "Prebuilt library v1 is selected using apex_contributions", + selectedDependencyName: "prebuilt_sdklib.v1", + expectedStubPath: "out/soong/.intermediates/prebuilt_sdklib.v1.stubs/android_common/combined/sdklib.stubs.jar", + }, + { + desc: "Prebuilt library v2 is selected using apex_contributions", + selectedDependencyName: "prebuilt_sdklib.v2", + expectedStubPath: "out/soong/.intermediates/prebuilt_sdklib.v2.stubs/android_common/combined/sdklib.stubs.jar", + }, + } + + fixture := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("sdklib", "sdklib.v1", "sdklib.v2"), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions", + } + }), + ) + + for _, tc := range testCases { + result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName)) + + // Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions + public := result.ModuleForTests("mymodule", "android_common") + rule := public.Output("javac/mymodule.jar") + inputs := rule.Implicits.Strings() + android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, tc.expectedStubPath) + } +}