Add apexes property to sdk

Specifying an apex in the apexes propety will cause all the
*classpath_fragments that are contents of the APEX to be automatically
added as members of the sdk and appear in the snapshot.

The purpose of this change is to dedup the APEX and sdk definitions and
try and avoid some of the issues that we have been finding while
attempting to build against the prebuilts.

Two tests, one each for bootclasspath_fragment and
systemserverclasspath_fragment, have been refactored to compare the
output when adding the *fragment to the sdk directly of via the APEX.
That ensures switching to use the APEX will not change the sdk snapshot
unless it was previously missing a *fragment.

There was also a slight difference in where the hidden API flags were
copied from. That should have no impact on the output as the flags are
identical.

The sdk snapshot generation needed some tweaks to avoid generating a
prebuilt for the APEX.

Bug: 232401814
Test: m nothing
Change-Id: I7aaf16a3a0ab4bebf97765d1484215cc008dc4b8
This commit is contained in:
Paul Duffin
2022-05-13 13:12:19 +00:00
parent 014fded49d
commit 4e7d1c43e2
9 changed files with 404 additions and 71 deletions

View File

@@ -433,6 +433,9 @@ be unnecessary as every module in the sdk already has its own licenses property.
traits := s.gatherTraits()
for _, member := range members {
memberType := member.memberType
if !memberType.ArePrebuiltsRequired() {
continue
}
name := member.name
requiredTraits := traits[name]
@@ -1319,6 +1322,119 @@ func (m multilibUsage) String() string {
}
}
// TODO(187910671): BEGIN - Remove once modules do not have an APEX and default variant.
// variantCoordinate contains the coordinates used to identify a variant of an SDK member.
type variantCoordinate struct {
// osType identifies the OS target of a variant.
osType android.OsType
// archId identifies the architecture and whether it is for the native bridge.
archId archId
// image is the image variant name.
image string
// linkType is the link type name.
linkType string
}
func getVariantCoordinate(ctx *memberContext, variant android.Module) variantCoordinate {
linkType := ""
if len(ctx.MemberType().SupportedLinkages()) > 0 {
linkType = getLinkType(variant)
}
return variantCoordinate{
osType: variant.Target().Os,
archId: archIdFromTarget(variant.Target()),
image: variant.ImageVariation().Variation,
linkType: linkType,
}
}
// selectApexVariantsWhereAvailable filters the input list of variants by selecting the APEX
// specific variant for a specific variantCoordinate when there is both an APEX and default variant.
//
// There is a long-standing issue where a module that is added to an APEX has both an APEX and
// default/platform variant created even when the module does not require a platform variant. As a
// result an indirect dependency onto a module via the APEX will use the APEX variant, whereas a
// direct dependency onto the module will use the default/platform variant. That would result in a
// failure while attempting to optimize the properties for a member as it would have two variants
// when only one was expected.
//
// This function mitigates that problem by detecting when there are two variants that differ only
// by apex variant, where one is the default/platform variant and one is the APEX variant. In that
// case it picks the APEX variant. It picks the APEX variant because that is the behavior that would
// be expected
func selectApexVariantsWhereAvailable(ctx *memberContext, variants []android.SdkAware) []android.SdkAware {
moduleCtx := ctx.sdkMemberContext
// Group the variants by coordinates.
variantsByCoord := make(map[variantCoordinate][]android.SdkAware)
for _, variant := range variants {
coord := getVariantCoordinate(ctx, variant)
variantsByCoord[coord] = append(variantsByCoord[coord], variant)
}
toDiscard := make(map[android.SdkAware]struct{})
for coord, list := range variantsByCoord {
count := len(list)
if count == 1 {
continue
}
variantsByApex := make(map[string]android.SdkAware)
conflictDetected := false
for _, variant := range list {
apexInfo := moduleCtx.OtherModuleProvider(variant, android.ApexInfoProvider).(android.ApexInfo)
apexVariationName := apexInfo.ApexVariationName
// If there are two variants for a specific APEX variation then there is conflict.
if _, ok := variantsByApex[apexVariationName]; ok {
conflictDetected = true
break
}
variantsByApex[apexVariationName] = variant
}
// If there are more than 2 apex variations or one of the apex variations is not the
// default/platform variation then there is a conflict.
if len(variantsByApex) != 2 {
conflictDetected = true
} else if _, ok := variantsByApex[""]; !ok {
conflictDetected = true
}
// If there are no conflicts then add the default/platform variation to the list to remove.
if !conflictDetected {
toDiscard[variantsByApex[""]] = struct{}{}
continue
}
// There are duplicate variants at this coordinate and they are not the default and APEX variant
// so fail.
variantDescriptions := []string{}
for _, m := range list {
variantDescriptions = append(variantDescriptions, fmt.Sprintf(" %s", m.String()))
}
moduleCtx.ModuleErrorf("multiple conflicting variants detected for OsType{%s}, %s, Image{%s}, Link{%s}\n%s",
coord.osType, coord.archId.String(), coord.image, coord.linkType,
strings.Join(variantDescriptions, "\n"))
}
// If there are any variants to discard then remove them from the list of variants, while
// preserving the order.
if len(toDiscard) > 0 {
filtered := []android.SdkAware{}
for _, variant := range variants {
if _, ok := toDiscard[variant]; !ok {
filtered = append(filtered, variant)
}
}
variants = filtered
}
return variants
}
// TODO(187910671): END - Remove once modules do not have an APEX and default variant.
type baseInfo struct {
Properties android.SdkMemberProperties
}
@@ -1374,7 +1490,14 @@ func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType,
if commonVariants, ok := variantsByArchId[commonArchId]; ok {
if len(osTypeVariants) != 1 {
panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants)))
variants := []string{}
for _, m := range osTypeVariants {
variants = append(variants, fmt.Sprintf(" %s", m.String()))
}
panic(fmt.Errorf("expected to only have 1 variant of %q when arch type is common but found %d\n%s",
ctx.Name(),
len(osTypeVariants),
strings.Join(variants, "\n")))
}
// A common arch type only has one variant and its properties should be treated
@@ -1854,7 +1977,8 @@ 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()
moduleCtx := ctx.sdkMemberContext
config := moduleCtx.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.
@@ -1879,9 +2003,10 @@ func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModu
}
}
variants := selectApexVariantsWhereAvailable(ctx, member.variants)
// Group the variants by os type.
variantsByOsType := make(map[android.OsType][]android.Module)
variants := member.Variants()
for _, variant := range variants {
osType := variant.Target().Os
variantsByOsType[osType] = append(variantsByOsType[osType], variant)
@@ -1927,7 +2052,7 @@ func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModu
}
// Extract properties which are common across all architectures and os types.
extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
extractCommonProperties(moduleCtx, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
// Add the common properties to the module.
addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)