Add corpus and dictionary properties to cc_fuzz.

Adds the corpus and dictionary properties to the cc_fuzz target.
Propagates these entries to the makefile backend via LOCAL_FUZZ_DATA, in
a similar manner to LOCAL_TEST_DATA.

Bug: 141026328
Test: m example_fuzzer, fuzz target should have adjacent corpus/dict
files.

Change-Id: If5add5a597cc479f4e084bdafbd0fc175cfd6321
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 66dd838..da7a5db 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -312,6 +312,33 @@
 	androidMkWriteTestData(test.data, ctx, ret)
 }
 
+func (fuzz *fuzzBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ctx.subAndroidMk(ret, fuzz.binaryDecorator)
+
+	var fuzzFiles []string
+	for _, d := range fuzz.corpus {
+		rel := d.Rel()
+		path := d.String()
+		path = strings.TrimSuffix(path, rel)
+		fuzzFiles = append(fuzzFiles, path+":corpus/"+d.Base())
+	}
+
+	if fuzz.dictionary != nil {
+		path := strings.TrimSuffix(fuzz.dictionary.String(), fuzz.dictionary.Rel())
+		fuzzFiles = append(fuzzFiles, path+":"+fuzz.dictionary.Base())
+	}
+
+	if len(fuzzFiles) > 0 {
+		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
+		})
+	}
+
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		fmt.Fprintln(w, "LOCAL_IS_FUZZ_TARGET := true")
+	})
+}
+
 func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	ctx.subAndroidMk(ret, test.libraryDecorator)
 }
diff --git a/cc/cc.go b/cc/cc.go
index fb7fca2..be64e09 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2172,6 +2172,7 @@
 		&BinaryLinkerProperties{},
 		&TestProperties{},
 		&TestBinaryProperties{},
+		&FuzzProperties{},
 		&StlProperties{},
 		&SanitizeProperties{},
 		&StripProperties{},
diff --git a/cc/fuzz.go b/cc/fuzz.go
index b0fb262..325be63 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -23,6 +23,14 @@
 	"android/soong/cc/config"
 )
 
+type FuzzProperties struct {
+	// Optional list of seed files to be installed to the fuzz target's output
+	// directory.
+	Corpus []string `android:"path"`
+	// Optional dictionary to be installed to the fuzz target's output directory.
+	Dictionary *string `android:"path"`
+}
+
 func init() {
 	android.RegisterModuleType("cc_fuzz", FuzzFactory)
 }
@@ -42,10 +50,15 @@
 type fuzzBinary struct {
 	*binaryDecorator
 	*baseCompiler
+
+	Properties FuzzProperties
+	corpus     android.Paths
+	dictionary android.Path
 }
 
 func (fuzz *fuzzBinary) linkerProps() []interface{} {
 	props := fuzz.binaryDecorator.linkerProps()
+	props = append(props, &fuzz.Properties)
 	return props
 }
 
@@ -81,9 +94,21 @@
 }
 
 func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
-	fuzz.binaryDecorator.baseInstaller.dir = filepath.Join("fuzz", ctx.Target().Arch.ArchType.String())
-	fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join("fuzz", ctx.Target().Arch.ArchType.String())
+	fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
+		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+	fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join(
+		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
 	fuzz.binaryDecorator.baseInstaller.install(ctx, file)
+
+	fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
+	if fuzz.Properties.Dictionary != nil {
+		fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
+		if fuzz.dictionary.Ext() != ".dict" {
+			ctx.PropertyErrorf("dictionary",
+				"Fuzzer dictionary %q does not have '.dict' extension",
+				fuzz.dictionary.String())
+		}
+	}
 }
 
 func NewFuzz(hod android.HostOrDeviceSupported) *Module {