Merge "mark platform un-availability"

This commit is contained in:
Treehugger Robot 2020-04-27 12:37:45 +00:00 committed by Gerrit Code Review
commit 01db260858
4 changed files with 129 additions and 27 deletions

View File

@ -198,6 +198,10 @@ func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod bluep
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 {

View File

@ -101,6 +101,16 @@ type ApexModule interface {
// Tests if this module is available for the specified APEX or ":platform"
AvailableFor(what string) 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]
// it returns 9 as string
@ -126,6 +136,8 @@ type ApexProperties struct {
Apex_available []string
Info ApexInfo `blueprint:"mutated"`
NotAvailableForPlatform bool `blueprint:"mutated"`
}
// Marker interface that identifies dependencies that are excluded from APEX
@ -215,6 +227,14 @@ 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.

View File

@ -746,6 +746,7 @@ func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
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
@ -784,6 +785,60 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) {
})
}
// 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 {

View File

@ -3750,22 +3750,12 @@ func TestApexAvailable_InvalidApexName(t *testing.T) {
}`)
}
func TestApexAvailable_CreatedForPlatform(t *testing.T) {
// 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")
func TestApexAvailable_CheckForPlatform(t *testing.T) {
ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["libbar", "libbaz"],
}
apex_key {
@ -3778,16 +3768,52 @@ func TestApexAvailable_CreatedForPlatform(t *testing.T) {
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())
}
// 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) {
testApex(t, `
ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@ -3810,17 +3836,14 @@ func TestApexAvailable_CreatedForApex(t *testing.T) {
},
}`)
// 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) {