Merge changes I154a6f3a,I79f0c20a,I605ae9af,I647c7305,I95e96e3e, ...

* changes:
  Move fuzzer's CollectAllSharedDependencies into GenerateAndroidBuildActions
  Support AllowMissingDependencies in prebuilt_apex modules
  Support AllowMissingDependencies for apex dependencies
  Add AllowMissingDependencies support for prebuilt_etc module with no src property
  Make OutputFileForModule work for AllowMissingDependencies
  Fix panics when target arch is riscv64
This commit is contained in:
Colin Cross
2022-10-05 21:25:17 +00:00
committed by Gerrit Code Review
14 changed files with 267 additions and 106 deletions

View File

@@ -15,10 +15,32 @@
package android
import (
"io/ioutil"
"os"
"testing"
)
func TestMain(m *testing.M) {
os.Exit(m.Run())
var buildDir string
func setUp() {
var err error
buildDir, err = ioutil.TempDir("", "android_test")
if err != nil {
panic(err)
}
}
func tearDown() {
os.RemoveAll(buildDir)
}
func TestMain(m *testing.M) {
run := func() int {
setUp()
defer tearDown()
return m.Run()
}
os.Exit(run())
}

View File

@@ -3546,10 +3546,29 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P
reportPathError(ctx, err)
return nil
}
if len(paths) == 0 {
type addMissingDependenciesIntf interface {
AddMissingDependencies([]string)
OtherModuleName(blueprint.Module) string
}
if mctx, ok := ctx.(addMissingDependenciesIntf); ok && ctx.Config().AllowMissingDependencies() {
mctx.AddMissingDependencies([]string{mctx.OtherModuleName(module)})
} else {
ReportPathErrorf(ctx, "failed to get output files from module %q", pathContextName(ctx, module))
}
// Return a fake output file to avoid nil dereferences of Path objects later.
// This should never get used for an actual build as the error or missing
// dependency has already been reported.
p, err := pathForSource(ctx, filepath.Join("missing_output_file", pathContextName(ctx, module)))
if err != nil {
reportPathError(ctx, err)
return nil
}
return p
}
if len(paths) > 1 {
ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one",
pathContextName(ctx, module))
return nil
}
return paths[0]
}
@@ -3561,18 +3580,12 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string)
return nil, fmt.Errorf("failed to get output file from module %q: %s",
pathContextName(ctx, module), err.Error())
}
if len(paths) == 0 {
return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module))
}
return paths, nil
} else if sourceFileProducer, ok := module.(SourceFileProducer); ok {
if tag != "" {
return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag)
}
paths := sourceFileProducer.Srcs()
if len(paths) == 0 {
return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module))
}
return paths, nil
} else {
return nil, fmt.Errorf("module %q is not an OutputFileProducer", pathContextName(ctx, module))

View File

@@ -15,6 +15,7 @@
package android
import (
"github.com/google/blueprint"
"path/filepath"
"runtime"
"testing"
@@ -978,3 +979,88 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) {
})
}
}
type fakeBlueprintModule struct{}
func (fakeBlueprintModule) Name() string { return "foo" }
func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {}
type sourceProducerTestModule struct {
fakeBlueprintModule
source Path
}
func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} }
type outputFileProducerTestModule struct {
fakeBlueprintModule
output map[string]Path
error map[string]error
}
func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) {
return PathsIfNonNil(o.output[tag]), o.error[tag]
}
type pathContextAddMissingDependenciesWrapper struct {
PathContext
missingDeps []string
}
func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) {
p.missingDeps = append(p.missingDeps, deps...)
}
func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string {
return module.Name()
}
func TestOutputFileForModule(t *testing.T) {
testcases := []struct {
name string
module blueprint.Module
tag string
env map[string]string
config func(*config)
expected string
missingDeps []string
}{
{
name: "SourceFileProducer",
module: &sourceProducerTestModule{source: PathForTesting("foo.txt")},
expected: "foo.txt",
},
{
name: "OutputFileProducer",
module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}},
expected: "foo.txt",
},
{
name: "OutputFileProducer_tag",
module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}},
tag: "foo",
expected: "foo.txt",
},
{
name: "OutputFileProducer_AllowMissingDependencies",
config: func(config *config) {
config.TestProductVariables.Allow_missing_dependencies = boolPtr(true)
},
module: &outputFileProducerTestModule{},
missingDeps: []string{"foo"},
expected: "missing_output_file/foo",
},
}
for _, tt := range testcases {
config := TestConfig(buildDir, tt.env, "", nil)
if tt.config != nil {
tt.config(config.config)
}
ctx := &pathContextAddMissingDependenciesWrapper{
PathContext: PathContextForTesting(config),
}
got := OutputFileForModule(ctx, tt.module, tt.tag)
AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got)
AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps)
}
}

