Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8e86068 authored by Yo Chiang's avatar Yo Chiang Committed by Gerrit Code Review
Browse files

Merge changes Ie540dba5,Ibfc29fe0,I99e97787

* changes:
  Refine ABI check and enable ABI check on APEX exported libs
  Refactor cc/cc.go cc/library.go shouldCreateSourceAbiDump()
  Refactor cc/sabi.go
parents e223512b d737d3f2
Loading
Loading
Loading
Loading
+5 −38
Original line number Diff line number Diff line
@@ -79,7 +79,6 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()

		ctx.BottomUp("coverage", coverageMutator).Parallel()
		ctx.TopDown("vndk_deps", sabiDepsMutator)

		ctx.TopDown("lto_deps", ltoDepsMutator)
		ctx.BottomUp("lto", ltoMutator).Parallel()
@@ -88,6 +87,11 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
	})

	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
		// sabi mutator needs to be run after apex mutator finishes.
		ctx.TopDown("sabi_deps", sabiDepsMutator)
	})

	ctx.RegisterSingletonType("kythe_extract_all", kytheExtractAllFactory)
}

@@ -415,7 +419,6 @@ type ModuleContextIntf interface {
	inRamdisk() bool
	inVendorRamdisk() bool
	inRecovery() bool
	shouldCreateSourceAbiDump() bool
	selectedStl() string
	baseModuleName() string
	getVndkExtendsModuleName() string
@@ -1279,42 +1282,6 @@ func (ctx *moduleContextImpl) mustUseVendorVariant() bool {
	return ctx.mod.MustUseVendorVariant()
}

// Check whether ABI dumps should be created for this module.
func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool {
	if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
		return false
	}

	// Coverage builds have extra symbols.
	if ctx.mod.isCoverageVariant() {
		return false
	}

	if ctx.ctx.Fuchsia() {
		return false
	}

	if sanitize := ctx.mod.sanitize; sanitize != nil {
		if !sanitize.isVariantOnProductionDevice() {
			return false
		}
	}
	if !ctx.ctx.Device() {
		// Host modules do not need ABI dumps.
		return false
	}
	if ctx.isNDKStubLibrary() {
		// Stubs do not need ABI dumps.
		return false
	}
	if lib := ctx.mod.library; lib != nil && lib.buildStubs() {
		// Stubs do not need ABI dumps.
		return false
	}

	return true
}

