Statically link the unwinder into binaries packaged into an unbundled APEX with legacy_android10_support: true.

Bug: 149075752
Test: tapas com.android.conscrypt com.android.tethering arm64
Test: m out/target/product/generic_arm64/{,symbols/}apex/com.android.{tethering,conscrypt}/lib64/libc++.so
Test: Verified that unwinder was dynamically linked to tethering's
Test: libc++ and statically linked to conscrypt's.
Test: lunch flame-userdebug && m
Test: Verified that unwinder was dynamically linked to /system/lib64/libc++.so
Change-Id: I98eed7cb4316962b19b5c12e150c224c25d0e91d
This commit is contained in:
Peter Collingbourne 2020-02-12 17:13:25 -08:00
parent edb3174967
commit dc4f986b2a
5 changed files with 125 additions and 44 deletions

View file

@ -19,6 +19,14 @@ import (
"sync" "sync"
) )
type ApexInfo struct {
// Name of the apex variant that this module is mutated into
ApexName string
// Whether this apex variant needs to target Android 10
LegacyAndroid10Support bool
}
// ApexModule is the interface that a module type is expected to implement if // 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 // 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). // is destined for an apex or not (installed to one of the regular partitions).
@ -38,12 +46,12 @@ type ApexModule interface {
Module Module
apexModuleBase() *ApexModuleBase apexModuleBase() *ApexModuleBase
// Marks that this module should be built for the APEXes of the specified names. // Marks that this module should be built for the specified APEXes.
// Call this before apex.apexMutator is run. // Call this before apex.apexMutator is run.
BuildForApexes(apexNames []string) BuildForApexes(apexes []ApexInfo)
// Returns the name of the APEXes that this modoule will be built for // Returns the APEXes that this module will be built for
ApexVariations() []string ApexVariations() []ApexInfo
// Returns the name of APEX that this module will be built for. Empty string // 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 // is returned when 'IsForPlatform() == true'. Note that a module can be
@ -72,10 +80,6 @@ type ApexModule interface {
// for an APEX marked via BuildForApexes(). // for an APEX marked via BuildForApexes().
CreateApexVariations(mctx BottomUpMutatorContext) []Module CreateApexVariations(mctx BottomUpMutatorContext) []Module
// Sets the name of the apex variant of this module. Called inside
// CreateApexVariations.
setApexName(apexName string)
// Tests if this module is available for the specified APEX or ":platform" // Tests if this module is available for the specified APEX or ":platform"
AvailableFor(what string) bool AvailableFor(what string) bool
@ -94,8 +98,7 @@ type ApexProperties struct {
// Default is ["//apex_available:platform"]. // Default is ["//apex_available:platform"].
Apex_available []string Apex_available []string
// Name of the apex variant that this module is mutated into Info ApexInfo `blueprint:"mutated"`
ApexName string `blueprint:"mutated"`
} }
// Provides default implementation for the ApexModule interface. APEX-aware // Provides default implementation for the ApexModule interface. APEX-aware
@ -106,37 +109,37 @@ type ApexModuleBase struct {
canHaveApexVariants bool canHaveApexVariants bool
apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator
apexVariations []string apexVariations []ApexInfo
} }
func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase { func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
return m return m
} }
func (m *ApexModuleBase) BuildForApexes(apexNames []string) { func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
m.apexVariationsLock.Lock() m.apexVariationsLock.Lock()
defer m.apexVariationsLock.Unlock() defer m.apexVariationsLock.Unlock()
for _, apexName := range apexNames { nextApex:
if !InList(apexName, m.apexVariations) { for _, apex := range apexes {
m.apexVariations = append(m.apexVariations, apexName) for _, v := range m.apexVariations {
if v.ApexName == apex.ApexName {
continue nextApex
}
} }
m.apexVariations = append(m.apexVariations, apex)
} }
} }
func (m *ApexModuleBase) ApexVariations() []string { func (m *ApexModuleBase) ApexVariations() []ApexInfo {
return m.apexVariations return m.apexVariations
} }
func (m *ApexModuleBase) ApexName() string { func (m *ApexModuleBase) ApexName() string {
return m.ApexProperties.ApexName return m.ApexProperties.Info.ApexName
} }
func (m *ApexModuleBase) IsForPlatform() bool { func (m *ApexModuleBase) IsForPlatform() bool {
return m.ApexProperties.ApexName == "" return m.ApexProperties.Info.ApexName == ""
}
func (m *ApexModuleBase) setApexName(apexName string) {
m.ApexProperties.ApexName = apexName
} }
func (m *ApexModuleBase) CanHaveApexVariants() bool { func (m *ApexModuleBase) CanHaveApexVariants() bool {
@ -185,25 +188,35 @@ func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
} }
} }
type byApexName []ApexInfo
func (a byApexName) Len() int { return len(a) }
func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName }
func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module { func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
if len(m.apexVariations) > 0 { if len(m.apexVariations) > 0 {
m.checkApexAvailableProperty(mctx) m.checkApexAvailableProperty(mctx)
sort.Strings(m.apexVariations) sort.Sort(byApexName(m.apexVariations))
variations := []string{} variations := []string{}
variations = append(variations, "") // Original variation for platform variations = append(variations, "") // Original variation for platform
variations = append(variations, m.apexVariations...) for _, apex := range m.apexVariations {
variations = append(variations, apex.ApexName)
}
defaultVariation := "" defaultVariation := ""
mctx.SetDefaultDependencyVariation(&defaultVariation) mctx.SetDefaultDependencyVariation(&defaultVariation)
modules := mctx.CreateVariations(variations...) modules := mctx.CreateVariations(variations...)
for i, m := range modules { for i, mod := range modules {
platformVariation := i == 0 platformVariation := i == 0
if platformVariation && !mctx.Host() && !m.(ApexModule).AvailableFor(AvailableToPlatform) { if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
m.SkipInstall() mod.SkipInstall()
}
if !platformVariation {
mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1]
} }
m.(ApexModule).setApexName(variations[i])
} }
return modules return modules
} }
@ -230,16 +243,16 @@ func apexNamesMap() map[string]map[string]bool {
// depended on by the specified APEXes. Directly depending means that a module // depended on by the specified APEXes. Directly depending means that a module
// is explicitly listed in the build definition of the APEX via properties like // is explicitly listed in the build definition of the APEX via properties like
// native_shared_libs, java_libs, etc. // native_shared_libs, java_libs, etc.
func UpdateApexDependency(apexNames []string, moduleName string, directDep bool) { func UpdateApexDependency(apexes []ApexInfo, moduleName string, directDep bool) {
apexNamesMapMutex.Lock() apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock() defer apexNamesMapMutex.Unlock()
for _, apexName := range apexNames { for _, apex := range apexes {
apexesForModule, ok := apexNamesMap()[moduleName] apexesForModule, ok := apexNamesMap()[moduleName]
if !ok { if !ok {
apexesForModule = make(map[string]bool) apexesForModule = make(map[string]bool)
apexNamesMap()[moduleName] = apexesForModule apexNamesMap()[moduleName] = apexesForModule
} }
apexesForModule[apexName] = apexesForModule[apexName] || directDep apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep
} }
} }

View file

@ -1024,17 +1024,17 @@ func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
// Mark the direct and transitive dependencies of apex bundles so that they // Mark the direct and transitive dependencies of apex bundles so that they
// can be built for the apex bundles. // can be built for the apex bundles.
func apexDepsMutator(mctx android.TopDownMutatorContext) { func apexDepsMutator(mctx android.TopDownMutatorContext) {
var apexBundleNames []string var apexBundles []android.ApexInfo
var directDep bool var directDep bool
if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex { if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
apexBundleNames = []string{mctx.ModuleName()} apexBundles = []android.ApexInfo{{mctx.ModuleName(), proptools.Bool(a.properties.Legacy_android10_support)}}
directDep = true directDep = true
} else if am, ok := mctx.Module().(android.ApexModule); ok { } else if am, ok := mctx.Module().(android.ApexModule); ok {
apexBundleNames = am.ApexVariations() apexBundles = am.ApexVariations()
directDep = false directDep = false
} }
if len(apexBundleNames) == 0 { if len(apexBundles) == 0 {
return return
} }
@ -1042,8 +1042,8 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) {
depName := mctx.OtherModuleName(child) depName := mctx.OtherModuleName(child)
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
(directDep || am.DepIsInSameApex(mctx, child)) { (directDep || am.DepIsInSameApex(mctx, child)) {
android.UpdateApexDependency(apexBundleNames, depName, directDep) android.UpdateApexDependency(apexBundles, depName, directDep)
am.BuildForApexes(apexBundleNames) am.BuildForApexes(apexBundles)
} }
}) })
} }

