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

This commit is contained in:
Aleksei Vetrov
2023-09-14 12:05:46 +00:00
committed by Gerrit Code Review
3 changed files with 80 additions and 19 deletions

View File

@@ -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)

View File

@@ -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,
Output: this.abiDumpPath,
Implicits: []android.Path{
symbolList,
headersList,
},
Output: this.abiDumpPath,
Args: map[string]string{
"symbolList": symbolList.String(),
"symbolList": symbolList.String(),
"headersList": headersList.String(),
},
})
}

View File

@@ -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.