func (ctx *moduleContextImpl) selectedStl() string {
	if stl := ctx.mod.stl; stl != nil {
		return stl.Properties.SelectedStl
+4 −0
Original line number Diff line number Diff line
@@ -249,6 +249,10 @@ func ClangFilterUnknownLldflags(lldflags []string) []string {
	return result
}

func ClangLibToolingFilterUnknownCflags(libToolingFlags []string) []string {
	return android.RemoveListFromList(libToolingFlags, ClangLibToolingUnknownCflags)
}

func inListSorted(s string, list []string) bool {
	for _, l := range list {
		if s == l {
+11 −54
Original line number Diff line number Diff line
@@ -594,59 +594,12 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d
	return flags
}

// Returns a string that represents the class of the ABI dump.
// Returns an empty string if ABI check is disabled for this library.
func (library *libraryDecorator) classifySourceAbiDump(ctx ModuleContext) string {
	enabled := library.Properties.Header_abi_checker.Enabled
	if enabled != nil && !Bool(enabled) {
		return ""
	}
	// Return NDK if the library is both NDK and LLNDK.
	if ctx.isNdk(ctx.Config()) {
		return "NDK"
	}
	if ctx.isLlndkPublic(ctx.Config()) {
		return "LLNDK"
	}
	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(ctx.Config()) {
		if ctx.isVndkSp() {
			if ctx.IsVndkExt() {
				return "VNDK-SP-ext"
			} else {
				return "VNDK-SP"
			}
		} else {
			if ctx.IsVndkExt() {
				return "VNDK-ext"
			} else {
				return "VNDK-core"
			}
		}
	}
	if Bool(enabled) || library.hasStubsVariants() {
		return "PLATFORM"
	}
	return ""
func (library *libraryDecorator) headerAbiCheckerEnabled() bool {
	return Bool(library.Properties.Header_abi_checker.Enabled)
}

func (library *libraryDecorator) shouldCreateSourceAbiDump(ctx ModuleContext) bool {
	if !ctx.shouldCreateSourceAbiDump() {
		return false
	}
	if !ctx.isForPlatform() {
		if !library.hasStubsVariants() {
			// Skip ABI checks if this library is for APEX but isn't exported.
			return false
		}
		if !Bool(library.Properties.Header_abi_checker.Enabled) {
			// Skip ABI checks if this library is for APEX and did not explicitly enable
			// ABI checks.
			// TODO(b/145608479): ABI checks should be enabled by default. Remove this
			// after evaluating the extra build time.
			return false
		}
	}
	return library.classifySourceAbiDump(ctx) != ""
func (library *libraryDecorator) headerAbiCheckerExplicitlyDisabled() bool {
	return !BoolDefault(library.Properties.Header_abi_checker.Enabled, true)
}

func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -668,7 +621,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
		}
		return Objects{}
	}
	if library.shouldCreateSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
	if library.sabi.shouldCreateSourceAbiDump() {
		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
		var SourceAbiFlags []string
		for _, dir := range exportIncludeDirs.Strings() {
@@ -718,6 +671,10 @@ type libraryInterface interface {
	setStatic()
	setShared()

	// Check whether header_abi_checker is enabled or explicitly disabled.
	headerAbiCheckerEnabled() bool
	headerAbiCheckerExplicitlyDisabled() bool

	// Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
	androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)

@@ -1158,7 +1115,7 @@ func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.
}

func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
	if library.shouldCreateSourceAbiDump(ctx) {
	if library.sabi.shouldCreateSourceAbiDump() {
		var vndkVersion string

		if ctx.useVndk() {
@@ -1183,7 +1140,7 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec
			library.Properties.Header_abi_checker.Exclude_symbol_versions,
			library.Properties.Header_abi_checker.Exclude_symbol_tags)

		addLsdumpPath(library.classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())

		refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
		if refAbiDumpFile != nil {
+155 −44
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
package cc

import (
	"strings"
	"sync"

	"android/soong/android"
@@ -24,11 +23,17 @@ import (

var (
	lsdumpPaths     []string
	sabiLock    sync.Mutex
	lsdumpPathsLock sync.Mutex
)

type SAbiProperties struct {
	CreateSAbiDumps    bool     `blueprint:"mutated"`
	// Whether ABI dump should be created for this module.
	// Set by `sabiDepsMutator` if this module is a shared library that needs ABI check, or a static
	// library that is depended on by an ABI checked library.
	ShouldCreateSourceAbiDump bool `blueprint:"mutated"`

	// Include directories that may contain ABI information exported by a library.
	// These directories are passed to the header-abi-dumper.
	ReexportedIncludes []string `blueprint:"mutated"`
}

@@ -36,66 +41,172 @@ type sabi struct {
	Properties SAbiProperties
}

func (sabimod *sabi) props() []interface{} {
	return []interface{}{&sabimod.Properties}
func (sabi *sabi) props() []interface{} {
	return []interface{}{&sabi.Properties}
}

func (sabimod *sabi) begin(ctx BaseModuleContext) {}
func (sabi *sabi) begin(ctx BaseModuleContext) {}

func (sabimod *sabi) deps(ctx BaseModuleContext, deps Deps) Deps {
func (sabi *sabi) deps(ctx BaseModuleContext, deps Deps) Deps {
	return deps
}

func inListWithPrefixSearch(flag string, filter []string) bool {
	// Assuming the filter is small enough.
	// If the suffix of a filter element is *, try matching prefixes as well.
	for _, f := range filter {
		if (f == flag) || (strings.HasSuffix(f, "*") && strings.HasPrefix(flag, strings.TrimSuffix(f, "*"))) {
			return true
func (sabi *sabi) flags(ctx ModuleContext, flags Flags) Flags {
	// Filter out flags which libTooling don't understand.
	// This is here for legacy reasons and future-proof, in case the version of libTooling and clang
	// diverge.
	flags.Local.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CFlags)
	flags.Global.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CFlags)
	flags.Local.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CppFlags)
	flags.Global.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CppFlags)
	return flags
}

// Returns true if ABI dump should be created for this library, either because library is ABI
// checked or is depended on by an ABI checked library.
// Could be called as a nil receiver.
func (sabi *sabi) shouldCreateSourceAbiDump() bool {
	return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump
}

// Returns a string that represents the class of the ABI dump.
// Returns an empty string if ABI check is disabled for this library.
func classifySourceAbiDump(ctx android.BaseModuleContext) string {
	m := ctx.Module().(*Module)
	if m.library.headerAbiCheckerExplicitlyDisabled() {
		return ""
	}
	// Return NDK if the library is both NDK and LLNDK.
	if m.IsNdk(ctx.Config()) {
		return "NDK"
	}
	if m.isLlndkPublic(ctx.Config()) {
		return "LLNDK"
	}
	if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate(ctx.Config()) {
		if m.isVndkSp() {
			if m.IsVndkExt() {
				return "VNDK-SP-ext"
			} else {
				return "VNDK-SP"
			}
		} else {
			if m.IsVndkExt() {
				return "VNDK-ext"
			} else {
				return "VNDK-core"
			}
		}
	}
	if m.library.headerAbiCheckerEnabled() || m.library.hasStubsVariants() {
		return "PLATFORM"
	}
	return ""
}

// Called from sabiDepsMutator to check whether ABI dumps should be created for this module.
// ctx should be wrapping a native library type module.
func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool {
	if ctx.Fuchsia() {
		return false
	}

func filterOutWithPrefix(list []string, filter []string) (remainder []string) {
	// Go through the filter, matching and optionally doing a prefix search for list elements.
	for _, l := range list {
		if !inListWithPrefixSearch(l, filter) {
			remainder = append(remainder, l)
	// Only generate ABI dump for device modules.
	if !ctx.Device() {
		return false
	}

	m := ctx.Module().(*Module)

	// Only create ABI dump for native library module types.
	if m.library == nil {
		return false
	}
	return

	// Create ABI dump for static libraries only if they are dependencies of ABI checked libraries.
	if m.library.static() {
		return m.sabi.shouldCreateSourceAbiDump()
	}

func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags {
	// Assuming that the cflags which clang LibTooling tools cannot
	// understand have not been converted to ninja variables yet.
	flags.Local.ToolingCFlags = filterOutWithPrefix(flags.Local.CFlags, config.ClangLibToolingUnknownCflags)
	flags.Global.ToolingCFlags = filterOutWithPrefix(flags.Global.CFlags, config.ClangLibToolingUnknownCflags)
	flags.Local.ToolingCppFlags = filterOutWithPrefix(flags.Local.CppFlags, config.ClangLibToolingUnknownCflags)
	flags.Global.ToolingCppFlags = filterOutWithPrefix(flags.Global.CppFlags, config.ClangLibToolingUnknownCflags)
	// Module is shared library type.

	return flags
	// Don't check uninstallable modules.
	if m.IsSkipInstall() {
		return false
	}

	// Don't check ramdisk or recovery variants. Only check core, vendor or product variants.
	if m.InRamdisk() || m.InVendorRamdisk() || m.InRecovery() {
		return false
	}

	// Don't create ABI dump for prebuilts.
	if m.Prebuilt() != nil || m.isSnapshotPrebuilt() {
		return false
	}

	// Coverage builds have extra symbols.
	if m.isCoverageVariant() {
		return false
	}

	// Some sanitizer variants may have different ABI.
	if m.sanitize != nil && !m.sanitize.isVariantOnProductionDevice() {
		return false
	}

	// Don't create ABI dump for stubs.
	if m.isNDKStubLibrary() || m.IsStubs() {
		return false
	}

	isPlatformVariant := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
	if isPlatformVariant {
		// Bionic libraries that are installed to the bootstrap directory are not ABI checked.
		// Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs,
		// are checked.
		if InstallToBootstrap(m.BaseModuleName(), ctx.Config()) {
			return false
		}
	} else {
		// Don't create ABI dump if this library is for APEX but isn't exported.
		if !m.HasStubsVariants() {
			return false
		}
	}
	return classifySourceAbiDump(ctx) != ""
}

// Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps
// of their dependencies would be generated.
func sabiDepsMutator(mctx android.TopDownMutatorContext) {
	if c, ok := mctx.Module().(*Module); ok &&
		((c.IsVndk() && c.UseVndk()) || c.isLlndk(mctx.Config()) ||
			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
		mctx.VisitDirectDeps(func(m android.Module) {
			if tag, ok := mctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok && tag.static() {
				cc, _ := m.(*Module)
				if cc == nil {
	// Escape hatch to not check any ABI dump.
	if mctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
		return
	}
				cc.sabi.Properties.CreateSAbiDumps = true
	// Only create ABI dump for native shared libraries and their static library dependencies.
	if m, ok := mctx.Module().(*Module); ok && m.sabi != nil {
		if shouldCreateSourceAbiDumpForLibrary(mctx) {
			// Mark this module so that .sdump / .lsdump for this library can be generated.
			m.sabi.Properties.ShouldCreateSourceAbiDump = true
			// Mark all of its static library dependencies.
			mctx.VisitDirectDeps(func(child android.Module) {
				depTag := mctx.OtherModuleDependencyTag(child)
				if libDepTag, ok := depTag.(libraryDependencyTag); ok && libDepTag.static() {
					if c, ok := child.(*Module); ok && c.sabi != nil {
						// Mark this module so that .sdump for this static library can be generated.
						c.sabi.Properties.ShouldCreateSourceAbiDump = true
					}
				}
			})
		}
	}
}

// Add an entry to the global list of lsdump. The list is exported to a Make variable by
// `cc.makeVarsProvider`.
func addLsdumpPath(lsdumpPath string) {
	sabiLock.Lock()
	lsdumpPathsLock.Lock()
	defer lsdumpPathsLock.Unlock()
	lsdumpPaths = append(lsdumpPaths, lsdumpPath)
	sabiLock.Unlock()
}