Exclude unsupported libraries from sdk snapshot
When an sdk snapshot is targeted at release X then it cannot include
bootclasspath fragment libraries which are not present in that build as
otherwise it causes build failures. It should also not include any
unsupported libraries, i.e. libraries that cannot work on that release.
This change causes sdk snapshot to exclude libraries that have a
min_sdk_version > target build release
It also ensures that hidden API flags do not include any information
from excluded libraries.
Bug: 240406019
Test: BUILD_NUMBER=fixed packages/modules/common/build/mainline_modules_sdks.sh
# Ran the previous command with and without this change to make
# sure that this change excludes framework-connectivity-t library from the
# tethering sdk snapshot for S, including from the hidden API flag files.
Change-Id: I57969b85a12e9e5a3fc76c055b260cec5d5f7d7f
diff --git a/android/sdk.go b/android/sdk.go
index a477cba..a9cc547 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -74,6 +74,26 @@
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 919181d..62683a4 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -257,7 +257,7 @@
// 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 @@
// 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 @@
// 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) 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 @@
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 @@
// 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 @@
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 @@
}
// 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 af11889..5474ae1 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -1041,8 +1041,11 @@
// 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 @@
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 @@
// * 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 @@
// 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 @@
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 @@
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 c93055a..4be0ace 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -895,3 +895,222 @@
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 7ab5285..d598834 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1004,7 +1004,7 @@
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 1ec12c3..8b8e1d7 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -482,6 +482,7 @@
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 5c9376b..81f3672 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -211,11 +211,14 @@
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 @@
// <arch>/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 @@
// 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) {
+ addMember := func(name string, export bool, exclude bool) {
+ if exclude {
+ excludedMembersByName[name] = struct{}{}
+ return
+ }
+
allMembersByName[name] = struct{}{}
if export {
exportedMembersByName[name] = struct{}{}
@@ -362,11 +389,15 @@
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 @@
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 @@
prebuiltModules: make(map[string]*bpModule),
allMembersByName: allMembersByName,
exportedMembersByName: exportedMembersByName,
+ excludedMembersByName: excludedMembersByName,
targetBuildRelease: targetBuildRelease,
}
s.builderForTests = builder
@@ -437,6 +460,10 @@
}
name := member.name
+ if _, ok := excludedMembersByName[name]; ok {
+ continue
+ }
+
requiredTraits := traits[name]
if requiredTraits == nil {
requiredTraits = android.EmptySdkMemberTraitSet()
@@ -1034,6 +1061,9 @@
// 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) 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 @@
// 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)