Merge "Do not allow updatable apps without min_sdk_version." into rvc-dev
diff --git a/Android.bp b/Android.bp
index 2a4653a..0621475 100644
--- a/Android.bp
+++ b/Android.bp
@@ -207,6 +207,7 @@
"cc/binary_sdk_member.go",
"cc/fuzz.go",
"cc/library.go",
+ "cc/library_headers.go",
"cc/library_sdk_member.go",
"cc/object.go",
"cc/test.go",
@@ -232,6 +233,7 @@
"cc/compiler_test.go",
"cc/gen_test.go",
"cc/genrule_test.go",
+ "cc/library_headers_test.go",
"cc/library_test.go",
"cc/object_test.go",
"cc/prebuilt_test.go",
@@ -534,6 +536,7 @@
"sdk/update.go",
],
testSrcs: [
+ "sdk/bp_test.go",
"sdk/cc_sdk_test.go",
"sdk/exports_test.go",
"sdk/java_sdk_test.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index dbf3aa8..6ba68af 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -29,7 +29,11 @@
)
func init() {
- RegisterSingletonType("androidmk", AndroidMkSingleton)
+ RegisterAndroidMkBuildComponents(InitRegistrationContext)
+}
+
+func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
}
// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
@@ -194,6 +198,10 @@
a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
+ if am, ok := mod.(ApexModule); ok {
+ a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform())
+ }
+
archStr := amod.Arch().ArchType.String()
host := false
switch amod.Os().Class {
diff --git a/android/apex.go b/android/apex.go
index 2b5072b..1a43ce4 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,6 +19,8 @@
"sort"
"strconv"
"sync"
+
+ "github.com/google/blueprint"
)
const (
@@ -32,6 +34,14 @@
MinSdkVersion int
}
+// Extracted from ApexModule to make it easier to define custom subsets of the
+// ApexModule interface and improve code navigation within the IDE.
+type DepIsInSameApex interface {
+ // DepIsInSameApex tests if the other module 'dep' is installed to the same
+ // APEX as this module
+ DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+}
+
// ApexModule is the interface that a module type is expected to implement if
// the module has to be built differently depending on whether the module
// is destined for an apex or not (installed to one of the regular partitions).
@@ -49,6 +59,8 @@
// respectively.
type ApexModule interface {
Module
+ DepIsInSameApex
+
apexModuleBase() *ApexModuleBase
// Marks that this module should be built for the specified APEXes.
@@ -88,9 +100,15 @@
// Tests if this module is available for the specified APEX or ":platform"
AvailableFor(what string) bool
- // DepIsInSameApex tests if the other module 'dep' is installed to the same
- // APEX as this module
- DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+ // Return true if this module is not available to platform (i.e. apex_available
+ // property doesn't have "//apex_available:platform"), or shouldn't be available
+ // to platform, which is the case when this module depends on other module that
+ // isn't available to platform.
+ NotAvailableForPlatform() bool
+
+ // Mark that this module is not available to platform. Set by the
+ // check-platform-availability mutator in the apex package.
+ SetNotAvailableForPlatform()
// Returns the highest version which is <= maxSdkVersion.
// For example, with maxSdkVersion is 10 and versionList is [9,11]
@@ -109,6 +127,17 @@
Apex_available []string
Info ApexInfo `blueprint:"mutated"`
+
+ NotAvailableForPlatform bool `blueprint:"mutated"`
+}
+
+// Marker interface that identifies dependencies that are excluded from APEX
+// contents.
+type ExcludeFromApexContentsTag interface {
+ blueprint.DependencyTag
+
+ // Method that differentiates this interface from others.
+ ExcludeFromApexContents()
}
// Provides default implementation for the ApexModule interface. APEX-aware
@@ -126,6 +155,10 @@
return m
}
+func (m *ApexModuleBase) ApexAvailable() []string {
+ return m.ApexProperties.Apex_available
+}
+
func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
m.apexVariationsLock.Lock()
defer m.apexVariationsLock.Unlock()
@@ -163,7 +196,7 @@
const (
AvailableToPlatform = "//apex_available:platform"
- availableToAnyApex = "//apex_available:anyapex"
+ AvailableToAnyApex = "//apex_available:anyapex"
)
func CheckAvailableForApex(what string, apex_available []string) bool {
@@ -173,13 +206,21 @@
return what == AvailableToPlatform
}
return InList(what, apex_available) ||
- (what != AvailableToPlatform && InList(availableToAnyApex, apex_available))
+ (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available))
}
func (m *ApexModuleBase) AvailableFor(what string) bool {
return CheckAvailableForApex(what, m.ApexProperties.Apex_available)
}
+func (m *ApexModuleBase) NotAvailableForPlatform() bool {
+ return m.ApexProperties.NotAvailableForPlatform
+}
+
+func (m *ApexModuleBase) SetNotAvailableForPlatform() {
+ m.ApexProperties.NotAvailableForPlatform = true
+}
+
func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool {
// By default, if there is a dependency from A to B, we try to include both in the same APEX,
// unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning true.
@@ -199,7 +240,7 @@
func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
for _, n := range m.ApexProperties.Apex_available {
- if n == AvailableToPlatform || n == availableToAnyApex {
+ if n == AvailableToPlatform || n == AvailableToAnyApex {
continue
}
if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
diff --git a/android/arch.go b/android/arch.go
index 73a490d..e440486 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -596,7 +596,7 @@
}()
var (
- osTypeList []OsType
+ OsTypeList []OsType
commonTargetMap = make(map[string]Target)
NoOsType OsType
@@ -607,6 +607,10 @@
Android = NewOsType("android", Device, false)
Fuchsia = NewOsType("fuchsia", Device, false)
+ // A pseudo OSType for a common os variant, which is OSType agnostic and which
+ // has dependencies on all the OS variants.
+ CommonOS = NewOsType("common_os", Generic, false)
+
osArchTypeMap = map[OsType][]ArchType{
Linux: []ArchType{X86, X86_64},
LinuxBionic: []ArchType{X86_64},
@@ -668,7 +672,7 @@
DefaultDisabled: defDisabled,
}
- osTypeList = append(osTypeList, os)
+ OsTypeList = append(OsTypeList, os)
if _, found := commonTargetMap[name]; found {
panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
@@ -680,7 +684,7 @@
}
func osByName(name string) OsType {
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
if os.Name == name {
return os
}
@@ -746,7 +750,7 @@
var moduleOSList []OsType
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
supportedClass := false
for _, osClass := range osClasses {
if os.Class == osClass {
@@ -775,12 +779,64 @@
osNames[i] = os.String()
}
- modules := mctx.CreateVariations(osNames...)
- for i, m := range modules {
- m.(Module).base().commonProperties.CompileOS = moduleOSList[i]
- m.(Module).base().setOSProperties(mctx)
+ createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
+ if createCommonOSVariant {
+ // A CommonOS variant was requested so add it to the list of OS's variants to
+ // create. It needs to be added to the end because it needs to depend on the
+ // the other variants in the list returned by CreateVariations(...) and inter
+ // variant dependencies can only be created from a later variant in that list to
+ // an earlier one. That is because variants are always processed in the order in
+ // which they are returned from CreateVariations(...).
+ osNames = append(osNames, CommonOS.Name)
+ moduleOSList = append(moduleOSList, CommonOS)
}
+ modules := mctx.CreateVariations(osNames...)
+ for i, m := range modules {
+ m.base().commonProperties.CompileOS = moduleOSList[i]
+ m.base().setOSProperties(mctx)
+ }
+
+ if createCommonOSVariant {
+ // A CommonOS variant was requested so add dependencies from it (the last one in
+ // the list) to the OS type specific variants.
+ last := len(modules) - 1
+ commonOSVariant := modules[last]
+ commonOSVariant.base().commonProperties.CommonOSVariant = true
+ for _, module := range modules[0:last] {
+ // Ignore modules that are enabled. Note, this will only avoid adding
+ // dependencies on OsType variants that are explicitly disabled in their
+ // properties. The CommonOS variant will still depend on disabled variants
+ // if they are disabled afterwards, e.g. in archMutator if
+ if module.Enabled() {
+ mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
+ }
+ }
+ }
+}
+
+// Identifies the dependency from CommonOS variant to the os specific variants.
+type commonOSTag struct{ blueprint.BaseDependencyTag }
+
+var commonOsToOsSpecificVariantTag = commonOSTag{}
+
+// Get the OsType specific variants for the current CommonOS variant.
+//
+// The returned list will only contain enabled OsType specific variants of the
+// module referenced in the supplied context. An empty list is returned if there
+// are no enabled variants or the supplied context is not for an CommonOS
+// variant.
+func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
+ var variants []Module
+ mctx.VisitDirectDeps(func(m Module) {
+ if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag {
+ if m.Enabled() {
+ variants = append(variants, m)
+ }
+ }
+ })
+
+ return variants
}
// archMutator splits a module into a variant for each Target requested by the module. Target selection
@@ -821,6 +877,15 @@
}
os := base.commonProperties.CompileOS
+ if os == CommonOS {
+ // Make sure that the target related properties are initialized for the
+ // CommonOS variant.
+ addTargetProperties(module, commonTargetMap[os.Name], nil, true)
+
+ // Do not create arch specific variants for the CommonOS variant.
+ return
+ }
+
osTargets := mctx.Config().Targets[os]
image := base.commonProperties.ImageVariation
// Filter NativeBridge targets unless they are explicitly supported
@@ -881,15 +946,17 @@
modules := mctx.CreateVariations(targetNames...)
for i, m := range modules {
- m.(Module).base().commonProperties.CompileTarget = targets[i]
- m.(Module).base().commonProperties.CompileMultiTargets = multiTargets
- if i == 0 {
- m.(Module).base().commonProperties.CompilePrimary = true
- }
+ addTargetProperties(m, targets[i], multiTargets, i == 0)
m.(Module).base().setArchProperties(mctx)
}
}
+func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
+ m.base().commonProperties.CompileTarget = target
+ m.base().commonProperties.CompileMultiTargets = multiTargets
+ m.base().commonProperties.CompilePrimary = primaryTarget
+}
+
func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
switch class {
case Device:
@@ -1004,7 +1071,7 @@
"Arm_on_x86",
"Arm_on_x86_64",
}
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
targets = append(targets, os.Field)
for _, archType := range osArchTypeMap[os] {
@@ -1711,6 +1778,8 @@
return ret
}
+// Return the set of Os specific common architecture targets for each Os in a list of
+// targets.
func getCommonTargets(targets []Target) []Target {
var ret []Target
set := make(map[string]bool)
diff --git a/android/config.go b/android/config.go
index 859e164..bf52c45 100644
--- a/android/config.go
+++ b/android/config.go
@@ -359,6 +359,9 @@
return Config{}, err
}
+ // Make the CommonOS OsType available for all products.
+ targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
+
var archConfig []archConfig
if Bool(config.Mega_device) {
archConfig = getMegaDeviceConfig()
diff --git a/android/module.go b/android/module.go
index 79693a1..f300e05 100644
--- a/android/module.go
+++ b/android/module.go
@@ -128,10 +128,20 @@
// and returns a top-down dependency path from a start module to current child module.
GetWalkPath() []Module
+ // GetTagPath is supposed to be called in visit function passed in WalkDeps()
+ // and returns a top-down dependency tags path from a start module to current child module.
+ // It has one less entry than GetWalkPath() as it contains the dependency tags that
+ // exist between each adjacent pair of modules in the GetWalkPath().
+ // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
+ GetTagPath() []blueprint.DependencyTag
+
AddMissingDependencies(missingDeps []string)
Target() Target
TargetPrimary() bool
+
+ // The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+ // responsible for creating.
MultiTargets() []Target
Arch() Arch
Os() OsType
@@ -361,6 +371,10 @@
}
}
+ // If set to true then the archMutator will create variants for each arch specific target
+ // (e.g. 32/64) that the module is required to produce. If set to false then it will only
+ // create a variant for the architecture and will list the additional arch specific targets
+ // that the variant needs to produce in the CompileMultiTargets property.
UseTargetVariants bool `blueprint:"mutated"`
Default_multilib string `blueprint:"mutated"`
@@ -439,16 +453,56 @@
Suffix *string `android:"arch_variant"`
} `android:"arch_variant"`
- // Set by TargetMutator
- CompileOS OsType `blueprint:"mutated"`
- CompileTarget Target `blueprint:"mutated"`
+ // The OsType of artifacts that this module variant is responsible for creating.
+ //
+ // Set by osMutator
+ CompileOS OsType `blueprint:"mutated"`
+
+ // The Target of artifacts that this module variant is responsible for creating.
+ //
+ // Set by archMutator
+ CompileTarget Target `blueprint:"mutated"`
+
+ // The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+ // responsible for creating.
+ //
+ // By default this is nil as, where necessary, separate variants are created for the
+ // different multilib types supported and that information is encapsulated in the
+ // CompileTarget so the module variant simply needs to create artifacts for that.
+ //
+ // However, if UseTargetVariants is set to false (e.g. by
+ // InitAndroidMultiTargetsArchModule) then no separate variants are created for the
+ // multilib targets. Instead a single variant is created for the architecture and
+ // this contains the multilib specific targets that this variant should create.
+ //
+ // Set by archMutator
CompileMultiTargets []Target `blueprint:"mutated"`
- CompilePrimary bool `blueprint:"mutated"`
+
+ // True if the module variant's CompileTarget is the primary target
+ //
+ // Set by archMutator
+ CompilePrimary bool `blueprint:"mutated"`
// Set by InitAndroidModule
HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
ArchSpecific bool `blueprint:"mutated"`
+ // If set to true then a CommonOS variant will be created which will have dependencies
+ // on all its OsType specific variants. Used by sdk/module_exports to create a snapshot
+ // that covers all os and architecture variants.
+ //
+ // The OsType specific variants can be retrieved by calling
+ // GetOsSpecificVariantsOfCommonOSVariant
+ //
+ // Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
+ CreateCommonOSVariant bool `blueprint:"mutated"`
+
+ // If set to true then this variant is the CommonOS variant that has dependencies on its
+ // OsType specific variants.
+ //
+ // Set by osMutator.
+ CommonOSVariant bool `blueprint:"mutated"`
+
SkipInstall bool `blueprint:"mutated"`
NamespaceExportedToMake bool `blueprint:"mutated"`
@@ -581,6 +635,14 @@
m.base().commonProperties.UseTargetVariants = false
}
+// As InitAndroidMultiTargetsArchModule except it creates an additional CommonOS variant that
+// has dependencies on all the OsType specific variants.
+func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
+ InitAndroidArchModule(m, hod, defaultMultilib)
+ m.base().commonProperties.UseTargetVariants = false
+ m.base().commonProperties.CreateCommonOSVariant = true
+}
+
// A ModuleBase object contains the properties that are common to all Android
// modules. It should be included as an anonymous field in every module
// struct definition. InitAndroidModule should then be called from the module's
@@ -772,6 +834,11 @@
return m.commonProperties.ArchSpecific
}
+// True if the current variant is a CommonOS variant, false otherwise.
+func (m *ModuleBase) IsCommonOSVariant() bool {
+ return m.commonProperties.CommonOSVariant
+}
+
func (m *ModuleBase) OsClassSupported() []OsClass {
switch m.commonProperties.HostOrDeviceSupported {
case HostSupported:
@@ -958,6 +1025,16 @@
}
}
+func (m *ModuleBase) getVariationByMutatorName(mutator string) string {
+ for i, v := range m.commonProperties.DebugMutators {
+ if v == mutator {
+ return m.commonProperties.DebugVariations[i]
+ }
+ }
+
+ return ""
+}
+
func (m *ModuleBase) InRamdisk() bool {
return m.base().commonProperties.ImageVariation == RamdiskVariation
}
@@ -1136,8 +1213,11 @@
blueprintCtx.GetMissingDependencies()
// For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and
- // are enabled.
- ctx.baseModuleContext.strictVisitDeps = true
+ // are enabled. Unless the module is a CommonOS variant which may have dependencies on disabled variants
+ // (because the dependencies are added before the modules are disabled). The
+ // GetOsSpecificVariantsOfCommonOSVariant(...) method will ensure that the disabled variants are
+ // ignored.
+ ctx.baseModuleContext.strictVisitDeps = !m.IsCommonOSVariant()
if ctx.config.captureBuild {
ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
@@ -1313,6 +1393,7 @@
debug bool
walkPath []Module
+ tagPath []blueprint.DependencyTag
strictVisitDeps bool // If true, enforce that all dependencies are enabled
}
@@ -1602,6 +1683,7 @@
func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
b.walkPath = []Module{b.Module()}
+ b.tagPath = []blueprint.DependencyTag{}
b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
childAndroidModule, _ := child.(Module)
parentAndroidModule, _ := parent.(Module)
@@ -1609,8 +1691,10 @@
// record walkPath before visit
for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+ b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
}
b.walkPath = append(b.walkPath, childAndroidModule)
+ b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
return visit(childAndroidModule, parentAndroidModule)
} else {
return false
@@ -1622,6 +1706,10 @@
return b.walkPath
}
+func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
+ return b.tagPath
+}
+
func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
m.bp.VisitAllModuleVariants(func(module blueprint.Module) {
visit(module.(Module))
diff --git a/android/paths.go b/android/paths.go
index 66725c6..0edda38 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1238,8 +1238,8 @@
return ret
}
-func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
- paths = append([]string{"ndk"}, paths...)
+func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
+ paths = append([]string{prefix}, paths...)
path, err := validatePath(paths...)
if err != nil {
reportPathError(ctx, err)
@@ -1247,6 +1247,14 @@
return InstallPath{basePath{path, ctx.Config(), ""}, ""}
}
+func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
+ return pathForNdkOrSdkInstall(ctx, "ndk", paths)
+}
+
+func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
+ return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
+}
+
func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String())
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 2d16f65..82745a4 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -39,6 +39,12 @@
// Mark this tag so dependencies that use it are excluded from visibility enforcement.
func (t prebuiltDependencyTag) ExcludeFromVisibilityEnforcement() {}
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t prebuiltDependencyTag) ExcludeFromApexContents() {}
+
+var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag
+var _ ExcludeFromApexContentsTag = PrebuiltDepTag
+
type PrebuiltProperties struct {
// When prefer is set to true the prebuilt will be used instead of any source module with
// a matching name.
@@ -50,12 +56,9 @@
type Prebuilt struct {
properties PrebuiltProperties
- module Module
- srcs *[]string
- // Metadata for single source Prebuilt modules.
- srcProps reflect.Value
- srcField reflect.StructField
+ srcsSupplier PrebuiltSrcsSupplier
+ srcsPropertyName string
}
func (p *Prebuilt) Name(name string) string {
@@ -72,31 +75,26 @@
// preference configs. We'll want to add native support for dynamic source cases if we end up having
// more modules like this.
func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
- if p.srcs != nil {
- if len(*p.srcs) == 0 {
- ctx.PropertyErrorf("srcs", "missing prebuilt source file")
+ if p.srcsSupplier != nil {
+ srcs := p.srcsSupplier()
+
+ if len(srcs) == 0 {
+ ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
return nil
}
- if len(*p.srcs) > 1 {
- ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+ if len(srcs) > 1 {
+ ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
return nil
}
// Return the singleton source after expanding any filegroup in the
// sources.
- return PathForModuleSrc(ctx, (*p.srcs)[0])
- } else {
- if !p.srcProps.IsValid() {
- ctx.ModuleErrorf("prebuilt source was not set")
- }
- src := p.getSingleSourceFieldValue()
- if src == "" {
- ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name),
- "missing prebuilt source file")
- return nil
- }
+ src := srcs[0]
return PathForModuleSrc(ctx, src)
+ } else {
+ ctx.ModuleErrorf("prebuilt source was not set")
+ return nil
}
}
@@ -104,18 +102,80 @@
return p.properties.UsePrebuilt
}
-func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+// Called to provide the srcs value for the prebuilt module.
+//
+// Return the src value or nil if it is not available.
+type PrebuiltSrcsSupplier func() []string
+
+// Initialize the module as a prebuilt module that uses the provided supplier to access the
+// prebuilt sources of the module.
+//
+// The supplier will be called multiple times and must return the same values each time it
+// is called. If it returns an empty array (or nil) then the prebuilt module will not be used
+// as a replacement for a source module with the same name even if prefer = true.
+//
+// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array
+// containing exactly one source file.
+//
+// The provided property name is used to provide helpful error messages in the event that
+// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
+func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
p := module.Prebuilt()
module.AddProperties(&p.properties)
- p.srcs = srcs
+
+ if srcsSupplier == nil {
+ panic(fmt.Errorf("srcsSupplier must not be nil"))
+ }
+ if srcsPropertyName == "" {
+ panic(fmt.Errorf("srcsPropertyName must not be empty"))
+ }
+
+ p.srcsSupplier = srcsSupplier
+ p.srcsPropertyName = srcsPropertyName
+}
+
+func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+ if srcs == nil {
+ panic(fmt.Errorf("srcs must not be nil"))
+ }
+
+ srcsSupplier := func() []string {
+ return *srcs
+ }
+
+ InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
}
func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
- p := module.Prebuilt()
- module.AddProperties(&p.properties)
- p.srcProps = reflect.ValueOf(srcProps).Elem()
- p.srcField, _ = p.srcProps.Type().FieldByName(srcField)
- p.checkSingleSourceProperties()
+ srcPropsValue := reflect.ValueOf(srcProps).Elem()
+ srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
+ if !srcPropsValue.IsValid() || srcStructField.Name == "" {
+ panic(fmt.Errorf("invalid single source prebuilt %+v", module))
+ }
+
+ if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface {
+ panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps))
+ }
+
+ srcFieldIndex := srcStructField.Index
+ srcPropertyName := proptools.PropertyNameForField(srcField)
+
+ srcsSupplier := func() []string {
+ value := srcPropsValue.FieldByIndex(srcFieldIndex)
+ if value.Kind() == reflect.Ptr {
+ value = value.Elem()
+ }
+ if value.Kind() != reflect.String {
+ panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value))
+ }
+ src := value.String()
+ if src == "" {
+ return nil
+ }
+ return []string{src}
+ }
+
+ InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName)
}
type PrebuiltInterface interface {
@@ -152,7 +212,7 @@
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
p := m.Prebuilt()
- if p.srcs == nil && !p.srcProps.IsValid() {
+ if p.srcsSupplier == nil {
panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
}
if !p.properties.SourceExists {
@@ -191,11 +251,7 @@
// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt
// will be used if it is marked "prefer" or if the source module is disabled.
func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
- if p.srcs != nil && len(*p.srcs) == 0 {
- return false
- }
-
- if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
+ if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
return false
}
@@ -210,24 +266,3 @@
func (p *Prebuilt) SourceExists() bool {
return p.properties.SourceExists
}
-
-func (p *Prebuilt) checkSingleSourceProperties() {
- if !p.srcProps.IsValid() || p.srcField.Name == "" {
- panic(fmt.Errorf("invalid single source prebuilt %+v", p))
- }
-
- if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface {
- panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps))
- }
-}
-
-func (p *Prebuilt) getSingleSourceFieldValue() string {
- value := p.srcProps.FieldByIndex(p.srcField.Index)
- if value.Kind() == reflect.Ptr {
- value = value.Elem()
- }
- if value.Kind() != reflect.String {
- panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name))
- }
- return value.String()
-}
diff --git a/android/sdk.go b/android/sdk.go
index d13ad7d..2fdaf35 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -22,17 +22,30 @@
"github.com/google/blueprint/proptools"
)
+// Extracted from SdkAware to make it easier to define custom subsets of the
+// SdkAware interface and improve code navigation within the IDE.
+//
+// In addition to its use in SdkAware this interface must also be implemented by
+// APEX to specify the SDKs required by that module and its contents. e.g. APEX
+// is expected to implement RequiredSdks() by reading its own properties like
+// `uses_sdks`.
+type RequiredSdks interface {
+ // The set of SDKs required by an APEX and its contents.
+ RequiredSdks() SdkRefs
+}
+
// 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
+ RequiredSdks
+
sdkBase() *SdkBase
MakeMemberOf(sdk SdkRef)
IsInAnySdk() bool
ContainingSdk() SdkRef
MemberName() string
BuildWithSdks(sdks SdkRefs)
- RequiredSdks() SdkRefs
}
// SdkRef refers to a version of an SDK
@@ -145,10 +158,6 @@
return s.properties.RequiredSdks
}
-func (s *SdkBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder) {
- sdkModuleContext.ModuleErrorf("module type " + sdkModuleContext.OtherModuleType(s.module) + " cannot be used in an sdk")
-}
-
// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
// SdkBase.
func InitSdkAwareModule(m SdkAware) {
@@ -186,9 +195,33 @@
// 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())
- SdkMemberReferencePropertyTag() BpPropertyTag
+ // bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true))
+ SdkMemberReferencePropertyTag(required bool) BpPropertyTag
}
type BpPropertyTag interface{}
@@ -295,14 +328,36 @@
// the module is not allowed in whichever sdk property it was added.
IsInstance(module Module) bool
- // Build the snapshot for the SDK member
+ // Add a prebuilt module that the sdk will populate.
//
- // The ModuleContext provided is for the SDK module, so information for
- // variants in the supplied member can be accessed using the Other... methods.
+ // Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
+ // method to build the snapshot. That method is deprecated because it requires the SdkMemberType
+ // implementation to do all the word.
//
- // The SdkMember is guaranteed to contain variants for which the
- // IsInstance(Module) method returned true.
- BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
+ // Otherwise, returning a non-nil value from this will cause the sdk module type to do the
+ // majority of the work to generate the snapshot. 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.
+ //
+ // * 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
+
+ // Create a structure into which variant specific properties can be added.
+ CreateVariantPropertiesStruct() SdkMemberProperties
}
// Base type for SdkMemberType implementations.
@@ -389,3 +444,84 @@
SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType)
}
}
+
+// Base structure for all implementations of SdkMemberProperties.
+//
+// Contains common properties that apply across many different member types. These
+// are not affected by the optimization to extract common values.
+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.
+ //
+ // This property is set after optimization so there is no point in trying to optimize it.
+ Compile_multilib string `sdk:"keep"`
+}
+
+// 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
+}
+
+// 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 {
+ // Access the base structure.
+ Base() *SdkMemberPropertiesBase
+
+ // Populate this structure with information from the variant.
+ PopulateFromVariant(ctx SdkMemberContext, variant Module)
+
+ // Add the information from this structure to the property set.
+ AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
+}
+
+// Provides access to information common to a specific member.
+type SdkMemberContext interface {
+
+ // The module context of the sdk common os variant which is creating the snapshot.
+ SdkModuleContext() ModuleContext
+
+ // The builder of the snapshot.
+ SnapshotBuilder() SnapshotBuilder
+
+ // The type of the member.
+ MemberType() SdkMemberType
+
+ // The name of the member.
+ //
+ // Provided for use by sdk members to create a member specific location within the snapshot
+ // into which to copy the prebuilt files.
+ Name() string
+}
diff --git a/android/testing.go b/android/testing.go
index 9aff039..90989ef 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -410,6 +410,10 @@
}
+func SetInMakeForTests(config Config) {
+ config.inMake = true
+}
+
func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) []AndroidMkEntries {
var p AndroidMkEntriesProvider
var ok bool
diff --git a/apex/apex.go b/apex/apex.go
index f394068..b69f01c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,6 +18,7 @@
"fmt"
"path"
"path/filepath"
+ "regexp"
"sort"
"strings"
"sync"
@@ -61,8 +62,26 @@
usesTag = dependencyTag{name: "uses"}
androidAppTag = dependencyTag{name: "androidApp", payload: true}
apexAvailWl = makeApexAvailableWhitelist()
+
+ inverseApexAvailWl = invertApexWhiteList(apexAvailWl)
)
+// Transform the map of apex -> modules to module -> apexes.
+func invertApexWhiteList(m map[string][]string) map[string][]string {
+ r := make(map[string][]string)
+ for apex, modules := range m {
+ for _, module := range modules {
+ r[module] = append(r[module], apex)
+ }
+ }
+ return r
+}
+
+// Retrieve the while list of apexes to which the supplied module belongs.
+func WhitelistedApexAvailable(moduleName string) []string {
+ return inverseApexAvailWl[normalizeModuleName(moduleName)]
+}
+
// This is a map from apex to modules, which overrides the
// apex_available setting for that particular module to make
// it available for the apex regardless of its setting.
@@ -91,7 +110,7 @@
//
// Module separator
//
- m["com.android.art"] = []string{
+ artApexContents := []string{
"art_cmdlineparser_headers",
"art_disassembler_headers",
"art_libartbase_headers",
@@ -103,7 +122,6 @@
"crtbegin_dynamic1",
"crtbegin_so1",
"crtbrand",
- "conscrypt.module.intra.core.api.stubs",
"dex2oat_headers",
"dt_fd_forward_export",
"icu4c_extra_headers",
@@ -152,6 +170,8 @@
"libziparchive",
"perfetto_trace_protos",
}
+ m["com.android.art.debug"] = artApexContents
+ m["com.android.art.release"] = artApexContents
//
// Module separator
//
@@ -392,7 +412,6 @@
"libprocessgroup",
"libprocessgroup_headers",
"libprocinfo",
- "libsonivox",
"libspeexresampler",
"libspeexresampler",
"libstagefright_esds",
@@ -542,7 +561,6 @@
"libnativebridge_lazy",
"libnativeloader_lazy",
"libnativewindow_headers",
- "libopus",
"libpdx_headers",
"libprocessgroup",
"libprocessgroup_headers",
@@ -773,7 +791,7 @@
//
// Module separator
//
- m["//any"] = []string{
+ m[android.AvailableToAnyApex] = []string{
"libatomic",
"libclang_rt",
"libgcc_stripped",
@@ -787,12 +805,6 @@
}
func init() {
- android.AddNeverAllowRules(android.NeverAllow().
- ModuleType("apex").
- With("updatable", "true").
- With("min_sdk_version", "").
- Because("All updatable apexes should set min_sdk_version."))
-
android.RegisterModuleType("apex", BundleFactory)
android.RegisterModuleType("apex_test", testApexBundleFactory)
android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
@@ -820,15 +832,19 @@
ctx.BottomUp("apex", apexMutator).Parallel()
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
+ ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
}
// Mark the direct and transitive dependencies of apex bundles so that they
// can be built for the apex bundles.
func apexDepsMutator(mctx android.TopDownMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
var apexBundles []android.ApexInfo
var directDep bool
if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
- apexBundles = []android.ApexInfo{android.ApexInfo{
+ apexBundles = []android.ApexInfo{{
ApexName: mctx.ModuleName(),
MinSdkVersion: a.minSdkVersion(mctx),
}}
@@ -842,22 +858,87 @@
return
}
- cur := mctx.Module().(interface {
- DepIsInSameApex(android.BaseModuleContext, android.Module) bool
- })
+ cur := mctx.Module().(android.DepIsInSameApex)
mctx.VisitDirectDeps(func(child android.Module) {
depName := mctx.OtherModuleName(child)
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
- cur.DepIsInSameApex(mctx, child) {
+ (cur.DepIsInSameApex(mctx, child) || inAnySdk(child)) {
android.UpdateApexDependency(apexBundles, depName, directDep)
am.BuildForApexes(apexBundles)
}
})
}
+// mark if a module cannot be available to platform. A module cannot be available
+// to platform if 1) it is explicitly marked as not available (i.e. "//apex_available:platform"
+// is absent) or 2) it depends on another module that isn't (or can't be) available to platform
+func markPlatformAvailability(mctx android.BottomUpMutatorContext) {
+ // Host and recovery are not considered as platform
+ if mctx.Host() || mctx.Module().InstallInRecovery() {
+ return
+ }
+
+ if am, ok := mctx.Module().(android.ApexModule); ok {
+ availableToPlatform := am.AvailableFor(android.AvailableToPlatform)
+
+ // In a rare case when a lib is marked as available only to an apex
+ // but the apex doesn't exist. This can happen in a partial manifest branch
+ // like master-art. Currently, libstatssocket in the stats APEX is causing
+ // this problem.
+ // Include the lib in platform because the module SDK that ought to provide
+ // it doesn't exist, so it would otherwise be left out completely.
+ // TODO(b/154888298) remove this by adding those libraries in module SDKS and skipping
+ // this check for libraries provided by SDKs.
+ if !availableToPlatform && !android.InAnyApex(am.Name()) {
+ availableToPlatform = true
+ }
+
+ // If any of the dep is not available to platform, this module is also considered
+ // as being not available to platform even if it has "//apex_available:platform"
+ mctx.VisitDirectDeps(func(child android.Module) {
+ if !am.DepIsInSameApex(mctx, child) {
+ // if the dependency crosses apex boundary, don't consider it
+ return
+ }
+ if dep, ok := child.(android.ApexModule); ok && dep.NotAvailableForPlatform() {
+ availableToPlatform = false
+ // TODO(b/154889534) trigger an error when 'am' has "//apex_available:platform"
+ }
+ })
+
+ // Exception 1: stub libraries and native bridge libraries are always available to platform
+ if cc, ok := mctx.Module().(*cc.Module); ok &&
+ (cc.IsStubs() || cc.Target().NativeBridge == android.NativeBridgeEnabled) {
+ availableToPlatform = true
+ }
+
+ // Exception 2: bootstrap bionic libraries are also always available to platform
+ if cc.InstallToBootstrap(mctx.ModuleName(), mctx.Config()) {
+ availableToPlatform = true
+ }
+
+ if !availableToPlatform {
+ am.SetNotAvailableForPlatform()
+ }
+ }
+}
+
+// If a module in an APEX depends on a module from an SDK then it needs an APEX
+// specific variant created for it. Refer to sdk.sdkDepsReplaceMutator.
+func inAnySdk(module android.Module) bool {
+ if sa, ok := module.(android.SdkAware); ok {
+ return sa.IsInAnySdk()
+ }
+
+ return false
+}
+
// Create apex variations if a module is included in APEX(s).
func apexMutator(mctx android.BottomUpMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
am.CreateApexVariations(mctx)
} else if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
@@ -895,6 +976,9 @@
}
func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
if ab, ok := mctx.Module().(*apexBundle); ok {
var variants []string
switch proptools.StringDefault(ab.properties.Payload_type, "image") {
@@ -1078,11 +1162,17 @@
// Should be only used in tests#.
Test_only_no_hashtree *bool
+ // Whenever apex_payload.img of the APEX should not be dm-verity signed.
+ // Should be only used in tests#.
+ Test_only_unsigned_payload *bool
+
IsCoverageVariant bool `blueprint:"mutated"`
// Whether this APEX is considered updatable or not. When set to true, this will enforce additional
- // rules for making sure that the APEX is truely updatable. This will also disable the size optimizations
- // like symlinking to the system libs. Default is false.
+ // rules for making sure that the APEX is truly updatable.
+ // - To be updatable, min_sdk_version should be set as well
+ // This will also disable the size optimizations like symlinking to the system libs.
+ // Default is false.
Updatable *bool
// The minimum SDK version that this apex must be compatible with.
@@ -1567,6 +1657,10 @@
return proptools.Bool(a.properties.Test_only_no_hashtree)
}
+func (a *apexBundle) testOnlyShouldSkipPayloadSign() bool {
+ return proptools.Bool(a.properties.Test_only_unsigned_payload)
+}
+
func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
if a.vndkApex {
return cc.VendorVariationPrefix + a.vndkVersion(config)
@@ -1718,15 +1812,16 @@
func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface {
android.Module
Privileged() bool
+ InstallApkName() string
OutputFile() android.Path
JacocoReportClassesFile() android.Path
Certificate() java.Certificate
-}, pkgName string) apexFile {
+}) apexFile {
appDir := "app"
if aapp.Privileged() {
appDir = "priv-app"
}
- dirInApex := filepath.Join(appDir, pkgName)
+ dirInApex := filepath.Join(appDir, aapp.InstallApkName())
fileToCopy := aapp.OutputFile()
af := newApexFile(ctx, fileToCopy, aapp.Name(), dirInApex, app, aapp)
af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
@@ -1749,10 +1844,14 @@
return true
}
+// Function called while walking an APEX's payload dependencies.
+//
+// Return true if the `to` module should be visited, false otherwise.
+type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
+
// Visit dependencies that contributes to the payload of this APEX
-func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
- do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
- ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
+ ctx.WalkDeps(func(child, parent android.Module) bool {
am, ok := child.(android.ApexModule)
if !ok || !am.CanHaveApexVariants() {
return false
@@ -1761,22 +1860,18 @@
// Check for the direct dependencies that contribute to the payload
if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
if dt.payload {
- do(ctx, parent, am, false /* externalDep */)
- return true
+ return do(ctx, parent, am, false /* externalDep */)
}
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
}
// Check for the indirect dependencies if it is considered as part of the APEX
if am.ApexName() != "" {
- do(ctx, parent, am, false /* externalDep */)
- return true
+ return do(ctx, parent, am, false /* externalDep */)
}
- do(ctx, parent, am, true /* externalDep */)
-
- // As soon as the dependency graph crosses the APEX boundary, don't go further.
- return false
+ return do(ctx, parent, am, true /* externalDep */)
})
}
@@ -1789,6 +1884,24 @@
return intVer
}
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
+
+func PrettyPrintTag(tag blueprint.DependencyTag) string {
+ // Use tag's custom String() method if available.
+ if stringer, ok := tag.(fmt.Stringer); ok {
+ return stringer.String()
+ }
+
+ // Otherwise, get a default string representation of the tag's struct.
+ tagString := fmt.Sprintf("%#v", tag)
+
+ // Remove the boilerplate from BaseDependencyTag as it adds no value.
+ tagString = tagCleaner.ReplaceAllString(tagString, "")
+ return tagString
+}
+
// Ensures that the dependencies are marked as available for this APEX
func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
// Let's be practical. Availability for test, host, and the VNDK apex isn't important
@@ -1803,24 +1916,55 @@
return
}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ if externalDep {
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
+ }
+
apexName := ctx.ModuleName()
fromName := ctx.OtherModuleName(from)
toName := ctx.OtherModuleName(to)
- if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
- return
+
+ // If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither
+ // do any of its dependencies.
+ if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
}
- ctx.ModuleErrorf("%q requires %q that is not available for the APEX.", fromName, toName)
+
+ if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
+ return true
+ }
+ message := ""
+ tagPath := ctx.GetTagPath()
+ // Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf().
+ walkPath := ctx.GetWalkPath()[1:]
+ for i, m := range walkPath {
+ message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String())
+ }
+ ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
+ // Visit this module's dependencies to check and report any issues with their availability.
+ return true
})
}
+func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
+ if proptools.Bool(a.properties.Updatable) {
+ if String(a.properties.Min_sdk_version) == "" {
+ ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
+ }
+ }
+}
+
// Collects the list of module names that directly or indirectly contributes to the payload of this APEX
func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
a.depInfos = make(map[string]depInfo)
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if from.Name() == to.Name() {
// This can happen for cc.reuseObjTag. We are not interested in tracking this.
- return
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return !externalDep
}
if info, exists := a.depInfos[to.Name()]; exists {
@@ -1836,6 +1980,9 @@
isExternal: externalDep,
}
}
+
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return !externalDep
})
}
@@ -1875,6 +2022,7 @@
}
a.checkApexAvailability(ctx)
+ a.checkUpdatable(ctx)
a.collectDepsInfo(ctx)
@@ -1912,6 +2060,9 @@
// TODO(jiyong) do this using walkPayloadDeps
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child)
+ if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
depName := ctx.OtherModuleName(child)
if _, isDirectDep := parent.(*apexBundle); isDirectDep {
switch depTag {
@@ -1960,14 +2111,13 @@
ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
}
case androidAppTag:
- pkgName := ctx.DeviceConfig().OverridePackageNameFor(depName)
if ap, ok := child.(*java.AndroidApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+ filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
return true // track transitive dependencies
} else if ap, ok := child.(*java.AndroidAppImport); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+ filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
} else if ap, ok := child.(*java.AndroidTestHelperApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+ filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
} else {
ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
}
@@ -2073,7 +2223,7 @@
filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
}
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
- ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
+ ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName)
}
}
}
@@ -2182,10 +2332,21 @@
func whitelistedApexAvailable(apex, moduleName string) bool {
key := apex
- key = strings.Replace(key, "test_", "", 1)
- key = strings.Replace(key, "com.android.art.debug", "com.android.art", 1)
- key = strings.Replace(key, "com.android.art.release", "com.android.art", 1)
+ moduleName = normalizeModuleName(moduleName)
+ if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+ return true
+ }
+
+ key = android.AvailableToAnyApex
+ if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+ return true
+ }
+
+ return false
+}
+
+func normalizeModuleName(moduleName string) string {
// Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
// system. Trim the prefix for the check since they are confusing
moduleName = strings.TrimPrefix(moduleName, "prebuilt_")
@@ -2194,17 +2355,7 @@
// We don't want to list them all
moduleName = "libclang_rt"
}
-
- if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
- return true
- }
-
- key = "//any"
- if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
- return true
- }
-
- return false
+ return moduleName
}
func newApexBundle() *apexBundle {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 4b56b6b..91ad6e8 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -141,6 +141,7 @@
"my_include": nil,
"foo/bar/MyClass.java": nil,
"prebuilt.jar": nil,
+ "prebuilt.so": nil,
"vendor/foo/devkeys/test.x509.pem": nil,
"vendor/foo/devkeys/test.pk8": nil,
"testkey.x509.pem": nil,
@@ -342,7 +343,7 @@
apex_available: [ "myapex" ],
}
- cc_library {
+ cc_library_shared {
name: "mylib2",
srcs: ["mylib.cpp"],
system_shared_libs: [],
@@ -356,6 +357,16 @@
],
}
+ cc_prebuilt_library_shared {
+ name: "mylib2",
+ srcs: ["prebuilt.so"],
+ // TODO: remove //apex_available:platform
+ apex_available: [
+ "//apex_available:platform",
+ "myapex",
+ ],
+ }
+
cc_library_static {
name: "libstatic",
srcs: ["mylib.cpp"],
@@ -3402,6 +3413,7 @@
dex_preopt: {
enabled: false,
},
+ filename: "AwesomePrebuiltAppFooPriv.apk",
}
`)
@@ -3410,7 +3422,47 @@
copyCmds := apexRule.Args["copy_commands"]
ensureContains(t, copyCmds, "image.apex/app/AppFooPrebuilt/AppFooPrebuilt.apk")
- ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AppFooPrivPrebuilt.apk")
+ ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AwesomePrebuiltAppFooPriv.apk")
+}
+
+func TestApexWithAppImportsPrefer(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apps: [
+ "AppFoo",
+ ],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ android_app {
+ name: "AppFoo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ android_app_import {
+ name: "AppFoo",
+ apk: "AppFooPrebuilt.apk",
+ filename: "AppFooPrebuilt.apk",
+ presigned: true,
+ prefer: true,
+ }
+ `, withFiles(map[string][]byte{
+ "AppFooPrebuilt.apk": nil,
+ }))
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "app/AppFoo/AppFooPrebuilt.apk",
+ })
}
func TestApexWithTestHelperApp(t *testing.T) {
@@ -3478,7 +3530,7 @@
}`)
}
-func TestApexAvailable(t *testing.T) {
+func TestApexAvailable_DirectDep(t *testing.T) {
// libfoo is not available to myapex, but only to otherapex
testApexError(t, "requires \"libfoo\" that is not available for the APEX", `
apex {
@@ -3511,9 +3563,17 @@
system_shared_libs: [],
apex_available: ["otherapex"],
}`)
+}
+func TestApexAvailable_IndirectDep(t *testing.T) {
// libbbaz is an indirect dep
- testApexError(t, "requires \"libbaz\" that is not available for the APEX", `
+ testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path:
+.*via tag apex\.dependencyTag.*"sharedLib".*
+.*-> libfoo.*link:shared.*
+.*via tag cc\.DependencyTag.*"shared".*
+.*-> libbar.*link:shared.*
+.*via tag cc\.DependencyTag.*"shared".*
+.*-> libbaz.*link:shared.*`, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3547,7 +3607,9 @@
stl: "none",
system_shared_libs: [],
}`)
+}
+func TestApexAvailable_InvalidApexName(t *testing.T) {
testApexError(t, "\"otherapex\" is not a valid module name", `
apex {
name: "myapex",
@@ -3568,7 +3630,7 @@
apex_available: ["otherapex"],
}`)
- ctx, _ := testApex(t, `
+ testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3604,22 +3666,14 @@
versions: ["10", "20", "30"],
},
}`)
+}
- // check that libfoo and libbar are created only for myapex, but not for the platform
- // TODO(jiyong) the checks for the platform variant are removed because we now create
- // the platform variant regardless of the apex_availability. Instead, we will make sure that
- // the platform variants are not used from other platform modules. When that is done,
- // these checks will be replaced by expecting a specific error message that will be
- // emitted when the platform variant is used.
- // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
- // ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
- // ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
- // ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
-
- ctx, _ = testApex(t, `
+func TestApexAvailable_CheckForPlatform(t *testing.T) {
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
+ native_shared_libs: ["libbar", "libbaz"],
}
apex_key {
@@ -3632,14 +3686,52 @@
name: "libfoo",
stl: "none",
system_shared_libs: [],
+ shared_libs: ["libbar"],
apex_available: ["//apex_available:platform"],
+ }
+
+ cc_library {
+ name: "libfoo2",
+ stl: "none",
+ system_shared_libs: [],
+ shared_libs: ["libbaz"],
+ apex_available: ["//apex_available:platform"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbaz",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["myapex"],
+ stubs: {
+ versions: ["1"],
+ },
}`)
- // check that libfoo is created only for the platform
- ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+ // libfoo shouldn't be available to platform even though it has "//apex_available:platform",
+ // because it depends on libbar which isn't available to platform
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+ if libfoo.NotAvailableForPlatform() != true {
+ t.Errorf("%q shouldn't be available to platform", libfoo.String())
+ }
- ctx, _ = testApex(t, `
+ // libfoo2 however can be available to platform because it depends on libbaz which provides
+ // stubs
+ libfoo2 := ctx.ModuleForTests("libfoo2", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+ if libfoo2.NotAvailableForPlatform() == true {
+ t.Errorf("%q should be available to platform", libfoo2.String())
+ }
+}
+
+func TestApexAvailable_CreatedForApex(t *testing.T) {
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3662,17 +3754,14 @@
},
}`)
- // shared variant of libfoo is only available to myapex
- // TODO(jiyong) the checks for the platform variant are removed because we now create
- // the platform variant regardless of the apex_availability. Instead, we will make sure that
- // the platform variants are not used from other platform modules. When that is done,
- // these checks will be replaced by expecting a specific error message that will be
- // emitted when the platform variant is used.
- // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
- // ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
- // // but the static variant is available to both myapex and the platform
- // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static_myapex")
- // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static")
+ libfooShared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+ if libfooShared.NotAvailableForPlatform() != true {
+ t.Errorf("%q shouldn't be available to platform", libfooShared.String())
+ }
+ libfooStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*cc.Module)
+ if libfooStatic.NotAvailableForPlatform() != false {
+ t.Errorf("%q should be available to platform", libfooStatic.String())
+ }
}
func TestOverrideApex(t *testing.T) {
@@ -3729,7 +3818,7 @@
copyCmds := apexRule.Args["copy_commands"]
ensureNotContains(t, copyCmds, "image.apex/app/app/app.apk")
- ensureContains(t, copyCmds, "image.apex/app/app/override_app.apk")
+ ensureContains(t, copyCmds, "image.apex/app/override_app/override_app.apk")
apexBundle := module.Module().(*apexBundle)
name := apexBundle.Name()
@@ -3951,6 +4040,7 @@
native_shared_libs: ["mylib"],
java_libs: ["myjar"],
updatable: true,
+ min_sdk_version: "current",
}
apex_key {
@@ -4060,6 +4150,27 @@
ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
}
+func TestApexMutatorsDontRunIfDisabled(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ delete(config.Targets, android.Android)
+ config.AndroidCommonTarget = android.Target{}
+ })
+
+ if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) {
+ t.Errorf("Expected variants: %v, but got: %v", expected, got)
+ }
+}
+
func TestAppBundle(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -4155,6 +4266,22 @@
}
}
+func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
+ testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+}
+
func TestNoUpdatableJarsInBootImage(t *testing.T) {
bp := `
java_library {
diff --git a/apex/builder.go b/apex/builder.go
index 1fc2233..0d7e801 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -219,14 +219,18 @@
func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
var noticeFiles android.Paths
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if externalDep {
- return
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
}
+
notice := to.NoticeFile()
if notice.Valid() {
noticeFiles = append(noticeFiles, notice.Path())
}
+
+ return true
})
if len(noticeFiles) == 0 {
@@ -480,6 +484,10 @@
optFlags = append(optFlags, "--no_hashtree")
}
+ if a.testOnlyShouldSkipPayloadSign() {
+ optFlags = append(optFlags, "--unsigned_payload")
+ }
+
if a.properties.Apex_name != nil {
// If apex_name is set, apexer can skip checking if key name matches with apex name.
// Note that apex_manifest is also mended.
@@ -583,7 +591,7 @@
apexBundleName := a.Name()
a.outputFile = android.PathForModuleInstall(&factx, "apex", apexBundleName)
- if a.installable() && a.GetOverriddenBy() == "" {
+ if a.installable() {
installPath := android.PathForModuleInstall(ctx, "apex", apexBundleName)
devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
addFlattenedFileContextsInfos(ctx, apexBundleName+":"+devicePath+":"+a.fileContexts.String())
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 53bc065..9b3235c 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -63,49 +63,12 @@
return false
}
-func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- info := mt.organizeVariants(member)
- buildSharedNativeBinarySnapshot(info, builder, member)
+func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
}
-// Organize the variants by architecture.
-func (mt *binarySdkMemberType) organizeVariants(member android.SdkMember) *nativeBinaryInfo {
- memberName := member.Name()
- info := &nativeBinaryInfo{
- name: memberName,
- memberType: mt,
- }
-
- for _, variant := range member.Variants() {
- ccModule := variant.(*Module)
-
- info.archVariantProperties = append(info.archVariantProperties, nativeBinaryInfoProperties{
- name: memberName,
- archType: ccModule.Target().Arch.ArchType.String(),
- outputFile: ccModule.OutputFile().Path(),
- })
- }
-
- // Initialize the unexported properties that will not be set during the
- // extraction process.
- info.commonProperties.name = memberName
-
- // Extract common properties from the arch specific properties.
- extractCommonProperties(&info.commonProperties, info.archVariantProperties)
-
- return info
-}
-
-func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
- pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
- pbm.AddProperty("compile_multilib", "both")
- archProperties := pbm.AddPropertySet("arch")
- for _, av := range info.archVariantProperties {
- archTypeProperties := archProperties.AddPropertySet(av.archType)
- archTypeProperties.AddProperty("srcs", []string{nativeBinaryPathFor(av)})
-
- builder.CopyToSnapshot(av.outputFile, nativeBinaryPathFor(av))
- }
+func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &nativeBinaryInfoProperties{}
}
const (
@@ -114,7 +77,7 @@
// path to the native binary. Relative to <sdk_root>/<api_dir>
func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
- return filepath.Join(lib.archType,
+ return filepath.Join(lib.OsPrefix(), lib.archType,
nativeBinaryDir, lib.outputFile.Base())
}
@@ -123,8 +86,7 @@
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeBinaryInfoProperties struct {
- // The name of the library, is not exported as this must not be changed during optimization.
- name string
+ android.SdkMemberPropertiesBase
// archType is not exported as if set (to a non default value) it is always arch specific.
// This is "" for common properties.
@@ -132,12 +94,50 @@
// outputFile is not exported as it is always arch specific.
outputFile android.Path
+
+ // The set of shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SharedLibs []string
+
+ // The set of system shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SystemSharedLibs []string
}
-// nativeBinaryInfo represents a collection of arch-specific modules having the same name
-type nativeBinaryInfo struct {
- name string
- memberType *binarySdkMemberType
- archVariantProperties []nativeBinaryInfoProperties
- commonProperties nativeBinaryInfoProperties
+func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ ccModule := variant.(*Module)
+
+ p.archType = ccModule.Target().Arch.ArchType.String()
+ p.outputFile = ccModule.OutputFile().Path()
+
+ if ccModule.linker != nil {
+ specifiedDeps := specifiedDeps{}
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+ p.SharedLibs = specifiedDeps.sharedLibs
+ p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+ }
+}
+
+func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if p.Compile_multilib != "" {
+ propertySet.AddProperty("compile_multilib", p.Compile_multilib)
+ }
+
+ builder := ctx.SnapshotBuilder()
+ if p.outputFile != nil {
+ propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
+
+ builder.CopyToSnapshot(p.outputFile, nativeBinaryPathFor(*p))
+ }
+
+ if len(p.SharedLibs) > 0 {
+ propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
+
+ if len(p.SystemSharedLibs) > 0 {
+ propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
}
diff --git a/cc/cc.go b/cc/cc.go
index 133b033..9baeceb 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -211,6 +211,9 @@
// Minimum sdk version supported when compiling against the ndk
Sdk_version *string
+ // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ Min_sdk_version *string
+
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
@@ -250,6 +253,8 @@
// Used by vendor snapshot to record dependencies from snapshot modules.
SnapshotSharedLibs []string `blueprint:"mutated"`
SnapshotRuntimeLibs []string `blueprint:"mutated"`
+
+ Installable *bool
}
type VendorProperties struct {
@@ -368,11 +373,21 @@
nativeCoverage() bool
coverageOutputFilePath() android.OptionalPath
+
+ // Get the deps that have been explicitly specified in the properties.
+ // Only updates the
+ linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
+}
+
+type specifiedDeps struct {
+ sharedLibs []string
+ systemSharedLibs []string
}
type installer interface {
installerProps() []interface{}
install(ctx ModuleContext, path android.Path)
+ everInstallable() bool
inData() bool
inSanitizerDir() bool
hostToolPath() android.OptionalPath
@@ -1513,6 +1528,13 @@
if ctx.Failed() {
return
}
+ } else if !proptools.BoolDefault(c.Properties.Installable, true) {
+ // If the module has been specifically configure to not be installed then
+ // skip the installation as otherwise it will break when running inside make
+ // as the output path to install will not be specified. Not all uninstallable
+ // modules can skip installation as some are needed for resolving make side
+ // dependencies.
+ c.SkipInstall()
}
}
@@ -2705,8 +2727,18 @@
}
}
+// Return true if the module is ever installable.
+func (c *Module) EverInstallable() bool {
+ return c.installer != nil &&
+ // Check to see whether the module is actually ever installable.
+ c.installer.everInstallable()
+}
+
func (c *Module) installable() bool {
- ret := c.installer != nil && !c.Properties.PreventInstall && c.outputFile.Valid()
+ ret := c.EverInstallable() &&
+ // Check to see whether the module has been configured to not be installed.
+ proptools.BoolDefault(c.Properties.Installable, true) &&
+ !c.Properties.PreventInstall && c.outputFile.Valid()
// The platform variant doesn't need further condition. Apex variants however might not
// be installable because it will likely to be included in the APEX and won't appear
diff --git a/cc/genrule.go b/cc/genrule.go
index 155e410..9331448 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -27,6 +27,7 @@
Vendor_available *bool
Ramdisk_available *bool
Recovery_available *bool
+ Sdk_version *string
}
// cc_genrule is a genrule that can depend on other cc_* objects.
diff --git a/cc/installer.go b/cc/installer.go
index 13a4119..0b4a68c 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -86,6 +86,11 @@
installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
}
+func (installer *baseInstaller) everInstallable() bool {
+ // Most cc modules are installable.
+ return true
+}
+
func (installer *baseInstaller) inData() bool {
return installer.location == InstallInData
}
diff --git a/cc/library.go b/cc/library.go
index 3bed8a0..c3b20b6 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -183,7 +183,6 @@
ctx.RegisterModuleType("cc_library", LibraryFactory)
ctx.RegisterModuleType("cc_library_host_static", LibraryHostStaticFactory)
ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
- ctx.RegisterModuleType("cc_library_headers", LibraryHeaderFactory)
}
// cc_library creates both static and/or shared libraries for a device and/or
@@ -196,6 +195,7 @@
module.sdkMemberTypes = []android.SdkMemberType{
sharedLibrarySdkMemberType,
staticLibrarySdkMemberType,
+ staticAndSharedLibrarySdkMemberType,
}
return module.Init()
}
@@ -233,16 +233,6 @@
return module.Init()
}
-// cc_library_headers contains a set of c/c++ headers which are imported by
-// other soong cc modules using the header_libs property. For best practices,
-// use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
-// Make.
-func LibraryHeaderFactory() android.Module {
- module, library := NewLibrary(android.HostAndDeviceSupported)
- library.HeaderOnly()
- return module.Init()
-}
-
type flagExporter struct {
Properties FlagExporterProperties
@@ -828,6 +818,23 @@
return deps
}
+func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+ specifiedDeps = library.baseLinker.linkerSpecifiedDeps(specifiedDeps)
+ var properties StaticOrSharedProperties
+ if library.static() {
+ properties = library.StaticProperties.Static
+ } else if library.shared() {
+ properties = library.SharedProperties.Shared
+ }
+
+ specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...)
+ specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
+
+ specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs)
+ specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
+ return specifiedDeps
+}
+
func (library *libraryDecorator) linkStatic(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
@@ -1232,6 +1239,12 @@
}
}
+func (library *libraryDecorator) everInstallable() bool {
+ // Only shared and static libraries are installed. Header libraries (which are
+ // neither static or shared) are not installed.
+ return library.shared() || library.static()
+}
+
func (library *libraryDecorator) static() bool {
return library.MutatedProperties.VariantIsStatic
}
@@ -1394,22 +1407,28 @@
if cc_prebuilt {
library := mctx.Module().(*Module).linker.(prebuiltLibraryInterface)
- // Always create both the static and shared variants for prebuilt libraries, and then disable the one
- // that is not being used. This allows them to share the name of a cc_library module, which requires that
- // all the variants of the cc_library also exist on the prebuilt.
- modules := mctx.CreateLocalVariations("static", "shared")
- static := modules[0].(*Module)
- shared := modules[1].(*Module)
+ // Differentiate between header only and building an actual static/shared library
+ if library.buildStatic() || library.buildShared() {
+ // Always create both the static and shared variants for prebuilt libraries, and then disable the one
+ // that is not being used. This allows them to share the name of a cc_library module, which requires that
+ // all the variants of the cc_library also exist on the prebuilt.
+ modules := mctx.CreateLocalVariations("static", "shared")
+ static := modules[0].(*Module)
+ shared := modules[1].(*Module)
- static.linker.(prebuiltLibraryInterface).setStatic()
- shared.linker.(prebuiltLibraryInterface).setShared()
+ static.linker.(prebuiltLibraryInterface).setStatic()
+ shared.linker.(prebuiltLibraryInterface).setShared()
- if !library.buildStatic() {
- static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+ if !library.buildStatic() {
+ static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+ }
+ if !library.buildShared() {
+ shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+ }
+ } else {
+ // Header only
}
- if !library.buildShared() {
- shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
- }
+
} else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
// Non-cc.Modules may need an empty variant for their mutators.
diff --git a/cc/library_headers.go b/cc/library_headers.go
new file mode 100644
index 0000000..88cf7af
--- /dev/null
+++ b/cc/library_headers.go
@@ -0,0 +1,56 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// 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 cc
+
+import "android/soong/android"
+
+func init() {
+ RegisterLibraryHeadersBuildComponents(android.InitRegistrationContext)
+
+ // Register sdk member types.
+ android.RegisterSdkMemberType(headersLibrarySdkMemberType)
+}
+
+var headersLibrarySdkMemberType = &librarySdkMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "native_header_libs",
+ SupportsSdk: true,
+ },
+ prebuiltModuleType: "cc_prebuilt_library_headers",
+ linkTypes: nil,
+}
+
+func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("cc_library_headers", LibraryHeaderFactory)
+ ctx.RegisterModuleType("cc_prebuilt_library_headers", prebuiltLibraryHeaderFactory)
+}
+
+// cc_library_headers contains a set of c/c++ headers which are imported by
+// other soong cc modules using the header_libs property. For best practices,
+// use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
+// Make.
+func LibraryHeaderFactory() android.Module {
+ module, library := NewLibrary(android.HostAndDeviceSupported)
+ library.HeaderOnly()
+ module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType}
+ return module.Init()
+}
+
+// cc_prebuilt_library_headers is a prebuilt version of cc_library_headers
+func prebuiltLibraryHeaderFactory() android.Module {
+ module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+ library.HeaderOnly()
+ return module.Init()
+}
diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go
new file mode 100644
index 0000000..564ef61
--- /dev/null
+++ b/cc/library_headers_test.go
@@ -0,0 +1,62 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// 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 cc
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestLibraryHeaders(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library_headers {
+ name: "headers",
+ export_include_dirs: ["my_include"],
+ }
+ cc_library_static {
+ name: "lib",
+ srcs: ["foo.c"],
+ header_libs: ["headers"],
+ }
+ `)
+
+ // test if header search paths are correctly added
+ cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+ cflags := cc.Args["cFlags"]
+ if !strings.Contains(cflags, " -Imy_include ") {
+ t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+ }
+}
+
+func TestPrebuiltLibraryHeaders(t *testing.T) {
+ ctx := testCc(t, `
+ cc_prebuilt_library_headers {
+ name: "headers",
+ export_include_dirs: ["my_include"],
+ }
+ cc_library_static {
+ name: "lib",
+ srcs: ["foo.c"],
+ header_libs: ["headers"],
+ }
+ `)
+
+ // test if header search paths are correctly added
+ cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+ cflags := cc.Args["cFlags"]
+ if !strings.Contains(cflags, " -Imy_include ") {
+ t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+ }
+}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index dd097cf..566bdce 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -16,10 +16,10 @@
import (
"path/filepath"
- "reflect"
"android/soong/android"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
// This file contains support for using cc library modules within an sdk.
@@ -42,10 +42,20 @@
linkTypes: []string{"static"},
}
+var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "native_libs",
+ SupportsSdk: true,
+ },
+ prebuiltModuleType: "cc_prebuilt_library",
+ linkTypes: []string{"static", "shared"},
+}
+
func init() {
// Register sdk member types.
android.RegisterSdkMemberType(sharedLibrarySdkMemberType)
android.RegisterSdkMemberType(staticLibrarySdkMemberType)
+ android.RegisterSdkMemberType(staticAndSharedLibrarySdkMemberType)
}
type librarySdkMemberType struct {
@@ -65,12 +75,19 @@
if version == "" {
version = LatestStubsVersionFor(mctx.Config(), name)
}
- for _, linkType := range mt.linkTypes {
+ if mt.linkTypes == nil {
mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: android.CoreVariation},
- {Mutator: "link", Variation: linkType},
{Mutator: "version", Variation: version},
}...), dependencyTag, name)
+ } else {
+ for _, linkType := range mt.linkTypes {
+ mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+ {Mutator: "image", Variation: android.CoreVariation},
+ {Mutator: "link", Variation: linkType},
+ {Mutator: "version", Variation: version},
+ }...), dependencyTag, name)
+ }
}
}
}
@@ -89,48 +106,25 @@
return false
}
-// copy exported header files and stub *.so files
-func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- info := mt.organizeVariants(member)
- buildSharedNativeLibSnapshot(sdkModuleContext, info, builder, member)
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType)
+
+ ccModule := member.Variants()[0].(*Module)
+
+ sdkVersion := ccModule.SdkVersion()
+ if sdkVersion != "" {
+ pbm.AddProperty("sdk_version", sdkVersion)
+ }
+
+ stl := ccModule.stl.Properties.Stl
+ if stl != nil {
+ pbm.AddProperty("stl", proptools.String(stl))
+ }
+ return pbm
}
-// Organize the variants by architecture.
-func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
- memberName := member.Name()
- info := &nativeLibInfo{
- name: memberName,
- memberType: mt,
- }
-
- for _, variant := range member.Variants() {
- ccModule := variant.(*Module)
-
- // Separate out the generated include dirs (which are arch specific) from the
- // include dirs (which may not be).
- exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
- ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
-
- info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
- name: memberName,
- archType: ccModule.Target().Arch.ArchType.String(),
- ExportedIncludeDirs: exportedIncludeDirs,
- exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
- ExportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
- ExportedFlags: ccModule.ExportedFlags(),
- exportedGeneratedHeaders: ccModule.ExportedGeneratedHeaders(),
- outputFile: ccModule.OutputFile().Path(),
- })
- }
-
- // Initialize the unexported properties that will not be set during the
- // extraction process.
- info.commonProperties.name = memberName
-
- // Extract common properties from the arch specific properties.
- extractCommonProperties(&info.commonProperties, info.archVariantProperties)
-
- return info
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &nativeLibInfoProperties{memberType: mt}
}
func isGeneratedHeaderDirectory(p android.Path) bool {
@@ -138,144 +132,137 @@
return gen
}
-// Extract common properties from a slice of property structures of the same type.
-//
-// All the property structures must be of the same type.
-// commonProperties - must be a pointer to the structure into which common properties will be added.
-// inputPropertiesSlice - must be a slice of input properties structures.
-//
-// Iterates over each exported field (capitalized name) and checks to see whether they
-// have the same value (using DeepEquals) across all the input properties. If it does not then no
-// change is made. Otherwise, the common value is stored in the field in the commonProperties
-// and the field in each of the input properties structure is set to its default value.
-func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
- commonStructValue := reflect.ValueOf(commonProperties).Elem()
- propertiesStructType := commonStructValue.Type()
+type includeDirsProperty struct {
+ // Accessor to retrieve the paths
+ pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths
- // Create an empty structure from which default values for the field can be copied.
- emptyStructValue := reflect.New(propertiesStructType).Elem()
+ // The name of the property in the prebuilt library, "" means there is no property.
+ propertyName string
- for f := 0; f < propertiesStructType.NumField(); f++ {
- // Check to see if all the structures have the same value for the field. The commonValue
- // is nil on entry to the loop and if it is nil on exit then there is no common value,
- // otherwise it points to the common value.
- var commonValue *reflect.Value
- sliceValue := reflect.ValueOf(inputPropertiesSlice)
+ // The directory within the snapshot directory into which items should be copied.
+ snapshotDir string
- for i := 0; i < sliceValue.Len(); i++ {
- structValue := sliceValue.Index(i)
- fieldValue := structValue.Field(f)
- if !fieldValue.CanInterface() {
- // The field is not exported so ignore it.
- continue
- }
+ // True if the items on the path should be copied.
+ copy bool
- if commonValue == nil {
- // Use the first value as the commonProperties value.
- commonValue = &fieldValue
- } else {
- // If the value does not match the current common value then there is
- // no value in common so break out.
- if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
- commonValue = nil
- break
- }
- }
- }
-
- // If the fields all have a common value then store it in the common struct field
- // and set the input struct's field to the empty value.
- if commonValue != nil {
- emptyValue := emptyStructValue.Field(f)
- commonStructValue.Field(f).Set(*commonValue)
- for i := 0; i < sliceValue.Len(); i++ {
- structValue := sliceValue.Index(i)
- fieldValue := structValue.Field(f)
- fieldValue.Set(emptyValue)
- }
- }
- }
+ // True if the paths represent directories, files if they represent files.
+ dirs bool
}
-func buildSharedNativeLibSnapshot(sdkModuleContext android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder, member android.SdkMember) {
- // a function for emitting include dirs
- addExportedDirCopyCommandsForNativeLibs := func(lib nativeLibInfoProperties) {
- // Do not include exportedGeneratedIncludeDirs in the list of directories whose
- // contents are copied as they are copied from exportedGeneratedHeaders below.
- includeDirs := lib.ExportedIncludeDirs
- includeDirs = append(includeDirs, lib.ExportedSystemIncludeDirs...)
- for _, dir := range includeDirs {
- // lib.ArchType is "" for common properties.
- targetDir := filepath.Join(lib.archType, nativeIncludeDir)
-
- // TODO(jiyong) copy headers having other suffixes
- headers, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.h", nil)
- for _, file := range headers {
- src := android.PathForSource(sdkModuleContext, file)
- dest := filepath.Join(targetDir, file)
- builder.CopyToSnapshot(src, dest)
- }
- }
-
- genHeaders := lib.exportedGeneratedHeaders
- for _, file := range genHeaders {
- // lib.ArchType is "" for common properties.
- targetDir := filepath.Join(lib.archType, nativeGeneratedIncludeDir)
-
- dest := filepath.Join(targetDir, lib.name, file.Rel())
- builder.CopyToSnapshot(file, dest)
- }
- }
-
- addExportedDirCopyCommandsForNativeLibs(info.commonProperties)
-
- // for each architecture
- for _, av := range info.archVariantProperties {
- builder.CopyToSnapshot(av.outputFile, nativeLibraryPathFor(av))
-
- addExportedDirCopyCommandsForNativeLibs(av)
- }
-
- info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
-}
-
-func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-
- pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
-
- addPossiblyArchSpecificProperties(info.commonProperties, pbm)
-
- archProperties := pbm.AddPropertySet("arch")
- for _, av := range info.archVariantProperties {
- archTypeProperties := archProperties.AddPropertySet(av.archType)
- // Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
- archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})
-
- addPossiblyArchSpecificProperties(av, archTypeProperties)
- }
- pbm.AddProperty("stl", "none")
- pbm.AddProperty("system_shared_libs", []string{})
+var includeDirProperties = []includeDirsProperty{
+ {
+ // ExportedIncludeDirs lists directories that contains some header files to be
+ // copied into a directory in the snapshot. The snapshot directories must be added to
+ // the export_include_dirs property in the prebuilt module in the snapshot.
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
+ propertyName: "export_include_dirs",
+ snapshotDir: nativeIncludeDir,
+ copy: true,
+ dirs: true,
+ },
+ {
+ // ExportedSystemIncludeDirs lists directories that contains some system header files to
+ // be copied into a directory in the snapshot. The snapshot directories must be added to
+ // the export_system_include_dirs property in the prebuilt module in the snapshot.
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
+ propertyName: "export_system_include_dirs",
+ snapshotDir: nativeIncludeDir,
+ copy: true,
+ dirs: true,
+ },
+ {
+ // exportedGeneratedIncludeDirs lists directories that contains some header files
+ // that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
+ // of these directories do not need to be copied, but these directories do need adding to
+ // the export_include_dirs property in the prebuilt module in the snapshot.
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
+ propertyName: "export_include_dirs",
+ snapshotDir: nativeGeneratedIncludeDir,
+ copy: false,
+ dirs: true,
+ },
+ {
+ // exportedGeneratedHeaders lists header files that are in one of the directories
+ // specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
+ // As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
+ // property in the prebuilt module in the snapshot.
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
+ propertyName: "",
+ snapshotDir: nativeGeneratedIncludeDir,
+ copy: true,
+ dirs: false,
+ },
}
// Add properties that may, or may not, be arch specific.
-func addPossiblyArchSpecificProperties(libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
- addExportedDirsForNativeLibs(libInfo, outputProperties, false /*systemInclude*/)
- addExportedDirsForNativeLibs(libInfo, outputProperties, true /*systemInclude*/)
-}
+func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
-// a function for emitting include dirs
-func addExportedDirsForNativeLibs(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
- includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
- if len(includeDirs) == 0 {
- return
+ // Copy the generated library to the snapshot and add a reference to it in the .bp module.
+ if libInfo.outputFile != nil {
+ nativeLibraryPath := nativeLibraryPathFor(libInfo)
+ builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath)
+ outputProperties.AddProperty("srcs", []string{nativeLibraryPath})
}
- var propertyName string
- if !systemInclude {
- propertyName = "export_include_dirs"
- } else {
- propertyName = "export_system_include_dirs"
+
+ if len(libInfo.SharedLibs) > 0 {
+ outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
}
- properties.AddProperty(propertyName, includeDirs)
+
+ if len(libInfo.SystemSharedLibs) > 0 {
+ outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
+
+ // Map from property name to the include dirs to add to the prebuilt module in the snapshot.
+ includeDirs := make(map[string][]string)
+
+ // Iterate over each include directory property, copying files and collating property
+ // values where necessary.
+ for _, propertyInfo := range includeDirProperties {
+ // Calculate the base directory in the snapshot into which the files will be copied.
+ // lib.ArchType is "" for common properties.
+ targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
+
+ propertyName := propertyInfo.propertyName
+
+ // Iterate over each path in one of the include directory properties.
+ for _, path := range propertyInfo.pathsGetter(libInfo) {
+
+ // Copy the files/directories when necessary.
+ if propertyInfo.copy {
+ if propertyInfo.dirs {
+ // When copying a directory glob and copy all the headers within it.
+ // TODO(jiyong) copy headers having other suffixes
+ headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil)
+ for _, file := range headers {
+ src := android.PathForSource(sdkModuleContext, file)
+ dest := filepath.Join(targetDir, file)
+ builder.CopyToSnapshot(src, dest)
+ }
+ } else {
+ // Otherwise, just copy the files.
+ dest := filepath.Join(targetDir, libInfo.name, path.Rel())
+ builder.CopyToSnapshot(path, dest)
+ }
+ }
+
+ // Only directories are added to a property.
+ if propertyInfo.dirs {
+ var snapshotPath string
+ if isGeneratedHeaderDirectory(path) {
+ snapshotPath = filepath.Join(targetDir, libInfo.name)
+ } else {
+ snapshotPath = filepath.Join(targetDir, path.String())
+ }
+
+ includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath)
+ }
+ }
+ }
+
+ // Add the collated include dir properties to the output.
+ for property, dirs := range includeDirs {
+ outputProperties.AddProperty(property, dirs)
+ }
}
const (
@@ -285,41 +272,20 @@
)
// path to the native library. Relative to <sdk_root>/<api_dir>
-func nativeLibraryPathFor(lib nativeLibInfoProperties) string {
- return filepath.Join(lib.archType,
+func nativeLibraryPathFor(lib *nativeLibInfoProperties) string {
+ return filepath.Join(lib.OsPrefix(), lib.archType,
nativeStubDir, lib.outputFile.Base())
}
-// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
-func nativeIncludeDirPathsFor(lib nativeLibInfoProperties, systemInclude bool) []string {
- var result []string
- var includeDirs []android.Path
- if !systemInclude {
- // Include the generated include dirs in the exported include dirs.
- includeDirs = append(lib.ExportedIncludeDirs, lib.exportedGeneratedIncludeDirs...)
- } else {
- includeDirs = lib.ExportedSystemIncludeDirs
- }
- for _, dir := range includeDirs {
- var path string
- if isGeneratedHeaderDirectory(dir) {
- path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
- } else {
- path = filepath.Join(nativeIncludeDir, dir.String())
- }
-
- // lib.ArchType is "" for common properties.
- path = filepath.Join(lib.archType, path)
- result = append(result, path)
- }
- return result
-}
-
// nativeLibInfoProperties represents properties of a native lib
//
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeLibInfoProperties struct {
+ android.SdkMemberPropertiesBase
+
+ memberType *librarySdkMemberType
+
// The name of the library, is not exported as this must not be changed during optimization.
name string
@@ -352,14 +318,53 @@
// This field is exported as its contents may not be arch specific.
ExportedFlags []string
+ // The set of shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SharedLibs []string
+
+ // The set of system shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SystemSharedLibs []string
+
// outputFile is not exported as it is always arch specific.
outputFile android.Path
}
-// nativeLibInfo represents a collection of arch-specific modules having the same name
-type nativeLibInfo struct {
- name string
- memberType *librarySdkMemberType
- archVariantProperties []nativeLibInfoProperties
- commonProperties nativeLibInfoProperties
+func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ ccModule := variant.(*Module)
+
+ // If the library has some link types then it produces an output binary file, otherwise it
+ // is header only.
+ if p.memberType.linkTypes != nil {
+ p.outputFile = ccModule.OutputFile().Path()
+ }
+
+ // Separate out the generated include dirs (which are arch specific) from the
+ // include dirs (which may not be).
+ exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
+ ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
+
+ p.name = variant.Name()
+ p.archType = ccModule.Target().Arch.ArchType.String()
+
+ // Make sure that the include directories are unique.
+ p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
+ p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs)
+ p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs())
+
+ p.ExportedFlags = ccModule.ExportedFlags()
+ if ccModule.linker != nil {
+ specifiedDeps := specifiedDeps{}
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+ p.SharedLibs = specifiedDeps.sharedLibs
+ p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+ }
+ p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+}
+
+func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet)
}
diff --git a/cc/linker.go b/cc/linker.go
index a7b621a..aa2d0ab 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -490,6 +490,12 @@
panic(fmt.Errorf("baseLinker doesn't know how to link"))
}
+func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+ specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs...)
+ specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
+ return specifiedDeps
+}
+
// Injecting version symbols
// Some host modules want a version number, but we don't want to rebuild it every time. Optionally add a step
// after linking that injects a constant placeholder with the current version number.
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 4f77d41..3dbd3e3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -23,6 +23,7 @@
}
func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("cc_prebuilt_library", PrebuiltLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
@@ -87,18 +88,25 @@
func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
- // TODO(ccross): verify shared library dependencies
- if len(p.properties.Srcs) > 0 {
- p.libraryDecorator.exportIncludes(ctx)
- p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
- p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
- p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
- p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
- p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+ p.libraryDecorator.exportIncludes(ctx)
+ p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+ p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+ p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+ p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+ p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+
+ // TODO(ccross): verify shared library dependencies
+ srcs := p.prebuiltSrcs()
+ if len(srcs) > 0 {
builderFlags := flagsToBuilderFlags(flags)
- in := p.Prebuilt.SingleSourcePath(ctx)
+ if len(srcs) > 1 {
+ ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+ return nil
+ }
+
+ in := android.PathForModuleSrc(ctx, srcs[0])
if p.shared() {
p.unstrippedOutputFile = in
@@ -122,6 +130,18 @@
return nil
}
+func (p *prebuiltLibraryLinker) prebuiltSrcs() []string {
+ srcs := p.properties.Srcs
+ if p.static() {
+ srcs = append(srcs, p.libraryDecorator.StaticProperties.Static.Srcs...)
+ }
+ if p.shared() {
+ srcs = append(srcs, p.libraryDecorator.SharedProperties.Shared.Srcs...)
+ }
+
+ return srcs
+}
+
func (p *prebuiltLibraryLinker) shared() bool {
return p.libraryDecorator.shared()
}
@@ -150,13 +170,28 @@
module.AddProperties(&prebuilt.properties)
- android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+ srcsSupplier := func() []string {
+ return prebuilt.prebuiltSrcs()
+ }
+
+ android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
// Prebuilt libraries can be used in SDKs.
android.InitSdkAwareModule(module)
return module, library
}
+// cc_prebuilt_library installs a precompiled shared library that are
+// listed in the srcs property in the device's directory.
+func PrebuiltLibraryFactory() android.Module {
+ module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+
+ // Prebuilt shared libraries can be included in APEXes
+ android.InitApexModule(module)
+
+ return module.Init()
+}
+
// cc_prebuilt_library_shared installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func PrebuiltSharedLibraryFactory() android.Module {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 3d809fc..0eca97f 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -59,36 +59,38 @@
name: "libe",
srcs: ["libe.a"],
}
+
+ cc_library {
+ name: "libf",
+ }
+
+ cc_prebuilt_library {
+ name: "libf",
+ static: {
+ srcs: ["libf.a"],
+ },
+ shared: {
+ srcs: ["libf.so"],
+ },
+ }
`
- fs := map[string][]byte{
- "liba.so": nil,
- "libb.a": nil,
- "libd.so": nil,
- "libe.a": nil,
- }
-
- config := TestConfig(buildDir, android.Android, nil, bp, fs)
-
- ctx := CreateTestContext()
-
- ctx.Register(config)
-
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
- android.FailIfErrored(t, errs)
- _, errs = ctx.PrepareBuildActions(config)
- android.FailIfErrored(t, errs)
+ ctx := testPrebuilt(t, bp)
// Verify that all the modules exist and that their dependencies were connected correctly
liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_static").Module()
libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_shared").Module()
libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_static").Module()
+ libfStatic := ctx.ModuleForTests("libf", "android_arm64_armv8-a_static").Module()
+ libfShared := ctx.ModuleForTests("libf", "android_arm64_armv8-a_shared").Module()
prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_shared").Module()
prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_static").Module()
prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_shared").Module()
prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_static").Module()
+ prebuiltLibfStatic := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_static").Module()
+ prebuiltLibfShared := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_shared").Module()
hasDep := func(m android.Module, wantDep android.Module) bool {
t.Helper()
@@ -116,4 +118,89 @@
if !hasDep(libe, prebuiltLibe) {
t.Errorf("libe missing dependency on prebuilt_libe")
}
+
+ if !hasDep(libfStatic, prebuiltLibfStatic) {
+ t.Errorf("libf static missing dependency on prebuilt_libf")
+ }
+
+ if !hasDep(libfShared, prebuiltLibfShared) {
+ t.Errorf("libf shared missing dependency on prebuilt_libf")
+ }
+}
+
+func testPrebuilt(t *testing.T, bp string) *android.TestContext {
+ fs := map[string][]byte{
+ "liba.so": nil,
+ "libb.a": nil,
+ "libd.so": nil,
+ "libe.a": nil,
+ "libf.a": nil,
+ "libf.so": nil,
+ }
+ config := TestConfig(buildDir, android.Android, nil, bp, fs)
+ ctx := CreateTestContext()
+
+ // Enable androidmk support.
+ // * Register the singleton
+ // * Configure that we are inside make
+ // * Add CommonOS to ensure that androidmk processing works.
+ android.RegisterAndroidMkBuildComponents(ctx)
+ android.SetInMakeForTests(config)
+
+ ctx.Register(config)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+ return ctx
+}
+
+func TestPrebuiltLibraryShared(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library_shared {
+ name: "libtest",
+ srcs: ["libf.so"],
+ strip: {
+ none: true,
+ },
+ }
+ `)
+
+ shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().String(), "libf.so")
+}
+
+func TestPrebuiltLibraryStatic(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library_static {
+ name: "libtest",
+ srcs: ["libf.a"],
+ }
+ `)
+
+ static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+ assertString(t, static.OutputFile().String(), "libf.a")
+}
+
+func TestPrebuiltLibrary(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library {
+ name: "libtest",
+ static: {
+ srcs: ["libf.a"],
+ },
+ shared: {
+ srcs: ["libf.so"],
+ },
+ strip: {
+ none: true,
+ },
+ }
+ `)
+
+ shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().String(), "libf.so")
+
+ static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+ assertString(t, static.OutputFile().String(), "libf.a")
}
diff --git a/cc/testing.go b/cc/testing.go
index 0578472..f85795b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -25,6 +25,7 @@
RegisterCCBuildComponents(ctx)
RegisterBinaryBuildComponents(ctx)
RegisterLibraryBuildComponents(ctx)
+ RegisterLibraryHeadersBuildComponents(ctx)
ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)
@@ -33,7 +34,7 @@
ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
}
-func GatherRequiredDepsForTest(os android.OsType) string {
+func GatherRequiredDepsForTest(oses ...android.OsType) string {
ret := `
toolchain_library {
name: "libatomic",
@@ -379,8 +380,9 @@
}
`
- if os == android.Fuchsia {
- ret += `
+ for _, os := range oses {
+ if os == android.Fuchsia {
+ ret += `
cc_library {
name: "libbioniccompat",
stl: "none",
@@ -390,6 +392,22 @@
stl: "none",
}
`
+ }
+ if os == android.Windows {
+ ret += `
+ toolchain_library {
+ name: "libwinpthread",
+ host_supported: true,
+ enabled: false,
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ src: "",
+ }
+ `
+ }
}
return ret
}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 0e1bfc6..f984966 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -47,6 +47,8 @@
const SystemPartition = "/system/"
const SystemOtherPartition = "/system_other/"
+var DexpreoptRunningInSoong = false
+
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConfig,
@@ -589,7 +591,14 @@
// at that time (Soong processes the jars in dependency order, which may be different from the
// the system server classpath order).
func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath {
- return android.PathForOutput(ctx, "system_server_dexjars", jar+".jar")
+ if DexpreoptRunningInSoong {
+ // Soong module, just use the default output directory $OUT/soong.
+ return android.PathForOutput(ctx, "system_server_dexjars", jar+".jar")
+ } else {
+ // Make module, default output directory is $OUT (passed via the "null config" created
+ // by dexpreopt_gen). Append Soong subdirectory to match Soong module paths.
+ return android.PathForOutput(ctx, "soong", "system_server_dexjars", jar+".jar")
+ }
}
func contains(l []string, s string) bool {
diff --git a/java/androidmk.go b/java/androidmk.go
index d8a3884..6f24f34 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -517,10 +517,21 @@
}
func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries {
+ // If the stubsSrcJar is not generated (because generate_stubs is false) then
+ // use the api file as the output file to ensure the relevant phony targets
+ // are created in make if only the api txt file is being generated. This is
+ // needed because an invalid output file would prevent the make entries from
+ // being written.
+ // TODO(b/146727827): Revert when we do not need to generate stubs and API separately.
+ distFile := android.OptionalPathForPath(dstubs.apiFile)
+ outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar)
+ if !outputFile.Valid() {
+ outputFile = distFile
+ }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- DistFile: android.OptionalPathForPath(dstubs.apiFile),
- OutputFile: android.OptionalPathForPath(dstubs.stubsSrcJar),
+ DistFile: distFile,
+ OutputFile: outputFile,
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
@@ -660,6 +671,7 @@
func(entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
entries.SetPath("LOCAL_MODULE_PATH", r.installDir.ToMakePath())
+ entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", r.properties.Overrides...)
},
},
}}
diff --git a/java/app.go b/java/app.go
index 8e21182..f812335 100755
--- a/java/app.go
+++ b/java/app.go
@@ -505,6 +505,10 @@
return certificates
}
+func (a *AndroidApp) InstallApkName() string {
+ return a.installApkName
+}
+
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
var apkDeps android.Paths
@@ -1115,6 +1119,10 @@
a.generateAndroidBuildActions(ctx)
}
+func (a *AndroidAppImport) InstallApkName() string {
+ return a.BaseModuleName()
+}
+
func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
numCertPropsSet := 0
if String(a.properties.Certificate) != "" {
@@ -1172,6 +1180,8 @@
dexOutput = dexUncompressed
}
+ apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
+
// Sign or align the package
// TODO: Handle EXTERNAL
if !Bool(a.properties.Presigned) {
@@ -1182,11 +1192,11 @@
ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
}
a.certificate = certificates[0]
- signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
+ signed := android.PathForModuleOut(ctx, "signed", apkFilename)
SignAppPackage(ctx, signed, dexOutput, certificates, nil)
a.outputFile = signed
} else {
- alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
+ alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
TransformZipAlign(ctx, alignedApk, dexOutput)
a.outputFile = alignedApk
a.certificate = presignedCertificate
@@ -1194,8 +1204,7 @@
// TODO: Optionally compress the output apk.
- a.installPath = ctx.InstallFile(installDir,
- proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk"), a.outputFile)
+ a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
// TODO: androidmk converter jni libs
}
@@ -1370,6 +1379,13 @@
// list of android_app modules whose resources are extracted and linked against
Resource_libs []string
+
+ // Names of modules to be overridden. Listed modules can only be other overlays
+ // (in Make or Soong).
+ // This does not completely prevent installation of the overridden overlays, but if both
+ // overlays would be installed by default (in PRODUCT_PACKAGES) the other overlay will be removed
+ // from PRODUCT_PACKAGES.
+ Overrides []string
}
func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/java/app_test.go b/java/app_test.go
index 134f171..55c1d76 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2482,6 +2482,7 @@
certificate: "platform",
product_specific: true,
theme: "faza",
+ overrides: ["foo"],
}
android_library {
@@ -2529,14 +2530,15 @@
if expected != signingFlag {
t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
}
- path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_CERTIFICATE"]
+ androidMkEntries := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0]
+ path := androidMkEntries.EntryMap["LOCAL_CERTIFICATE"]
expectedPath := []string{"build/make/target/product/security/platform.x509.pem"}
if !reflect.DeepEqual(path, expectedPath) {
t.Errorf("Unexpected LOCAL_CERTIFICATE value: %v, expected: %v", path, expectedPath)
}
// Check device location.
- path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"]
expectedPath = []string{"/tmp/target/product/test_device/product/overlay"}
if !reflect.DeepEqual(path, expectedPath) {
t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
@@ -2544,9 +2546,75 @@
// A themed module has a different device location
m = ctx.ModuleForTests("foo_themed", "android_common")
- path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ androidMkEntries = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0]
+ path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"]
expectedPath = []string{"/tmp/target/product/test_device/product/overlay/faza"}
if !reflect.DeepEqual(path, expectedPath) {
t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
}
+
+ overrides := androidMkEntries.EntryMap["LOCAL_OVERRIDES_PACKAGES"]
+ expectedOverrides := []string{"foo"}
+ if !reflect.DeepEqual(overrides, expectedOverrides) {
+ t.Errorf("Unexpected LOCAL_OVERRIDES_PACKAGES value: %v, expected: %v", overrides, expectedOverrides)
+ }
+}
+
+func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_defaults {
+ name: "rro_defaults",
+ theme: "default_theme",
+ product_specific: true,
+ aaptflags: ["--keep-raw-values"],
+ }
+
+ runtime_resource_overlay {
+ name: "foo_with_defaults",
+ defaults: ["rro_defaults"],
+ }
+
+ runtime_resource_overlay {
+ name: "foo_barebones",
+ }
+ `)
+
+ //
+ // RRO module with defaults
+ //
+ m := ctx.ModuleForTests("foo_with_defaults", "android_common")
+
+ // Check AAPT2 link flags.
+ aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ")
+ expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
+ absentFlags := android.RemoveListFromList(expectedFlags, aapt2Flags)
+ if len(absentFlags) > 0 {
+ t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags)
+ }
+
+ // Check device location.
+ path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ expectedPath := []string{"/tmp/target/product/test_device/product/overlay/default_theme"}
+ if !reflect.DeepEqual(path, expectedPath) {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH value: %q, expected: %q", path, expectedPath)
+ }
+
+ //
+ // RRO module without defaults
+ //
+ m = ctx.ModuleForTests("foo_barebones", "android_common")
+
+ // Check AAPT2 link flags.
+ aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ")
+ unexpectedFlags := "--keep-raw-values"
+ if inList(unexpectedFlags, aapt2Flags) {
+ t.Errorf("unexpected value, %q is present in aapt2 link flags, %q", unexpectedFlags, aapt2Flags)
+ }
+
+ // Check device location.
+ path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ expectedPath = []string{"/tmp/target/product/test_device/system/overlay"}
+ if !reflect.DeepEqual(path, expectedPath) {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
+ }
}
diff --git a/java/builder.go b/java/builder.go
index f09cd98..ad9afee 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -195,7 +195,7 @@
classpath classpath
java9Classpath classpath
processorPath classpath
- processor string
+ processors []string
systemModules *systemModules
aidlFlags string
aidlDeps android.Paths
@@ -269,8 +269,8 @@
deps = append(deps, flags.processorPath...)
processor := "-proc:none"
- if flags.processor != "" {
- processor = "-processor " + flags.processor
+ if len(flags.processors) > 0 {
+ processor = "-processor " + strings.Join(flags.processors, ",")
}
intermediatesDir := "xref"
@@ -384,8 +384,8 @@
deps = append(deps, flags.processorPath...)
processor := "-proc:none"
- if flags.processor != "" {
- processor = "-processor " + flags.processor
+ if len(flags.processors) > 0 {
+ processor = "-processor " + strings.Join(flags.processors, ",")
}
srcJarDir := "srcjars"
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 40cfe4f..28a2c8a 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -62,6 +62,10 @@
}
}
+func init() {
+ dexpreopt.DexpreoptRunningInSoong = true
+}
+
func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
global := dexpreopt.GetGlobalConfig(ctx)
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 1c2c447..7ac71a4 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -257,6 +257,11 @@
// if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
Create_doc_stubs *bool
+ // if set to false then do not write out stubs. Defaults to true.
+ //
+ // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
+ Generate_stubs *bool
+
// is set to true, Metalava will allow framework SDK to contain API levels annotations.
Api_levels_annotations_enabled *bool
@@ -1201,7 +1206,7 @@
}
}
-func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
+func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Api_filename) != "" {
@@ -1227,11 +1232,13 @@
cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
}
- if Bool(d.properties.Create_doc_stubs) {
- cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
- } else {
- cmd.FlagWithArg("--stubs ", stubsDir.String())
- cmd.Flag("--exclude-documentation-from-stubs")
+ if stubsDir.Valid() {
+ if Bool(d.properties.Create_doc_stubs) {
+ cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
+ } else {
+ cmd.FlagWithArg("--stubs ", stubsDir.String())
+ cmd.Flag("--exclude-documentation-from-stubs")
+ }
}
}
@@ -1388,15 +1395,18 @@
// Create rule for metalava
- d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
- stubsDir := android.PathForModuleOut(ctx, "stubsDir")
rule := android.NewRuleBuilder()
- rule.Command().Text("rm -rf").Text(stubsDir.String())
- rule.Command().Text("mkdir -p").Text(stubsDir.String())
+ generateStubs := BoolDefault(d.properties.Generate_stubs, true)
+ var stubsDir android.OptionalPath
+ if generateStubs {
+ d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
+ stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "stubsDir"))
+ rule.Command().Text("rm -rf").Text(stubsDir.String())
+ rule.Command().Text("mkdir -p").Text(stubsDir.String())
+ }
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
@@ -1422,13 +1432,15 @@
cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
}
- rule.Command().
- BuiltTool(ctx, "soong_zip").
- Flag("-write_if_changed").
- Flag("-jar").
- FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
- FlagWithArg("-C ", stubsDir.String()).
- FlagWithArg("-D ", stubsDir.String())
+ if generateStubs {
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-jar").
+ FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
+ FlagWithArg("-C ", stubsDir.String()).
+ FlagWithArg("-D ", stubsDir.String())
+ }
if Bool(d.properties.Write_sdk_values) {
d.metadataZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-metadata.zip")
@@ -1512,40 +1524,35 @@
apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
- updatedBaselineOutput := android.PathForModuleOut(ctx, "current_baseline.txt")
+
+ if baselineFile.Valid() {
+ ctx.PropertyErrorf("current API check can't have a baseline file. (module %s)", ctx.ModuleName())
+ }
d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
rule := android.NewRuleBuilder()
+ // Diff command line.
+ // -F matches the closest "opening" line, such as "package xxx{"
+ // and " public class Yyy {".
+ diff := `diff -u -F '{ *$'`
+
rule.Command().Text("( true")
+ rule.Command().
+ Text(diff).
+ Input(apiFile).Input(d.apiFile)
- srcJarDir := android.PathForModuleOut(ctx, "current-apicheck", "srcjars")
- srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
-
- cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
- deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
-
- cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles).
- FlagWithInput("--check-compatibility:api:current ", apiFile).
- FlagWithInput("--check-compatibility:removed:current ", removedApiFile)
-
- d.inclusionAnnotationsFlags(ctx, cmd)
- d.mergeAnnoDirFlags(ctx, cmd)
-
- if baselineFile.Valid() {
- cmd.FlagWithInput("--baseline ", baselineFile.Path())
- cmd.FlagWithOutput("--update-baseline ", updatedBaselineOutput)
- }
-
- zipSyncCleanupCmd(rule, srcJarDir)
+ rule.Command().
+ Text(diff).
+ Input(removedApiFile).Input(d.removedApiFile)
msg := fmt.Sprintf(`\n******************************\n`+
`You have tried to change the API from what has been previously approved.\n\n`+
`To make these errors go away, you have two choices:\n`+
- ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
- ` errors above.\n\n`+
- ` 2. You can update current.txt by executing the following command:\n`+
+ ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
+ ` to the new methods, etc. shown in the above diff.\n\n`+
+ ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
` make %s-update-current-api\n\n`+
` To submit the revised current.txt to the main Android repository,\n`+
` you will need approval.\n`+
@@ -1558,7 +1565,7 @@
Text("; exit 38").
Text(")")
- rule.Build(pctx, ctx, "metalavaCurrentApiCheck", "metalava check current API")
+ rule.Build(pctx, ctx, "metalavaCurrentApiCheck", "check current API")
d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
@@ -1927,18 +1934,33 @@
return ok
}
-func (mt *droidStubsSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- variants := member.Variants()
- if len(variants) != 1 {
- sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
+func (mt *droidStubsSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_stubs_sources")
+}
+
+func (mt *droidStubsSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &droidStubsInfoProperties{}
+}
+
+type droidStubsInfoProperties struct {
+ android.SdkMemberPropertiesBase
+
+ StubsSrcJar android.Path
+}
+
+func (p *droidStubsInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ droidstubs := variant.(*Droidstubs)
+ p.StubsSrcJar = droidstubs.stubsSrcJar
+}
+
+func (p *droidStubsInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if p.StubsSrcJar != nil {
+ builder := ctx.SnapshotBuilder()
+
+ snapshotRelativeDir := filepath.Join("java", ctx.Name()+"_stubs_sources")
+
+ builder.UnzipToSnapshot(p.StubsSrcJar, snapshotRelativeDir)
+
+ propertySet.AddProperty("srcs", []string{snapshotRelativeDir})
}
- variant := variants[0]
- d, _ := variant.(*Droidstubs)
- stubsSrcJar := d.stubsSrcJar
-
- snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
- builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
-
- pbm := builder.AddPrebuiltModule(member, "prebuilt_stubs_sources")
- pbm.AddProperty("srcs", []string{snapshotRelativeDir})
}
diff --git a/java/java.go b/java/java.go
index 7956813..5d77807 100644
--- a/java/java.go
+++ b/java/java.go
@@ -39,11 +39,17 @@
// Register sdk member types.
android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
- android.RegisterSdkMemberType(&implLibrarySdkMemberType{
- librarySdkMemberType{
- android.SdkMemberTypeBase{
- PropertyName: "java_libs",
- },
+ android.RegisterSdkMemberType(&librarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_libs",
+ },
+ func(j *Library) android.Path {
+ implementationJars := j.ImplementationJars()
+ if len(implementationJars) != 1 {
+ panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+ }
+
+ return implementationJars[0]
},
})
@@ -1128,7 +1134,8 @@
flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
flags.processorPath = append(flags.processorPath, deps.processorPath...)
- flags.processor = strings.Join(deps.processorClasses, ",")
+ flags.processors = append(flags.processors, deps.processorClasses...)
+ flags.processors = android.FirstUniqueStrings(flags.processors)
if len(flags.bootClasspath) == 0 && ctx.Host() && !flags.javaVersion.usesJavaModules() &&
decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() {
@@ -1263,7 +1270,7 @@
srcJars = append(srcJars, kaptSrcJar)
// Disable annotation processing in javac, it's already been handled by kapt
flags.processorPath = nil
- flags.processor = ""
+ flags.processors = nil
}
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
@@ -1758,11 +1765,6 @@
if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
return true
}
- // Also, a dependency to an sdk member is also considered as such. This is required because
- // sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
- if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
- return true
- }
return false
}
@@ -1860,16 +1862,20 @@
)
// path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
-func sdkSnapshotFilePathForJar(member android.SdkMember) string {
- return sdkSnapshotFilePathForMember(member, jarFileSuffix)
+func sdkSnapshotFilePathForJar(osPrefix, name string) string {
+ return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
}
-func sdkSnapshotFilePathForMember(member android.SdkMember, suffix string) string {
- return filepath.Join(javaDir, member.Name()+suffix)
+func sdkSnapshotFilePathForMember(osPrefix, name string, suffix string) string {
+ return filepath.Join(javaDir, osPrefix, name+suffix)
}
type librarySdkMemberType struct {
android.SdkMemberTypeBase
+
+ // Function to retrieve the appropriate output jar (implementation or header) from
+ // the library.
+ jarToExportGetter func(j *Library) android.Path
}
func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
@@ -1881,75 +1887,67 @@
return ok
}
-func (mt *librarySdkMemberType) buildSnapshot(
- sdkModuleContext android.ModuleContext,
- builder android.SnapshotBuilder,
- member android.SdkMember,
- jarToExportGetter func(j *Library) android.Path) {
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_import")
+}
- variants := member.Variants()
- if len(variants) != 1 {
- sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
- for _, variant := range variants {
- sdkModuleContext.ModuleErrorf(" %q", variant)
- }
- }
- variant := variants[0]
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &librarySdkMemberProperties{}
+}
+
+type librarySdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ JarToExport android.Path
+ AidlIncludeDirs android.Paths
+}
+
+func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
j := variant.(*Library)
- exportedJar := jarToExportGetter(j)
- snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
- builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+ p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(j)
+ p.AidlIncludeDirs = j.AidlIncludeDirs()
+}
- for _, dir := range j.AidlIncludeDirs() {
- // TODO(jiyong): copy parcelable declarations only
- aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
- for _, file := range aidlFiles {
- builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
- }
+func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ builder := ctx.SnapshotBuilder()
+
+ exportedJar := p.JarToExport
+ if exportedJar != nil {
+ snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+ builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+ propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
}
- module := builder.AddPrebuiltModule(member, "java_import")
- module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+ aidlIncludeDirs := p.AidlIncludeDirs
+ if len(aidlIncludeDirs) != 0 {
+ sdkModuleContext := ctx.SdkModuleContext()
+ for _, dir := range aidlIncludeDirs {
+ // TODO(jiyong): copy parcelable declarations only
+ aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
+ for _, file := range aidlFiles {
+ builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
+ }
+ }
+
+ // TODO(b/151933053) - add aidl include dirs property
+ }
}
-var javaHeaderLibsSdkMemberType android.SdkMemberType = &headerLibrarySdkMemberType{
- librarySdkMemberType{
- android.SdkMemberTypeBase{
- PropertyName: "java_header_libs",
- SupportsSdk: true,
- },
+var javaHeaderLibsSdkMemberType android.SdkMemberType = &librarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_header_libs",
+ SupportsSdk: true,
},
-}
-
-type headerLibrarySdkMemberType struct {
- librarySdkMemberType
-}
-
-func (mt *headerLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
+ func(j *Library) android.Path {
headerJars := j.HeaderJars()
if len(headerJars) != 1 {
panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
}
return headerJars[0]
- })
-}
-
-type implLibrarySdkMemberType struct {
- librarySdkMemberType
-}
-
-func (mt *implLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
- implementationJars := j.ImplementationJars()
- if len(implementationJars) != 1 {
- panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
- }
-
- return implementationJars[0]
- })
+ },
}
// java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
@@ -2100,31 +2098,50 @@
return ok
}
-func (mt *testSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- variants := member.Variants()
- if len(variants) != 1 {
- sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
- for _, variant := range variants {
- sdkModuleContext.ModuleErrorf(" %q", variant)
- }
- }
- variant := variants[0]
- j := variant.(*Test)
+func (mt *testSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_test_import")
+}
- implementationJars := j.ImplementationJars()
+func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &testSdkMemberProperties{}
+}
+
+type testSdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ JarToExport android.Path
+ TestConfig android.Path
+}
+
+func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ test := variant.(*Test)
+
+ implementationJars := test.ImplementationJars()
if len(implementationJars) != 1 {
- panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+ panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
}
- snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
- builder.CopyToSnapshot(implementationJars[0], snapshotRelativeJavaLibPath)
+ p.JarToExport = implementationJars[0]
+ p.TestConfig = test.testConfig
+}
- snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(member, testConfigSuffix)
- builder.CopyToSnapshot(j.testConfig, snapshotRelativeTestConfigPath)
+func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ builder := ctx.SnapshotBuilder()
- module := builder.AddPrebuiltModule(member, "java_test_import")
- module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
- module.AddProperty("test_config", snapshotRelativeTestConfigPath)
+ exportedJar := p.JarToExport
+ if exportedJar != nil {
+ snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+ builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+ propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+ }
+
+ testConfig := p.TestConfig
+ if testConfig != nil {
+ snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), ctx.Name(), testConfigSuffix)
+ builder.CopyToSnapshot(testConfig, snapshotRelativeTestConfigPath)
+ propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
+ }
}
// java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
@@ -2327,7 +2344,7 @@
//
type ImportProperties struct {
- Jars []string `android:"path"`
+ Jars []string `android:"path,arch_variant"`
Sdk_version *string
@@ -2487,11 +2504,6 @@
if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
return true
}
- // Also, a dependency to an sdk member is also considered as such. This is required because
- // sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
- if sa, ok := dep.(android.SdkAware); ok && sa.IsInAnySdk() {
- return true
- }
return false
}
@@ -2733,6 +2745,7 @@
&sdkLibraryProperties{},
&DexImportProperties{},
&android.ApexProperties{},
+ &RuntimeResourceOverlayProperties{},
)
android.InitDefaultsModule(module)
diff --git a/java/kotlin.go b/java/kotlin.go
index cb7da20..9b160a0 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -136,8 +136,11 @@
kaptProcessorPath := flags.processorPath.FormRepeatedClassPath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=")
kaptProcessor := ""
- if flags.processor != "" {
- kaptProcessor = "-P plugin:org.jetbrains.kotlin.kapt3:processors=" + flags.processor
+ for i, p := range flags.processors {
+ if i > 0 {
+ kaptProcessor += " "
+ }
+ kaptProcessor += "-P plugin:org.jetbrains.kotlin.kapt3:processors=" + p
}
encodedJavacFlags := kaptEncodeFlags([][2]string{
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 5c6d45f..60ca1c4 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -88,7 +88,7 @@
java_library {
name: "foo",
srcs: ["a.java", "b.kt"],
- plugins: ["bar"],
+ plugins: ["bar", "baz"],
}
java_plugin {
@@ -96,6 +96,12 @@
processor_class: "com.bar",
srcs: ["b.java"],
}
+
+ java_plugin {
+ name: "baz",
+ processor_class: "com.baz",
+ srcs: ["b.java"],
+ }
`)
buildOS := android.BuildOs.String()
@@ -105,6 +111,7 @@
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
+ baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
// Test that the kotlin and java sources are passed to kapt and kotlinc
if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
@@ -136,11 +143,12 @@
}
// Test that the processors are passed to kapt
- expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar
+ expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
+ " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
}
- expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar"
+ expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
if kapt.Args["kaptProcessor"] != expectedProcessor {
t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 374a5e5..a478a7d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -15,17 +15,18 @@
package java
import (
- "android/soong/android"
-
"fmt"
"path"
"path/filepath"
+ "reflect"
"sort"
"strings"
"sync"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android"
)
const (
@@ -66,6 +67,9 @@
// The name of the api scope, e.g. public, system, test
name string
+ // The name of the field in the dynamically created structure.
+ fieldName string
+
// The tag to use to depend on the stubs library module.
stubsTag scopeDependencyTag
@@ -86,11 +90,14 @@
// *current. Older stubs library built with a numbered SDK version is created from
// the prebuilt jar.
sdkVersion string
+
+ // Extra arguments to pass to droidstubs for this scope.
+ droidstubsArgs []string
}
// Initialize a scope, creating and adding appropriate dependency tags
func initApiScope(scope *apiScope) *apiScope {
- //apiScope := &scope
+ scope.fieldName = proptools.FieldNameForProperty(scope.name)
scope.stubsTag = scopeDependencyTag{
name: scope.name + "-stubs",
apiScope: scope,
@@ -131,6 +138,7 @@
moduleSuffix: sdkSystemApiSuffix,
apiFileMakeVariableSuffix: "_SYSTEM",
sdkVersion: "system_current",
+ droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi"},
})
apiScopeTest = initApiScope(&apiScope{
name: "test",
@@ -138,6 +146,7 @@
moduleSuffix: sdkTestApiSuffix,
apiFileMakeVariableSuffix: "_TEST",
sdkVersion: "test_current",
+ droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
})
allApiScopes = apiScopes{
apiScopePublic,
@@ -162,6 +171,14 @@
sort.Strings(*javaSdkLibraries)
ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " "))
})
+
+ // Register sdk member types.
+ android.RegisterSdkMemberType(&sdkLibrarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_sdk_libs",
+ SupportsSdk: true,
+ },
+ })
}
func RegisterSdkLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -451,7 +468,7 @@
mctx.CreateModule(LibraryFactory, &props)
}
-// Creates a droiddoc module that creates stubs source files from the given full source
+// Creates a droidstubs module that creates stubs source files from the given full source
// files
func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
props := struct {
@@ -506,15 +523,15 @@
props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
- droiddocArgs := []string{}
+ droidstubsArgs := []string{}
if len(module.sdkLibraryProperties.Api_packages) != 0 {
- droiddocArgs = append(droiddocArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
+ droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
}
if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 {
- droiddocArgs = append(droiddocArgs,
+ droidstubsArgs = append(droidstubsArgs,
android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
}
- droiddocArgs = append(droiddocArgs, module.sdkLibraryProperties.Droiddoc_options...)
+ droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
disabledWarnings := []string{
"MissingPermission",
"BroadcastBehavior",
@@ -526,16 +543,12 @@
"Todo",
"Typo",
}
- droiddocArgs = append(droiddocArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
+ droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
- switch apiScope {
- case apiScopeSystem:
- droiddocArgs = append(droiddocArgs, "-showAnnotation android.annotation.SystemApi")
- case apiScopeTest:
- droiddocArgs = append(droiddocArgs, " -showAnnotation android.annotation.TestApi")
- }
+ // Add in scope specific arguments.
+ droidstubsArgs = append(droidstubsArgs, apiScope.droidstubsArgs...)
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
- props.Args = proptools.StringPtr(strings.Join(droiddocArgs, " "))
+ props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
// List of APIs identified from the provided source files are created. They are later
// compared against to the not-yet-released (a.k.a current) list of APIs and to the
@@ -805,36 +818,74 @@
// List of shared java libs, common to all scopes, that this module has
// dependencies to
Libs []string
-
- // Properties associated with the public api scope.
- Public sdkLibraryScopeProperties
-
- // Properties associated with the system api scope.
- System sdkLibraryScopeProperties
-
- // Properties associated with the test api scope.
- Test sdkLibraryScopeProperties
}
type sdkLibraryImport struct {
android.ModuleBase
android.DefaultableModuleBase
prebuilt android.Prebuilt
+ android.ApexModuleBase
+ android.SdkBase
properties sdkLibraryImportProperties
+ // Map from api scope to the scope specific property structure.
+ scopeProperties map[*apiScope]*sdkLibraryScopeProperties
+
commonToSdkLibraryAndImport
}
var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
+// The type of a structure that contains a field of type sdkLibraryScopeProperties
+// for each apiscope in allApiScopes, e.g. something like:
+// struct {
+// Public sdkLibraryScopeProperties
+// System sdkLibraryScopeProperties
+// ...
+// }
+var allScopeStructType = createAllScopePropertiesStructType()
+
+// Dynamically create a structure type for each apiscope in allApiScopes.
+func createAllScopePropertiesStructType() reflect.Type {
+ var fields []reflect.StructField
+ for _, apiScope := range allApiScopes {
+ field := reflect.StructField{
+ Name: apiScope.fieldName,
+ Type: reflect.TypeOf(sdkLibraryScopeProperties{}),
+ }
+ fields = append(fields, field)
+ }
+
+ return reflect.StructOf(fields)
+}
+
+// Create an instance of the scope specific structure type and return a map
+// from apiscope to a pointer to each scope specific field.
+func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProperties) {
+ allScopePropertiesPtr := reflect.New(allScopeStructType)
+ allScopePropertiesStruct := allScopePropertiesPtr.Elem()
+ scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties)
+
+ for _, apiScope := range allApiScopes {
+ field := allScopePropertiesStruct.FieldByName(apiScope.fieldName)
+ scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties)
+ }
+
+ return allScopePropertiesPtr.Interface(), scopeProperties
+}
+
// java_sdk_library_import imports a prebuilt java_sdk_library.
func sdkLibraryImportFactory() android.Module {
module := &sdkLibraryImport{}
- module.AddProperties(&module.properties)
+ allScopeProperties, scopeToProperties := createPropertiesInstance()
+ module.scopeProperties = scopeToProperties
+ module.AddProperties(&module.properties, allScopeProperties)
android.InitPrebuiltModule(module, &[]string{""})
+ android.InitApexModule(module)
+ android.InitSdkAwareModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
@@ -856,48 +907,12 @@
module.prebuilt.ForcePrefer()
}
- for apiScope, scopeProperties := range module.scopeProperties() {
+ for apiScope, scopeProperties := range module.scopeProperties {
if len(scopeProperties.Jars) == 0 {
continue
}
- // Creates a java import for the jar with ".stubs" suffix
- props := struct {
- Name *string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- Sdk_version *string
- Libs []string
- Jars []string
- Prefer *bool
- }{}
-
- props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
- props.Sdk_version = scopeProperties.Sdk_version
- // Prepend any of the libs from the legacy public properties to the libs for each of the
- // scopes to avoid having to duplicate them in each scope.
- props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
- props.Jars = scopeProperties.Jars
-
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
- }
-
- // If the build should use prebuilt sdks then set prefer to true on the stubs library.
- // That will cause the prebuilt version of the stubs to override the source version.
- if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
- props.Prefer = proptools.BoolPtr(true)
- }
-
- mctx.CreateModule(ImportFactory, &props)
+ module.createJavaImportForStubs(mctx, apiScope, scopeProperties)
}
javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -906,16 +921,44 @@
*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
}
-func (module *sdkLibraryImport) scopeProperties() map[*apiScope]*sdkLibraryScopeProperties {
- p := make(map[*apiScope]*sdkLibraryScopeProperties)
- p[apiScopePublic] = &module.properties.Public
- p[apiScopeSystem] = &module.properties.System
- p[apiScopeTest] = &module.properties.Test
- return p
+func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.LoadHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+ // Creates a java import for the jar with ".stubs" suffix
+ props := struct {
+ Name *string
+ Soc_specific *bool
+ Device_specific *bool
+ Product_specific *bool
+ System_ext_specific *bool
+ Sdk_version *string
+ Libs []string
+ Jars []string
+ Prefer *bool
+ }{}
+ props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
+ props.Sdk_version = scopeProperties.Sdk_version
+ // Prepend any of the libs from the legacy public properties to the libs for each of the
+ // scopes to avoid having to duplicate them in each scope.
+ props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
+ props.Jars = scopeProperties.Jars
+ if module.SocSpecific() {
+ props.Soc_specific = proptools.BoolPtr(true)
+ } else if module.DeviceSpecific() {
+ props.Device_specific = proptools.BoolPtr(true)
+ } else if module.ProductSpecific() {
+ props.Product_specific = proptools.BoolPtr(true)
+ } else if module.SystemExtSpecific() {
+ props.System_ext_specific = proptools.BoolPtr(true)
+ }
+ // If the build should use prebuilt sdks then set prefer to true on the stubs library.
+ // That will cause the prebuilt version of the stubs to override the source version.
+ if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ props.Prefer = proptools.BoolPtr(true)
+ }
+ mctx.CreateModule(ImportFactory, &props)
}
func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- for apiScope, scopeProperties := range module.scopeProperties() {
+ for apiScope, scopeProperties := range module.scopeProperties {
if len(scopeProperties.Jars) == 0 {
continue
}
@@ -1082,3 +1125,81 @@
},
}}
}
+
+type sdkLibrarySdkMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (s *sdkLibrarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*SdkLibrary)
+ return ok
+}
+
+func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_sdk_library_import")
+}
+
+func (s *sdkLibrarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &sdkLibrarySdkMemberProperties{}
+}
+
+type sdkLibrarySdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ // Scope to per scope properties.
+ Scopes map[*apiScope]scopeProperties
+
+ // Additional libraries that the exported stubs libraries depend upon.
+ Libs []string
+}
+
+type scopeProperties struct {
+ Jars android.Paths
+ SdkVersion string
+}
+
+func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ sdk := variant.(*SdkLibrary)
+
+ s.Scopes = make(map[*apiScope]scopeProperties)
+ for _, apiScope := range allApiScopes {
+ paths := sdk.getScopePaths(apiScope)
+ jars := paths.stubsImplPath
+ if len(jars) > 0 {
+ properties := scopeProperties{}
+ properties.Jars = jars
+ properties.SdkVersion = apiScope.sdkVersion
+ s.Scopes[apiScope] = properties
+ }
+ }
+
+ s.Libs = sdk.properties.Libs
+}
+
+func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ for _, apiScope := range allApiScopes {
+ if properties, ok := s.Scopes[apiScope]; ok {
+ scopeSet := propertySet.AddPropertySet(apiScope.name)
+
+ var jars []string
+ for _, p := range properties.Jars {
+ dest := filepath.Join("sdk_library", s.OsPrefix(), apiScope.name, ctx.Name()+"-stubs.jar")
+ ctx.SnapshotBuilder().CopyToSnapshot(p, dest)
+ jars = append(jars, dest)
+ }
+ scopeSet.AddProperty("jars", jars)
+
+ if properties.SdkVersion != "" {
+ scopeSet.AddProperty("sdk_version", properties.SdkVersion)
+ }
+ }
+ }
+
+ if len(s.Libs) > 0 {
+ propertySet.AddPropertyWithTag("libs", s.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(false))
+ }
+}
diff --git a/java/system_modules.go b/java/system_modules.go
index 47de6e3..7394fd5 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -242,18 +242,28 @@
return false
}
-func (mt *systemModulesSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- variants := member.Variants()
- if len(variants) != 1 {
- sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
- for _, variant := range variants {
- sdkModuleContext.ModuleErrorf(" %q", variant)
- }
- }
- variant := variants[0]
- systemModule := variant.(*SystemModules)
+func (mt *systemModulesSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_system_modules_import")
+}
- pbm := builder.AddPrebuiltModule(member, "java_system_modules_import")
- // Add the references to the libraries that form the system module.
- pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag())
+type systemModulesInfoProperties struct {
+ android.SdkMemberPropertiesBase
+
+ Libs []string
+}
+
+func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &systemModulesInfoProperties{}
+}
+
+func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ systemModule := variant.(*SystemModules)
+ p.Libs = systemModule.properties.Libs
+}
+
+func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if len(p.Libs) > 0 {
+ // Add the references to the libraries that form the system module.
+ propertySet.AddPropertyWithTag("libs", p.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true))
+ }
}
diff --git a/sdk/bp.go b/sdk/bp.go
index 6936daf..68fe7ab 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -35,7 +35,7 @@
func (s *bpPropertySet) AddProperty(name string, value interface{}) {
if s.properties[name] != nil {
- panic("Property %q already exists in property set")
+ panic(fmt.Sprintf("Property %q already exists in property set", name))
}
s.properties[name] = value
@@ -48,8 +48,7 @@
}
func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
- set := &bpPropertySet{}
- set.init()
+ set := newPropertySet()
s.AddProperty(name, set)
return set
}
@@ -62,7 +61,7 @@
return s.tags[name]
}
-func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
+func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
var newOrder []string
for _, name := range s.order {
value := s.properties[name]
@@ -70,7 +69,13 @@
var newValue interface{}
var newTag android.BpPropertyTag
if propertySet, ok := value.(*bpPropertySet); ok {
- newValue, newTag = transformer.transformPropertySet(name, propertySet, tag)
+ var newPropertySet *bpPropertySet
+ newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag)
+ if newPropertySet == nil {
+ newValue = nil
+ } else {
+ newValue = newPropertySet
+ }
} else {
newValue, newTag = transformer.transformProperty(name, value, tag)
}
@@ -88,6 +93,16 @@
s.order = newOrder
}
+func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+ newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag)
+ if newPropertySet != nil {
+ newPropertySet.transformContents(transformer)
+
+ newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag)
+ }
+ return newPropertySet, newTag
+}
+
func (s *bpPropertySet) setProperty(name string, value interface{}) {
if s.properties[name] == nil {
s.AddProperty(name, value)
@@ -136,7 +151,17 @@
// The name will be "" for the top level property set.
//
// Returning (nil, ...) will cause the property set to be removed.
- transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
+ transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
+
+ // Transform the property set, returning the new property set/tag to insert back into the
+ // parent property set (or module if this is the top level property set).
+ //
+ // This will be called after transforming the properties in the supplied set.
+ //
+ // The name will be "" for the top level property set.
+ //
+ // Returning (nil, ...) will cause the property set to be removed.
+ transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
// Transform a property, return the new value/tag to insert back into the property set.
//
@@ -165,7 +190,11 @@
return module
}
-func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+func (t identityTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+ return propertySet, tag
+}
+
+func (t identityTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
return propertySet, tag
}
@@ -180,12 +209,13 @@
func (m *bpModule) transform(transformer bpTransformer) *bpModule {
transformedModule := transformer.transformModule(m)
// Copy the contents of the returned property set into the module and then transform that.
- transformedModule.bpPropertySet, _ = transformer.transformPropertySet("", transformedModule.bpPropertySet, nil)
- transformedModule.bpPropertySet.transform(transformer)
+ transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
return transformedModule
}
-type deepCopyTransformation struct{}
+type deepCopyTransformation struct {
+ identityTransformation
+}
func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
// Take a shallow copy of the module. Any mutable property values will be copied by the
@@ -194,7 +224,7 @@
return &moduleCopy
}
-func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+func (t deepCopyTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
// Create a shallow copy of the properties map. Any mutable property values will be copied by the
// transformer.
propertiesCopy := make(map[string]interface{})
@@ -253,10 +283,19 @@
}
func (f *bpFile) newModule(moduleType string) *bpModule {
+ return newModule(moduleType)
+}
+
+func newModule(moduleType string) *bpModule {
module := &bpModule{
moduleType: moduleType,
- bpPropertySet: &bpPropertySet{},
+ bpPropertySet: newPropertySet(),
}
- module.bpPropertySet.init()
return module
}
+
+func newPropertySet() *bpPropertySet {
+ set := &bpPropertySet{}
+ set.init()
+ return set
+}
diff --git a/sdk/bp_test.go b/sdk/bp_test.go
new file mode 100644
index 0000000..f89f38c
--- /dev/null
+++ b/sdk/bp_test.go
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 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 sdk
+
+import (
+ "testing"
+
+ "android/soong/android"
+)
+
+type removeFredTransformation struct {
+ identityTransformation
+}
+
+func (t removeFredTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+ if name == "fred" {
+ return nil, nil
+ }
+ return value, tag
+}
+
+func (t removeFredTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+ if name == "fred" {
+ return nil, nil
+ }
+ return propertySet, tag
+}
+
+func (t removeFredTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+ if len(propertySet.properties) == 0 {
+ return nil, nil
+ }
+ return propertySet, tag
+}
+
+func TestTransformRemoveProperty(t *testing.T) {
+
+ helper := &TestHelper{t}
+
+ set := newPropertySet()
+ set.AddProperty("name", "name")
+ set.AddProperty("fred", "12")
+
+ set.transformContents(removeFredTransformation{})
+
+ contents := &generatedContents{}
+ outputPropertySet(contents, set)
+ helper.AssertTrimmedStringEquals("removing property failed", "name: \"name\",\\n", contents.content.String())
+}
+
+func TestTransformRemovePropertySet(t *testing.T) {
+
+ helper := &TestHelper{t}
+
+ set := newPropertySet()
+ set.AddProperty("name", "name")
+ set.AddPropertySet("fred")
+
+ set.transformContents(removeFredTransformation{})
+
+ contents := &generatedContents{}
+ outputPropertySet(contents, set)
+ helper.AssertTrimmedStringEquals("removing property set failed", "name: \"name\",\\n", contents.content.String())
+}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 9c8e292..0a4e16d 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -17,6 +17,7 @@
import (
"testing"
+ "android/soong/android"
"android/soong/cc"
)
@@ -24,11 +25,13 @@
t.Helper()
fs := map[string][]byte{
- "Test.cpp": nil,
- "include/Test.h": nil,
- "arm64/include/Arm64Test.h": nil,
- "libfoo.so": nil,
- "aidl/foo/bar/Test.aidl": nil,
+ "Test.cpp": nil,
+ "include/Test.h": nil,
+ "include-android/AndroidTest.h": nil,
+ "include-host/HostTest.h": nil,
+ "arm64/include/Arm64Test.h": nil,
+ "libfoo.so": nil,
+ "aidl/foo/bar/Test.aidl": nil,
}
return testSdkWithFs(t, bp, fs)
}
@@ -54,7 +57,7 @@
arm64Output := result.Module("sdkmember", "android_arm64_armv8-a_shared").(*cc.Module).OutputFile()
var inputs []string
- buildParams := result.Module("mysdk", "android_common").BuildParamsForTests()
+ buildParams := result.Module("mysdk", android.CommonOS.Name).BuildParamsForTests()
for _, bp := range buildParams {
if bp.Input != nil {
inputs = append(inputs, bp.Input.String())
@@ -250,7 +253,7 @@
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAllCopyRules(`
include/Test.h -> include/include/Test.h
.intermediates/mynativelib1/android_arm64_armv8-a_shared/mynativelib1.so -> arm64/lib/mynativelib1.so
@@ -287,13 +290,15 @@
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library_shared {
name: "mysdk_mynativelib@current",
sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -304,13 +309,12 @@
srcs: ["arm/lib/mynativelib.so"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
name: "mynativelib",
prefer: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -321,8 +325,6 @@
srcs: ["arm/lib/mynativelib.so"],
},
},
- stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -356,13 +358,14 @@
}
`)
- result.CheckSnapshot("mymodule_exports", "android_common", "",
+ result.CheckSnapshot("mymodule_exports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_binary {
name: "mymodule_exports_mynativebinary@current",
sdk_member_name: "mynativebinary",
+ installable: false,
compile_multilib: "both",
arch: {
arm64: {
@@ -400,6 +403,114 @@
)
}
+func TestMultipleHostOsTypesSnapshotWithCcBinary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "myexports",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["mynativebinary"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ cc_binary {
+ name: "mynativebinary",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ ],
+ compile_multilib: "both",
+ system_shared_libs: [],
+ stl: "none",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+ name: "myexports_mynativebinary@current",
+ sdk_member_name: "mynativebinary",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ target: {
+ linux_glibc: {
+ compile_multilib: "both",
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/bin/mynativebinary"],
+ },
+ windows: {
+ compile_multilib: "64",
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+ },
+ },
+}
+
+cc_prebuilt_binary {
+ name: "mynativebinary",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ target: {
+ linux_glibc: {
+ compile_multilib: "both",
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/bin/mynativebinary"],
+ },
+ windows: {
+ compile_multilib: "64",
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["myexports_mynativebinary@current"],
+ target: {
+ windows: {
+ compile_multilib: "64",
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativebinary/linux_glibc_x86_64/mynativebinary -> linux_glibc/x86_64/bin/mynativebinary
+.intermediates/mynativebinary/linux_glibc_x86/mynativebinary -> linux_glibc/x86/bin/mynativebinary
+.intermediates/mynativebinary/windows_x86_64/mynativebinary.exe -> windows/x86_64/bin/mynativebinary.exe
+`),
+ )
+}
+
func TestSnapshotWithCcSharedLibrary(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -413,6 +524,7 @@
"Test.cpp",
"aidl/foo/bar/Test.aidl",
],
+ apex_available: ["apex1", "apex2"],
export_include_dirs: ["include"],
aidl: {
export_aidl_headers: true,
@@ -422,13 +534,19 @@
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library_shared {
name: "mysdk_mynativelib@current",
sdk_member_name: "mynativelib",
+ apex_available: [
+ "apex1",
+ "apex2",
+ ],
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -440,13 +558,16 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
name: "mynativelib",
prefer: false,
+ apex_available: [
+ "apex1",
+ "apex2",
+ ],
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -458,8 +579,6 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -481,6 +600,189 @@
)
}
+func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: [
+ "mynativelib",
+ "myothernativelib",
+ "mysystemnativelib",
+ ],
+ }
+
+ cc_library {
+ name: "mysystemnativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "myothernativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ system_shared_libs: [
+ // A reference to a library that is not an sdk member. Uses libm as that
+ // is in the default set of modules available to this test and so is available
+ // both here and also when the generated Android.bp file is tested in
+ // CheckSnapshot(). This ensures that the system_shared_libs property correctly
+ // handles references to modules that are not sdk members.
+ "libm",
+ ],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "mynativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ shared_libs: [
+ // A reference to another sdk member.
+ "myothernativelib",
+ ],
+ target: {
+ android: {
+ shared: {
+ shared_libs: [
+ // A reference to a library that is not an sdk member. The libc library
+ // is used here to check that the shared_libs property is handled correctly
+ // in a similar way to how libm is used to check system_shared_libs above.
+ "libc",
+ ],
+ },
+ },
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
+ shared_libs: [
+ "mysdk_myothernativelib@current",
+ "libc",
+ ],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ stl: "none",
+ shared_libs: [
+ "myothernativelib",
+ "libc",
+ ],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_myothernativelib@current",
+ sdk_member_name: "myothernativelib",
+ installable: false,
+ stl: "none",
+ system_shared_libs: ["libm"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/myothernativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/myothernativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "myothernativelib",
+ prefer: false,
+ stl: "none",
+ system_shared_libs: ["libm"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/myothernativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/myothernativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mysystemnativelib@current",
+ sdk_member_name: "mysystemnativelib",
+ installable: false,
+ stl: "none",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mysystemnativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mysystemnativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysystemnativelib",
+ prefer: false,
+ stl: "none",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mysystemnativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mysystemnativelib.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_shared_libs: [
+ "mysdk_mynativelib@current",
+ "mysdk_myothernativelib@current",
+ "mysdk_mysystemnativelib@current",
+ ],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so
+.intermediates/myothernativelib/android_arm64_armv8-a_shared/myothernativelib.so -> arm64/lib/myothernativelib.so
+.intermediates/myothernativelib/android_arm_armv7-a-neon_shared/myothernativelib.so -> arm/lib/myothernativelib.so
+.intermediates/mysystemnativelib/android_arm64_armv8-a_shared/mysystemnativelib.so -> arm64/lib/mysystemnativelib.so
+.intermediates/mysystemnativelib/android_arm_armv7-a-neon_shared/mysystemnativelib.so -> arm/lib/mysystemnativelib.so
+`),
+ )
+}
+
func TestHostSnapshotWithCcSharedLibrary(t *testing.T) {
// b/145598135 - Generating host snapshots for anything other than linux is not supported.
SkipIfNotLinux(t)
@@ -507,10 +809,11 @@
},
system_shared_libs: [],
stl: "none",
+ sdk_version: "minimum",
}
`)
- result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -519,6 +822,9 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
+ sdk_version: "minimum",
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -530,8 +836,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
@@ -539,6 +843,8 @@
prefer: false,
device_supported: false,
host_supported: true,
+ sdk_version: "minimum",
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -550,8 +856,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -575,6 +879,103 @@
)
}
+func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mynativelib"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ cc_library_shared {
+ name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ ],
+ system_shared_libs: [],
+ stl: "none",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ stl: "none",
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/lib/mynativelib.dll"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/lib/mynativelib.dll"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mysdk_mynativelib@current"],
+ target: {
+ windows: {
+ compile_multilib: "64",
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> linux_glibc/x86_64/lib/mynativelib.so
+.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> linux_glibc/x86/lib/mynativelib.so
+.intermediates/mynativelib/windows_x86_64_shared/mynativelib.dll -> windows/x86_64/lib/mynativelib.dll
+`),
+ )
+}
+
func TestSnapshotWithCcStaticLibrary(t *testing.T) {
result := testSdkWithCc(t, `
module_exports {
@@ -597,13 +998,15 @@
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library_static {
name: "myexports_mynativelib@current",
sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -615,13 +1018,12 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
name: "mynativelib",
prefer: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -633,8 +1035,6 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
@@ -685,7 +1085,7 @@
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -694,6 +1094,8 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -705,8 +1107,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
@@ -714,6 +1114,7 @@
prefer: false,
device_supported: false,
host_supported: true,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -725,8 +1126,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
@@ -749,3 +1148,359 @@
`),
)
}
+
+func TestSnapshotWithCcLibrary(t *testing.T) {
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "myexports",
+ native_libs: ["mynativelib"],
+ }
+
+ cc_library {
+ name: "mynativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ export_include_dirs: ["include"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library {
+ name: "myexports_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+ arch: {
+ arm64: {
+ static: {
+ srcs: ["arm64/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ },
+ arm: {
+ static: {
+ srcs: ["arm/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+ },
+}
+
+cc_prebuilt_library {
+ name: "mynativelib",
+ prefer: false,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+ arch: {
+ arm64: {
+ static: {
+ srcs: ["arm64/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ },
+ arm: {
+ static: {
+ srcs: ["arm/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ native_libs: ["myexports_mynativelib@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+.intermediates/mynativelib/android_arm64_armv8-a_static/mynativelib.a -> arm64/lib/mynativelib.a
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_static/mynativelib.a -> arm/lib/mynativelib.a
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
+ )
+}
+
+func TestHostSnapshotWithMultiLib64(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "myexports",
+ device_supported: false,
+ host_supported: true,
+ target: {
+ host: {
+ compile_multilib: "64",
+ },
+ },
+ native_static_libs: ["mynativelib"],
+ }
+
+ cc_library_static {
+ name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ "aidl/foo/bar/Test.aidl",
+ ],
+ export_include_dirs: ["include"],
+ aidl: {
+ export_aidl_headers: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_static {
+ name: "myexports_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+ arch: {
+ x86_64: {
+ srcs: ["x86_64/lib/mynativelib.a"],
+ export_include_dirs: ["x86_64/include_gen/mynativelib"],
+ },
+ },
+}
+
+cc_prebuilt_library_static {
+ name: "mynativelib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+ arch: {
+ x86_64: {
+ srcs: ["x86_64/lib/mynativelib.a"],
+ export_include_dirs: ["x86_64/include_gen/mynativelib"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ device_supported: false,
+ host_supported: true,
+ native_static_libs: ["myexports_mynativelib@current"],
+ target: {
+ linux_glibc: {
+ compile_multilib: "64",
+ },
+ },
+}`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/mynativelib.a -> x86_64/lib/mynativelib.a
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/Test.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/BnTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BnTest.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/BpTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BpTest.h
+`),
+ )
+}
+
+func TestSnapshotWithCcHeadersLibrary(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_header_libs: ["mynativeheaders"],
+ }
+
+ cc_library_headers {
+ name: "mynativeheaders",
+ export_include_dirs: ["include"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+ name: "mysdk_mynativeheaders@current",
+ sdk_member_name: "mynativeheaders",
+ stl: "none",
+ export_include_dirs: ["include/include"],
+}
+
+cc_prebuilt_library_headers {
+ name: "mynativeheaders",
+ prefer: false,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+`),
+ )
+}
+
+func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ native_header_libs: ["mynativeheaders"],
+ }
+
+ cc_library_headers {
+ name: "mynativeheaders",
+ device_supported: false,
+ host_supported: true,
+ export_include_dirs: ["include"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+ name: "mysdk_mynativeheaders@current",
+ sdk_member_name: "mynativeheaders",
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+}
+
+cc_prebuilt_library_headers {
+ name: "mynativeheaders",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+`),
+ )
+}
+
+func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ native_header_libs: ["mynativeheaders"],
+ }
+
+ cc_library_headers {
+ name: "mynativeheaders",
+ host_supported: true,
+ system_shared_libs: [],
+ stl: "none",
+ export_system_include_dirs: ["include"],
+ target: {
+ android: {
+ export_include_dirs: ["include-android"],
+ },
+ host: {
+ export_include_dirs: ["include-host"],
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+ name: "mysdk_mynativeheaders@current",
+ sdk_member_name: "mynativeheaders",
+ host_supported: true,
+ stl: "none",
+ export_system_include_dirs: ["include/include"],
+ target: {
+ android: {
+ export_include_dirs: ["include/include-android"],
+ },
+ linux_glibc: {
+ export_include_dirs: ["include/include-host"],
+ },
+ },
+}
+
+cc_prebuilt_library_headers {
+ name: "mynativeheaders",
+ prefer: false,
+ host_supported: true,
+ stl: "none",
+ export_system_include_dirs: ["include/include"],
+ target: {
+ android: {
+ export_include_dirs: ["include/include-android"],
+ },
+ linux_glibc: {
+ export_include_dirs: ["include/include-host"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+include-android/AndroidTest.h -> include/include-android/AndroidTest.h
+include-host/HostTest.h -> include/include-host/HostTest.h
+`),
+ )
+}
diff --git a/sdk/exports_test.go b/sdk/exports_test.go
index b905d71..20e2521 100644
--- a/sdk/exports_test.go
+++ b/sdk/exports_test.go
@@ -42,7 +42,7 @@
"package/Android.bp": []byte(packageBp),
})
- result.CheckSnapshot("myexports", "android_common", "package",
+ result.CheckSnapshot("myexports", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 0737e5e..bce2ab3 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -24,7 +24,51 @@
fs := map[string][]byte{
"Test.java": nil,
"aidl/foo/bar/Test.aidl": nil,
+
+ // For java_sdk_library
+ "api/current.txt": nil,
+ "api/removed.txt": nil,
+ "api/system-current.txt": nil,
+ "api/system-removed.txt": nil,
+ "api/test-current.txt": nil,
+ "api/test-removed.txt": nil,
+ "build/soong/scripts/gen-java-current-api-files.sh": nil,
}
+
+ // for java_sdk_library tests
+ bp = `
+java_system_modules_import {
+ name: "core-current-stubs-system-modules",
+}
+java_system_modules_import {
+ name: "core-platform-api-stubs-system-modules",
+}
+java_import {
+ name: "core.platform.api.stubs",
+}
+java_sdk_library_import {
+ name: "android_stubs_current",
+}
+java_sdk_library_import {
+ name: "android_system_stubs_current",
+}
+java_sdk_library_import {
+ name: "android_test_stubs_current",
+}
+java_import {
+ name: "core-lambda-stubs",
+ sdk_version: "none",
+}
+java_import {
+ name: "ext",
+ sdk_version: "none",
+}
+java_import {
+ name: "framework",
+ sdk_version: "none",
+}
+` + bp
+
return testSdkWithFs(t, bp, fs)
}
@@ -53,30 +97,18 @@
system_modules: "none",
sdk_version: "none",
host_supported: true,
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
}
java_import {
name: "sdkmember_mysdk_1",
sdk_member_name: "sdkmember",
host_supported: true,
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
}
java_import {
name: "sdkmember_mysdk_2",
sdk_member_name: "sdkmember",
host_supported: true,
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
}
java_library {
@@ -141,7 +173,7 @@
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -196,7 +228,7 @@
}
`)
- result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -230,6 +262,72 @@
)
}
+func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ java_header_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ host_supported: true,
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+ )
+}
+
func TestSnapshotWithJavaImplLibrary(t *testing.T) {
result := testSdkWithJava(t, `
module_exports {
@@ -250,7 +348,7 @@
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -305,7 +403,7 @@
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -356,7 +454,7 @@
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -409,7 +507,7 @@
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -503,7 +601,7 @@
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -526,7 +624,7 @@
`),
checkAllCopyRules(""),
- checkMergeZip(".intermediates/myexports/android_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+ checkMergeZip(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
)
}
@@ -552,7 +650,7 @@
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -580,7 +678,7 @@
}
`),
checkAllCopyRules(""),
- checkMergeZip(".intermediates/myexports/linux_glibc_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+ checkMergeZip(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
)
}
@@ -612,7 +710,7 @@
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -702,7 +800,7 @@
}
`)
- result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -750,3 +848,194 @@
checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
)
}
+
+func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ module_exports {
+ name: "myexports",
+ host_supported: true,
+ java_libs: ["myjavalib"],
+ target: {
+ android: {
+ java_header_libs: ["androidjavalib"],
+ },
+ host: {
+ java_header_libs: ["hostjavalib"],
+ },
+ },
+ }
+
+ java_library {
+ name: "myjavalib",
+ host_supported: true,
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_library {
+ name: "androidjavalib",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_library_host {
+ name: "hostjavalib",
+ srcs: ["Test.java"],
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "myexports_hostjavalib@current",
+ sdk_member_name: "hostjavalib",
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+ name: "hostjavalib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+ name: "myexports_androidjavalib@current",
+ sdk_member_name: "androidjavalib",
+ jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+ name: "androidjavalib",
+ prefer: false,
+ jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+ name: "myexports_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ host_supported: true,
+ java_libs: ["myexports_myjavalib@current"],
+ target: {
+ android: {
+ java_header_libs: ["myexports_androidjavalib@current"],
+ },
+ linux_glibc: {
+ java_header_libs: ["myexports_hostjavalib@current"],
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/hostjavalib/linux_glibc_common/javac/hostjavalib.jar -> java/hostjavalib.jar
+.intermediates/androidjavalib/android_common/turbine-combined/androidjavalib.jar -> java/androidjavalib.jar
+.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+ )
+}
+
+func TestSnapshotWithJavaSdkLibrary(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_sdk_libs: ["myjavalib"],
+ }
+
+ java_sdk_library {
+ name: "myjavalib",
+ apex_available: ["//apex_available:anyapex"],
+ srcs: ["Test.java"],
+ sdk_version: "current",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ apex_available: ["//apex_available:anyapex"],
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ sdk_version: "current",
+ },
+ system: {
+ jars: ["sdk_library/system/myjavalib-stubs.jar"],
+ sdk_version: "system_current",
+ },
+ test: {
+ jars: ["sdk_library/test/myjavalib-stubs.jar"],
+ sdk_version: "test_current",
+ },
+}
+
+java_sdk_library_import {
+ name: "myjavalib",
+ prefer: false,
+ apex_available: ["//apex_available:anyapex"],
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ sdk_version: "current",
+ },
+ system: {
+ jars: ["sdk_library/system/myjavalib-stubs.jar"],
+ sdk_version: "system_current",
+ },
+ test: {
+ jars: ["sdk_library/test/myjavalib-stubs.jar"],
+ sdk_version: "test_current",
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_sdk_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.test/android_common/javac/myjavalib.stubs.test.jar -> sdk_library/test/myjavalib-stubs.jar
+`),
+ )
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 4976dc0..cb5a605 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -50,8 +50,17 @@
// list properties, e.g. java_libs.
dynamicMemberTypeListProperties interface{}
- // The set of exported members.
- exportedMembers map[string]struct{}
+ // Information about the OsType specific member variants associated with this variant.
+ //
+ // Set by OsType specific variants in the collectMembers() method and used by the
+ // CommonOS variant when building the snapshot. That work is all done on separate
+ // calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be
+ // called for the OsType specific variants before the CommonOS variant (because
+ // the latter depends on the former).
+ memberRefs []sdkMemberRef
+
+ // The multilib variants that are used by this sdk variant.
+ multilibUsages multilibUsage
properties sdkProperties
@@ -143,6 +152,7 @@
fields = append(fields, reflect.StructField{
Name: proptools.FieldNameForProperty(p),
Type: reflect.TypeOf([]string{}),
+ Tag: `android:"arch_variant"`,
})
// Copy the field index for use in the getter func as using the loop variable directly will
@@ -201,7 +211,7 @@
// properties for the member type specific list properties.
s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberListProperties()
s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties)
- android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
+ android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(s)
android.AddLoadHook(s, func(ctx android.LoadHookContext) {
type props struct {
@@ -225,26 +235,19 @@
}
func (s *sdk) getExportedMembers() map[string]struct{} {
- if s.exportedMembers == nil {
- // Collect all the exported members.
- s.exportedMembers = make(map[string]struct{})
+ // Collect all the exported members.
+ exportedMembers := make(map[string]struct{})
- for _, memberListProperty := range s.memberListProperties() {
- names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
+ for _, memberListProperty := range s.memberListProperties() {
+ names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
- // Every member specified explicitly in the properties is exported by the sdk.
- for _, name := range names {
- s.exportedMembers[name] = struct{}{}
- }
+ // Every member specified explicitly in the properties is exported by the sdk.
+ for _, name := range names {
+ exportedMembers[name] = struct{}{}
}
}
- return s.exportedMembers
-}
-
-func (s *sdk) isInternalMember(memberName string) bool {
- _, ok := s.getExportedMembers()[memberName]
- return !ok
+ return exportedMembers
}
func (s *sdk) snapshot() bool {
@@ -252,10 +255,31 @@
}
func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if !s.snapshot() {
+ if s.snapshot() {
// We don't need to create a snapshot out of sdk_snapshot.
// That doesn't make sense. We need a snapshot to create sdk_snapshot.
- s.snapshotFile = android.OptionalPathForPath(s.buildSnapshot(ctx))
+ return
+ }
+
+ // This method is guaranteed to be called on OsType specific variants before it is called
+ // on their corresponding CommonOS variant.
+ if !s.IsCommonOSVariant() {
+ // Update the OsType specific sdk variant with information about its members.
+ s.collectMembers(ctx)
+ } else {
+ // Get the OsType specific variants on which the CommonOS depends.
+ osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx)
+ var sdkVariants []*sdk
+ for _, m := range osSpecificVariants {
+ if sdkVariant, ok := m.(*sdk); ok {
+ sdkVariants = append(sdkVariants, sdkVariant)
+ }
+ }
+
+ // Generate the snapshot from the member info.
+ p := s.buildSnapshot(ctx, sdkVariants)
+ s.snapshotFile = android.OptionalPathForPath(p)
+ ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), s.Name()+"-current.zip", p)
}
}
@@ -288,7 +312,7 @@
ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
}
-// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
+// RegisterPostDepsMutators registers post-deps mutators to support modules implementing SdkAware
// interface and the sdk module type. This function has been made public to be called by tests
// outside of the sdk package
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
@@ -320,11 +344,14 @@
// Step 1: create dependencies from an SDK module to its members.
func memberMutator(mctx android.BottomUpMutatorContext) {
if s, ok := mctx.Module().(*sdk); ok {
- if s.Enabled() {
+ // Add dependencies from enabled and non CommonOS variants to the sdk member variants.
+ if s.Enabled() && !s.IsCommonOSVariant() {
for _, memberListProperty := range s.memberListProperties() {
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
- tag := memberListProperty.dependencyTag
- memberListProperty.memberType.AddDependencies(mctx, tag, names)
+ if len(names) > 0 {
+ tag := memberListProperty.dependencyTag
+ memberListProperty.memberType.AddDependencies(mctx, tag, names)
+ }
}
}
}
@@ -404,23 +431,31 @@
}
}
-// Step 6: ensure that the dependencies from outside of the APEX are all from the required SDKs
+// Step 6: ensure that the dependencies outside of the APEX are all from the required SDKs
func sdkRequirementsMutator(mctx android.TopDownMutatorContext) {
if m, ok := mctx.Module().(interface {
- DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool
- RequiredSdks() android.SdkRefs
+ android.DepIsInSameApex
+ android.RequiredSdks
}); ok {
requiredSdks := m.RequiredSdks()
if len(requiredSdks) == 0 {
return
}
mctx.VisitDirectDeps(func(dep android.Module) {
- if mctx.OtherModuleDependencyTag(dep) == android.DefaultsDepTag {
+ tag := mctx.OtherModuleDependencyTag(dep)
+ if tag == android.DefaultsDepTag {
// dependency to defaults is always okay
return
}
- // If the dep is from outside of the APEX, but is not in any of the
+ // Ignore the dependency from the unversioned member to any versioned members as an
+ // apex that depends on the unversioned member will not also be depending on a versioned
+ // member.
+ if _, ok := tag.(sdkMemberVersionedDepTag); ok {
+ return
+ }
+
+ // If the dep is outside of the APEX, but is not in any of the
// required SDKs, we know that the dep is a violation.
if sa, ok := dep.(android.SdkAware); ok {
if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 53c2971..fde9230 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -16,6 +16,8 @@
import (
"testing"
+
+ "github.com/google/blueprint/proptools"
)
// Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
@@ -146,7 +148,7 @@
"package/Android.bp": []byte(packageBp),
})
- result.CheckSnapshot("mysdk", "android_common", "package",
+ result.CheckSnapshot("mysdk", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -206,3 +208,122 @@
}
`))
}
+
+func TestSDkInstall(t *testing.T) {
+ sdk := `
+ sdk {
+ name: "mysdk",
+ }
+ `
+ result := testSdkWithFs(t, ``,
+ map[string][]byte{
+ "Android.bp": []byte(sdk),
+ })
+
+ result.CheckSnapshot("mysdk", "",
+ checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
+ )
+}
+
+type EmbeddedPropertiesStruct struct {
+ S_Embedded_Common string
+ S_Embedded_Different string
+}
+
+type testPropertiesStruct struct {
+ private string
+ Public_Kept string `sdk:"keep"`
+ S_Common string
+ S_Different string
+ A_Common []string
+ A_Different []string
+ F_Common *bool
+ F_Different *bool
+ EmbeddedPropertiesStruct
+}
+
+func TestCommonValueOptimization(t *testing.T) {
+ common := &testPropertiesStruct{}
+ structs := []*testPropertiesStruct{
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "common",
+ S_Different: "upper",
+ A_Common: []string{"first", "second"},
+ A_Different: []string{"alpha", "beta"},
+ F_Common: proptools.BoolPtr(false),
+ F_Different: proptools.BoolPtr(false),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "embedded_upper",
+ },
+ },
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "common",
+ S_Different: "lower",
+ A_Common: []string{"first", "second"},
+ A_Different: []string{"alpha", "delta"},
+ F_Common: proptools.BoolPtr(false),
+ F_Different: proptools.BoolPtr(true),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "embedded_lower",
+ },
+ },
+ }
+
+ extractor := newCommonValueExtractor(common)
+ extractor.extractCommonProperties(common, structs)
+
+ h := TestHelper{t}
+ h.AssertDeepEquals("common properties not correct", common,
+ &testPropertiesStruct{
+ private: "",
+ Public_Kept: "",
+ S_Common: "common",
+ S_Different: "",
+ A_Common: []string{"first", "second"},
+ A_Different: []string(nil),
+ F_Common: proptools.BoolPtr(false),
+ F_Different: nil,
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "",
+ },
+ })
+
+ h.AssertDeepEquals("updated properties[0] not correct", structs[0],
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "",
+ S_Different: "upper",
+ A_Common: nil,
+ A_Different: []string{"alpha", "beta"},
+ F_Common: nil,
+ F_Different: proptools.BoolPtr(false),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "",
+ S_Embedded_Different: "embedded_upper",
+ },
+ })
+
+ h.AssertDeepEquals("updated properties[1] not correct", structs[1],
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "",
+ S_Different: "lower",
+ A_Common: nil,
+ A_Different: []string{"alpha", "delta"},
+ F_Common: nil,
+ F_Different: proptools.BoolPtr(true),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "",
+ S_Embedded_Different: "embedded_lower",
+ },
+ })
+}
diff --git a/sdk/testing.go b/sdk/testing.go
index ae0620d..570ea0f 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -19,6 +19,7 @@
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
"strings"
"testing"
@@ -40,7 +41,7 @@
name: "myapex.cert",
certificate: "myapex",
}
- ` + cc.GatherRequiredDepsForTest(android.Android)
+ ` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
mockFS := map[string][]byte{
"build/make/target/product/security": nil,
@@ -61,8 +62,24 @@
config := android.TestArchConfig(buildDir, nil, bp, mockFS)
+ // Add windows as a default disable OS to test behavior when some OS variants
+ // are disabled.
+ config.Targets[android.Windows] = []android.Target{
+ {android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""},
+ }
+
ctx := android.NewTestArchContext()
+ // Enable androidmk support.
+ // * Register the singleton
+ // * Configure that we are inside make
+ // * Add CommonOS to ensure that androidmk processing works.
+ android.RegisterAndroidMkBuildComponents(ctx)
+ android.SetInMakeForTests(config)
+ config.Targets[android.CommonOS] = []android.Target{
+ {android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", ""},
+ }
+
// from android package
android.RegisterPackageBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
@@ -73,6 +90,7 @@
// from java package
java.RegisterJavaBuildComponents(ctx)
java.RegisterAppBuildComponents(ctx)
+ java.RegisterSdkLibraryBuildComponents(ctx)
java.RegisterStubsBuildComponents(ctx)
java.RegisterSystemModulesBuildComponents(ctx)
@@ -160,6 +178,13 @@
h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
}
+func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
+ h.t.Helper()
+ if !reflect.DeepEqual(actual, expected) {
+ h.t.Errorf("%s: expected %#v, actual %#v", message, expected, actual)
+ }
+}
+
// Encapsulates result of processing an SDK definition. Provides support for
// checking the state of the build structures.
type testSdkResult struct {
@@ -182,15 +207,23 @@
buildParams := sdk.BuildParamsForTests()
copyRules := &strings.Builder{}
+ otherCopyRules := &strings.Builder{}
+ snapshotDirPrefix := sdk.builderForTests.snapshotDir.String() + "/"
for _, bp := range buildParams {
switch bp.Rule.String() {
case android.Cp.String():
- // Get source relative to build directory.
- src := android.NormalizePathForTesting(bp.Input)
+ output := bp.Output
// Get destination relative to the snapshot root
- dest := bp.Output.Rel()
- _, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
- info.snapshotContents = append(info.snapshotContents, dest)
+ dest := output.Rel()
+ src := android.NormalizePathForTesting(bp.Input)
+ // We differentiate between copy rules for the snapshot, and copy rules for the install file.
+ if strings.HasPrefix(output.String(), snapshotDirPrefix) {
+ // Get source relative to build directory.
+ _, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
+ info.snapshotContents = append(info.snapshotContents, dest)
+ } else {
+ _, _ = fmt.Fprintf(otherCopyRules, "%s -> %s\n", src, dest)
+ }
case repackageZip.String():
// Add the destdir to the snapshot contents as that is effectively where
@@ -223,6 +256,7 @@
}
info.copyRules = copyRules.String()
+ info.otherCopyRules = otherCopyRules.String()
return info
}
@@ -240,9 +274,12 @@
// Takes a list of functions which check different facets of the snapshot build rules.
// Allows each test to customize what is checked without duplicating lots of code
// or proliferating check methods of different flavors.
-func (r *testSdkResult) CheckSnapshot(name string, variant string, dir string, checkers ...snapshotBuildInfoChecker) {
+func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snapshotBuildInfoChecker) {
r.t.Helper()
+ // The sdk CommonOS variant is always responsible for generating the snapshot.
+ variant := android.CommonOS.Name
+
sdk := r.Module(name, variant).(*sdk)
snapshotBuildInfo := r.getSdkSnapshotBuildInfo(sdk)
@@ -295,6 +332,13 @@
}
}
+func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
+ return func(info *snapshotBuildInfo) {
+ info.r.t.Helper()
+ info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules)
+ }
+}
+
// Check that the specified path is in the list of zips to merge with the intermediate zip.
func checkMergeZip(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
@@ -321,10 +365,14 @@
// snapshot.
snapshotContents []string
- // A formatted representation of the src/dest pairs, one pair per line, of the format
- // src -> dest
+ // A formatted representation of the src/dest pairs for a snapshot, one pair per line,
+ // of the format src -> dest
copyRules string
+ // A formatted representation of the src/dest pairs for files not in a snapshot, one pair
+ // per line, of the format src -> dest
+ otherCopyRules string
+
// The path to the intermediate zip, which is a zip created from the source files copied
// into the snapshot directory and which will be merged with other zips to form the final output.
// Is am empty string if there is no intermediate zip because there are no zips to merge in.
diff --git a/sdk/update.go b/sdk/update.go
index ff567be..e14347f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -17,8 +17,11 @@
import (
"fmt"
"reflect"
+ "sort"
"strings"
+ "android/soong/apex"
+ "android/soong/cc"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -104,13 +107,10 @@
// Collect all the members.
//
-// The members are first grouped by type and then grouped by name. The order of
-// the types is the order they are referenced in android.SdkMemberTypesRegistry.
-// The names are in the order in which the dependencies were added.
-func (s *sdk) collectMembers(ctx android.ModuleContext) []*sdkMember {
- byType := make(map[android.SdkMemberType][]*sdkMember)
- byName := make(map[string]*sdkMember)
-
+// Returns a list containing type (extracted from the dependency tag) and the variant
+// plus the multilib usages.
+func (s *sdk) collectMembers(ctx android.ModuleContext) {
+ s.multilibUsages = multilibNone
ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
tag := ctx.OtherModuleDependencyTag(child)
if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
@@ -121,18 +121,10 @@
ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
}
- name := ctx.OtherModuleName(child)
+ // Keep track of which multilib variants are used by the sdk.
+ s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
- member := byName[name]
- if member == nil {
- member = &sdkMember{memberType: memberType, name: name}
- byName[name] = member
- byType[memberType] = append(byType[memberType], member)
- }
-
- // Only append new variants to the list. This is needed because a member can be both
- // exported by the sdk and also be a transitive sdk member.
- member.variants = appendUniqueVariants(member.variants, child.(android.SdkAware))
+ s.memberRefs = append(s.memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
// If the member type supports transitive sdk members then recurse down into
// its dependencies, otherwise exit traversal.
@@ -141,6 +133,35 @@
return false
})
+}
+
+// Organize the members.
+//
+// The members are first grouped by type and then grouped by name. The order of
+// the types is the order they are referenced in android.SdkMemberTypesRegistry.
+// The names are in the order in which the dependencies were added.
+//
+// Returns the members as well as the multilib setting to use.
+func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) []*sdkMember {
+ byType := make(map[android.SdkMemberType][]*sdkMember)
+ byName := make(map[string]*sdkMember)
+
+ for _, memberRef := range memberRefs {
+ memberType := memberRef.memberType
+ variant := memberRef.variant
+
+ name := ctx.OtherModuleName(variant)
+ member := byName[name]
+ if member == nil {
+ member = &sdkMember{memberType: memberType, name: name}
+ byName[name] = member
+ byType[memberType] = append(byType[memberType], member)
+ }
+
+ // Only append new variants to the list. This is needed because a member can be both
+ // exported by the sdk and also be a transitive sdk member.
+ member.variants = appendUniqueVariants(member.variants, variant)
+ }
var members []*sdkMember
for _, memberListProperty := range s.memberListProperties() {
@@ -186,7 +207,26 @@
// 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) android.OutputPath {
+func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
+
+ allMembersByName := make(map[string]struct{})
+ exportedMembersByName := make(map[string]struct{})
+ var memberRefs []sdkMemberRef
+ for _, sdkVariant := range sdkVariants {
+ memberRefs = append(memberRefs, sdkVariant.memberRefs...)
+
+ // Record the names of all the members, both explicitly specified and implicitly
+ // included.
+ for _, memberRef := range sdkVariant.memberRefs {
+ allMembersByName[memberRef.variant.Name()] = struct{}{}
+ }
+
+ // Merge the exported member sets from all sdk variants.
+ for key, _ := range sdkVariant.getExportedMembers() {
+ exportedMembersByName[key] = struct{}{}
+ }
+ }
+
snapshotDir := android.PathForModuleOut(ctx, "snapshot")
bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
@@ -196,19 +236,27 @@
}
builder := &snapshotBuilder{
- ctx: ctx,
- sdk: s,
- version: "current",
- snapshotDir: snapshotDir.OutputPath,
- copies: make(map[string]string),
- filesToZip: []android.Path{bp.path},
- bpFile: bpFile,
- prebuiltModules: make(map[string]*bpModule),
+ ctx: ctx,
+ sdk: s,
+ version: "current",
+ snapshotDir: snapshotDir.OutputPath,
+ copies: make(map[string]string),
+ filesToZip: []android.Path{bp.path},
+ bpFile: bpFile,
+ prebuiltModules: make(map[string]*bpModule),
+ allMembersByName: allMembersByName,
+ exportedMembersByName: exportedMembersByName,
}
s.builderForTests = builder
- for _, member := range s.collectMembers(ctx) {
- member.memberType.BuildSnapshot(ctx, builder, member)
+ members := s.organizeMembers(ctx, memberRefs)
+ for _, member := range members {
+ memberType := member.memberType
+
+ memberCtx := &memberContext{ctx, builder, memberType, member.name}
+
+ prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
+ s.createMemberSnapshot(memberCtx, member, prebuiltModule)
}
// Create a transformer that will transform an unversioned module into a versioned module.
@@ -219,6 +267,9 @@
unversionedTransformer := unversionedTransformation{builder: builder}
for _, unversioned := range builder.prebuiltOrder {
+ // Prune any empty property sets.
+ unversioned = unversioned.transform(pruneEmptySetTransformer{})
+
// Copy the unversioned module so it can be modified to make it versioned.
versioned := unversioned.deepCopy()
@@ -248,13 +299,46 @@
snapshotModule.AddProperty("visibility", visibility)
}
- addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
- for _, memberListProperty := range s.memberListProperties() {
- names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
- if len(names) > 0 {
- snapshotModule.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names))
+ addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
+
+ var dynamicMemberPropertiesList []interface{}
+ osTypeToMemberProperties := make(map[android.OsType]*sdk)
+ for _, sdkVariant := range sdkVariants {
+ properties := sdkVariant.dynamicMemberTypeListProperties
+ osTypeToMemberProperties[sdkVariant.Target().Os] = sdkVariant
+ dynamicMemberPropertiesList = append(dynamicMemberPropertiesList, properties)
+ }
+
+ // Extract the common lists of members into a separate struct.
+ commonDynamicMemberProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
+ extractor := newCommonValueExtractor(commonDynamicMemberProperties)
+ extractor.extractCommonProperties(commonDynamicMemberProperties, dynamicMemberPropertiesList)
+
+ // Add properties common to all os types.
+ s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
+
+ // Iterate over the os types in a fixed order.
+ targetPropertySet := snapshotModule.AddPropertySet("target")
+ for _, osType := range s.getPossibleOsTypes() {
+ if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
+ osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
+
+ // Compile_multilib defaults to both and must always be set to both on the
+ // device and so only needs to be set when targeted at the host and is neither
+ // unspecified or both.
+ multilib := sdkVariant.multilibUsages
+ if (osType.Class == android.Host || osType.Class == android.HostCross) &&
+ multilib != multilibNone && multilib != multilibBoth {
+ osPropertySet.AddProperty("compile_multilib", multilib.String())
+ }
+
+ s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
}
}
+
+ // Prune any empty property sets.
+ snapshotModule.transform(pruneEmptySetTransformer{})
+
bpFile.AddModule(snapshotModule)
// generate Android.bp
@@ -305,11 +389,32 @@
return outputZipFile
}
+func (s *sdk) addMemberPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, dynamicMemberTypeListProperties interface{}) {
+ for _, memberListProperty := range s.memberListProperties() {
+ names := memberListProperty.getter(dynamicMemberTypeListProperties)
+ if len(names) > 0 {
+ propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
+ }
+ }
+}
+
type propertyTag struct {
name string
}
-var sdkMemberReferencePropertyTag = propertyTag{"sdkMemberReferencePropertyTag"}
+// A BpPropertyTag to add to a property that contains references to other sdk members.
+//
+// This will cause the references to be rewritten to a versioned reference in the version
+// specific instance of a snapshot module.
+var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"}
+var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"}
+
+// A BpPropertyTag that indicates the property should only be present in the versioned
+// module.
+//
+// This will cause the property to be removed from the unversioned instance of a
+// snapshot module.
+var sdkVersionedOnlyPropertyTag = propertyTag{"sdkVersionedOnlyPropertyTag"}
type unversionedToVersionedTransformation struct {
identityTransformation
@@ -320,14 +425,15 @@
// Use a versioned name for the module but remember the original name for the
// snapshot.
name := module.getValue("name").(string)
- module.setProperty("name", t.builder.versionedSdkMemberName(name))
+ module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
module.insertAfter("name", "sdk_member_name", name)
return module
}
func (t unversionedToVersionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
- if tag == sdkMemberReferencePropertyTag {
- return t.builder.versionedSdkMemberNames(value.([]string)), tag
+ if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+ required := tag == requiredSdkMemberReferencePropertyTag
+ return t.builder.versionedSdkMemberNames(value.([]string), required), tag
} else {
return value, tag
}
@@ -341,7 +447,7 @@
func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
// If the module is an internal member then use a unique name for it.
name := module.getValue("name").(string)
- module.setProperty("name", t.builder.unversionedSdkMemberName(name))
+ module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
// Set prefer: false - this is not strictly required as that is the default.
module.insertAfter("name", "prefer", false)
@@ -350,13 +456,31 @@
}
func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
- if tag == sdkMemberReferencePropertyTag {
- return t.builder.unversionedSdkMemberNames(value.([]string)), tag
+ if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+ required := tag == requiredSdkMemberReferencePropertyTag
+ return t.builder.unversionedSdkMemberNames(value.([]string), required), tag
+ } else if tag == sdkVersionedOnlyPropertyTag {
+ // The property is not allowed in the unversioned module so remove it.
+ return nil, nil
} else {
return value, tag
}
}
+type pruneEmptySetTransformer struct {
+ identityTransformation
+}
+
+var _ bpTransformer = (*pruneEmptySetTransformer)(nil)
+
+func (t pruneEmptySetTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+ if len(propertySet.properties) == 0 {
+ return nil, nil
+ } else {
+ return propertySet, tag
+ }
+}
+
func generateBpContents(contents *generatedContents, bpFile *bpFile) {
contents.Printfln("// This is auto-generated. DO NOT EDIT.")
for _, bpModule := range bpFile.order {
@@ -369,41 +493,53 @@
func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
contents.Indent()
+
+ // Output the properties first, followed by the nested sets. This ensures a
+ // consistent output irrespective of whether property sets are created before
+ // or after the properties. This simplifies the creation of the module.
for _, name := range set.order {
value := set.getValue(name)
- reflectedValue := reflect.ValueOf(value)
- t := reflectedValue.Type()
-
- kind := t.Kind()
- switch kind {
- case reflect.Slice:
- length := reflectedValue.Len()
+ switch v := value.(type) {
+ case []string:
+ length := len(v)
if length > 1 {
contents.Printfln("%s: [", name)
contents.Indent()
for i := 0; i < length; i = i + 1 {
- contents.Printfln("%q,", reflectedValue.Index(i).Interface())
+ contents.Printfln("%q,", v[i])
}
contents.Dedent()
contents.Printfln("],")
} else if length == 0 {
contents.Printfln("%s: [],", name)
} else {
- contents.Printfln("%s: [%q],", name, reflectedValue.Index(0).Interface())
+ contents.Printfln("%s: [%q],", name, v[0])
}
- case reflect.Bool:
- contents.Printfln("%s: %t,", name, reflectedValue.Bool())
- case reflect.Ptr:
- contents.Printfln("%s: {", name)
- outputPropertySet(contents, reflectedValue.Interface().(*bpPropertySet))
- contents.Printfln("},")
+ case bool:
+ contents.Printfln("%s: %t,", name, v)
+
+ case *bpPropertySet:
+ // Do not write property sets in the properties phase.
default:
contents.Printfln("%s: %q,", name, value)
}
}
+
+ for _, name := range set.order {
+ value := set.getValue(name)
+
+ // Only write property sets in the sets phase.
+ switch v := value.(type) {
+ case *bpPropertySet:
+ contents.Printfln("%s: {", name)
+ outputPropertySet(contents, v)
+ contents.Printfln("},")
+ }
+ }
+
contents.Dedent()
}
@@ -429,6 +565,12 @@
prebuiltModules map[string]*bpModule
prebuiltOrder []*bpModule
+
+ // The set of all members by name.
+ allMembersByName map[string]struct{}
+
+ // The set of exported members by name.
+ exportedMembersByName map[string]struct{}
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -480,69 +622,137 @@
m := s.bpFile.newModule(moduleType)
m.AddProperty("name", name)
- if s.sdk.isInternalMember(name) {
+ variant := member.Variants()[0]
+
+ if s.isInternalMember(name) {
// An internal member is only referenced from the sdk snapshot which is in the
// same package so can be marked as private.
m.AddProperty("visibility", []string{"//visibility:private"})
} else {
// Extract visibility information from a member variant. All variants have the same
// visibility so it doesn't matter which one is used.
- visibility := android.EffectiveVisibilityRules(s.ctx, member.Variants()[0])
+ visibility := android.EffectiveVisibilityRules(s.ctx, variant)
if len(visibility) != 0 {
m.AddProperty("visibility", visibility)
}
}
- addHostDeviceSupportedProperties(&s.sdk.ModuleBase, m)
+ deviceSupported := false
+ hostSupported := false
+
+ for _, variant := range member.Variants() {
+ osClass := variant.Target().Os.Class
+ if osClass == android.Host || osClass == android.HostCross {
+ hostSupported = true
+ } else if osClass == android.Device {
+ deviceSupported = true
+ }
+ }
+
+ addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
+
+ // Where available copy apex_available properties from the member.
+ if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
+ apexAvailable := apexAware.ApexAvailable()
+
+ // Add in any white listed apex available settings.
+ apexAvailable = append(apexAvailable, apex.WhitelistedApexAvailable(member.Name())...)
+
+ if len(apexAvailable) > 0 {
+ // Remove duplicates and sort.
+ apexAvailable = android.FirstUniqueStrings(apexAvailable)
+ sort.Strings(apexAvailable)
+
+ m.AddProperty("apex_available", apexAvailable)
+ }
+ }
+
+ // Disable installation in the versioned module of those modules that are ever installable.
+ if installable, ok := variant.(interface{ EverInstallable() bool }); ok {
+ if installable.EverInstallable() {
+ m.AddPropertyWithTag("installable", false, sdkVersionedOnlyPropertyTag)
+ }
+ }
s.prebuiltModules[name] = m
s.prebuiltOrder = append(s.prebuiltOrder, m)
return m
}
-func addHostDeviceSupportedProperties(module *android.ModuleBase, bpModule *bpModule) {
- if !module.DeviceSupported() {
+func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
+ if !deviceSupported {
bpModule.AddProperty("device_supported", false)
}
- if module.HostSupported() {
+ if hostSupported {
bpModule.AddProperty("host_supported", true)
}
}
-func (s *snapshotBuilder) SdkMemberReferencePropertyTag() android.BpPropertyTag {
- return sdkMemberReferencePropertyTag
+func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag {
+ if required {
+ return requiredSdkMemberReferencePropertyTag
+ } else {
+ return optionalSdkMemberReferencePropertyTag
+ }
+}
+
+func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag {
+ return optionalSdkMemberReferencePropertyTag
}
// Get a versioned name appropriate for the SDK snapshot version being taken.
-func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string) string {
+func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string, required bool) string {
+ if _, ok := s.allMembersByName[unversionedName]; !ok {
+ if required {
+ s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+ }
+ return unversionedName
+ }
return versionedSdkMemberName(s.ctx, unversionedName, s.version)
}
-func (s *snapshotBuilder) versionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) versionedSdkMemberNames(members []string, required bool) []string {
var references []string = nil
for _, m := range members {
- references = append(references, s.versionedSdkMemberName(m))
+ references = append(references, s.versionedSdkMemberName(m, required))
}
return references
}
// Get an internal name unique to the sdk.
-func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string) string {
- if s.sdk.isInternalMember(unversionedName) {
+func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string, required bool) string {
+ if _, ok := s.allMembersByName[unversionedName]; !ok {
+ if required {
+ s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+ }
+ return unversionedName
+ }
+
+ if s.isInternalMember(unversionedName) {
return s.ctx.ModuleName() + "_" + unversionedName
} else {
return unversionedName
}
}
-func (s *snapshotBuilder) unversionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) unversionedSdkMemberNames(members []string, required bool) []string {
var references []string = nil
for _, m := range members {
- references = append(references, s.unversionedSdkMemberName(m))
+ references = append(references, s.unversionedSdkMemberName(m, required))
}
return references
}
+func (s *snapshotBuilder) isInternalMember(memberName string) bool {
+ _, ok := s.exportedMembersByName[memberName]
+ return !ok
+}
+
+type sdkMemberRef struct {
+ memberType android.SdkMemberType
+ variant android.SdkAware
+}
+
var _ android.SdkMember = (*sdkMember)(nil)
type sdkMember struct {
@@ -558,3 +768,556 @@
func (m *sdkMember) Variants() []android.SdkAware {
return m.variants
}
+
+// Track usages of multilib variants.
+type multilibUsage int
+
+const (
+ multilibNone multilibUsage = 0
+ multilib32 multilibUsage = 1
+ multilib64 multilibUsage = 2
+ multilibBoth = multilib32 | multilib64
+)
+
+// Add the multilib that is used in the arch type.
+func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage {
+ multilib := archType.Multilib
+ switch multilib {
+ case "":
+ return m
+ case "lib32":
+ return m | multilib32
+ case "lib64":
+ return m | multilib64
+ default:
+ panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
+ }
+}
+
+func (m multilibUsage) String() string {
+ switch m {
+ case multilibNone:
+ return ""
+ case multilib32:
+ return "32"
+ case multilib64:
+ return "64"
+ case multilibBoth:
+ return "both"
+ default:
+ panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
+ m, multilibNone, multilib32, multilib64, multilibBoth))
+ }
+}
+
+type baseInfo struct {
+ Properties android.SdkMemberProperties
+}
+
+type osTypeSpecificInfo struct {
+ baseInfo
+
+ osType android.OsType
+
+ // The list of arch type specific info for this os type.
+ //
+ // Nil if there is one variant whose arch type is common
+ archInfos []*archTypeSpecificInfo
+}
+
+type variantPropertiesFactoryFunc func() android.SdkMemberProperties
+
+// Create a new osTypeSpecificInfo for the specified os type and its properties
+// structures populated with information from the variants.
+func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo {
+ osInfo := &osTypeSpecificInfo{
+ osType: osType,
+ }
+
+ osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
+ properties := variantPropertiesFactory()
+ properties.Base().Os = osType
+ return properties
+ }
+
+ // Create a structure into which properties common across the architectures in
+ // this os type will be stored.
+ osInfo.Properties = osSpecificVariantPropertiesFactory()
+
+ // Group the variants by arch type.
+ var variantsByArchName = make(map[string][]android.Module)
+ var archTypes []android.ArchType
+ for _, variant := range osTypeVariants {
+ archType := variant.Target().Arch.ArchType
+ archTypeName := archType.Name
+ if _, ok := variantsByArchName[archTypeName]; !ok {
+ archTypes = append(archTypes, archType)
+ }
+
+ variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant)
+ }
+
+ if commonVariants, ok := variantsByArchName["common"]; ok {
+ if len(osTypeVariants) != 1 {
+ panic("Expected to only have 1 variant when arch type is common but found " + string(len(osTypeVariants)))
+ }
+
+ // A common arch type only has one variant and its properties should be treated
+ // as common to the os type.
+ osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
+ } else {
+ // Create an arch specific info for each supported architecture type.
+ for _, archType := range archTypes {
+ archTypeName := archType.Name
+
+ archVariants := variantsByArchName[archTypeName]
+ archInfo := newArchSpecificInfo(ctx, archType, osSpecificVariantPropertiesFactory, archVariants)
+
+ osInfo.archInfos = append(osInfo.archInfos, archInfo)
+ }
+ }
+
+ return osInfo
+}
+
+// Optimize the properties by extracting common properties from arch type specific
+// properties into os type specific properties.
+func (osInfo *osTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+ // Nothing to do if there is only a single common architecture.
+ if len(osInfo.archInfos) == 0 {
+ return
+ }
+
+ multilib := multilibNone
+ var archPropertiesList []android.SdkMemberProperties
+ for _, archInfo := range osInfo.archInfos {
+ multilib = multilib.addArchType(archInfo.archType)
+
+ // Optimize the arch properties first.
+ archInfo.optimizeProperties(commonValueExtractor)
+
+ archPropertiesList = append(archPropertiesList, archInfo.Properties)
+ }
+
+ commonValueExtractor.extractCommonProperties(osInfo.Properties, archPropertiesList)
+
+ // Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+ osInfo.Properties.Base().Compile_multilib = multilib.String()
+}
+
+// Add the properties for an os to a property set.
+//
+// Maps the properties related to the os variants through to an appropriate
+// module structure that will produce equivalent set of variants when it is
+// processed in a build.
+func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) {
+
+ var osPropertySet android.BpPropertySet
+ var archPropertySet android.BpPropertySet
+ var archOsPrefix string
+ if osInfo.Properties.Base().Os_count == 1 {
+ // There is only one os type present in the variants so don't bother
+ // with adding target specific properties.
+
+ // Create a structure that looks like:
+ // module_type {
+ // name: "...",
+ // ...
+ // <common properties>
+ // ...
+ // <single os type specific properties>
+ //
+ // arch: {
+ // <arch specific sections>
+ // }
+ //
+ osPropertySet = bpModule
+ archPropertySet = osPropertySet.AddPropertySet("arch")
+
+ // Arch specific properties need to be added to an arch specific section
+ // within arch.
+ archOsPrefix = ""
+ } else {
+ // Create a structure that looks like:
+ // module_type {
+ // name: "...",
+ // ...
+ // <common properties>
+ // ...
+ // target: {
+ // <arch independent os specific sections, e.g. android>
+ // ...
+ // <arch and os specific sections, e.g. android_x86>
+ // }
+ //
+ osType := osInfo.osType
+ osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
+ archPropertySet = targetPropertySet
+
+ // Arch specific properties need to be added to an os and arch specific
+ // section prefixed with <os>_.
+ archOsPrefix = osType.Name + "_"
+ }
+
+ // Add the os specific but arch independent properties to the module.
+ osInfo.Properties.AddToPropertySet(ctx, osPropertySet)
+
+ // Add arch (and possibly os) specific sections for each set of arch (and possibly
+ // os) specific properties.
+ //
+ // The archInfos list will be empty if the os contains variants for the common
+ // architecture.
+ for _, archInfo := range osInfo.archInfos {
+ archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix)
+ }
+}
+
+type archTypeSpecificInfo struct {
+ baseInfo
+
+ archType android.ArchType
+
+ linkInfos []*linkTypeSpecificInfo
+}
+
+// Create a new archTypeSpecificInfo for the specified arch type and its properties
+// structures populated with information from the variants.
+func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
+
+ // Create an arch specific info into which the variant properties can be copied.
+ archInfo := &archTypeSpecificInfo{archType: archType}
+
+ // Create the properties into which the arch type specific properties will be
+ // added.
+ archInfo.Properties = variantPropertiesFactory()
+
+ if len(archVariants) == 1 {
+ archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
+ } else {
+ // There is more than one variant for this arch type which must be differentiated
+ // by link type.
+ for _, linkVariant := range archVariants {
+ linkType := getLinkType(linkVariant)
+ if linkType == "" {
+ panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants)))
+ } else {
+ linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant)
+
+ archInfo.linkInfos = append(archInfo.linkInfos, linkInfo)
+ }
+ }
+ }
+
+ return archInfo
+}
+
+// Get the link type of the variant
+//
+// If the variant is not differentiated by link type then it returns "",
+// otherwise it returns one of "static" or "shared".
+func getLinkType(variant android.Module) string {
+ linkType := ""
+ if linkable, ok := variant.(cc.LinkableInterface); ok {
+ if linkable.Shared() && linkable.Static() {
+ panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String()))
+ } else if linkable.Shared() {
+ linkType = "shared"
+ } else if linkable.Static() {
+ linkType = "static"
+ } else {
+ panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String()))
+ }
+ }
+ return linkType
+}
+
+// Optimize the properties by extracting common properties from link type specific
+// properties into arch type specific properties.
+func (archInfo *archTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+ if len(archInfo.linkInfos) == 0 {
+ return
+ }
+
+ var propertiesList []android.SdkMemberProperties
+ for _, linkInfo := range archInfo.linkInfos {
+ propertiesList = append(propertiesList, linkInfo.Properties)
+ }
+
+ commonValueExtractor.extractCommonProperties(archInfo.Properties, propertiesList)
+}
+
+// Add the properties for an arch type to a property set.
+func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
+ archTypeName := archInfo.archType.Name
+ archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
+ archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet)
+
+ for _, linkInfo := range archInfo.linkInfos {
+ linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
+ linkInfo.Properties.AddToPropertySet(ctx, linkPropertySet)
+ }
+}
+
+type linkTypeSpecificInfo struct {
+ baseInfo
+
+ linkType string
+}
+
+// Create a new linkTypeSpecificInfo for the specified link type and its properties
+// structures populated with information from the variant.
+func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo {
+ linkInfo := &linkTypeSpecificInfo{
+ baseInfo: baseInfo{
+ // Create the properties into which the link type specific properties will be
+ // added.
+ Properties: variantPropertiesFactory(),
+ },
+ linkType: linkType,
+ }
+ linkInfo.Properties.PopulateFromVariant(ctx, linkVariant)
+ return linkInfo
+}
+
+type memberContext struct {
+ sdkMemberContext android.ModuleContext
+ builder *snapshotBuilder
+ memberType android.SdkMemberType
+ name string
+}
+
+func (m *memberContext) SdkModuleContext() android.ModuleContext {
+ return m.sdkMemberContext
+}
+
+func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
+ return m.builder
+}
+
+func (m *memberContext) MemberType() android.SdkMemberType {
+ return m.memberType
+}
+
+func (m *memberContext) Name() string {
+ return m.name
+}
+
+func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
+
+ memberType := member.memberType
+
+ // 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)
+ }
+
+ osCount := len(variantsByOsType)
+ variantPropertiesFactory := func() android.SdkMemberProperties {
+ properties := memberType.CreateVariantPropertiesStruct()
+ base := properties.Base()
+ base.Os_count = osCount
+ return properties
+ }
+
+ osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
+
+ // The set of properties that are common across all architectures and os types.
+ commonProperties := variantPropertiesFactory()
+ commonProperties.Base().Os = android.CommonOS
+
+ // Create common value extractor that can be used to optimize the properties.
+ commonValueExtractor := newCommonValueExtractor(commonProperties)
+
+ // The list of property structures which are os type specific but common across
+ // architectures within that os type.
+ var osSpecificPropertiesList []android.SdkMemberProperties
+
+ for osType, osTypeVariants := range variantsByOsType {
+ osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants)
+ osTypeToInfo[osType] = osInfo
+ // Add the os specific properties to a list of os type specific yet architecture
+ // independent properties structs.
+ osSpecificPropertiesList = append(osSpecificPropertiesList, osInfo.Properties)
+
+ // Optimize the properties across all the variants for a specific os type.
+ osInfo.optimizeProperties(commonValueExtractor)
+ }
+
+ // Extract properties which are common across all architectures and os types.
+ commonValueExtractor.extractCommonProperties(commonProperties, osSpecificPropertiesList)
+
+ // Add the common properties to the module.
+ commonProperties.AddToPropertySet(ctx, bpModule)
+
+ // Create a target property set into which target specific properties can be
+ // added.
+ targetPropertySet := bpModule.AddPropertySet("target")
+
+ // Iterate over the os types in a fixed order.
+ for _, osType := range s.getPossibleOsTypes() {
+ osInfo := osTypeToInfo[osType]
+ if osInfo == nil {
+ continue
+ }
+
+ osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
+ }
+}
+
+// Compute the list of possible os types that this sdk could support.
+func (s *sdk) getPossibleOsTypes() []android.OsType {
+ var osTypes []android.OsType
+ for _, osType := range android.OsTypeList {
+ if s.DeviceSupported() {
+ if osType.Class == android.Device && osType != android.Fuchsia {
+ osTypes = append(osTypes, osType)
+ }
+ }
+ if s.HostSupported() {
+ if osType.Class == android.Host || osType.Class == android.HostCross {
+ osTypes = append(osTypes, osType)
+ }
+ }
+ }
+ sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
+ return osTypes
+}
+
+// Given a struct value, access a field within that struct (or one of its embedded
+// structs).
+type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
+
+// Supports extracting common values from a number of instances of a properties
+// structure into a separate common set of properties.
+type commonValueExtractor struct {
+ // The getters for every field from which common values can be extracted.
+ fieldGetters []fieldAccessorFunc
+}
+
+// Create a new common value extractor for the structure type for the supplied
+// properties struct.
+//
+// The returned extractor can be used on any properties structure of the same type
+// as the supplied set of properties.
+func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor {
+ structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
+ extractor := &commonValueExtractor{}
+ extractor.gatherFields(structType, nil)
+ return extractor
+}
+
+// Gather the fields from the supplied structure type from which common values will
+// be extracted.
+//
+// This is recursive function. If it encounters an embedded field (no field name)
+// that is a struct then it will recurse into that struct passing in the accessor
+// for the field. That will then be used in the accessors for the fields in the
+// embedded struct.
+func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc) {
+ for f := 0; f < structType.NumField(); f++ {
+ field := structType.Field(f)
+ if field.PkgPath != "" {
+ // Ignore unexported fields.
+ continue
+ }
+
+ // Ignore fields whose value should be kept.
+ if proptools.HasTag(field, "sdk", "keep") {
+ continue
+ }
+
+ // Save a copy of the field index for use in the function.
+ fieldIndex := f
+ fieldGetter := func(value reflect.Value) reflect.Value {
+ if containingStructAccessor != nil {
+ // This is an embedded structure so first access the field for the embedded
+ // structure.
+ value = containingStructAccessor(value)
+ }
+
+ // Skip through interface and pointer values to find the structure.
+ value = getStructValue(value)
+
+ // Return the field.
+ return value.Field(fieldIndex)
+ }
+
+ if field.Type.Kind() == reflect.Struct && field.Anonymous {
+ // Gather fields from the embedded structure.
+ e.gatherFields(field.Type, fieldGetter)
+ } else {
+ e.fieldGetters = append(e.fieldGetters, fieldGetter)
+ }
+ }
+}
+
+func getStructValue(value reflect.Value) reflect.Value {
+foundStruct:
+ for {
+ kind := value.Kind()
+ switch kind {
+ case reflect.Interface, reflect.Ptr:
+ value = value.Elem()
+ case reflect.Struct:
+ break foundStruct
+ default:
+ panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind))
+ }
+ }
+ return value
+}
+
+// Extract common properties from a slice of property structures of the same type.
+//
+// All the property structures must be of the same type.
+// commonProperties - must be a pointer to the structure into which common properties will be added.
+// inputPropertiesSlice - must be a slice of input properties structures.
+//
+// Iterates over each exported field (capitalized name) and checks to see whether they
+// have the same value (using DeepEquals) across all the input properties. If it does not then no
+// change is made. Otherwise, the common value is stored in the field in the commonProperties
+// and the field in each of the input properties structure is set to its default value.
+func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
+ commonPropertiesValue := reflect.ValueOf(commonProperties)
+ commonStructValue := commonPropertiesValue.Elem()
+
+ for _, fieldGetter := range e.fieldGetters {
+ // Check to see if all the structures have the same value for the field. The commonValue
+ // is nil on entry to the loop and if it is nil on exit then there is no common value,
+ // otherwise it points to the common value.
+ var commonValue *reflect.Value
+ sliceValue := reflect.ValueOf(inputPropertiesSlice)
+
+ for i := 0; i < sliceValue.Len(); i++ {
+ itemValue := sliceValue.Index(i)
+ fieldValue := fieldGetter(itemValue)
+
+ if commonValue == nil {
+ // Use the first value as the commonProperties value.
+ commonValue = &fieldValue
+ } else {
+ // If the value does not match the current common value then there is
+ // no value in common so break out.
+ if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
+ commonValue = nil
+ break
+ }
+ }
+ }
+
+ // If the fields all have a common value then store it in the common struct field
+ // and set the input struct's field to the empty value.
+ if commonValue != nil {
+ emptyValue := reflect.Zero(commonValue.Type())
+ fieldGetter(commonStructValue).Set(*commonValue)
+ for i := 0; i < sliceValue.Len(); i++ {
+ itemValue := sliceValue.Index(i)
+ fieldValue := fieldGetter(itemValue)
+ fieldValue.Set(emptyValue)
+ }
+ }
+ }
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 65dbb22..14fab68 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -115,6 +115,7 @@
type syspropLibrary struct {
android.ModuleBase
+ android.ApexModuleBase
properties syspropLibraryProperties
@@ -149,6 +150,12 @@
// Whether public stub exists or not.
Public_stub *bool `blueprint:"mutated"`
+
+ Cpp struct {
+ // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ // Forwarded to cc_library.min_sdk_version
+ Min_sdk_version *string
+ }
}
var (
@@ -296,6 +303,7 @@
&m.properties,
)
android.InitAndroidModule(m)
+ android.InitApexModule(m)
android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
return m
}
@@ -323,6 +331,8 @@
Recovery_available *bool
Vendor_available *bool
Host_supported *bool
+ Apex_available []string
+ Min_sdk_version *string
}
type javaLibraryProperties struct {
@@ -411,6 +421,8 @@
ccProps.Recovery_available = m.properties.Recovery_available
ccProps.Vendor_available = m.properties.Vendor_available
ccProps.Host_supported = m.properties.Host_supported
+ ccProps.Apex_available = m.ApexProperties.Apex_available
+ ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version
ctx.CreateModule(cc.LibraryFactory, &ccProps)
scope := "internal"
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 51da222..8503386 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -15,6 +15,8 @@
package sysprop
import (
+ "reflect"
+
"android/soong/android"
"android/soong/cc"
"android/soong/java"
@@ -157,6 +159,7 @@
ctx := test(t, `
sysprop_library {
name: "sysprop-platform",
+ apex_available: ["//apex_available:platform"],
srcs: ["android/sysprop/PlatformProperties.sysprop"],
api_packages: ["android.sysprop"],
property_owner: "Platform",
@@ -305,7 +308,12 @@
"android_arm64_armv8-a_shared",
"android_arm64_armv8-a_static",
} {
- ctx.ModuleForTests("libsysprop-platform", variant)
+ library := ctx.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
+ expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
+ if !reflect.DeepEqual(library.ApexProperties.Apex_available, expectedApexAvailableOnLibrary) {
+ t.Errorf("apex available property on libsysprop-platform must be %#v, but was %#v.",
+ expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
+ }
// core variant of vendor-owned sysprop_library is for product
ctx.ModuleForTests("libsysprop-vendor", variant)