View File

@@ -286,6 +286,9 @@ type apexArchBundleProperties struct {
Arm64 struct {
ApexNativeDependencies
}
Riscv64 struct {
ApexNativeDependencies
}
X86 struct {
ApexNativeDependencies
}
@@ -787,6 +790,8 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
depsList = append(depsList, a.archProperties.Arch.Arm.ApexNativeDependencies)
case android.Arm64:
depsList = append(depsList, a.archProperties.Arch.Arm64.ApexNativeDependencies)
case android.Riscv64:
depsList = append(depsList, a.archProperties.Arch.Riscv64.ApexNativeDependencies)
case android.X86:
depsList = append(depsList, a.archProperties.Arch.X86.ApexNativeDependencies)
case android.X86_64:
@@ -1559,7 +1564,7 @@ func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, h
dirInApex = filepath.Join(dirInApex, "bionic")
}
fileToCopy := ccMod.OutputFile().Path()
fileToCopy := android.OutputFileForModule(ctx, ccMod, "")
androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName
return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod)
}
@@ -1570,7 +1575,7 @@ func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFil
dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
}
dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
fileToCopy := cc.OutputFile().Path()
fileToCopy := android.OutputFileForModule(ctx, cc, "")
androidMkModuleName := cc.BaseModuleName() + cc.Properties.SubName
af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, cc)
af.symlinks = cc.Symlinks()
@@ -1583,7 +1588,7 @@ func apexFileForRustExecutable(ctx android.BaseModuleContext, rustm *rust.Module
if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
}
fileToCopy := rustm.OutputFile().Path()
fileToCopy := android.OutputFileForModule(ctx, rustm, "")
androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm)
return af
@@ -1602,7 +1607,7 @@ func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) a
if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
}
fileToCopy := rustm.OutputFile().Path()
fileToCopy := android.OutputFileForModule(ctx, rustm, "")
androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm)
}

View File

@@ -537,7 +537,11 @@ func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext,
}
if src == "" {
ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String())
if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{ctx.OtherModuleName(prebuilt)})
} else {
ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String())
}
// Drop through to return an empty string as the src (instead of nil) to avoid the prebuilt
// logic from reporting a more general, less useful message.
}

View File

@@ -28,6 +28,8 @@ func minApiForArch(ctx android.BaseModuleContext,
return ctx.Config().MinSupportedSdkVersion()
case android.Arm64, android.X86_64:
return android.FirstLp64Version
case android.Riscv64:
return android.FutureApiLevel
default:
panic(fmt.Errorf("Unknown arch %q", arch))
}

View File

@@ -3330,6 +3330,11 @@ func (c *Module) OutputFiles(tag string) (android.Paths, error) {
return android.Paths{c.outputFile.Path()}, nil
}
return android.Paths{}, nil
case "unstripped":
if c.linker != nil {
return android.PathsIfNonNil(c.linker.unstrippedOutputFilePath()), nil
}
return nil, nil
default:
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}

View File

