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

Commit 7ab127f7 authored by Aleksei Vetrov's avatar Aleksei Vetrov Committed by Gerrit Code Review
Browse files

Merge "NDK library: collect NDK headers for ABI monitoring" into main

parents 732b37f7 262ed1a3
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ type headerModule struct {

	properties headerProperties

	srcPaths     android.Paths
	installPaths android.Paths
	licensePath  android.Path
}
@@ -125,8 +126,8 @@ func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {

	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))

	srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
	for _, header := range srcFiles {
	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
	for _, header := range m.srcPaths {
		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
			String(m.properties.To))
		installedPath := ctx.InstallFile(installDir, header.Base(), header)
@@ -193,6 +194,7 @@ type versionedHeaderModule struct {

	properties versionedHeaderProperties

	srcPaths     android.Paths
	installPaths android.Paths
	licensePath  android.Path
}
@@ -211,9 +213,9 @@ func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleCo

	fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
	toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
	srcFiles := ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
	m.srcPaths = ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
	var installPaths []android.WritablePath
	for _, header := range srcFiles {
	for _, header := range m.srcPaths {
		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
		installPath := installDir.Join(ctx, header.Base())
		installPaths = append(installPaths, installPath)
@@ -224,11 +226,11 @@ func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleCo
		ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
	}

	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
}

func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
	srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
	srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
	// The versioner depends on a dependencies directory to simplify determining include paths
	// when parsing headers. This directory contains architecture specific directories as well
	// as a common directory, each of which contains symlinks to the actually directories to
@@ -253,7 +255,7 @@ func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir andro
		Rule:            versionBionicHeaders,
		Description:     "versioner preprocess " + srcDir.Rel(),
		Output:          timestampFile,
		Implicits:       append(srcFiles, depsGlob...),
		Implicits:       append(srcPaths, depsGlob...),
		ImplicitOutputs: installPaths,
		Args: map[string]string{
			"depsPath": depsPath.String(),
@@ -317,6 +319,7 @@ type preprocessedHeadersModule struct {

	properties preprocessedHeadersProperties

	srcPaths     android.Paths
	installPaths android.Paths
	licensePath  android.Path
}
@@ -329,9 +332,9 @@ func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.Modu
	preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))

	srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
	installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
	for _, src := range srcFiles {
	for _, src := range m.srcPaths {
		installPath := installDir.Join(ctx, src.Base())
		m.installPaths = append(m.installPaths, installPath)

+16 −5
Original line number Diff line number Diff line
@@ -43,11 +43,17 @@ var (
			CommandDeps: []string{"$ndkStubGenerator"},
		}, "arch", "apiLevel", "apiMap", "flags")

	// $headersList should include paths to public headers. All types
	// that are defined outside of public headers will be excluded from
	// ABI monitoring.
	//
	// STG tool doesn't access content of files listed in $headersList,
	// so there is no need to add them to dependencies.
	stg = pctx.AndroidStaticRule("stg",
		blueprint.RuleParams{
			Command:     "$stg -S :$symbolList --elf $in -o $out",
			Command:     "$stg -S :$symbolList --file-filter :$headersList --elf $in -o $out",
			CommandDeps: []string{"$stg"},
		}, "symbolList")
		}, "symbolList", "headersList")

	stgdiff = pctx.AndroidStaticRule("stgdiff",
		blueprint.RuleParams{
@@ -347,14 +353,19 @@ func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) {
	this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
		this.apiLevel.String(), ctx.Arch().ArchType.String(),
		this.libraryName(ctx), "abi.stg")
	headersList := getNdkABIHeadersFile(ctx)
	ctx.Build(pctx, android.BuildParams{
		Rule:        stg,
		Description: fmt.Sprintf("stg %s", implementationLibrary),
		Input:       implementationLibrary,
		Implicit:    symbolList,
		Implicits: []android.Path{
			symbolList,
			headersList,
		},
		Output: this.abiDumpPath,
		Args: map[string]string{
			"symbolList":  symbolList.String(),
			"headersList": headersList.String(),
		},
	})
}
+52 −5
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ package cc

import (
	"android/soong/android"
	"strings"
)

func init() {
@@ -96,15 +97,56 @@ func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath {
	return android.PathForOutput(ctx, "ndk.timestamp")
}

// The list of all NDK headers as they are located in the repo.
// Used for ABI monitoring to track only structures defined in NDK headers.
func getNdkABIHeadersFile(ctx android.PathContext) android.WritablePath {
	return android.PathForOutput(ctx, "ndk_abi_headers.txt")
}

func NdkSingleton() android.Singleton {
	return &ndkSingleton{}
}

// Collect all NDK exported headers paths into a file that is used to
// detect public types that should be ABI monitored.
//
// Assume that we have the following code in exported header:
//
//	typedef struct Context Context;
//	typedef struct Output {
//	    ...
//	} Output;
//	void DoSomething(Context* ctx, Output* output);
//
// If none of public headers exported to end-users contain definition of
// "struct Context", then "struct Context" layout and members shouldn't be
// monitored. However we use DWARF information from a real library, which
// may have access to the definition of "string Context" from
// implementation headers, and it will leak to ABI.
//
// STG tool doesn't access source and header files, only DWARF information
// from compiled library. And the DWARF contains file name where a type is
// defined. So we need a rule to build a list of paths to public headers,
// so STG can distinguish private types from public and do not monitor
// private types that are not accessible to library users.
func writeNdkAbiSrcFilter(ctx android.BuilderContext,
	headerSrcPaths android.Paths, outputFile android.WritablePath) {
	var filterBuilder strings.Builder
	filterBuilder.WriteString("[decl_file_allowlist]\n")
	for _, headerSrcPath := range headerSrcPaths {
		filterBuilder.WriteString(headerSrcPath.String())
		filterBuilder.WriteString("\n")
	}

	android.WriteFileRule(ctx, outputFile, filterBuilder.String())
}

type ndkSingleton struct{}

func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
	var staticLibInstallPaths android.Paths
	var headerPaths android.Paths
	var headerSrcPaths android.Paths
	var headerInstallPaths android.Paths
	var installPaths android.Paths
	var licensePaths android.Paths
	ctx.VisitAllModules(func(module android.Module) {
@@ -113,19 +155,22 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
		}

		if m, ok := module.(*headerModule); ok {
			headerPaths = append(headerPaths, m.installPaths...)
			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
			installPaths = append(installPaths, m.installPaths...)
			licensePaths = append(licensePaths, m.licensePath)
		}

		if m, ok := module.(*versionedHeaderModule); ok {
			headerPaths = append(headerPaths, m.installPaths...)
			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
			installPaths = append(installPaths, m.installPaths...)
			licensePaths = append(licensePaths, m.licensePath)
		}

		if m, ok := module.(*preprocessedHeadersModule); ok {
			headerPaths = append(headerPaths, m.installPaths...)
			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
			installPaths = append(installPaths, m.installPaths...)
			licensePaths = append(licensePaths, m.licensePath)
		}
@@ -175,9 +220,11 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
	ctx.Build(pctx, android.BuildParams{
		Rule:      android.Touch,
		Output:    getNdkHeadersTimestampFile(ctx),
		Implicits: headerPaths,
		Implicits: headerInstallPaths,
	})

	writeNdkAbiSrcFilter(ctx, headerSrcPaths, getNdkABIHeadersFile(ctx))

	fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx))

	// There's a phony "ndk" rule defined in core/main.mk that depends on this.