diff --git a/android/sdk.go b/android/sdk.go index a477cbaaf..a9cc547e0 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -74,6 +74,26 @@ type SdkAware interface { sdkAwareWithoutModule } +// minApiLevelForSdkSnapshot provides access to the min_sdk_version for MinApiLevelForSdkSnapshot +type minApiLevelForSdkSnapshot interface { + MinSdkVersion(ctx EarlyModuleContext) SdkSpec +} + +// MinApiLevelForSdkSnapshot returns the ApiLevel of the min_sdk_version of the supplied module. +// +// If the module does not provide a min_sdk_version then it defaults to 1. +func MinApiLevelForSdkSnapshot(ctx EarlyModuleContext, module Module) ApiLevel { + minApiLevel := NoneApiLevel + if m, ok := module.(minApiLevelForSdkSnapshot); ok { + minApiLevel = m.MinSdkVersion(ctx).ApiLevel + } + if minApiLevel == NoneApiLevel { + // The default min API level is 1. + minApiLevel = uncheckedFinalApiLevel(1) + } + return minApiLevel +} + // SdkRef refers to a version of an SDK type SdkRef struct { Name string diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index 919181dbe..62683a4d3 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -257,7 +257,7 @@ type commonBootclasspathFragment interface { // Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the // module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a // versioned sdk. - produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput + produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput // produceBootImageFiles will attempt to produce rules to create the boot image files at the paths // predefined in the bootImageConfig. @@ -761,7 +761,7 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // Delegate the production of the hidden API all-flags.csv file to a module type specific method. common := ctx.Module().(commonBootclasspathFragment) - output := common.produceHiddenAPIOutput(ctx, contents, input) + output := common.produceHiddenAPIOutput(ctx, contents, fragments, input) // If the source or prebuilts module does not provide a signature patterns file then generate one // from the flags. @@ -769,7 +769,7 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // their own. if output.SignaturePatternsPath == nil { output.SignaturePatternsPath = buildRuleSignaturePatternsFile( - ctx, output.AllFlagsPath, []string{"*"}, nil, nil) + ctx, output.AllFlagsPath, []string{"*"}, nil, nil, "") } // Initialize a HiddenAPIInfo structure. @@ -863,7 +863,7 @@ func (b *BootclasspathFragmentModule) isTestFragment() bool { func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput { // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the // paths to the created files. - flagOutput := hiddenAPIFlagRulesForBootclasspathFragment(ctx, bootDexInfoByModule, contents, input) + flagOutput := hiddenAPIFlagRulesForBootclasspathFragment(ctx, bootDexInfoByModule, contents, input, suffix) // If the module specifies split_packages or package_prefixes then use those to generate the // signature patterns. @@ -872,7 +872,7 @@ func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.Mod singlePackages := input.SinglePackages if splitPackages != nil || packagePrefixes != nil || singlePackages != nil { flagOutput.SignaturePatternsPath = buildRuleSignaturePatternsFile( - ctx, flagOutput.AllFlagsPath, splitPackages, packagePrefixes, singlePackages) + ctx, flagOutput.AllFlagsPath, splitPackages, packagePrefixes, singlePackages, suffix) } else if !b.isTestFragment() { ctx.ModuleErrorf(`Must specify at least one of the split_packages, package_prefixes and single_packages properties If this is a new bootclasspath_fragment or you are unsure what to do add the @@ -889,7 +889,7 @@ func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.Mod // produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files) // for the fragment as well as encoding the flags in the boot dex jars. -func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { // Gather information about the boot dex files for the boot libraries provided by this fragment. bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents) @@ -905,7 +905,41 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC EncodedBootDexFilesByModule: encodedBootDexFilesByModule, } - flagFilesByCategory := input.FlagFilesByCategory + // Get the ApiLevel associated with SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE, defaulting to current + // if not set. + config := ctx.Config() + targetApiLevel := android.ApiLevelOrPanic(ctx, + config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", "current")) + + // Filter the contents list to remove any modules that do not support the target build release. + // The current build release supports all the modules. + contentsForSdkSnapshot := []android.Module{} + for _, module := range contents { + // If the module has a min_sdk_version that is higher than the target build release then it will + // not work on the target build release and so must not be included in the sdk snapshot. + minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, module) + if minApiLevel.GreaterThan(targetApiLevel) { + continue + } + + contentsForSdkSnapshot = append(contentsForSdkSnapshot, module) + } + + var flagFilesByCategory FlagFilesByCategory + if len(contentsForSdkSnapshot) != len(contents) { + // The sdk snapshot has different contents to the runtime fragment so it is not possible to + // reuse the hidden API information generated for the fragment. So, recompute that information + // for the sdk snapshot. + filteredInput := b.createHiddenAPIFlagInput(ctx, contentsForSdkSnapshot, fragments) + + // Gather information about the boot dex files for the boot libraries provided by this fragment. + filteredBootDexInfoByModule := extractBootDexInfoFromModules(ctx, contentsForSdkSnapshot) + flagOutput = b.generateHiddenApiFlagRules(ctx, contentsForSdkSnapshot, filteredInput, filteredBootDexInfoByModule, "-for-sdk-snapshot") + flagFilesByCategory = filteredInput.FlagFilesByCategory + } else { + // The sdk snapshot has the same contents as the runtime fragment so reuse that information. + flagFilesByCategory = input.FlagFilesByCategory + } // Make the information available for the sdk snapshot. ctx.SetProvider(HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{ @@ -1219,7 +1253,7 @@ func (module *PrebuiltBootclasspathFragmentModule) Name() string { } // produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified. -func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path { if src == nil { return defaultPath diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index af1188903..5474ae11e 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -1041,8 +1041,11 @@ func (s SignatureCsvSubsets) RelativeToTop() []string { // patterns that will select a subset of the monolithic flags. func buildRuleSignaturePatternsFile( ctx android.ModuleContext, flagsPath android.Path, - splitPackages []string, packagePrefixes []string, singlePackages []string) android.Path { - patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv") + splitPackages []string, packagePrefixes []string, singlePackages []string, + suffix string) android.Path { + hiddenApiSubDir := "modular-hiddenapi" + suffix + + patternsFile := android.PathForModuleOut(ctx, hiddenApiSubDir, "signature-patterns.csv") // Create a rule to validate the output from the following rule. rule := android.NewRuleBuilder(pctx, ctx) @@ -1059,7 +1062,7 @@ func buildRuleSignaturePatternsFile( FlagForEachArg("--package-prefix ", packagePrefixes). FlagForEachArg("--single-package ", singlePackages). FlagWithOutput("--output ", patternsFile) - rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns") + rule.Build("hiddenAPISignaturePatterns"+suffix, "hidden API signature patterns"+suffix) return patternsFile } @@ -1147,27 +1150,27 @@ func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name strin // * metadata.csv // * index.csv // * all-flags.csv -func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput) HiddenAPIFlagOutput { - hiddenApiSubDir := "modular-hiddenapi" +func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput { + hiddenApiSubDir := "modular-hiddenapi" + suffix // Generate the stub-flags.csv. stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv") - buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil) + buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile"+suffix, "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil) // Extract the classes jars from the contents. classesJars := extractClassesJarsFromModules(contents) // Generate the set of flags from the annotations in the source code. annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv") - buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV) + buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags"+suffix, classesJars, stubFlagsCSV, annotationFlagsCSV) // Generate the metadata from the annotations in the source code. metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv") - buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV) + buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata"+suffix, classesJars, stubFlagsCSV, metadataCSV) // Generate the index file from the CSV files in the classes jars. indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv") - buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV) + buildRuleToGenerateIndex(ctx, "modular hiddenapi index"+suffix, classesJars, indexCSV) // Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files // containing dex signatures of all the removed APIs. In the monolithic files that is done by @@ -1175,25 +1178,25 @@ func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootD // signatures, see the combined-removed-dex module. This does that automatically by using the // *removed.txt files retrieved from the java_sdk_library modules that are specified in the // stub_libs and contents properties of a bootclasspath_fragment. - removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles) + removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, suffix, input.RemovedTxtFiles) // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex // files. allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv") - buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures) + buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags"+suffix, "modular hiddenapi all flags"+suffix, allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures) // Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be // compared against the monolithic stub flags. filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv") - buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags", - "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV, + buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags"+suffix, + "modular hiddenapi filtered stub flags"+suffix, stubFlagsCSV, filteredStubFlagsCSV, HIDDENAPI_STUB_FLAGS_IMPL_FLAGS) // Generate the filtered-flags.csv file which contains the filtered flags that will be compared // against the monolithic flags. filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv") - buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags", - "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV, + buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags"+suffix, + "modular hiddenapi filtered flags"+suffix, allFlagsCSV, filteredFlagsCSV, HIDDENAPI_FLAGS_CSV_IMPL_FLAGS) // Store the paths in the info for use by other modules and sdk snapshot generation. @@ -1223,12 +1226,12 @@ func hiddenAPIEncodeRulesForBootclasspathFragment(ctx android.ModuleContext, boo return encodedBootDexJarsByModule } -func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath { +func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix string, removedTxtFiles android.Paths) android.OptionalPath { if len(removedTxtFiles) == 0 { return android.OptionalPath{} } - output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt") + output := android.PathForModuleOut(ctx, "module-hiddenapi"+suffix, "removed-dex-signatures.txt") rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). @@ -1236,7 +1239,7 @@ func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedT Flag("--no-banner"). Inputs(removedTxtFiles). FlagWithOutput("--dex-api ", output) - rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures") + rule.Build("modular-hiddenapi-removed-dex-signatures"+suffix, "modular hiddenapi removed dex signatures"+suffix) return android.OptionalPathForPath(output) } diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index c93055a51..4be0ace68 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -895,3 +895,222 @@ my-unsupported-packages.txt -> hiddenapi/my-unsupported-packages.txt snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot), ) } + +func testSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T, targetBuildRelease string, + expectedSdkSnapshot string, + expectedCopyRules string, + expectedStubFlagsInputs []string, + suffix string) { + + result := android.GroupFixturePreparers( + prepareForSdkTestWithJava, + java.PrepareForTestWithJavaDefaultModules, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.FixtureWithLastReleaseApis("mysdklibrary", "mynewsdklibrary"), + java.FixtureConfigureApexBootJars("myapex:mysdklibrary", "myapex:mynewsdklibrary"), + prepareForSdkTestWithApex, + + // Add a platform_bootclasspath that depends on the fragment. + fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"), + + android.FixtureMergeEnv(map[string]string{ + "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease, + }), + + android.FixtureWithRootAndroidBp(` + sdk { + name: "mysdk", + apexes: ["myapex"], + } + + apex { + name: "myapex", + key: "myapex.key", + min_sdk_version: "S", + bootclasspath_fragments: ["mybootclasspathfragment"], + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + apex_available: ["myapex"], + contents: [ + "mysdklibrary", + "mynewsdklibrary", + ], + + hidden_api: { + split_packages: [], + }, + } + + java_sdk_library { + name: "mysdklibrary", + apex_available: ["myapex"], + srcs: ["Test.java"], + shared_library: false, + public: {enabled: true}, + min_sdk_version: "S", + } + + java_sdk_library { + name: "mynewsdklibrary", + apex_available: ["myapex"], + srcs: ["Test.java"], + compile_dex: true, + public: {enabled: true}, + min_sdk_version: "Tiramisu", + permitted_packages: ["mynewsdklibrary"], + } + `), + ).RunTest(t) + + bcpf := result.ModuleForTests("mybootclasspathfragment", "android_common") + rule := bcpf.Output("out/soong/.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi" + suffix + "/stub-flags.csv") + android.AssertPathsRelativeToTopEquals(t, "stub flags inputs", expectedStubFlagsInputs, rule.Implicits) + + CheckSnapshot(t, result, "mysdk", "", + checkAndroidBpContents(expectedSdkSnapshot), + checkAllCopyRules(expectedCopyRules), + ) +} + +func TestSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T) { + t.Run("target S build", func(t *testing.T) { + expectedSnapshot := ` +// This is auto-generated. DO NOT EDIT. + +prebuilt_bootclasspath_fragment { + name: "mybootclasspathfragment", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + contents: ["mysdklibrary"], + hidden_api: { + annotation_flags: "hiddenapi/annotation-flags.csv", + metadata: "hiddenapi/metadata.csv", + index: "hiddenapi/index.csv", + stub_flags: "hiddenapi/stub-flags.csv", + all_flags: "hiddenapi/all-flags.csv", + }, +} + +java_sdk_library_import { + name: "mysdklibrary", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + shared_library: false, + public: { + jars: ["sdk_library/public/mysdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"], + current_api: "sdk_library/public/mysdklibrary.txt", + removed_api: "sdk_library/public/mysdklibrary-removed.txt", + sdk_version: "current", + }, +} +` + expectedCopyRules := ` +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/annotation-flags.csv -> hiddenapi/annotation-flags.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/metadata.csv -> hiddenapi/metadata.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/index.csv -> hiddenapi/index.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/stub-flags.csv -> hiddenapi/stub-flags.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/all-flags.csv -> hiddenapi/all-flags.csv +.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar +.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt +.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt +` + + // On S the stub flags should only be generated from mysdklibrary as mynewsdklibrary is not part + // of the snapshot. + expectedStubFlagsInputs := []string{ + "out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar", + "out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar", + } + + testSnapshotWithBootClasspathFragment_MinSdkVersion(t, "S", + expectedSnapshot, expectedCopyRules, expectedStubFlagsInputs, "-for-sdk-snapshot") + }) + + t.Run("target-Tiramisu-build", func(t *testing.T) { + expectedSnapshot := ` +// This is auto-generated. DO NOT EDIT. + +prebuilt_bootclasspath_fragment { + name: "mybootclasspathfragment", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + contents: [ + "mysdklibrary", + "mynewsdklibrary", + ], + hidden_api: { + annotation_flags: "hiddenapi/annotation-flags.csv", + metadata: "hiddenapi/metadata.csv", + index: "hiddenapi/index.csv", + signature_patterns: "hiddenapi/signature-patterns.csv", + filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv", + filtered_flags: "hiddenapi/filtered-flags.csv", + }, +} + +java_sdk_library_import { + name: "mysdklibrary", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + shared_library: false, + public: { + jars: ["sdk_library/public/mysdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"], + current_api: "sdk_library/public/mysdklibrary.txt", + removed_api: "sdk_library/public/mysdklibrary-removed.txt", + sdk_version: "current", + }, +} + +java_sdk_library_import { + name: "mynewsdklibrary", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + shared_library: true, + compile_dex: true, + permitted_packages: ["mynewsdklibrary"], + public: { + jars: ["sdk_library/public/mynewsdklibrary-stubs.jar"], + stub_srcs: ["sdk_library/public/mynewsdklibrary_stub_sources"], + current_api: "sdk_library/public/mynewsdklibrary.txt", + removed_api: "sdk_library/public/mynewsdklibrary-removed.txt", + sdk_version: "current", + }, +} +` + expectedCopyRules := ` +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/index.csv -> hiddenapi/index.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv +.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv +.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar +.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt +.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt +.intermediates/mynewsdklibrary.stubs/android_common/javac/mynewsdklibrary.stubs.jar -> sdk_library/public/mynewsdklibrary-stubs.jar +.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_api.txt -> sdk_library/public/mynewsdklibrary.txt +.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_removed.txt -> sdk_library/public/mynewsdklibrary-removed.txt +` + + // On tiramisu the stub flags should be generated from both mynewsdklibrary and mysdklibrary as + // they are both part of the snapshot. + expectedStubFlagsInputs := []string{ + "out/soong/.intermediates/mynewsdklibrary.stubs/android_common/dex/mynewsdklibrary.stubs.jar", + "out/soong/.intermediates/mynewsdklibrary/android_common/aligned/mynewsdklibrary.jar", + "out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar", + "out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar", + } + + testSnapshotWithBootClasspathFragment_MinSdkVersion(t, "Tiramisu", + expectedSnapshot, expectedCopyRules, expectedStubFlagsInputs, "") + }) +} diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 7ab5285c6..d59883435 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -1004,7 +1004,7 @@ func TestSnapshotWithJavaSdkLibrary_AnnotationsZip_PreT(t *testing.T) { java_sdk_library { name: "myjavalib", srcs: ["Test.java"], - sdk_version: "current", + sdk_version: "S", shared_library: false, annotations_enabled: true, public: { diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 1ec12c346..8b8e1d701 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -482,6 +482,7 @@ java_import { name: "mysdklibrary", srcs: ["Test.java"], compile_dex: true, + sdk_version: "S", public: {enabled: true}, permitted_packages: ["mysdklibrary"], } diff --git a/sdk/update.go b/sdk/update.go index 5c9376b5d..81f3672fc 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -211,11 +211,14 @@ func (s *sdk) collectMembers(ctx android.ModuleContext) { container = parent.(android.SdkAware) } + minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, child) + export := memberTag.ExportMember() s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{ sdkVariant: s, memberType: memberType, variant: child.(android.SdkAware), + minApiLevel: minApiLevel, container: container, export: export, exportedComponentsInfo: exportedComponentsInfo, @@ -332,10 +335,28 @@ const BUILD_NUMBER_FILE = "snapshot-creation-build-number.txt" // /lib/ // libFoo.so : a stub library +func (s sdk) targetBuildRelease(ctx android.ModuleContext) *buildRelease { + config := ctx.Config() + targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", buildReleaseCurrent.name) + targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv) + if err != nil { + ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err) + targetBuildRelease = buildReleaseCurrent + } + + return targetBuildRelease +} + // buildSnapshot is the main function in this source file. It creates rules to copy // the contents (header files, stub libraries, etc) into the zip file. func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) { + targetBuildRelease := s.targetBuildRelease(ctx) + targetApiLevel, err := android.ApiLevelFromUser(ctx, targetBuildRelease.name) + if err != nil { + targetApiLevel = android.FutureApiLevel + } + // Aggregate all the sdkMemberVariantDep instances from all the sdk variants. hasLicenses := false var memberVariantDeps []sdkMemberVariantDep @@ -346,12 +367,18 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) { // Filter out any sdkMemberVariantDep that is a component of another. memberVariantDeps = filterOutComponents(ctx, memberVariantDeps) - // Record the names of all the members, both explicitly specified and implicitly - // included. + // Record the names of all the members, both explicitly specified and implicitly included. Also, + // record the names of any members that should be excluded from this snapshot. allMembersByName := make(map[string]struct{}) exportedMembersByName := make(map[string]struct{}) + excludedMembersByName := make(map[string]struct{}) + + addMember := func(name string, export bool, exclude bool) { + if exclude { + excludedMembersByName[name] = struct{}{} + return + } - addMember := func(name string, export bool) { allMembersByName[name] = struct{}{} if export { exportedMembersByName[name] = struct{}{} @@ -362,11 +389,15 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) { name := memberVariantDep.variant.Name() export := memberVariantDep.export - addMember(name, export) + // If the minApiLevel of the member is greater than the target API level then exclude it from + // this snapshot. + exclude := memberVariantDep.minApiLevel.GreaterThan(targetApiLevel) + + addMember(name, export, exclude) // Add any components provided by the module. for _, component := range memberVariantDep.exportedComponentsInfo.Components { - addMember(component, export) + addMember(component, export, exclude) } if memberVariantDep.memberType == android.LicenseModuleSdkMemberType { @@ -382,18 +413,9 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) { modules: make(map[string]*bpModule), } - config := ctx.Config() - // Always add -current to the end snapshotFileSuffix := "-current" - targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", buildReleaseCurrent.name) - targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv) - if err != nil { - ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err) - targetBuildRelease = buildReleaseCurrent - } - builder := &snapshotBuilder{ ctx: ctx, sdk: s, @@ -404,6 +426,7 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) { prebuiltModules: make(map[string]*bpModule), allMembersByName: allMembersByName, exportedMembersByName: exportedMembersByName, + excludedMembersByName: excludedMembersByName, targetBuildRelease: targetBuildRelease, } s.builderForTests = builder @@ -437,6 +460,10 @@ be unnecessary as every module in the sdk already has its own licenses property. } name := member.name + if _, ok := excludedMembersByName[name]; ok { + continue + } + requiredTraits := traits[name] if requiredTraits == nil { requiredTraits = android.EmptySdkMemberTraitSet() @@ -1034,6 +1061,9 @@ type snapshotBuilder struct { // The set of exported members by name. exportedMembersByName map[string]struct{} + // The set of members which have been excluded from this snapshot; by name. + excludedMembersByName map[string]struct{} + // The target build release for which the snapshot is to be generated. targetBuildRelease *buildRelease @@ -1218,6 +1248,9 @@ func (s *snapshotBuilder) snapshotSdkMemberName(name string, required bool) stri func (s *snapshotBuilder) snapshotSdkMemberNames(members []string, required bool) []string { var references []string = nil for _, m := range members { + if _, ok := s.excludedMembersByName[m]; ok { + continue + } references = append(references, s.snapshotSdkMemberName(m, required)) } return references @@ -1260,6 +1293,9 @@ type sdkMemberVariantDep struct { // The names of additional component modules provided by the variant. exportedComponentsInfo android.ExportedComponentsInfo + + // The minimum API level on which this module is supported. + minApiLevel android.ApiLevel } var _ android.SdkMember = (*sdkMember)(nil)