@@ -103,6 +103,7 @@ type fuzzBinary struct {
*baseCompiler
fuzzPackagedModule fuzz.FuzzPackagedModule
installedSharedDeps []string
sharedLibraries android.Paths
}
func (fuzz *fuzzBinary) fuzzBinary() bool {
@@ -142,13 +143,6 @@ func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
return flags
}
func UnstrippedOutputFile(module android.Module) android.Path {
if mod, ok := module.(LinkableInterface); ok {
return mod.UnstrippedOutputFile()
}
panic("UnstrippedOutputFile called on non-LinkableInterface module: " + module.Name())
}
// IsValidSharedDependency takes a module and determines if it is a unique shared library
// that should be installed in the fuzz target output directories. This function
// returns true, unless:
@@ -270,22 +264,9 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
}
// Grab the list of required shared libraries.
seen := make(map[string]bool)
var sharedLibraries android.Paths
ctx.WalkDeps(func(child, parent android.Module) bool {
if seen[child.Name()] {
return false
}
seen[child.Name()] = true
fuzzBin.sharedLibraries = CollectAllSharedDependencies(ctx)
if IsValidSharedDependency(child) {
sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile())
return true
}
return false
})
for _, lib := range sharedLibraries {
for _, lib := range fuzzBin.sharedLibraries {
fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
sharedLibraryInstallLocation(
lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
@@ -412,9 +393,6 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
// Grab the list of required shared libraries.
sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, UnstrippedOutputFile, IsValidSharedDependency)
var files []fuzz.FileToZip
builder := android.NewRuleBuilder(pctx, ctx)
@@ -422,10 +400,10 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
files = s.PackageArtifacts(ctx, module, fpm, archDir, builder)
// Package shared libraries
files = append(files, GetSharedLibsToZip(sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
files = append(files, GetSharedLibsToZip(fuzzModule.sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
// The executable.
files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""})
files = append(files, fuzz.FileToZip{android.OutputFileForModule(ctx, ccModule, "unstripped"), ""})
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {
@@ -494,3 +472,46 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface,
}
return files
}
// CollectAllSharedDependencies search over the provided module's dependencies using
// VisitDirectDeps and WalkDeps to enumerate all shared library dependencies.
// VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer
// runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies
// have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
func CollectAllSharedDependencies(ctx android.ModuleContext) android.Paths {
seen := make(map[string]bool)
recursed := make(map[string]bool)
var sharedLibraries android.Paths
// Enumerate the first level of dependencies, as we discard all non-library
// modules in the BFS loop below.
ctx.VisitDirectDeps(func(dep android.Module) {
if !IsValidSharedDependency(dep) {
return
}
if seen[ctx.OtherModuleName(dep)] {
return
}
seen[ctx.OtherModuleName(dep)] = true
sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, dep, "unstripped"))
})
ctx.WalkDeps(func(child, parent android.Module) bool {
if !IsValidSharedDependency(child) {
return false
}
if !seen[ctx.OtherModuleName(child)] {
seen[ctx.OtherModuleName(child)] = true
sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, child, "unstripped"))
}
if recursed[ctx.OtherModuleName(child)] {
return false
}
recursed[ctx.OtherModuleName(child)] = true
return true
})
return sharedLibraries
}

View File

