platform_build_soong/android/sdk.go
Paul Duffin 4e7d1c43e2 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
2022-07-06 15:58:43 +00:00

1022 lines
39 KiB
Go

// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package android
import (
"fmt"
"sort"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
// sdkAwareWithoutModule is provided simply to improve code navigation with the IDE.
type sdkAwareWithoutModule interface {
// SdkMemberComponentName will return the name to use for a component of this module based on the
// base name of this module.
//
// The baseName is the name returned by ModuleBase.BaseModuleName(), i.e. the name specified in
// the name property in the .bp file so will not include the prebuilt_ prefix.
//
// The componentNameCreator is a func for creating the name of a component from the base name of
// the module, e.g. it could just append ".component" to the name passed in.
//
// This is intended to be called by prebuilt modules that create component models. It is because
// prebuilt module base names come in a variety of different forms:
// * unversioned - this is the same as the source module.
// * internal to an sdk - this is the unversioned name prefixed by the base name of the sdk
// module.
// * versioned - this is the same as the internal with the addition of an "@<version>" suffix.
//
// While this can be called from a source module in that case it will behave the same way as the
// unversioned name and return the result of calling the componentNameCreator func on the supplied
// base name.
//
// e.g. Assuming the componentNameCreator func simply appends ".component" to the name passed in
// then this will work as follows:
// * An unversioned name of "foo" will return "foo.component".
// * An internal to the sdk name of "sdk_foo" will return "sdk_foo.component".
// * A versioned name of "sdk_foo@current" will return "sdk_foo.component@current".
//
// Note that in the latter case the ".component" suffix is added before the version. Adding it
// after would change the version.
SdkMemberComponentName(baseName string, componentNameCreator func(string) string) string
sdkBase() *SdkBase
MakeMemberOf(sdk SdkRef)
IsInAnySdk() bool
// IsVersioned determines whether the module is versioned, i.e. has a name of the form
// <name>@<version>
IsVersioned() bool
ContainingSdk() SdkRef
MemberName() string
}
// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
// built with SDK
type SdkAware interface {
Module
sdkAwareWithoutModule
}
// SdkRef refers to a version of an SDK
type SdkRef struct {
Name string
Version string
}
// Unversioned determines if the SdkRef is referencing to the unversioned SDK module
func (s SdkRef) Unversioned() bool {
return s.Version == ""
}
// String returns string representation of this SdkRef for debugging purpose
func (s SdkRef) String() string {
if s.Name == "" {
return "(No Sdk)"
}
if s.Unversioned() {
return s.Name
}
return s.Name + string(SdkVersionSeparator) + s.Version
}
// SdkVersionSeparator is a character used to separate an sdk name and its version
const SdkVersionSeparator = '@'
// ParseSdkRef parses a `name@version` style string into a corresponding SdkRef struct
func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef {
tokens := strings.Split(str, string(SdkVersionSeparator))
if len(tokens) < 1 || len(tokens) > 2 {
ctx.PropertyErrorf(property, "%q does not follow name@version syntax", str)
return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"}
}
name := tokens[0]
var version string
if len(tokens) == 2 {
version = tokens[1]
}
return SdkRef{Name: name, Version: version}
}
type SdkRefs []SdkRef
// Contains tells if the given SdkRef is in this list of SdkRef's
func (refs SdkRefs) Contains(s SdkRef) bool {
for _, r := range refs {
if r == s {
return true
}
}
return false
}
type sdkProperties struct {
// The SDK that this module is a member of. nil if it is not a member of any SDK
ContainingSdk *SdkRef `blueprint:"mutated"`
// Name of the module that this sdk member is representing
Sdk_member_name *string
}
// SdkBase is a struct that is expected to be included in module types to implement the SdkAware
// interface. InitSdkAwareModule should be called to initialize this struct.
type SdkBase struct {
properties sdkProperties
module SdkAware
}
func (s *SdkBase) sdkBase() *SdkBase {
return s
}
func (s *SdkBase) SdkMemberComponentName(baseName string, componentNameCreator func(string) string) string {
if s.MemberName() == "" {
return componentNameCreator(baseName)
} else {
index := strings.LastIndex(baseName, "@")
unversionedName := baseName[:index]
unversionedComponentName := componentNameCreator(unversionedName)
versionSuffix := baseName[index:]
return unversionedComponentName + versionSuffix
}
}
// MakeMemberOf sets this module to be a member of a specific SDK
func (s *SdkBase) MakeMemberOf(sdk SdkRef) {
s.properties.ContainingSdk = &sdk
}
// IsInAnySdk returns true if this module is a member of any SDK
func (s *SdkBase) IsInAnySdk() bool {
return s.properties.ContainingSdk != nil
}
// IsVersioned returns true if this module is versioned.
func (s *SdkBase) IsVersioned() bool {
return strings.Contains(s.module.Name(), "@")
}
// ContainingSdk returns the SDK that this module is a member of
func (s *SdkBase) ContainingSdk() SdkRef {
if s.properties.ContainingSdk != nil {
return *s.properties.ContainingSdk
}
return SdkRef{Name: "", Version: ""}
}
// MemberName returns the name of the module that this SDK member is overriding
func (s *SdkBase) MemberName() string {
return proptools.String(s.properties.Sdk_member_name)
}
// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
// SdkBase.
func InitSdkAwareModule(m SdkAware) {
base := m.sdkBase()
base.module = m
m.AddProperties(&base.properties)
}
// IsModuleInVersionedSdk returns true if the module is an versioned sdk.
func IsModuleInVersionedSdk(module Module) bool {
if s, ok := module.(SdkAware); ok {
if !s.ContainingSdk().Unversioned() {
return true
}
}
return false
}
// SnapshotBuilder provides support for generating the build rules which will build the snapshot.
type SnapshotBuilder interface {
// CopyToSnapshot generates a rule that will copy the src to the dest (which is a snapshot
// relative path) and add the dest to the zip.
CopyToSnapshot(src Path, dest string)
// EmptyFile returns the path to an empty file.
//
// This can be used by sdk member types that need to create an empty file in the snapshot, simply
// pass the value returned from this to the CopyToSnapshot() method.
EmptyFile() Path
// UnzipToSnapshot generates a rule that will unzip the supplied zip into the snapshot relative
// directory destDir.
UnzipToSnapshot(zipPath Path, destDir string)
// AddPrebuiltModule adds a new prebuilt module to the snapshot.
//
// It is intended to be called from SdkMemberType.AddPrebuiltModule which can add module type
// specific properties that are not variant specific. The following properties will be
// automatically populated before returning.
//
// * name
// * sdk_member_name
// * prefer
//
// Properties that are variant specific will be handled by SdkMemberProperties structure.
//
// Each module created by this method can be output to the generated Android.bp file in two
// different forms, depending on the setting of the SOONG_SDK_SNAPSHOT_VERSION build property.
// The two forms are:
// 1. A versioned Soong module that is referenced from a corresponding similarly versioned
// snapshot module.
// 2. An unversioned Soong module that.
//
// See sdk/update.go for more information.
AddPrebuiltModule(member SdkMember, moduleType string) BpModule
// SdkMemberReferencePropertyTag returns a property tag to use when adding a property to a
// BpModule that contains references to other sdk members.
//
// Using this will ensure that the reference is correctly output for both versioned and
// unversioned prebuilts in the snapshot.
//
// "required: true" means that the property must only contain references to other members of the
// sdk. Passing a reference to a module that is not a member of the sdk will result in a build
// error.
//
// "required: false" means that the property can contain references to modules that are either
// members or not members of the sdk. If a reference is to a module that is a non member then the
// reference is left unchanged, i.e. it is not transformed as references to members are.
//
// The handling of the member names is dependent on whether it is an internal or exported member.
// An exported member is one whose name is specified in one of the member type specific
// properties. An internal member is one that is added due to being a part of an exported (or
// other internal) member and is not itself an exported member.
//
// Member names are handled as follows:
// * When creating the unversioned form of the module the name is left unchecked unless the member
// is internal in which case it is transformed into an sdk specific name, i.e. by prefixing with
// the sdk name.
//
// * When creating the versioned form of the module the name is transformed into a versioned sdk
// specific name, i.e. by prefixing with the sdk name and suffixing with the version.
//
// e.g.
// bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true))
SdkMemberReferencePropertyTag(required bool) BpPropertyTag
}
// BpPropertyTag is a marker interface that can be associated with properties in a BpPropertySet to
// provide additional information which can be used to customize their behavior.
type BpPropertyTag interface{}
// BpPropertySet is a set of properties for use in a .bp file.
type BpPropertySet interface {
// AddProperty adds a property.
//
// The value can be one of the following types:
// * string
// * array of the above
// * bool
// For these types it is an error if multiple properties with the same name
// are added.
//
// * pointer to a struct
// * BpPropertySet
//
// A pointer to a Blueprint-style property struct is first converted into a
// BpPropertySet by traversing the fields and adding their values as
// properties in a BpPropertySet. A field with a struct value is itself
// converted into a BpPropertySet before adding.
//
// Adding a BpPropertySet is done as follows:
// * If no property with the name exists then the BpPropertySet is added
// directly to this property. Care must be taken to ensure that it does not
// introduce a cycle.
// * If a property exists with the name and the current value is a
// BpPropertySet then every property of the new BpPropertySet is added to
// the existing BpPropertySet.
// * Otherwise, if a property exists with the name then it is an error.
AddProperty(name string, value interface{})
// AddPropertyWithTag adds a property with an associated property tag.
AddPropertyWithTag(name string, value interface{}, tag BpPropertyTag)
// AddPropertySet adds a property set with the specified name and returns it so that additional
// properties can be added to it.
AddPropertySet(name string) BpPropertySet
// AddCommentForProperty adds a comment for the named property (or property set).
AddCommentForProperty(name, text string)
}
// BpModule represents a module definition in a .bp file.
type BpModule interface {
BpPropertySet
// ModuleType returns the module type of the module
ModuleType() string
// Name returns the name of the module or "" if no name has been specified.
Name() string
}
// BpPrintable is a marker interface that must be implemented by any struct that is added as a
// property value.
type BpPrintable interface {
bpPrintable()
}
// BpPrintableBase must be embedded within any struct that is added as a
// property value.
type BpPrintableBase struct {
}
func (b BpPrintableBase) bpPrintable() {
}
var _ BpPrintable = BpPrintableBase{}
// sdkRegisterable defines the interface that must be implemented by objects that can be registered
// in an sdkRegistry.
type sdkRegisterable interface {
// SdkPropertyName returns the name of the corresponding property on an sdk module.
SdkPropertyName() string
}
// sdkRegistry provides support for registering and retrieving objects that define properties for
// use by sdk and module_exports module types.
type sdkRegistry struct {
// The list of registered objects sorted by property name.
list []sdkRegisterable
}
// copyAndAppend creates a new sdkRegistry that includes all the traits registered in
// this registry plus the supplied trait.
func (r *sdkRegistry) copyAndAppend(registerable sdkRegisterable) *sdkRegistry {
oldList := r.list
// Make sure that list does not already contain the property. Uses a simple linear search instead
// of a binary search even though the list is sorted. That is because the number of items in the
// list is small and so not worth the overhead of a binary search.
found := false
newPropertyName := registerable.SdkPropertyName()
for _, r := range oldList {
if r.SdkPropertyName() == newPropertyName {
found = true
break
}
}
if found {
names := []string{}
for _, r := range oldList {
names = append(names, r.SdkPropertyName())
}
panic(fmt.Errorf("duplicate properties found, %q already exists in %q", newPropertyName, names))
}
// Copy the slice just in case this is being read while being modified, e.g. when testing.
list := make([]sdkRegisterable, 0, len(oldList)+1)
list = append(list, oldList...)
list = append(list, registerable)
// Sort the registered objects by their property name to ensure that registry order has no effect
// on behavior.
sort.Slice(list, func(i1, i2 int) bool {
t1 := list[i1]
t2 := list[i2]
return t1.SdkPropertyName() < t2.SdkPropertyName()
})
// Create a new registry so the pointer uniquely identifies the set of registered types.
return &sdkRegistry{
list: list,
}
}
// registeredObjects returns the list of registered instances.
func (r *sdkRegistry) registeredObjects() []sdkRegisterable {
return r.list
}
// uniqueOnceKey returns a key that uniquely identifies this instance and can be used with
// OncePer.Once
func (r *sdkRegistry) uniqueOnceKey() OnceKey {
// Use the pointer to the registry as the unique key. The pointer is used because it is guaranteed
// to uniquely identify the contained list. The list itself cannot be used as slices are not
// comparable. Using the pointer does mean that two separate registries with identical lists would
// have different keys and so cause whatever information is cached to be created multiple times.
// However, that is not an issue in practice as it should not occur outside tests. Constructing a
// string representation of the list to use instead would avoid that but is an unnecessary
// complication that provides no significant benefit.
return NewCustomOnceKey(r)
}
// SdkMemberTrait represents a trait that members of an sdk module can contribute to the sdk
// snapshot.
//
// A trait is simply a characteristic of sdk member that is not required by default which may be
// required for some members but not others. Traits can cause additional information to be output
// to the sdk snapshot or replace the default information exported for a member with something else.
// e.g.
// * By default cc libraries only export the default image variants to the SDK. However, for some
// members it may be necessary to export specific image variants, e.g. vendor, or recovery.
// * By default cc libraries export all the configured architecture variants except for the native
// bridge architecture variants. However, for some members it may be necessary to export the
// native bridge architecture variants as well.
// * By default cc libraries export the platform variant (i.e. sdk:). However, for some members it
// may be necessary to export the sdk variant (i.e. sdk:sdk).
//
// A sdk can request a module to provide no traits, one trait or a collection of traits. The exact
// behavior of a trait is determined by how SdkMemberType implementations handle the traits. A trait
// could be specific to one SdkMemberType or many. Some trait combinations could be incompatible.
//
// The sdk module type will create a special traits structure that contains a property for each
// trait registered with RegisterSdkMemberTrait(). The property names are those returned from
// SdkPropertyName(). Each property contains a list of modules that are required to have that trait.
// e.g. something like this:
//
// sdk {
// name: "sdk",
// ...
// traits: {
// recovery_image: ["module1", "module4", "module5"],
// native_bridge: ["module1", "module2"],
// native_sdk: ["module1", "module3"],
// ...
// },
// ...
// }
type SdkMemberTrait interface {
// SdkPropertyName returns the name of the traits property on an sdk module.
SdkPropertyName() string
}
var _ sdkRegisterable = (SdkMemberTrait)(nil)
// SdkMemberTraitBase is the base struct that must be embedded within any type that implements
// SdkMemberTrait.
type SdkMemberTraitBase struct {
// PropertyName is the name of the property
PropertyName string
}
func (b *SdkMemberTraitBase) SdkPropertyName() string {
return b.PropertyName
}
// SdkMemberTraitSet is a set of SdkMemberTrait instances.
type SdkMemberTraitSet interface {
// Empty returns true if this set is empty.
Empty() bool
// Contains returns true if this set contains the specified trait.
Contains(trait SdkMemberTrait) bool
// Subtract returns a new set containing all elements of this set except for those in the
// other set.
Subtract(other SdkMemberTraitSet) SdkMemberTraitSet
// String returns a string representation of the set and its contents.
String() string
}
func NewSdkMemberTraitSet(traits []SdkMemberTrait) SdkMemberTraitSet {
if len(traits) == 0 {
return EmptySdkMemberTraitSet()
}
m := sdkMemberTraitSet{}
for _, trait := range traits {
m[trait] = true
}
return m
}
func EmptySdkMemberTraitSet() SdkMemberTraitSet {
return (sdkMemberTraitSet)(nil)
}
type sdkMemberTraitSet map[SdkMemberTrait]bool
var _ SdkMemberTraitSet = (sdkMemberTraitSet{})
func (s sdkMemberTraitSet) Empty() bool {
return len(s) == 0
}
func (s sdkMemberTraitSet) Contains(trait SdkMemberTrait) bool {
return s[trait]
}
func (s sdkMemberTraitSet) Subtract(other SdkMemberTraitSet) SdkMemberTraitSet {
if other.Empty() {
return s
}
var remainder []SdkMemberTrait
for trait, _ := range s {
if !other.Contains(trait) {
remainder = append(remainder, trait)
}
}
return NewSdkMemberTraitSet(remainder)
}
func (s sdkMemberTraitSet) String() string {
list := []string{}
for trait, _ := range s {
list = append(list, trait.SdkPropertyName())
}
sort.Strings(list)
return fmt.Sprintf("[%s]", strings.Join(list, ","))
}
var registeredSdkMemberTraits = &sdkRegistry{}
// RegisteredSdkMemberTraits returns a OnceKey and a sorted list of registered traits.
//
// The key uniquely identifies the array of traits and can be used with OncePer.Once() to cache
// information derived from the array of traits.
func RegisteredSdkMemberTraits() (OnceKey, []SdkMemberTrait) {
registerables := registeredSdkMemberTraits.registeredObjects()
traits := make([]SdkMemberTrait, len(registerables))
for i, registerable := range registerables {
traits[i] = registerable.(SdkMemberTrait)
}
return registeredSdkMemberTraits.uniqueOnceKey(), traits
}
// RegisterSdkMemberTrait registers an SdkMemberTrait object to allow them to be used in the
// module_exports, module_exports_snapshot, sdk and sdk_snapshot module types.
func RegisterSdkMemberTrait(trait SdkMemberTrait) {
registeredSdkMemberTraits = registeredSdkMemberTraits.copyAndAppend(trait)
}
// SdkMember is an individual member of the SDK.
//
// It includes all of the variants that the SDK depends upon.
type SdkMember interface {
// Name returns the name of the member.
Name() string
// Variants returns all the variants of this module depended upon by the SDK.
Variants() []SdkAware
}
// SdkMemberDependencyTag is the interface that a tag must implement in order to allow the
// dependent module to be automatically added to the sdk.
type SdkMemberDependencyTag interface {
blueprint.DependencyTag
// SdkMemberType returns the SdkMemberType that will be used to automatically add the child module
// to the sdk.
//
// Returning nil will prevent the module being added to the sdk.
SdkMemberType(child Module) SdkMemberType
// ExportMember determines whether a module added to the sdk through this tag will be exported
// from the sdk or not.
//
// An exported member is added to the sdk using its own name, e.g. if "foo" was exported from sdk
// "bar" then its prebuilt would be simply called "foo". A member can be added to the sdk via
// multiple tags and if any of those tags returns true from this method then the membe will be
// exported. Every module added directly to the sdk via one of the member type specific
// properties, e.g. java_libs, will automatically be exported.
//
// If a member is not exported then it is treated as an internal implementation detail of the
// sdk and so will be added with an sdk specific name. e.g. if "foo" was an internal member of sdk
// "bar" then its prebuilt would be called "bar_foo". Additionally its visibility will be set to
// "//visibility:private" so it will not be accessible from outside its Android.bp file.
ExportMember() bool
}
var _ SdkMemberDependencyTag = (*sdkMemberDependencyTag)(nil)
var _ ReplaceSourceWithPrebuilt = (*sdkMemberDependencyTag)(nil)
type sdkMemberDependencyTag struct {
blueprint.BaseDependencyTag
memberType SdkMemberType
export bool
}
func (t *sdkMemberDependencyTag) SdkMemberType(_ Module) SdkMemberType {
return t.memberType
}
func (t *sdkMemberDependencyTag) ExportMember() bool {
return t.export
}
// ReplaceSourceWithPrebuilt prevents dependencies from the sdk/module_exports onto their members
// from being replaced with a preferred prebuilt.
func (t *sdkMemberDependencyTag) ReplaceSourceWithPrebuilt() bool {
return false
}
// DependencyTagForSdkMemberType creates an SdkMemberDependencyTag that will cause any
// dependencies added by the tag to be added to the sdk as the specified SdkMemberType and exported
// (or not) as specified by the export parameter.
func DependencyTagForSdkMemberType(memberType SdkMemberType, export bool) SdkMemberDependencyTag {
return &sdkMemberDependencyTag{memberType: memberType, export: export}
}
// SdkMemberType is the interface that must be implemented for every type that can be a member of an
// sdk.
//
// The basic implementation should look something like this, where ModuleType is
// the name of the module type being supported.
//
// type moduleTypeSdkMemberType struct {
// android.SdkMemberTypeBase
// }
//
// func init() {
// android.RegisterSdkMemberType(&moduleTypeSdkMemberType{
// SdkMemberTypeBase: android.SdkMemberTypeBase{
// PropertyName: "module_types",
// },
// }
// }
//
// ...methods...
//
type SdkMemberType interface {
// SdkPropertyName returns the name of the member type property on an sdk module.
SdkPropertyName() string
// RequiresBpProperty returns true if this member type requires its property to be usable within
// an Android.bp file.
RequiresBpProperty() bool
// SupportedBuildReleases returns the string representation of a set of target build releases that
// support this member type.
SupportedBuildReleases() string
// UsableWithSdkAndSdkSnapshot returns true if the member type supports the sdk/sdk_snapshot,
// false otherwise.
UsableWithSdkAndSdkSnapshot() bool
// IsHostOsDependent returns true if prebuilt host artifacts may be specific to the host OS. Only
// applicable to modules where HostSupported() is true. If this is true, snapshots will list each
// host OS variant explicitly and disable all other host OS'es.
IsHostOsDependent() bool
// SupportedLinkages returns the names of the linkage variants supported by this module.
SupportedLinkages() []string
// ArePrebuiltsRequired returns true if prebuilts are required in the sdk snapshot, false
// otherwise.
ArePrebuiltsRequired() bool
// AddDependencies adds dependencies from the SDK module to all the module variants the member
// type contributes to the SDK. `names` is the list of module names given in the member type
// property (as returned by SdkPropertyName()) in the SDK module. The exact set of variants
// required is determined by the SDK and its properties. The dependencies must be added with the
// supplied tag.
//
// The BottomUpMutatorContext provided is for the SDK module.
AddDependencies(ctx SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string)
// IsInstance returns true if the supplied module is an instance of this member type.
//
// This is used to check the type of each variant before added to the SdkMember. Returning false
// will cause an error to be logged explaining that the module is not allowed in whichever sdk
// property it was added.
IsInstance(module Module) bool
// UsesSourceModuleTypeInSnapshot returns true when the AddPrebuiltModule() method returns a
// source module type.
UsesSourceModuleTypeInSnapshot() bool
// AddPrebuiltModule is called to add a prebuilt module that the sdk will populate.
//
// The sdk module code generates the snapshot as follows:
//
// * A properties struct of type SdkMemberProperties is created for each variant and
// populated with information from the variant by calling PopulateFromVariant(SdkAware)
// on the struct.
//
// * An additional properties struct is created into which the common properties will be
// added.
//
// * The variant property structs are analysed to find exported (capitalized) fields which
// have common values. Those fields are cleared and the common value added to the common
// properties.
//
// A field annotated with a tag of `sdk:"keep"` will be treated as if it
// was not capitalized, i.e. not optimized for common values.
//
// A field annotated with a tag of `android:"arch_variant"` will be allowed to have
// values that differ by arch, fields not tagged as such must have common values across
// all variants.
//
// * Additional field tags can be specified on a field that will ignore certain values
// for the purpose of common value optimization. A value that is ignored must have the
// default value for the property type. This is to ensure that significant value are not
// ignored by accident. The purpose of this is to allow the snapshot generation to reflect
// the behavior of the runtime. e.g. if a property is ignored on the host then a property
// that is common for android can be treated as if it was common for android and host as
// the setting for host is ignored anyway.
// * `sdk:"ignored-on-host" - this indicates the property is ignored on the host variant.
//
// * The sdk module type populates the BpModule structure, creating the arch specific
// structure and calls AddToPropertySet(...) on the properties struct to add the member
// specific properties in the correct place in the structure.
//
AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule
// CreateVariantPropertiesStruct creates a structure into which variant specific properties can be
// added.
CreateVariantPropertiesStruct() SdkMemberProperties
// SupportedTraits returns the set of traits supported by this member type.
SupportedTraits() SdkMemberTraitSet
// Overrides returns whether type overrides other SdkMemberType
Overrides(SdkMemberType) bool
}
var _ sdkRegisterable = (SdkMemberType)(nil)
// SdkDependencyContext provides access to information needed by the SdkMemberType.AddDependencies()
// implementations.
type SdkDependencyContext interface {
BottomUpMutatorContext
// RequiredTraits returns the set of SdkMemberTrait instances that the sdk requires the named
// member to provide.
RequiredTraits(name string) SdkMemberTraitSet
// RequiresTrait returns true if the sdk requires the member with the supplied name to provide the
// supplied trait.
RequiresTrait(name string, trait SdkMemberTrait) bool
}
// SdkMemberTypeBase is the base type for SdkMemberType implementations and must be embedded in any
// struct that implements SdkMemberType.
type SdkMemberTypeBase struct {
PropertyName string
// Property names that this SdkMemberTypeBase can override, this is useful when a module type is a
// superset of another module type.
OverridesPropertyNames map[string]bool
// The names of linkage variants supported by this module.
SupportedLinkageNames []string
// When set to true BpPropertyNotRequired indicates that the member type does not require the
// property to be specifiable in an Android.bp file.
BpPropertyNotRequired bool
// The name of the first targeted build release.
//
// If not specified then it is assumed to be available on all targeted build releases.
SupportedBuildReleaseSpecification string
// Set to true if this must be usable with the sdk/sdk_snapshot module types. Otherwise, it will
// only be usable with module_exports/module_exports_snapshots module types.
SupportsSdk bool
// Set to true if prebuilt host artifacts of this member may be specific to the host OS. Only
// applicable to modules where HostSupported() is true.
HostOsDependent bool
// When set to true UseSourceModuleTypeInSnapshot indicates that the member type creates a source
// module type in its SdkMemberType.AddPrebuiltModule() method. That prevents the sdk snapshot
// code from automatically adding a prefer: true flag.
UseSourceModuleTypeInSnapshot bool
// Set to proptools.BoolPtr(false) if this member does not generate prebuilts but is only provided
// to allow the sdk to gather members from this member's dependencies. If not specified then
// defaults to true.
PrebuiltsRequired *bool
// The list of supported traits.
Traits []SdkMemberTrait
}
func (b *SdkMemberTypeBase) SdkPropertyName() string {
return b.PropertyName
}
func (b *SdkMemberTypeBase) RequiresBpProperty() bool {
return !b.BpPropertyNotRequired
}
func (b *SdkMemberTypeBase) SupportedBuildReleases() string {
return b.SupportedBuildReleaseSpecification
}
func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool {
return b.SupportsSdk
}
func (b *SdkMemberTypeBase) IsHostOsDependent() bool {
return b.HostOsDependent
}
func (b *SdkMemberTypeBase) ArePrebuiltsRequired() bool {
return proptools.BoolDefault(b.PrebuiltsRequired, true)
}
func (b *SdkMemberTypeBase) UsesSourceModuleTypeInSnapshot() bool {
return b.UseSourceModuleTypeInSnapshot
}
func (b *SdkMemberTypeBase) SupportedTraits() SdkMemberTraitSet {
return NewSdkMemberTraitSet(b.Traits)
}
func (b *SdkMemberTypeBase) Overrides(other SdkMemberType) bool {
return b.OverridesPropertyNames[other.SdkPropertyName()]
}
func (b *SdkMemberTypeBase) SupportedLinkages() []string {
return b.SupportedLinkageNames
}
// registeredModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports
// modules.
var registeredModuleExportsMemberTypes = &sdkRegistry{}
// registeredSdkMemberTypes is the set of registered registeredSdkMemberTypes for sdk modules.
var registeredSdkMemberTypes = &sdkRegistry{}
// RegisteredSdkMemberTypes returns a OnceKey and a sorted list of registered types.
//
// If moduleExports is true then the slice of types includes all registered types that can be used
// with the module_exports and module_exports_snapshot module types. Otherwise, the slice of types
// only includes those registered types that can be used with the sdk and sdk_snapshot module
// types.
//
// The key uniquely identifies the array of types and can be used with OncePer.Once() to cache
// information derived from the array of types.
func RegisteredSdkMemberTypes(moduleExports bool) (OnceKey, []SdkMemberType) {
var registry *sdkRegistry
if moduleExports {
registry = registeredModuleExportsMemberTypes
} else {
registry = registeredSdkMemberTypes
}
registerables := registry.registeredObjects()
types := make([]SdkMemberType, len(registerables))
for i, registerable := range registerables {
types[i] = registerable.(SdkMemberType)
}
return registry.uniqueOnceKey(), types
}
// RegisterSdkMemberType registers an SdkMemberType object to allow them to be used in the
// module_exports, module_exports_snapshot and (depending on the value returned from
// SdkMemberType.UsableWithSdkAndSdkSnapshot) the sdk and sdk_snapshot module types.
func RegisterSdkMemberType(memberType SdkMemberType) {
// All member types are usable with module_exports.
registeredModuleExportsMemberTypes = registeredModuleExportsMemberTypes.copyAndAppend(memberType)
// Only those that explicitly indicate it are usable with sdk.
if memberType.UsableWithSdkAndSdkSnapshot() {
registeredSdkMemberTypes = registeredSdkMemberTypes.copyAndAppend(memberType)
}
}
// SdkMemberPropertiesBase is the base structure for all implementations of SdkMemberProperties and
// must be embedded in any struct that implements SdkMemberProperties.
//
// Contains common properties that apply across many different member types.
type SdkMemberPropertiesBase struct {
// The number of unique os types supported by the member variants.
//
// If a member has a variant with more than one os type then it will need to differentiate
// the locations of any of their prebuilt files in the snapshot by os type to prevent them
// from colliding. See OsPrefix().
//
// This property is the same for all variants of a member and so would be optimized away
// if it was not explicitly kept.
Os_count int `sdk:"keep"`
// The os type for which these properties refer.
//
// Provided to allow a member to differentiate between os types in the locations of their
// prebuilt files when it supports more than one os type.
//
// This property is the same for all os type specific variants of a member and so would be
// optimized away if it was not explicitly kept.
Os OsType `sdk:"keep"`
// The setting to use for the compile_multilib property.
Compile_multilib string `android:"arch_variant"`
}
// OsPrefix returns the os prefix to use for any file paths in the sdk.
//
// Is an empty string if the member only provides variants for a single os type, otherwise
// is the OsType.Name.
func (b *SdkMemberPropertiesBase) OsPrefix() string {
if b.Os_count == 1 {
return ""
} else {
return b.Os.Name
}
}
func (b *SdkMemberPropertiesBase) Base() *SdkMemberPropertiesBase {
return b
}
// SdkMemberProperties is the interface to be implemented on top of a structure that contains
// variant specific information.
//
// Struct fields that are capitalized are examined for common values to extract. Fields that are not
// capitalized are assumed to be arch specific.
type SdkMemberProperties interface {
// Base returns the base structure.
Base() *SdkMemberPropertiesBase
// PopulateFromVariant populates this structure with information from a module variant.
//
// It will typically be called once for each variant of a member module that the SDK depends upon.
PopulateFromVariant(ctx SdkMemberContext, variant Module)
// AddToPropertySet adds the information from this structure to the property set.
//
// This will be called for each instance of this structure on which the PopulateFromVariant method
// was called and also on a number of different instances of this structure into which properties
// common to one or more variants have been copied. Therefore, implementations of this must handle
// the case when this structure is only partially populated.
AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
}
// SdkMemberContext provides access to information common to a specific member.
type SdkMemberContext interface {
// SdkModuleContext returns the module context of the sdk common os variant which is creating the
// snapshot.
//
// This is common to all members of the sdk and is not specific to the member being processed.
// If information about the member being processed needs to be obtained from this ModuleContext it
// must be obtained using one of the OtherModule... methods not the Module... methods.
SdkModuleContext() ModuleContext
// SnapshotBuilder the builder of the snapshot.
SnapshotBuilder() SnapshotBuilder
// MemberType returns the type of the member currently being processed.
MemberType() SdkMemberType
// Name returns the name of the member currently being processed.
//
// Provided for use by sdk members to create a member specific location within the snapshot
// into which to copy the prebuilt files.
Name() string
// RequiresTrait returns true if this member is expected to provide the specified trait.
RequiresTrait(trait SdkMemberTrait) bool
}
// ExportedComponentsInfo contains information about the components that this module exports to an
// sdk snapshot.
//
// A component of a module is a child module that the module creates and which forms an integral
// part of the functionality that the creating module provides. A component module is essentially
// owned by its creator and is tightly coupled to the creator and other components.
//
// e.g. the child modules created by prebuilt_apis are not components because they are not tightly
// coupled to the prebuilt_apis module. Once they are created the prebuilt_apis ignores them. The
// child impl and stub library created by java_sdk_library (and corresponding import) are components
// because the creating module depends upon them in order to provide some of its own functionality.
//
// A component is exported if it is part of an sdk snapshot. e.g. The xml and impl child modules are
// components but they are not exported as they are not part of an sdk snapshot.
//
// This information is used by the sdk snapshot generation code to ensure that it does not create
// an sdk snapshot that contains a declaration of the component module and the module that creates
// it as that would result in duplicate modules when attempting to use the snapshot. e.g. a snapshot
// that included the java_sdk_library_import "foo" and also a java_import "foo.stubs" would fail
// as there would be two modules called "foo.stubs".
type ExportedComponentsInfo struct {
// The names of the exported components.
Components []string
}
var ExportedComponentsInfoProvider = blueprint.NewProvider(ExportedComponentsInfo{})
// AdditionalSdkInfo contains additional properties to add to the generated SDK info file.
type AdditionalSdkInfo struct {
Properties map[string]interface{}
}
var AdditionalSdkInfoProvider = blueprint.NewProvider(AdditionalSdkInfo{})