View file

@ -3437,6 +3437,7 @@ func TestLegacyAndroid10Support(t *testing.T) {
apex { apex {
name: "myapex", name: "myapex",
key: "myapex.key", key: "myapex.key",
native_shared_libs: ["mylib"],
legacy_android10_support: true, legacy_android10_support: true,
} }
@ -3445,12 +3446,54 @@ func TestLegacyAndroid10Support(t *testing.T) {
public_key: "testkey.avbpubkey", public_key: "testkey.avbpubkey",
private_key: "testkey.pem", private_key: "testkey.pem",
} }
`)
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
stl: "libc++",
system_shared_libs: [],
apex_available: [ "myapex" ],
}
cc_library {
name: "libc++",
srcs: ["mylib.cpp"],
stl: "none",
system_shared_libs: [],
apex_available: [ "myapex" ],
}
cc_library_static {
name: "libc++demangle",
srcs: ["mylib.cpp"],
stl: "none",
system_shared_libs: [],
}
cc_library_static {
name: "libunwind_llvm",
srcs: ["mylib.cpp"],
stl: "none",
system_shared_libs: [],
}
`, withUnbundledBuild)
module := ctx.ModuleForTests("myapex", "android_common_myapex_image") module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
args := module.Rule("apexRule").Args args := module.Rule("apexRule").Args
ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String()) ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
ensureNotContains(t, args["opt_flags"], "--no_hashtree") ensureNotContains(t, args["opt_flags"], "--no_hashtree")
// The copies of the libraries in the apex should have one more dependency than
// the ones outside the apex, namely the unwinder. Ideally we should check
// the dependency names directly here but for some reason the names are blank in
// this test.
for _, lib := range []string{"libc++", "mylib"} {
apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits
nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits
if len(apexImplicits) != len(nonApexImplicits)+1 {
t.Errorf("%q missing unwinder dep", lib)
}
}
} }
func TestJavaSDKLibrary(t *testing.T) { func TestJavaSDKLibrary(t *testing.T) {

View file

@ -95,6 +95,8 @@ type Deps struct {
HeaderLibs []string HeaderLibs []string
RuntimeLibs []string RuntimeLibs []string
StaticUnwinderIfLegacy bool
ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string
ObjFiles []string ObjFiles []string
@ -385,6 +387,7 @@ var (
lateSharedDepTag = DependencyTag{Name: "late shared", Library: true, Shared: true} lateSharedDepTag = DependencyTag{Name: "late shared", Library: true, Shared: true}
staticExportDepTag = DependencyTag{Name: "static", Library: true, ReexportFlags: true} staticExportDepTag = DependencyTag{Name: "static", Library: true, ReexportFlags: true}
lateStaticDepTag = DependencyTag{Name: "late static", Library: true} lateStaticDepTag = DependencyTag{Name: "late static", Library: true}
staticUnwinderDepTag = DependencyTag{Name: "static unwinder", Library: true}
wholeStaticDepTag = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true} wholeStaticDepTag = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true}
headerDepTag = DependencyTag{Name: "header", Library: true} headerDepTag = DependencyTag{Name: "header", Library: true}
headerExportDepTag = DependencyTag{Name: "header", Library: true, ReexportFlags: true} headerExportDepTag = DependencyTag{Name: "header", Library: true, ReexportFlags: true}
@ -1796,6 +1799,12 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
}, depTag, lib) }, depTag, lib)
} }
if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
}, staticUnwinderDepTag, staticUnwinder(actx))
}
for _, lib := range deps.LateStaticLibs { for _, lib := range deps.LateStaticLibs {
actx.AddVariationDependencies([]blueprint.Variation{ actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"}, {Mutator: "link", Variation: "static"},
@ -2169,6 +2178,14 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
} }
} }
if depTag == staticUnwinderDepTag {
if c.ApexProperties.Info.LegacyAndroid10Support {
depTag = StaticDepTag
} else {
return
}
}
// Extract ExplicitlyVersioned field from the depTag and reset it inside the struct. // Extract ExplicitlyVersioned field from the depTag and reset it inside the struct.
// Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true // Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true
// won't be matched to SharedDepTag and lateSharedDepTag. // won't be matched to SharedDepTag and lateSharedDepTag.