@@ -296,27 +296,37 @@ func (p *PrebuiltEtc) ExcludeFromRecoverySnapshot() bool {
}
func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if p.properties.Src == nil {
ctx.PropertyErrorf("src", "missing prebuilt source file")
return
}
p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
// Determine the output file basename.
// If Filename is set, use the name specified by the property.
// If Filename_from_src is set, use the source file name.
// Otherwise use the module name.
filename := proptools.String(p.properties.Filename)
filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
if filename != "" {
if filenameFromSrc {
ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
return
if p.properties.Src != nil {
p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
// Determine the output file basename.
// If Filename is set, use the name specified by the property.
// If Filename_from_src is set, use the source file name.
// Otherwise use the module name.
if filename != "" {
if filenameFromSrc {
ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
return
}
} else if filenameFromSrc {
filename = p.sourceFilePath.Base()
} else {
filename = ctx.ModuleName()
}
} else if ctx.Config().AllowMissingDependencies() {
// If no srcs was set and AllowMissingDependencies is enabled then
// mark the module as missing dependencies and set a fake source path
// and file name.
ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"})
p.sourceFilePath = android.PathForModuleSrc(ctx)
if filename == "" {
filename = ctx.ModuleName()
}
} else if filenameFromSrc {
filename = p.sourceFilePath.Base()
} else {
filename = ctx.ModuleName()
ctx.PropertyErrorf("src", "missing prebuilt source file")
return
}
p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath

View File

@@ -195,6 +195,30 @@ func TestPrebuiltEtcHost(t *testing.T) {
}
}
func TestPrebuiltEtcAllowMissingDependencies(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForPrebuiltEtcTest,
android.PrepareForTestDisallowNonExistentPaths,
android.FixtureModifyConfig(
func(config android.Config) {
config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
}),
).RunTestWithBp(t, `
prebuilt_etc {
name: "foo.conf",
filename_from_src: true,
arch: {
x86: {
src: "x86.conf",
},
},
}
`)
android.AssertStringEquals(t, "expected error rule", "android/soong/android.Error",
result.ModuleForTests("foo.conf", "android_arm64_armv8-a").Output("foo.conf").Rule.String())
}
func TestPrebuiltRootInstallDirPath(t *testing.T) {
result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
prebuilt_root {

View File

@@ -379,42 +379,3 @@ func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets str
sort.Strings(fuzzTargets)
ctx.Strict(targets, strings.Join(fuzzTargets, " "))
}
// CollectAllSharedDependencies performs a breadth-first search over the provided module's
// dependencies using `visitDirectDeps` to enumerate all shared library
// dependencies. We require breadth-first expansion, as otherwise we may
// incorrectly use the core libraries (sanitizer runtimes, libc, libdl, etc.)
// from a dependency. This may cause issues when dependencies have explicit
// sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
func CollectAllSharedDependencies(ctx android.SingletonContext, module android.Module, unstrippedOutputFile func(module android.Module) android.Path, isValidSharedDependency func(dependency android.Module) bool) android.Paths {
var fringe []android.Module
seen := make(map[string]bool)
// Enumerate the first level of dependencies, as we discard all non-library
// modules in the BFS loop below.
ctx.VisitDirectDeps(module, func(dep android.Module) {
if isValidSharedDependency(dep) {
fringe = append(fringe, dep)
}
})
var sharedLibraries android.Paths
for i := 0; i < len(fringe); i++ {
module := fringe[i]
if seen[module.Name()] {
continue
}
seen[module.Name()] = true
sharedLibraries = append(sharedLibraries, unstrippedOutputFile(module))
ctx.VisitDirectDeps(module, func(dep android.Module) {
if isValidSharedDependency(dep) && !seen[dep.Name()] {
fringe = append(fringe, dep)
}
})
}
return sharedLibraries
}

View File

@@ -90,10 +90,11 @@ func (as *AndroidAppSet) APKCertsFile() android.Path {
}
var TargetCpuAbi = map[string]string{
"arm": "ARMEABI_V7A",
"arm64": "ARM64_V8A",
"x86": "X86",
"x86_64": "X86_64",
"arm": "ARMEABI_V7A",
"arm64": "ARM64_V8A",
"riscv64": "RISCV64",
"x86": "X86",
"x86_64": "X86_64",
}
func SupportedAbis(ctx android.ModuleContext) []string {

View File

@@ -25,7 +25,7 @@ var (
Riscv64ArchFeatureRustFlags = map[string][]string{"": {}}
Riscv64LinkFlags = []string{}
Riscv64ArchVariantRustFlags = map[string][]string{}
Riscv64ArchVariantRustFlags = map[string][]string{"": {}}
)
func init() {

View File

@@ -34,6 +34,7 @@ type fuzzDecorator struct {
*binaryDecorator
fuzzPackagedModule fuzz.FuzzPackagedModule
sharedLibraries android.Paths
}
var _ compiler = (*fuzzDecorator)(nil)
@@ -86,6 +87,15 @@ func (fuzzer *fuzzDecorator) compilerProps() []interface{} {
&fuzzer.fuzzPackagedModule.FuzzProperties)
}
func (fuzzer *fuzzDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
out := fuzzer.binaryDecorator.compile(ctx, flags, deps)
// Grab the list of required shared libraries.
fuzzer.sharedLibraries = cc.CollectAllSharedDependencies(ctx)
return out
}
func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage {
return RlibLinkage
}
@@ -149,11 +159,8 @@ func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
// The executable.
files = append(files, fuzz.FileToZip{rustModule.UnstrippedOutputFile(), ""})
// Grab the list of required shared libraries.
sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, cc.UnstrippedOutputFile, cc.IsValidSharedDependency)
// Package shared libraries
files = append(files, cc.GetSharedLibsToZip(sharedLibraries, rustModule, &s.FuzzPackager, archString, "lib", &sharedLibraryInstalled)...)
files = append(files, cc.GetSharedLibsToZip(fuzzModule.sharedLibraries, rustModule, &s.FuzzPackager, archString, "lib", &sharedLibraryInstalled)...)
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {