Merge changes I350fe490,I31e61862,I09b78e38

am: 1ee00b54d9

Change-Id: I2ea8c8333ecd2d48111131b6236d3005cb6f9075
This commit is contained in:
Jiyong Park 2018-12-15 05:59:22 -08:00 committed by android-build-merger
commit 04f6a9db21
6 changed files with 212 additions and 87 deletions

View file

@ -14,7 +14,11 @@
package android
import "sync"
import (
"sync"
"github.com/google/blueprint"
)
// 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
@ -25,7 +29,7 @@ import "sync"
// or C APIs from other APEXs.
//
// A module implementing this interface will be mutated into multiple
// variations by the apex mutator if it is directly or indirectly included
// variations by apex.apexMutator if it is directly or indirectly included
// in one or more APEXs. Specifically, if a module is included in apex.foo and
// apex.bar then three apex variants are created: platform, apex.foo and
// apex.bar. The platform variant is for the regular partitions
@ -35,31 +39,44 @@ type ApexModule interface {
Module
apexModuleBase() *ApexModuleBase
// Marks that this module should be built for the APEX of the specified name
// Marks that this module should be built for the APEX of the specified name.
// Call this before apex.apexMutator is run.
BuildForApex(apexName string)
// Tests whether this module will be built for the platform or not (= APEXs)
IsForPlatform() bool
// Returns the name of APEX that this module will be built for. Empty string
// is returned when 'IsForPlatform() == true'. Note that a module can be
// included to multiple APEXs, in which case, the module is mutated into
// included in multiple APEXes, in which case, the module is mutated into
// multiple modules each of which for an APEX. This method returns the
// name of the APEX that a variant module is for.
// Call this after apex.apexMutator is run.
ApexName() string
// Tests if this module can have APEX variants. APEX variants are
// Tests whether this module will be built for the platform or not.
// This is a shortcut for ApexName() == ""
IsForPlatform() bool
// Tests if this module could have APEX variants. APEX variants are
// created only for the modules that returns true here. This is useful
// for not creating APEX variants for shared libraries such as NDK stubs.
// for not creating APEX variants for certain types of shared libraries
// such as NDK stubs.
CanHaveApexVariants() bool
// Tests if this module can be installed to APEX as a file. For example,
// this would return true for shared libs while return false for static
// libs.
IsInstallableToApex() bool
// Mutate this module into one or more variants each of which is built
// for an APEX marked via BuildForApex().
CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module
// Sets the name of the apex variant of this module. Called inside
// CreateApexVariations.
setApexName(apexName string)
}
type ApexProperties struct {
// Name of the apex variant that this module is mutated into
ApexName string `blueprint:"mutated"`
}
@ -69,6 +86,7 @@ type ApexModuleBase struct {
ApexProperties ApexProperties
canHaveApexVariants bool
apexVariations []string
}
func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
@ -76,15 +94,21 @@ func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
}
func (m *ApexModuleBase) BuildForApex(apexName string) {
m.ApexProperties.ApexName = apexName
if !InList(apexName, m.apexVariations) {
m.apexVariations = append(m.apexVariations, apexName)
}
}
func (m *ApexModuleBase) ApexName() string {
return m.ApexProperties.ApexName
}
func (m *ApexModuleBase) IsForPlatform() bool {
return m.ApexProperties.ApexName == ""
}
func (m *ApexModuleBase) ApexName() string {
return m.ApexProperties.ApexName
func (m *ApexModuleBase) setApexName(apexName string) {
m.ApexProperties.ApexName = apexName
}
func (m *ApexModuleBase) CanHaveApexVariants() bool {
@ -96,61 +120,73 @@ func (m *ApexModuleBase) IsInstallableToApex() bool {
return false
}
// This structure maps a module name to the set of APEX bundle names that the module
// should be built for. Examples:
func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
if len(m.apexVariations) > 0 {
// The original module is mutated into "platform" variation.
variations := []string{"platform"}
for _, a := range m.apexVariations {
variations = append(variations, a)
}
modules := mctx.CreateVariations(variations...)
for i, m := range modules {
if i == 0 {
continue // platform
}
m.(ApexModule).setApexName(variations[i])
}
return modules
}
return nil
}
var apexData OncePer
var apexNamesMapMutex sync.Mutex
// This structure maintains the global mapping in between modules and APEXes.
// Examples:
//
// ...["foo"]["bar"] == true: module foo is directly depended on by APEX bar
// ...["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar
// ...["foo"]["bar"] doesn't exist: foo is not built for APEX bar
// ...["foo"] doesn't exist: foo is not built for any APEX
func apexBundleNamesMap(config Config) map[string]map[string]bool {
return config.Once("apexBundleNames", func() interface{} {
// apexNamesMap()["foo"]["bar"] == true: module foo is directly depended on by APEX bar
// apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar
// apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar
func apexNamesMap() map[string]map[string]bool {
return apexData.Once("apexNames", func() interface{} {
return make(map[string]map[string]bool)
}).(map[string]map[string]bool)
}
var bundleNamesMapMutex sync.Mutex
// Mark that a module named moduleName should be built for an apex named bundleName
// directDep should be set to true if the module is a direct dependency of the apex.
func BuildModuleForApexBundle(ctx BaseModuleContext, moduleName string, bundleName string, directDep bool) {
bundleNamesMapMutex.Lock()
defer bundleNamesMapMutex.Unlock()
bundleNames, ok := apexBundleNamesMap(ctx.Config())[moduleName]
// Update the map to mark that a module named moduleName is directly or indirectly
// depended on by an APEX named apexName. Directly depending means that a module
// is explicitly listed in the build definition of the APEX via properties like
// native_shared_libs, java_libs, etc.
func UpdateApexDependency(apexName string, moduleName string, directDep bool) {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
apexNames, ok := apexNamesMap()[moduleName]
if !ok {
bundleNames = make(map[string]bool)
apexBundleNamesMap(ctx.Config())[moduleName] = bundleNames
apexNames = make(map[string]bool)
apexNamesMap()[moduleName] = apexNames
}
bundleNames[bundleName] = bundleNames[bundleName] || directDep
apexNames[apexName] = apexNames[apexName] || directDep
}
// Returns the list of apex bundle names that the module named moduleName
// should be built for.
func GetApexBundlesForModule(ctx BaseModuleContext, moduleName string) map[string]bool {
bundleNamesMapMutex.Lock()
defer bundleNamesMapMutex.Unlock()
return apexBundleNamesMap(ctx.Config())[moduleName]
}
// Tests if moduleName is directly depended on by bundleName (i.e. referenced in
// native_shared_libs, etc.)
func DirectlyInApex(config Config, bundleName string, moduleName string) bool {
bundleNamesMapMutex.Lock()
defer bundleNamesMapMutex.Unlock()
if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok {
return bundleNames[bundleName]
// Tests whether a module named moduleName is directly depended on by an APEX
// named apexName.
func DirectlyInApex(apexName string, moduleName string) bool {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
if apexNames, ok := apexNamesMap()[moduleName]; ok {
return apexNames[apexName]
}
return false
}
// Tests if moduleName is directly depended on by any APEX. If this returns true,
// that means the module is part of the platform.
func DirectlyInAnyApex(config Config, moduleName string) bool {
bundleNamesMapMutex.Lock()
defer bundleNamesMapMutex.Unlock()
if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok {
for bn := range bundleNames {
if bundleNames[bn] {
// Tests whether a module named moduleName is directly depended on by any APEX.
func DirectlyInAnyApex(moduleName string) bool {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
if apexNames, ok := apexNamesMap()[moduleName]; ok {
for an := range apexNames {
if apexNames[an] {
return true
}
}
@ -158,6 +194,27 @@ func DirectlyInAnyApex(config Config, moduleName string) bool {
return false
}
// Tests whether a module named module is depended on (including both
// direct and indirect dependencies) by any APEX.
func InAnyApex(moduleName string) bool {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
apexNames, ok := apexNamesMap()[moduleName]
return ok && len(apexNames) > 0
}
func GetApexesForModule(moduleName string) []string {
ret := []string{}
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
if apexNames, ok := apexNamesMap()[moduleName]; ok {
for an := range apexNames {
ret = append(ret, an)
}
}
return ret
}
func InitApexModule(m ApexModule) {
base := m.apexModuleBase()
base.canHaveApexVariants = true

View file

@ -150,11 +150,13 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) {
if _, ok := mctx.Module().(*apexBundle); ok {
apexBundleName := mctx.ModuleName()
mctx.WalkDeps(func(child, parent android.Module) bool {
depName := mctx.OtherModuleName(child)
// If the parent is apexBundle, this child is directly depended.
_, directDep := parent.(*apexBundle)
android.UpdateApexDependency(apexBundleName, depName, directDep)
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() {
moduleName := mctx.OtherModuleName(am) + "-" + am.Target().String()
// If the parent is apexBundle, this child is directly depended.
_, directDep := parent.(*apexBundle)
android.BuildModuleForApexBundle(mctx, moduleName, apexBundleName, directDep)
am.BuildForApex(apexBundleName)
return true
} else {
return false
@ -166,21 +168,7 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) {
// Create apex variations if a module is included in APEX(s).
func apexMutator(mctx android.BottomUpMutatorContext) {
if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
moduleName := mctx.ModuleName() + "-" + am.Target().String()
bundleNames := android.GetApexBundlesForModule(mctx, moduleName)
if len(bundleNames) > 0 {
variations := []string{"platform"}
for bn := range bundleNames {
variations = append(variations, bn)
}
modules := mctx.CreateVariations(variations...)
for i, m := range modules {
if i == 0 {
continue // platform
}
m.(android.ApexModule).BuildForApex(variations[i])
}
}
am.CreateApexVariations(mctx)
} else if _, ok := mctx.Module().(*apexBundle); ok {
// apex bundle itself is mutated so that it and its modules have same
// apex variant.

View file

@ -318,6 +318,73 @@ func TestApexWithStubs(t *testing.T) {
ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so")
}
func TestApexWithExplicitStubsDependency(t *testing.T) {
ctx := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["mylib"],
}
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
shared_libs: ["libfoo#10"],
system_shared_libs: [],
stl: "none",
}
cc_library {
name: "libfoo",
srcs: ["mylib.cpp"],
shared_libs: ["libbar"],
system_shared_libs: [],
stl: "none",
stubs: {
versions: ["10", "20", "30"],
},
}
cc_library {
name: "libbar",
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
}
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
// Ensure that direct non-stubs dep is always included
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so")
// Ensure that dependency of stubs is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with version 10 of libfoo
ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10_myapex/libfoo.so")
// ... and not linking to the non-stub (impl) variant of libfoo
ensureNotContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_myapex/libfoo.so")
libFooStubsLdFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_10_myapex").Rule("ld").Args["libFlags"]
// Ensure that libfoo stubs is not linking to libbar (since it is a stubs)
ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
}
func TestApexWithSystemLibsStubs(t *testing.T) {
ctx := testApex(t, `
apex {

View file

@ -76,6 +76,9 @@ func (c *Module) AndroidMk() android.AndroidMkData {
if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
}
if len(c.Properties.ApexesProvidingSharedLibs) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(c.Properties.ApexesProvidingSharedLibs, " "))
}
fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.getMakeLinkType())
if c.useVndk() {
fmt.Fprintln(w, "LOCAL_USE_VNDK := true")

View file

@ -183,12 +183,13 @@ type BaseProperties struct {
// Minimum sdk version supported when compiling against the ndk
Sdk_version *string
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
HideFromMake bool `blueprint:"mutated"`
PreventInstall bool `blueprint:"mutated"`
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
HideFromMake bool `blueprint:"mutated"`
PreventInstall bool `blueprint:"mutated"`
ApexesProvidingSharedLibs []string `blueprint:"mutated"`
UseVndk bool `blueprint:"mutated"`
@ -1106,7 +1107,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
addSharedLibDependencies := func(depTag dependencyTag, name string, version string) {
var variations []blueprint.Variation
variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
versionVariantAvail := ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery()
versionVariantAvail := !ctx.useVndk() && !c.inRecovery()
if version != "" && versionVariantAvail {
// Version is explicitly specified. i.e. libFoo#30
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
@ -1421,9 +1422,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok {
depIsStubs := dependentLibrary.buildStubs()
depHasStubs := ccDep.HasStubsVariants()
depNameWithTarget := depName + "-" + ccDep.Target().String()
depInSameApex := android.DirectlyInApex(ctx.Config(), c.ApexName(), depNameWithTarget)
depInPlatform := !android.DirectlyInAnyApex(ctx.Config(), depNameWithTarget)
depInSameApex := android.DirectlyInApex(c.ApexName(), depName)
depInPlatform := !android.DirectlyInAnyApex(depName)
var useThisDep bool
if depIsStubs && explicitlyVersioned {
@ -1579,6 +1579,20 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
// Export the shared libs to Make.
switch depTag {
case sharedDepTag, sharedExportDepTag, lateSharedDepTag:
// Dependency to the stubs lib which is already included in an APEX
// is not added to the androidmk dependency
if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok {
if dependentLibrary.buildStubs() && android.InAnyApex(depName) {
// Also add the dependency to the APEX(es) providing the library so that
// m <module> can trigger building the APEXes as well.
for _, an := range android.GetApexesForModule(depName) {
c.Properties.ApexesProvidingSharedLibs = append(
c.Properties.ApexesProvidingSharedLibs, an)
}
break
}
}
// Note: the order of libs in this list is not important because
// they merely serve as Make dependencies and do not affect this lib itself.
c.Properties.AndroidMkSharedLibs = append(

View file

@ -1016,10 +1016,6 @@ func latestStubsVersionFor(config android.Config, name string) string {
// Version mutator splits a module into the mandatory non-stubs variant
// (which is unnamed) and zero or more stubs variants.
func VersionMutator(mctx android.BottomUpMutatorContext) {
if mctx.Os() != android.Android {
return
}
if m, ok := mctx.Module().(*Module); ok && !m.inRecovery() && m.linker != nil {
if library, ok := m.linker.(*libraryDecorator); ok && library.buildShared() &&
len(library.Properties.Stubs.Versions) > 0 {