View file

@ -151,6 +151,14 @@ func needsLibAndroidSupport(ctx BaseModuleContext) bool {
return version < 21 return version < 21
} }
func staticUnwinder(ctx android.BaseModuleContext) string {
if ctx.Arch().ArchType == android.Arm {
return "libunwind_llvm"
} else {
return "libgcc_stripped"
}
}
func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
switch stl.Properties.SelectedStl { switch stl.Properties.SelectedStl {
case "libstdc++": case "libstdc++":
@ -172,16 +180,16 @@ func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
} }
if ctx.toolchain().Bionic() { if ctx.toolchain().Bionic() {
if ctx.staticBinary() { if ctx.staticBinary() {
deps.StaticLibs = append(deps.StaticLibs, "libm", "libc") deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", staticUnwinder(ctx))
if ctx.Arch().ArchType == android.Arm { } else {
deps.StaticLibs = append(deps.StaticLibs, "libunwind_llvm") deps.StaticUnwinderIfLegacy = true
} else {
deps.StaticLibs = append(deps.StaticLibs, "libgcc_stripped")
}
} }
} }
case "": case "":
// None or error. // None or error.
if ctx.toolchain().Bionic() && ctx.Module().Name() == "libc++" {
deps.StaticUnwinderIfLegacy = true
}
case "ndk_system": case "ndk_system":
// TODO: Make a system STL prebuilt for the NDK. // TODO: Make a system STL prebuilt for the NDK.
// The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have // The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have