Add apex_available to control the availablity of a module to APEXes

apex_available property controls the availability of a module to APEXes.
For example, `apex_available: ["myapex", "otherapex"]` makes the module
available only to the two APEXes: myapex and otherapex, and nothing
else, even to the platform.

If the module is intended to be available to any APEX, then a pseudo
name "//apex_available:anyapex" can be used.

If the module is intended to be available to the platform, then another
pseudo name "//apex_available:platform" is used.

For now, if unspecified, this property defaults to ["//apex_available:platform",
"//apex_available:anyapex"], which means the module is available to everybody.
This will be reduced to ["//apex_available:platform"], when marking for
apex_available for existing modules are finished.

Bug: 139870423
Bug: 128708192
Test: m
Change-Id: Id4b233c3056c7858f984cbf9427cfac4118b2682
This commit is contained in:
Jiyong Park 2019-09-30 16:04:35 +09:00
parent fdc9afa15b
commit 127b40b316
3 changed files with 206 additions and 2 deletions

View File

@ -78,12 +78,23 @@ type ApexModule interface {
// Return the no_apex property
NoApex() bool
// Tests if this module is available for the specified APEX or ":platform"
AvailableFor(what string) bool
}
type ApexProperties struct {
// Whether this module should not be part of any APEX. Default is false.
// TODO(b/128708192): remove this as this is equal to apex_available: [":platform"]
No_apex *bool
// Availability of this module in APEXes. Only the listed APEXes can include this module.
// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
// "//apex_available:platform" refers to non-APEX partitions like "system.img".
// Default is ["//apex_available:platform", "//apex_available:anyapex"].
// TODO(b/128708192) change the default to ["//apex_available:platform"]
Apex_available []string
// Name of the apex variant that this module is mutated into
ApexName string `blueprint:"mutated"`
}
@ -136,15 +147,46 @@ func (m *ApexModuleBase) NoApex() bool {
return proptools.Bool(m.ApexProperties.No_apex)
}
const (
availableToPlatform = "//apex_available:platform"
availableToAnyApex = "//apex_available:anyapex"
)
func (m *ApexModuleBase) AvailableFor(what string) bool {
if len(m.ApexProperties.Apex_available) == 0 {
// apex_available defaults to ["//apex_available:platform", "//apex_available:anyapex"],
// which means 'available to everybody'.
return true
}
return InList(what, m.ApexProperties.Apex_available) ||
(what != availableToPlatform && InList(availableToAnyApex, m.ApexProperties.Apex_available))
}
func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
for _, n := range m.ApexProperties.Apex_available {
if n == availableToPlatform || n == availableToAnyApex {
continue
}
if !mctx.OtherModuleExists(n) {
mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n)
}
}
}
func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
if len(m.apexVariations) > 0 {
m.checkApexAvailableProperty(mctx)
sort.Strings(m.apexVariations)
variations := []string{""} // Original variation for platform
variations := []string{}
availableForPlatform := m.AvailableFor(availableToPlatform)
if availableForPlatform {
variations = append(variations, "") // Original variation for platform
}
variations = append(variations, m.apexVariations...)
modules := mctx.CreateVariations(variations...)
for i, m := range modules {
if i == 0 {
if availableForPlatform && i == 0 {
continue
}
m.(ApexModule).setApexName(variations[i])

View File

@ -1215,6 +1215,16 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
}
// check apex_available requirements
for _, fi := range filesInfo {
if am, ok := fi.module.(android.ApexModule); ok {
if !am.AvailableFor(ctx.ModuleName()) {
ctx.ModuleErrorf("requires %q that is not available for the APEX", fi.module.Name())
return
}
}
}
// prepend the name of this APEX to the module names. These names will be the names of
// modules that will be defined if the APEX is flattened.
for i := range filesInfo {

View File

@ -2422,6 +2422,158 @@ func TestApexWithApps(t *testing.T) {
}
func TestApexAvailable(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 {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["libfoo"],
}
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
apex {
name: "otherapex",
key: "otherapex.key",
native_shared_libs: ["libfoo"],
}
apex_key {
name: "otherapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
cc_library {
name: "libfoo",
stl: "none",
system_shared_libs: [],
apex_available: ["otherapex"],
}`)
// libbar is an indirect dep
testApexError(t, "requires \"libbar\" that is not available for the APEX", `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["libfoo"],
}
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
apex {
name: "otherapex",
key: "otherapex.key",
native_shared_libs: ["libfoo"],
}
apex_key {
name: "otherapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
cc_library {
name: "libfoo",
stl: "none",
shared_libs: ["libbar"],
system_shared_libs: [],
apex_available: ["myapex", "otherapex"],
}
cc_library {
name: "libbar",
stl: "none",
system_shared_libs: [],
apex_available: ["otherapex"],
}`)
testApexError(t, "\"otherapex\" is not a valid module name", `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["libfoo"],
}
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
cc_library {
name: "libfoo",
stl: "none",
system_shared_libs: [],
apex_available: ["otherapex"],
}`)
ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["libfoo", "libbar"],
}
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
cc_library {
name: "libfoo",
stl: "none",
system_shared_libs: [],
apex_available: ["myapex"],
}
cc_library {
name: "libbar",
stl: "none",
system_shared_libs: [],
apex_available: ["//apex_available:anyapex"],
}`)
// check that libfoo and libbar are created only for myapex, but not for the platform
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex")
ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared")
ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared_myapex")
ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared")
ctx, _ = testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
}
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
cc_library {
name: "libfoo",
stl: "none",
system_shared_libs: [],
apex_available: ["//apex_available:platform"],
}`)
// check that libfoo is created only for the platform
ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared")
}
func TestMain(m *testing.M) {
run := func() int {
setUp()