Merge "Remove implementation_deps from cc_library headers"
diff --git a/android/buildinfo_prop.go b/android/buildinfo_prop.go
index 6339a71..acebdbb 100644
--- a/android/buildinfo_prop.go
+++ b/android/buildinfo_prop.go
@@ -89,6 +89,7 @@
writeProp("ro.build.version.security_patch", config.PlatformSecurityPatch())
writeProp("ro.build.version.base_os", config.PlatformBaseOS())
writeProp("ro.build.version.min_supported_target_sdk", config.PlatformMinSupportedTargetSdkVersion())
+ writeProp("ro.build.version.known_codenames", config.PlatformVersionKnownCodenames())
if config.Eng() {
writeProp("ro.build.type", "eng")
@@ -109,7 +110,6 @@
writeProp("ro.build.display.id", $BUILD_DISPLAY_ID)
writeProp("ro.build.version.incremental", $BUILD_NUMBER)
writeProp("ro.build.version.preview_sdk_fingerprint", $PLATFORM_PREVIEW_SDK_FINGERPRINT)
- writeProp("ro.build.version.known_codenames", $PLATFORM_VERSION_KNOWN_CODENAMES)
writeProp("ro.build.version.release_or_preview_display", $PLATFORM_DISPLAY_VERSION)
writeProp("ro.build.date", `$DATE`)
writeProp("ro.build.date.utc", `$DATE +%s`)
diff --git a/android/config.go b/android/config.go
index ef71292..cd902cb 100644
--- a/android/config.go
+++ b/android/config.go
@@ -793,6 +793,10 @@
return String(c.productVariables.Platform_version_last_stable)
}
+func (c *config) PlatformVersionKnownCodenames() string {
+ return String(c.productVariables.Platform_version_known_codenames)
+}
+
func (c *config) MinSupportedSdkVersion() ApiLevel {
return uncheckedFinalApiLevel(19)
}
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 48c1383..f2ab0a4 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -105,7 +105,7 @@
if p := base.commonProperties.Effective_package_name; p != nil {
args = append(args,
- `-p "`+proptools.NinjaAndShellEscape(*p)+`"`)
+ `-p `+proptools.NinjaAndShellEscapeIncludingSpaces(*p))
}
args = append(args,
diff --git a/android/mutator.go b/android/mutator.go
index f06ecda..7f93baf 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -93,6 +93,7 @@
TopDown(name string, m TopDownMutator) MutatorHandle
BottomUp(name string, m BottomUpMutator) MutatorHandle
BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle
+ Transition(name string, m TransitionMutator)
}
type RegisterMutatorFunc func(RegisterMutatorsContext)
@@ -421,6 +422,124 @@
return mutator
}
+type IncomingTransitionContext interface {
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // Config returns the configuration for the build.
+ Config() Config
+}
+
+type OutgoingTransitionContext interface {
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // DepTag() Returns the dependency tag through which this dependency is
+ // reached
+ DepTag() blueprint.DependencyTag
+}
+type TransitionMutator interface {
+ // Split returns the set of variations that should be created for a module no
+ // matter who depends on it. Used when Make depends on a particular variation
+ // or when the module knows its variations just based on information given to
+ // it in the Blueprint file. This method should not mutate the module it is
+ // called on.
+ Split(ctx BaseModuleContext) []string
+
+ // OutCalled on a module to determine which variation it wants from its direct
+ // dependencies. The dependency itself can override this decision. This method
+ // should not mutate the module itself.
+ OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
+
+ // Called on a module to determine which variation it should be in based on
+ // the variation modules that depend on it want. This gives the module a final
+ // say about its own variations. This method should not mutate the module
+ // itself.
+ IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
+
+ // Called after a module was split into multiple variations on each variation.
+ // It should not split the module any further but adding new dependencies is
+ // fine. Unlike all the other methods on TransitionMutator, this method is
+ // allowed to mutate the module.
+ Mutate(ctx BottomUpMutatorContext, variation string)
+}
+
+type androidTransitionMutator struct {
+ finalPhase bool
+ bazelConversionMode bool
+ mutator TransitionMutator
+}
+
+func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
+ if m, ok := ctx.Module().(Module); ok {
+ moduleContext := m.base().baseModuleContextFactory(ctx)
+ moduleContext.bazelConversionMode = a.bazelConversionMode
+ return a.mutator.Split(&moduleContext)
+ } else {
+ return []string{""}
+ }
+}
+
+type outgoingTransitionContextImpl struct {
+ bp blueprint.OutgoingTransitionContext
+}
+
+func (c *outgoingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag {
+ return c.bp.DepTag()
+}
+
+func (a *androidTransitionMutator) OutgoingTransition(ctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
+ if _, ok := ctx.Module().(Module); ok {
+ return a.mutator.OutgoingTransition(&outgoingTransitionContextImpl{bp: ctx}, sourceVariation)
+ } else {
+ return ""
+ }
+}
+
+type incomingTransitionContextImpl struct {
+ bp blueprint.IncomingTransitionContext
+}
+
+func (c *incomingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *incomingTransitionContextImpl) Config() Config {
+ return c.bp.Config().(Config)
+}
+
+func (a *androidTransitionMutator) IncomingTransition(ctx blueprint.IncomingTransitionContext, incomingVariation string) string {
+ if _, ok := ctx.Module().(Module); ok {
+ return a.mutator.IncomingTransition(&incomingTransitionContextImpl{bp: ctx}, incomingVariation)
+ } else {
+ return ""
+ }
+}
+
+func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
+ if am, ok := ctx.Module().(Module); ok {
+ a.mutator.Mutate(bottomUpMutatorContextFactory(ctx, am, a.finalPhase, a.bazelConversionMode), variation)
+ }
+}
+
+func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) {
+ atm := &androidTransitionMutator{
+ finalPhase: x.finalPhase,
+ bazelConversionMode: x.bazelConversionMode,
+ mutator: m,
+ }
+ mutator := &mutator{
+ name: name,
+ transitionMutator: atm}
+ x.mutators = append(x.mutators, mutator)
+}
+
func (x *registerMutatorsContext) mutatorName(name string) string {
if x.bazelConversionMode {
return name + "_bp2build"
@@ -456,6 +575,8 @@
handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator)
} else if mutator.topDownMutator != nil {
handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator)
+ } else if mutator.transitionMutator != nil {
+ blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator)
}
if mutator.parallel {
handle.Parallel()
diff --git a/android/register.go b/android/register.go
index c505833..4ff8fff 100644
--- a/android/register.go
+++ b/android/register.go
@@ -96,10 +96,11 @@
var preSingletons sortableComponents
type mutator struct {
- name string
- bottomUpMutator blueprint.BottomUpMutator
- topDownMutator blueprint.TopDownMutator
- parallel bool
+ name string
+ bottomUpMutator blueprint.BottomUpMutator
+ topDownMutator blueprint.TopDownMutator
+ transitionMutator blueprint.TransitionMutator
+ parallel bool
}
var _ sortableComponent = &mutator{}
diff --git a/android/variable.go b/android/variable.go
index 9478c0c..734ed1b 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -200,6 +200,7 @@
Platform_min_supported_target_sdk_version *string `json:",omitempty"`
Platform_base_os *string `json:",omitempty"`
Platform_version_last_stable *string `json:",omitempty"`
+ Platform_version_known_codenames *string `json:",omitempty"`
DeviceName *string `json:",omitempty"`
DeviceProduct *string `json:",omitempty"`
diff --git a/cc/cc.go b/cc/cc.go
index 55c0e48..f04b6f0 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -95,6 +95,10 @@
HeaderLibs []string
RuntimeLibs []string
+ // UnexportedStaticLibs are static libraries that are also passed to -Wl,--exclude-libs= to
+ // prevent automatically exporting symbols.
+ UnexportedStaticLibs []string
+
// Used for data dependencies adjacent to tests
DataLibs []string
DataBins []string
@@ -156,6 +160,7 @@
GeneratedDeps android.Paths
Flags []string
+ LdFlags []string
IncludeDirs android.Paths
SystemIncludeDirs android.Paths
ReexportedDirs android.Paths
@@ -678,6 +683,9 @@
// Whether or not this dependency has to be followed for the apex variants
excludeInApex bool
+
+ // If true, don't automatically export symbols from the static library into a shared library.
+ unexportedSymbols bool
}
// header returns true if the libraryDependencyTag is tagging a header lib dependency.
@@ -982,6 +990,7 @@
return library.shared()
}
}
+
panic(fmt.Errorf("Shared() called on non-library module: %q", c.BaseModuleName()))
}
@@ -1921,6 +1930,8 @@
flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-isystem "+dir.String())
}
+ flags.Local.LdFlags = append(flags.Local.LdFlags, deps.LdFlags...)
+
c.flags = flags
// We need access to all the flags seen by a source file.
if c.sabi != nil {
@@ -2368,6 +2379,13 @@
}, depTag, RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
}
+ for _, lib := range deps.UnexportedStaticLibs {
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency, unexportedSymbols: true}
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "static"},
+ }, depTag, RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+ }
+
for _, lib := range deps.LateSharedLibs {
if inList(lib, sharedLibNames) {
// This is to handle the case that some of the late shared libs (libc, libdl, libm, ...)
@@ -2866,6 +2884,10 @@
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
}
+ if libDepTag.unexportedSymbols {
+ depPaths.LdFlags = append(depPaths.LdFlags,
+ "-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
+ }
}
if libDepTag.static() && !libDepTag.wholeStatic {
diff --git a/cc/linkable.go b/cc/linkable.go
index 04eab39..c58bfdf 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -22,13 +22,6 @@
// than left undefined.
IsSanitizerExplicitlyDisabled(t SanitizerType) bool
- // SanitizeDep returns true if the module is statically linked into another that is sanitized
- // with the given sanitizer.
- SanitizeDep(t SanitizerType) bool
-
- // SetSanitizeDep marks a module as a static dependency of another module to be sanitized.
- SetSanitizeDep(t SanitizerType)
-
// SetSanitizer enables or disables the specified sanitizer type if it's supported, otherwise this should panic.
SetSanitizer(t SanitizerType, b bool)
diff --git a/cc/linker.go b/cc/linker.go
index 4e9404c..78d2d41 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -399,7 +399,7 @@
if ctx.toolchain().Bionic() {
// libclang_rt.builtins has to be last on the command line
if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
- deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
+ deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
if inList("libdl", deps.SharedLibs) {
@@ -422,7 +422,7 @@
}
} else if ctx.toolchain().Musl() {
if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
- deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
+ deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
}
@@ -530,10 +530,6 @@
}
}
- if ctx.toolchain().LibclangRuntimeLibraryArch() != "" {
- flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--exclude-libs="+config.BuiltinsRuntimeLibrary(ctx.toolchain())+".a")
- }
-
CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags)
flags.Local.LdFlags = append(flags.Local.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index da15b59..e0779c6 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -153,9 +153,10 @@
func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) {
switch t {
- case Asan, Hwasan, Fuzzer, scs, tsan, cfi:
- ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t))
- ctx.BottomUp(t.variationName(), sanitizerMutator(t))
+ case cfi, Hwasan, Asan, tsan, Fuzzer, scs:
+ sanitizer := &sanitizerSplitMutator{t}
+ ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
+ ctx.Transition(t.variationName(), sanitizer)
case Memtag_heap, intOverflow:
// do nothing
default:
@@ -276,7 +277,6 @@
type SanitizeProperties struct {
Sanitize SanitizeUserProps `android:"arch_variant"`
SanitizerEnabled bool `blueprint:"mutated"`
- SanitizeDepTypes []SanitizerType `blueprint:"mutated"`
MinimalRuntimeDep bool `blueprint:"mutated"`
BuiltinsDep bool `blueprint:"mutated"`
UbsanRuntimeDep bool `blueprint:"mutated"`
@@ -588,13 +588,6 @@
}
func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
- minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
-
- if sanitize.Properties.MinimalRuntimeDep {
- flags.Local.LdFlags = append(flags.Local.LdFlags,
- "-Wl,--exclude-libs,"+minimalRuntimeLib)
- }
-
if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
return flags
}
@@ -724,7 +717,6 @@
if enableMinimalRuntime(sanitize) {
flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
@@ -906,7 +898,7 @@
// Determines if the current module is a static library going to be captured
// as vendor snapshot. Such modules must create both cfi and non-cfi variants,
// except for ones which explicitly disable cfi.
-func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
+func needsCfiForVendorSnapshot(mctx android.BaseModuleContext) bool {
if snapshot.IsVendorProprietaryModule(mctx) {
return false
}
@@ -934,62 +926,232 @@
!c.IsSanitizerExplicitlyDisabled(cfi)
}
-// Propagate sanitizer requirements down from binaries
-func sanitizerDepsMutator(t SanitizerType) func(android.TopDownMutatorContext) {
- return func(mctx android.TopDownMutatorContext) {
- if c, ok := mctx.Module().(PlatformSanitizeable); ok {
- enabled := c.IsSanitizerEnabled(t)
- if t == cfi && needsCfiForVendorSnapshot(mctx) {
- // We shouldn't change the result of isSanitizerEnabled(cfi) to correctly
- // determine defaultVariation in sanitizerMutator below.
- // Instead, just mark SanitizeDep to forcefully create cfi variant.
+type sanitizerSplitMutator struct {
+ sanitizer SanitizerType
+}
+
+// If an APEX is sanitized or not depends on whether it contains at least one
+// sanitized module. Transition mutators cannot propagate information up the
+// dependency graph this way, so we need an auxiliary mutator to do so.
+func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDownMutatorContext) {
+ if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
+ enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if c, ok := dep.(*Module); ok && c.sanitize.isSanitizerEnabled(s.sanitizer) {
enabled = true
- c.SetSanitizeDep(t)
}
- if enabled {
- isSanitizableDependencyTag := c.SanitizableDepTagChecker()
- mctx.WalkDeps(func(child, parent android.Module) bool {
- if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
- return false
- }
- if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
- !d.SanitizeNever() &&
- !d.IsSanitizerExplicitlyDisabled(t) {
- if t == cfi || t == Hwasan || t == scs || t == Asan {
- if d.StaticallyLinked() && d.SanitizerSupported(t) {
- // Rust does not support some of these sanitizers, so we need to check if it's
- // supported before setting this true.
- d.SetSanitizeDep(t)
- }
- } else {
- d.SetSanitizeDep(t)
- }
- }
- return true
- })
+ })
+
+ if enabled {
+ sanitizeable.EnableSanitizer(s.sanitizer.name())
+ }
+ }
+}
+
+func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string {
+ if c, ok := ctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+ if s.sanitizer == cfi && needsCfiForVendorSnapshot(ctx) {
+ return []string{"", s.sanitizer.variationName()}
+ }
+
+ // If the given sanitizer is not requested in the .bp file for a module, it
+ // won't automatically build the sanitized variation.
+ if !c.IsSanitizerEnabled(s.sanitizer) {
+ return []string{""}
+ }
+
+ if c.Binary() {
+ // If a sanitizer is enabled for a binary, we do not build the version
+ // without the sanitizer
+ return []string{s.sanitizer.variationName()}
+ } else if c.StaticallyLinked() || c.Header() {
+ // For static libraries, we build both versions. Some Make modules
+ // apparently depend on this behavior.
+ return []string{"", s.sanitizer.variationName()}
+ } else {
+ // We only build the requested variation of dynamic libraries
+ return []string{s.sanitizer.variationName()}
+ }
+ }
+
+ if _, ok := ctx.Module().(JniSanitizeable); ok {
+ // TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
+ // that is short-circuited for now
+ return []string{""}
+ }
+
+ // If an APEX has a sanitized dependency, we build the APEX in the sanitized
+ // variation. This is useful because such APEXes require extra dependencies.
+ if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
+ enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
+ if enabled {
+ return []string{s.sanitizer.variationName()}
+ } else {
+ return []string{""}
+ }
+ }
+
+ if c, ok := ctx.Module().(*Module); ok {
+ //TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
+
+ // Check if it's a snapshot module supporting sanitizer
+ if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
+ return []string{"", s.sanitizer.variationName()}
+ } else {
+ return []string{""}
+ }
+ }
+
+ return []string{""}
+}
+
+func (s *sanitizerSplitMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ if c, ok := ctx.Module().(PlatformSanitizeable); ok {
+ if !c.SanitizableDepTagChecker()(ctx.DepTag()) {
+ // If the dependency is through a non-sanitizable tag, use the
+ // non-sanitized variation
+ return ""
+ }
+
+ return sourceVariation
+ } else if _, ok := ctx.Module().(JniSanitizeable); ok {
+ // TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
+ // that is short-circuited for now
+ return ""
+ } else {
+ // Otherwise, do not rock the boat.
+ return sourceVariation
+ }
+}
+
+func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ if d, ok := ctx.Module().(PlatformSanitizeable); ok {
+ if dm, ok := ctx.Module().(*Module); ok {
+ if ss, ok := dm.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
+ return incomingVariation
}
- } else if jniSanitizeable, ok := mctx.Module().(JniSanitizeable); ok {
- // If it's a Java module with native dependencies through jni,
- // set the sanitizer for them
- if jniSanitizeable.IsSanitizerEnabledForJni(mctx, t.name()) {
- mctx.VisitDirectDeps(func(child android.Module) {
- if c, ok := child.(PlatformSanitizeable); ok &&
- mctx.OtherModuleDependencyTag(child) == JniFuzzLibTag &&
- c.SanitizePropDefined() &&
- !c.SanitizeNever() &&
- !c.IsSanitizerExplicitlyDisabled(t) {
- c.SetSanitizeDep(t)
- }
- })
+ }
+
+ if !d.SanitizePropDefined() ||
+ d.SanitizeNever() ||
+ d.IsSanitizerExplicitlyDisabled(s.sanitizer) ||
+ !d.SanitizerSupported(s.sanitizer) {
+ // If a module opts out of a sanitizer, use its non-sanitized variation
+ return ""
+ }
+
+ // Binaries are always built in the variation they requested.
+ if d.Binary() {
+ if d.IsSanitizerEnabled(s.sanitizer) {
+ return s.sanitizer.variationName()
+ } else {
+ return ""
}
- } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
- // If an APEX module includes a lib which is enabled for a sanitizer T, then
- // the APEX module is also enabled for the same sanitizer type.
- mctx.VisitDirectDeps(func(child android.Module) {
- if c, ok := child.(*Module); ok && c.sanitize.isSanitizerEnabled(t) {
- sanitizeable.EnableSanitizer(t.name())
+ }
+
+ // If a shared library requests to be sanitized, it will be built for that
+ // sanitizer. Otherwise, some sanitizers propagate through shared library
+ // dependency edges, some do not.
+ if !d.StaticallyLinked() && !d.Header() {
+ if d.IsSanitizerEnabled(s.sanitizer) {
+ return s.sanitizer.variationName()
+ }
+
+ if s.sanitizer == cfi || s.sanitizer == Hwasan || s.sanitizer == scs || s.sanitizer == Asan {
+ return ""
+ }
+ }
+
+ // Static and header libraries inherit whether they are sanitized from the
+ // module they are linked into
+ return incomingVariation
+ } else if d, ok := ctx.Module().(Sanitizeable); ok {
+ // If an APEX contains a sanitized module, it will be built in the variation
+ // corresponding to that sanitizer.
+ enabled := d.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
+ if enabled {
+ return s.sanitizer.variationName()
+ }
+
+ return incomingVariation
+ }
+
+ return ""
+}
+
+func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, variationName string) {
+ sanitizerVariation := variationName == s.sanitizer.variationName()
+
+ if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+ sanitizerEnabled := c.IsSanitizerEnabled(s.sanitizer)
+
+ oneMakeVariation := false
+ if c.StaticallyLinked() || c.Header() {
+ if s.sanitizer != cfi && s.sanitizer != scs && s.sanitizer != Hwasan {
+ // These sanitizers export only one variation to Make. For the rest,
+ // Make targets can depend on both the sanitized and non-sanitized
+ // versions.
+ oneMakeVariation = true
+ }
+ } else if !c.Binary() {
+ // Shared library. These are the sanitizers that do propagate through shared
+ // library dependencies and therefore can cause multiple variations of a
+ // shared library to be built.
+ if s.sanitizer != cfi && s.sanitizer != Hwasan && s.sanitizer != scs && s.sanitizer != Asan {
+ oneMakeVariation = true
+ }
+ }
+
+ if oneMakeVariation {
+ if sanitizerEnabled != sanitizerVariation {
+ c.SetPreventInstall()
+ c.SetHideFromMake()
+ }
+ }
+
+ if sanitizerVariation {
+ c.SetSanitizer(s.sanitizer, true)
+
+ // CFI is incompatible with ASAN so disable it in ASAN variations
+ if s.sanitizer.incompatibleWithCfi() {
+ cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
+ if mctx.Device() && cfiSupported {
+ c.SetSanitizer(cfi, false)
}
- })
+ }
+
+ // locate the asan libraries under /data/asan
+ if !c.Binary() && !c.StaticallyLinked() && !c.Header() && mctx.Device() && s.sanitizer == Asan && sanitizerEnabled {
+ c.SetInSanitizerDir()
+ }
+
+ if c.StaticallyLinked() && c.ExportedToMake() {
+ if s.sanitizer == Hwasan {
+ hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
+ } else if s.sanitizer == cfi {
+ cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
+ }
+ }
+ } else if c.IsSanitizerEnabled(s.sanitizer) {
+ // Disable the sanitizer for the non-sanitized variation
+ c.SetSanitizer(s.sanitizer, false)
+ }
+ } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
+ // If an APEX has sanitized dependencies, it gets a few more dependencies
+ if sanitizerVariation {
+ sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name())
+ }
+ } else if c, ok := mctx.Module().(*Module); ok {
+ if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
+ c.linker.(snapshotSanitizer).setSanitizerVariation(s.sanitizer, sanitizerVariation)
+
+ // Export the static lib name to make
+ if c.static() && c.ExportedToMake() {
+ if s.sanitizer == cfi {
+ // use BaseModuleName which is the name for Make.
+ cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
+ }
+ }
}
}
}
@@ -1217,7 +1379,7 @@
}
// static executable gets static runtime libs
- depTag := libraryDependencyTag{Kind: staticLibraryDependency}
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, unexportedSymbols: true}
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
if c.Device() {
@@ -1315,16 +1477,6 @@
return c.sanitize.isSanitizerEnabled(t)
}
-func (c *Module) SanitizeDep(t SanitizerType) bool {
- for _, e := range c.sanitize.Properties.SanitizeDepTypes {
- if t == e {
- return true
- }
- }
-
- return false
-}
-
func (c *Module) StaticallyLinked() bool {
return c.static()
}
@@ -1341,123 +1493,8 @@
}
}
-func (c *Module) SetSanitizeDep(t SanitizerType) {
- if !c.SanitizeDep(t) {
- c.sanitize.Properties.SanitizeDepTypes = append(c.sanitize.Properties.SanitizeDepTypes, t)
- }
-}
-
var _ PlatformSanitizeable = (*Module)(nil)
-// Create sanitized variants for modules that need them
-func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
- return func(mctx android.BottomUpMutatorContext) {
- if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
-
- // Make sure we're not setting CFI to any value if it's not supported.
- cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
-
- if c.Binary() && c.IsSanitizerEnabled(t) {
- modules := mctx.CreateVariations(t.variationName())
- modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
- } else if c.IsSanitizerEnabled(t) || c.SanitizeDep(t) {
- isSanitizerEnabled := c.IsSanitizerEnabled(t)
- if c.StaticallyLinked() || c.Header() || t == Fuzzer {
- // Static and header libs are split into non-sanitized and sanitized variants.
- // Shared libs are not split. However, for asan and fuzzer, we split even for shared
- // libs because a library sanitized for asan/fuzzer can't be linked from a library
- // that isn't sanitized for asan/fuzzer.
- //
- // Note for defaultVariation: since we don't split for shared libs but for static/header
- // libs, it is possible for the sanitized variant of a static/header lib to depend
- // on non-sanitized variant of a shared lib. Such unfulfilled variation causes an
- // error when the module is split. defaultVariation is the name of the variation that
- // will be used when such a dangling dependency occurs during the split of the current
- // module. By setting it to the name of the sanitized variation, the dangling dependency
- // is redirected to the sanitized variant of the dependent module.
- defaultVariation := t.variationName()
- // Not all PlatformSanitizeable modules support the CFI sanitizer
- mctx.SetDefaultDependencyVariation(&defaultVariation)
-
- modules := mctx.CreateVariations("", t.variationName())
- modules[0].(PlatformSanitizeable).SetSanitizer(t, false)
- modules[1].(PlatformSanitizeable).SetSanitizer(t, true)
-
- if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
- // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
- // are incompatible with cfi
- modules[1].(PlatformSanitizeable).SetSanitizer(cfi, false)
- }
-
- // For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
- // to Make, because the sanitized version has a different suffix in name.
- // For other types of sanitizers, suppress the variation that is disabled.
- if t != cfi && t != scs && t != Hwasan {
- if isSanitizerEnabled {
- modules[0].(PlatformSanitizeable).SetPreventInstall()
- modules[0].(PlatformSanitizeable).SetHideFromMake()
- } else {
- modules[1].(PlatformSanitizeable).SetPreventInstall()
- modules[1].(PlatformSanitizeable).SetHideFromMake()
- }
- }
-
- // Export the static lib name to make
- if c.StaticallyLinked() && c.ExportedToMake() {
- if t == cfi {
- cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
- } else if t == Hwasan {
- hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
- }
- }
- } else {
- // Shared libs are not split. Only the sanitized variant is created.
- modules := mctx.CreateVariations(t.variationName())
- modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
-
- // locate the asan libraries under /data/asan
- if mctx.Device() && t == Asan && isSanitizerEnabled {
- modules[0].(PlatformSanitizeable).SetInSanitizerDir()
- }
-
- if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
- // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
- // are incompatible with cfi
- modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
- }
- }
- }
- } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx.Config(), t.name()) {
- // APEX fuzz modules fall here
- sanitizeable.AddSanitizerDependencies(mctx, t.name())
- mctx.CreateVariations(t.variationName())
- } else if _, ok := mctx.Module().(JniSanitizeable); ok {
- // Java fuzz modules fall here
- mctx.CreateVariations(t.variationName())
- } else if c, ok := mctx.Module().(*Module); ok {
- //TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
-
- // Check if it's a snapshot module supporting sanitizer
- if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) {
- // Set default variation as above.
- defaultVariation := t.variationName()
- mctx.SetDefaultDependencyVariation(&defaultVariation)
- modules := mctx.CreateVariations("", t.variationName())
- modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false)
- modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true)
-
- // Export the static lib name to make
- if c.static() && c.ExportedToMake() {
- if t == cfi {
- // use BaseModuleName which is the name for Make.
- cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
- }
- }
- }
- }
- }
-}
-
type sanitizerStaticLibsMap struct {
// libsMap contains one list of modules per each image and each arch.
// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index c1ca034..5d7e7d8 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "runtime"
"strings"
"testing"
@@ -201,6 +202,125 @@
t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
}
+func TestUbsan(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("requires linux")
+ }
+
+ bp := `
+ cc_binary {
+ name: "bin_with_ubsan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ ],
+ static_libs: [
+ "libstatic",
+ "libnoubsan",
+ ],
+ sanitize: {
+ undefined: true,
+ }
+ }
+
+ cc_binary {
+ name: "bin_depends_ubsan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ ],
+ static_libs: [
+ "libstatic",
+ "libubsan",
+ "libnoubsan",
+ ],
+ }
+
+ cc_binary {
+ name: "bin_no_ubsan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ ],
+ static_libs: [
+ "libstatic",
+ "libnoubsan",
+ ],
+ }
+
+ cc_library_shared {
+ name: "libshared",
+ host_supported: true,
+ shared_libs: ["libtransitive"],
+ }
+
+ cc_library_shared {
+ name: "libtransitive",
+ host_supported: true,
+ }
+
+ cc_library_static {
+ name: "libubsan",
+ host_supported: true,
+ sanitize: {
+ undefined: true,
+ }
+ }
+
+ cc_library_static {
+ name: "libstatic",
+ host_supported: true,
+ }
+
+ cc_library_static {
+ name: "libnoubsan",
+ host_supported: true,
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ check := func(t *testing.T, result *android.TestResult, variant string) {
+ staticVariant := variant + "_static"
+
+ minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant)
+
+ // The binaries, one with ubsan and one without
+ binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant)
+ binDependsUbsan := result.ModuleForTests("bin_depends_ubsan", variant)
+ binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant)
+
+ android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs",
+ strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "),
+ minimalRuntime.OutputFiles(t, "")[0].String())
+
+ android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_depends_ubsan static libs",
+ strings.Split(binDependsUbsan.Rule("ld").Args["libFlags"], " "),
+ minimalRuntime.OutputFiles(t, "")[0].String())
+
+ android.AssertStringListDoesNotContain(t, "unexpected libclang_rt.ubsan_minimal in bin_no_ubsan static libs",
+ strings.Split(binNoUbsan.Rule("ld").Args["libFlags"], " "),
+ minimalRuntime.OutputFiles(t, "")[0].String())
+
+ android.AssertStringListContains(t, "missing -Wl,--exclude-libs for minimal runtime in bin_with_ubsan",
+ strings.Split(binWithUbsan.Rule("ld").Args["ldFlags"], " "),
+ "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+
+ android.AssertStringListContains(t, "missing -Wl,--exclude-libs for minimal runtime in bin_depends_ubsan static libs",
+ strings.Split(binDependsUbsan.Rule("ld").Args["ldFlags"], " "),
+ "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+
+ android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_no_ubsan static libs",
+ strings.Split(binNoUbsan.Rule("ld").Args["ldFlags"], " "),
+ "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+ }
+
+ t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
+ t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+}
+
type MemtagNoteType int
const (
diff --git a/cc/testing.go b/cc/testing.go
index ecdae8b..077fcda 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -73,7 +73,6 @@
nocrt: true,
system_shared_libs: [],
stl: "none",
- srcs: [""],
check_elf_files: false,
sanitize: {
never: true,
@@ -84,6 +83,7 @@
name: "libcompiler_rt-extras",
defaults: ["toolchain_libs_defaults"],
vendor_ramdisk_available: true,
+ srcs: [""],
}
cc_prebuilt_library_static {
@@ -93,11 +93,13 @@
vendor_available: true,
vendor_ramdisk_available: true,
native_bridge_supported: true,
+ srcs: [""],
}
cc_prebuilt_library_shared {
name: "libclang_rt.hwasan",
defaults: ["toolchain_libs_defaults"],
+ srcs: [""],
}
cc_prebuilt_library_static {
@@ -108,6 +110,7 @@
],
vendor_ramdisk_available: true,
native_bridge_supported: true,
+ srcs: [""],
}
cc_prebuilt_library_static {
@@ -116,17 +119,34 @@
"linux_bionic_supported",
"toolchain_libs_defaults",
],
+ srcs: [""],
}
// Needed for sanitizer
cc_prebuilt_library_shared {
name: "libclang_rt.ubsan_standalone",
defaults: ["toolchain_libs_defaults"],
+ srcs: [""],
}
cc_prebuilt_library_static {
name: "libclang_rt.ubsan_minimal",
defaults: ["toolchain_libs_defaults"],
+ host_supported: true,
+ target: {
+ android_arm64: {
+ srcs: ["libclang_rt.ubsan_minimal.android_arm64.a"],
+ },
+ android_arm: {
+ srcs: ["libclang_rt.ubsan_minimal.android_arm.a"],
+ },
+ linux_glibc_x86_64: {
+ srcs: ["libclang_rt.ubsan_minimal.x86_64.a"],
+ },
+ linux_glibc_x86: {
+ srcs: ["libclang_rt.ubsan_minimal.x86.a"],
+ },
+ },
}
cc_library {
@@ -546,6 +566,11 @@
"defaults/cc/common/crtend_so.c": nil,
"defaults/cc/common/crtend.c": nil,
"defaults/cc/common/crtbrand.c": nil,
+
+ "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
+ "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil,
+ "defaults/cc/common/libclang_rt.ubsan_minimal.x86_64.a": nil,
+ "defaults/cc/common/libclang_rt.ubsan_minimal.x86.a": nil,
}.AddToFixture(),
// Place the default cc test modules that are common to all platforms in a location that will not
diff --git a/rust/sanitize.go b/rust/sanitize.go
index aadc00f..536fcbd 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -49,8 +49,7 @@
Memtag_heap *bool `android:"arch_variant"`
}
}
- SanitizerEnabled bool `blueprint:"mutated"`
- SanitizeDepTypes []cc.SanitizerType `blueprint:"mutated"`
+ SanitizerEnabled bool `blueprint:"mutated"`
// Used when we need to place libraries in their own directory, such as ASAN.
InSanitizerDir bool `blueprint:"mutated"`
@@ -444,28 +443,12 @@
return mod.sanitize.isSanitizerExplicitlyDisabled(t)
}
-func (mod *Module) SanitizeDep(t cc.SanitizerType) bool {
- for _, e := range mod.sanitize.Properties.SanitizeDepTypes {
- if t == e {
- return true
- }
- }
-
- return false
-}
-
func (mod *Module) SetSanitizer(t cc.SanitizerType, b bool) {
if !Bool(mod.sanitize.Properties.Sanitize.Never) {
mod.sanitize.SetSanitizer(t, b)
}
}
-func (c *Module) SetSanitizeDep(t cc.SanitizerType) {
- if !c.SanitizeDep(t) {
- c.sanitize.Properties.SanitizeDepTypes = append(c.sanitize.Properties.SanitizeDepTypes, t)
- }
-}
-
func (mod *Module) StaticallyLinked() bool {
if lib, ok := mod.compiler.(libraryInterface); ok {
return lib.rlib() || lib.static()
diff --git a/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
new file mode 100755
index 0000000..4b2f795
--- /dev/null
+++ b/tests/apex_comparison_tests.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+set -euo pipefail
+
+# Soong/Bazel integration test for building unbundled apexes in the real source tree.
+#
+# These tests build artifacts from head and compares their contents.
+
+if [ ! -e "build/make/core/Makefile" ]; then
+ echo "$0 must be run from the top of the Android source tree."
+ exit 1
+fi
+
+############
+# Test Setup
+############
+
+OUTPUT_DIR="$(mktemp -d)"
+SOONG_OUTPUT_DIR="$OUTPUT_DIR/soong"
+BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel"
+
+function cleanup {
+ # call bazel clean because some bazel outputs don't have w bits.
+ call_bazel clean
+ rm -rf "${OUTPUT_DIR}"
+}
+trap cleanup EXIT
+
+###########
+# Run Soong
+###########
+export UNBUNDLED_BUILD_SDKS_FROM_SOURCE=true # don't rely on prebuilts
+export TARGET_BUILD_APPS="com.android.adbd com.android.tzdata build.bazel.examples.apex.minimal"
+packages/modules/common/build/build_unbundled_mainline_module.sh \
+ --product module_arm \
+ --dist_dir "$SOONG_OUTPUT_DIR"
+
+######################
+# Run bp2build / Bazel
+######################
+build/soong/soong_ui.bash --make-mode BP2BUILD_VERBOSE=1 --skip-soong-tests bp2build
+
+function call_bazel() {
+ tools/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
+}
+BAZEL_OUT="$(call_bazel info output_path)"
+
+call_bazel build --config=bp2build --config=ci --config=android_arm \
+ //packages/modules/adb/apex:com.android.adbd \
+ //system/timezone/apex:com.android.tzdata \
+ //build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal.apex
+
+# Build debugfs separately, as it's not a dep of apexer, but needs to be an explicit arg.
+call_bazel build --config=bp2build --config=linux_x86_64 //external/e2fsprogs/debugfs
+DEBUGFS_PATH="$BAZEL_OUT/linux_x86_64-fastbuild/bin/external/e2fsprogs/debugfs/debugfs"
+
+function run_deapexer() {
+ call_bazel run --config=bp2build --config=linux_x86_64 //system/apex/tools:deapexer \
+ -- \
+ --debugfs_path="$DEBUGFS_PATH" \
+ $@
+}
+
+#######
+# Tests
+#######
+
+function compare_deapexer_list() {
+ local APEX_DIR=$1; shift
+ local APEX=$1; shift
+
+ # Compare the outputs of `deapexer list`, which lists the contents of the apex filesystem image.
+ local SOONG_APEX="$SOONG_OUTPUT_DIR/$APEX"
+ local BAZEL_APEX="$BAZEL_OUT/android_arm-fastbuild/bin/$APEX_DIR/$APEX"
+
+ local SOONG_LIST="$OUTPUT_DIR/soong.list"
+ local BAZEL_LIST="$OUTPUT_DIR/bazel.list"
+
+ run_deapexer list "$SOONG_APEX" > "$SOONG_LIST"
+ run_deapexer list "$BAZEL_APEX" > "$BAZEL_LIST"
+
+ if cmp -s "$SOONG_LIST" "$BAZEL_LIST"
+ then
+ echo "ok: $APEX"
+ else
+ echo "contents of $APEX are different between Soong and Bazel:"
+ echo
+ echo expected
+ echo
+ cat "$SOONG_LIST"
+ echo
+ echo got
+ echo
+ cat "$BAZEL_LIST"
+ exit 1
+ fi
+}
+
+compare_deapexer_list packages/modules/adb/apex com.android.adbd.apex
+compare_deapexer_list system/timezone/apex com.android.tzdata.apex
+compare_deapexer_list build/bazel/examples/apex/minimal build.bazel.examples.apex.minimal.apex
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 76a918b..1e07727 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -9,3 +9,7 @@
"$TOP/build/soong/tests/bp2build_bazel_test.sh"
"$TOP/build/soong/tests/soong_test.sh"
"$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug
+
+# The following tests build against the full source tree and don't rely on the
+# mock client.
+"$TOP/build/soong/tests/apex_comparison_tests.sh"