Support generating sdk snapshot for specific build release

Previously, the sdk snapshot was assumed to be generated for the
current build system. This change adds support for the
SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE environment variable which can
be used to select the target build release in which the generated
snapshot will be used.

At the moment this will only affect the properties that are output but
if/when it becomes necessary it can also be used to control more
aspects of the snapshots such as supported member types or even
members.

This change does not modify any properties that are build release
specific. That will come in following changes. However, it does add a
test that targets build release S which defines a baseline for
properties that will be affected in following changes. That baseline
makes it easier to see the effect of those follow up changes.

Bug: 197842263
Test: m nothing
Change-Id: I5cfde5e9e86af522b0d5030d301e116b0233fd62
Merged-In: I5cfde5e9e86af522b0d5030d301e116b0233fd62
(cherry picked from commit ef2df587be)
This commit is contained in:
Paul Duffin 2021-09-24 14:58:27 +01:00
parent 3ea9205285
commit 24c545e317
4 changed files with 170 additions and 3 deletions

View file

@ -15,11 +15,13 @@
package sdk
import (
"android/soong/android"
"log"
"os"
"testing"
"android/soong/android"
"android/soong/java"
"github.com/google/blueprint/proptools"
)
@ -661,4 +663,86 @@ sdk_snapshot {
snapshotTestPreparer(checkSnapshotWithoutSource, android.FixtureWithRootAndroidBp(bp)),
)
})
t.Run("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S", func(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("mysdklibrary"),
android.FixtureWithRootAndroidBp(`
sdk {
name: "mysdk",
bootclasspath_fragments: ["mybootclasspathfragment"],
}
bootclasspath_fragment {
name: "mybootclasspathfragment",
apex_available: ["myapex"],
contents: ["mysdklibrary"],
}
java_sdk_library {
name: "mysdklibrary",
srcs: ["Test.java"],
compile_dex: true,
public: {enabled: true},
permitted_packages: ["mysdklibrary"],
}
`),
android.FixtureMergeEnv(map[string]string{
"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S",
}),
).RunTest(t)
CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
prebuilt_bootclasspath_fragment {
name: "mybootclasspathfragment",
prefer: false,
visibility: ["//visibility:public"],
apex_available: ["myapex"],
contents: ["mysdklibrary"],
hidden_api: {
stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
all_flags: "hiddenapi/all-flags.csv",
},
}
java_sdk_library_import {
name: "mysdklibrary",
prefer: false,
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
shared_library: true,
compile_dex: true,
permitted_packages: ["mysdklibrary"],
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",
},
}
`),
checkAllCopyRules(`
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/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
`),
)
})
}

View file

@ -136,6 +136,7 @@ func getSdkSnapshotBuildInfo(t *testing.T, result *android.TestResult, sdk *sdk)
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(),
snapshotTestCustomizations: map[snapshotTest]*snapshotTestCustomization{},
targetBuildRelease: sdk.builderForTests.targetBuildRelease,
}
buildParams := sdk.BuildParamsForTests()
@ -253,6 +254,13 @@ func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir st
}
fs[filepath.Join(snapshotSubDir, "Android.bp")] = []byte(snapshotBuildInfo.androidBpContents)
// If the generated snapshot builders not for the current release then it cannot be loaded by
// the current release.
currentBuildRelease := latestBuildRelease()
if snapshotBuildInfo.targetBuildRelease != currentBuildRelease {
return
}
// The preparers from the original source fixture.
sourcePreparers := result.Preparer()
@ -476,6 +484,9 @@ type snapshotBuildInfo struct {
// The final output zip.
outputZip string
// The target build release.
targetBuildRelease *buildRelease
// The test specific customizations for each snapshot test.
snapshotTestCustomizations map[snapshotTest]*snapshotTestCustomization
}

View file

@ -50,6 +50,19 @@ import (
// snapshot module only. The zip file containing the generated snapshot will be
// <sdk-name>-<number>.zip.
//
// SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE
// This allows the target build release (i.e. the release version of the build within which
// the snapshot will be used) of the snapshot to be specified. If unspecified then it defaults
// to the current build release version. Otherwise, it must be the name of one of the build
// releases defined in nameToBuildRelease, e.g. S, T, etc..
//
// The generated snapshot must only be used in the specified target release. If the target
// build release is not the current build release then the generated Android.bp file not be
// checked for compatibility.
//
// e.g. if setting SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S will cause the generated snapshot
// to be compatible with S.
//
var pctx = android.NewPackageContext("android/soong/sdk")
@ -319,6 +332,14 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) andro
snapshotZipFileSuffix = "-" + version
}
currentBuildRelease := latestBuildRelease()
targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", currentBuildRelease.name)
targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv)
if err != nil {
ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err)
targetBuildRelease = currentBuildRelease
}
builder := &snapshotBuilder{
ctx: ctx,
sdk: s,
@ -330,6 +351,7 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) andro
prebuiltModules: make(map[string]*bpModule),
allMembersByName: allMembersByName,
exportedMembersByName: exportedMembersByName,
targetBuildRelease: targetBuildRelease,
}
s.builderForTests = builder
@ -402,7 +424,11 @@ be unnecessary as every module in the sdk already has its own licenses property.
generateBpContents(&bp.generatedContents, bpFile)
contents := bp.content.String()
syntaxCheckSnapshotBpFile(ctx, contents)
// If the snapshot is being generated for the current build release then check the syntax to make
// sure that it is compatible.
if targetBuildRelease == currentBuildRelease {
syntaxCheckSnapshotBpFile(ctx, contents)
}
bp.build(pctx, ctx, nil)
@ -939,6 +965,9 @@ type snapshotBuilder struct {
// The set of exported members by name.
exportedMembersByName map[string]struct{}
// The target build release for which the snapshot is to be generated.
targetBuildRelease *buildRelease
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@ -1303,6 +1332,16 @@ func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType,
return osInfo
}
func (osInfo *osTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
if len(osInfo.archInfos) == 0 {
pruner.pruneProperties(osInfo.Properties)
} else {
for _, archInfo := range osInfo.archInfos {
archInfo.pruneUnsupportedProperties(pruner)
}
}
}
// Optimize the properties by extracting common properties from arch type specific
// properties into os type specific properties.
func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
@ -1472,6 +1511,16 @@ func getLinkType(variant android.Module) string {
return linkType
}
func (archInfo *archTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
if len(archInfo.imageVariantInfos) == 0 {
pruner.pruneProperties(archInfo.Properties)
} else {
for _, imageVariantInfo := range archInfo.imageVariantInfos {
imageVariantInfo.pruneUnsupportedProperties(pruner)
}
}
}
// Optimize the properties by extracting common properties from link type specific
// properties into arch type specific properties.
func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
@ -1557,6 +1606,16 @@ func newImageVariantSpecificInfo(ctx android.SdkMemberContext, imageVariant stri
return imageInfo
}
func (imageInfo *imageVariantSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
if len(imageInfo.linkInfos) == 0 {
pruner.pruneProperties(imageInfo.Properties)
} else {
for _, linkInfo := range imageInfo.linkInfos {
linkInfo.pruneUnsupportedProperties(pruner)
}
}
}
// Optimize the properties by extracting common properties from link type specific
// properties into arch type specific properties.
func (imageInfo *imageVariantSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
@ -1623,6 +1682,10 @@ func (l *linkTypeSpecificInfo) addToPropertySet(ctx *memberContext, propertySet
addSdkMemberPropertiesToSet(ctx, l.Properties, linkPropertySet)
}
func (l *linkTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
pruner.pruneProperties(l.Properties)
}
func (l *linkTypeSpecificInfo) String() string {
return fmt.Sprintf("LinkType{%s}", l.linkType)
}
@ -1655,12 +1718,13 @@ func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModu
memberType := member.memberType
// Do not add the prefer property if the member snapshot module is a source module type.
config := ctx.sdkMemberContext.Config()
if !memberType.UsesSourceModuleTypeInSnapshot() {
// Set the prefer based on the environment variable. This is a temporary work around to allow a
// snapshot to be created that sets prefer: true.
// TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
// dynamically at build time not at snapshot generation time.
prefer := ctx.sdkMemberContext.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
prefer := config.IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
// Set prefer. Setting this to false is not strictly required as that is the default but it does
// provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
@ -1691,6 +1755,11 @@ func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModu
commonProperties := variantPropertiesFactory()
commonProperties.Base().Os = android.CommonOS
// Create a property pruner that will prune any properties unsupported by the target build
// release.
targetBuildRelease := ctx.builder.targetBuildRelease
unsupportedPropertyPruner := newPropertyPrunerByBuildRelease(commonProperties, targetBuildRelease)
// Create common value extractor that can be used to optimize the properties.
commonValueExtractor := newCommonValueExtractor(commonProperties)
@ -1705,6 +1774,8 @@ func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModu
// independent properties structs.
osSpecificPropertiesContainers = append(osSpecificPropertiesContainers, osInfo)
osInfo.pruneUnsupportedProperties(unsupportedPropertyPruner)
// Optimize the properties across all the variants for a specific os type.
osInfo.optimizeProperties(ctx, commonValueExtractor)
}

View file

@ -163,6 +163,7 @@ var BannerVars = []string{
"AUX_OS_VARIANT_LIST",
"PRODUCT_SOONG_NAMESPACES",
"SOONG_SDK_SNAPSHOT_PREFER",
"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE",
"SOONG_SDK_SNAPSHOT_VERSION",
}