hidl_interface: generate VTS things am: eaba923a4e
am: 464c725e06

Change-Id: Ie26b31302e18ef8ebba9a360c7877e7a327e0b70
diff --git a/build/fqName.go b/build/fqName.go
index 88f7dc0..f4ce0eb 100644
--- a/build/fqName.go
+++ b/build/fqName.go
@@ -124,3 +124,25 @@
 func (f *fqName) adapterHelperHeadersName() string {
 	return f.string() + "-adapter-helper_genc++_headers"
 }
+
+func (f *fqName) vtsSpecName() string {
+	return f.string() + "-vts.spec"
+}
+func (f *fqName) vtsDriverSourcesName() string {
+	return f.string() + "-vts.driver_genc++"
+}
+func (f *fqName) vtsDriverHeadersName() string {
+	return f.string() + "-vts.driver_genc++_headers"
+}
+func (f *fqName) vtsDriverName() string {
+	return f.string() + "-vts.driver"
+}
+func (f *fqName) vtsProfilerSourcesName() string {
+	return f.string() + "-vts.profiler_genc++"
+}
+func (f *fqName) vtsProfilerHeadersName() string {
+	return f.string() + "-vts.profiler_genc++_headers"
+}
+func (f *fqName) vtsProfilerName() string {
+	return f.string() + "-vts.profiler"
+}
diff --git a/build/hidl_interface.go b/build/hidl_interface.go
index 799da71..5b67d9a 100644
--- a/build/hidl_interface.go
+++ b/build/hidl_interface.go
@@ -16,7 +16,9 @@
 
 import (
 	"fmt"
+	"sort"
 	"strings"
+	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -32,7 +34,9 @@
 
 	pctx = android.NewPackageContext("android/hidl")
 
-	hidl     = pctx.HostBinToolVariable("hidl", "hidl-gen")
+	hidl = pctx.HostBinToolVariable("hidl", "hidl-gen")
+	vtsc = pctx.HostBinToolVariable("vtsc", "vtsc")
+
 	hidlRule = pctx.StaticRule("hidlRule", blueprint.RuleParams{
 		Depfile:     "${depfile}",
 		Deps:        blueprint.DepsGCC,
@@ -40,10 +44,17 @@
 		CommandDeps: []string{"${hidl}"},
 		Description: "HIDL ${language}: ${in} => ${out}",
 	}, "depfile", "fqName", "genDir", "language", "roots")
+
+	vtsRule = pctx.StaticRule("vtsRule", blueprint.RuleParams{
+		Command:     "rm -rf ${genDir} && ${vtsc} -m${mode} -t${type} ${inputDir}/${packagePath} ${genDir}/${packagePath}",
+		CommandDeps: []string{"${vtsc}"},
+		Description: "VTS ${mode} ${type}: ${in} => ${out}",
+	}, "mode", "type", "inputDir", "genDir", "packagePath")
 )
 
 func init() {
 	android.RegisterModuleType("hidl_interface", hidlInterfaceFactory)
+	android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
 }
 
 type hidlGenProperties struct {
@@ -79,6 +90,13 @@
 		g.genOutputs = append(g.genOutputs, android.PathForModuleGen(ctx, output))
 	}
 
+	if g.properties.Language == "vts" && isVtsSpecPackage(ctx.ModuleName()) {
+		vtsList := vtsList(ctx.AConfig())
+		vtsListMutex.Lock()
+		*vtsList = append(*vtsList, g.genOutputs.Paths()...)
+		vtsListMutex.Unlock()
+	}
+
 	var fullRootOptions []string
 	var currentPath android.OptionalPath
 	ctx.VisitDirectDeps(func(dep android.Module) {
@@ -147,6 +165,83 @@
 	return g
 }
 
+type vtscProperties struct {
+	Mode        string
+	Type        string
+	SpecName    string // e.g. foo-vts.spec
+	Outputs     []string
+	PackagePath string // e.g. android/hardware/foo/1.0/
+}
+
+type vtscRule struct {
+	android.ModuleBase
+
+	properties vtscProperties
+
+	genOutputDir android.Path
+	genInputDir  android.Path
+	genInputs    android.Paths
+	genOutputs   android.WritablePaths
+}
+
+var _ android.SourceFileProducer = (*vtscRule)(nil)
+var _ genrule.SourceFileGenerator = (*vtscRule)(nil)
+
+func (g *vtscRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	g.genOutputDir = android.PathForModuleGen(ctx)
+
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		if specs, ok := dep.(*hidlGenRule); ok {
+			g.genInputDir = specs.genOutputDir
+			g.genInputs = specs.genOutputs.Paths()
+		}
+	})
+
+	for _, output := range g.properties.Outputs {
+		g.genOutputs = append(g.genOutputs, android.PathForModuleGen(ctx, output))
+	}
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:    vtsRule,
+		Inputs:  g.genInputs,
+		Outputs: g.genOutputs,
+		Args: map[string]string{
+			"mode":        g.properties.Mode,
+			"type":        g.properties.Type,
+			"inputDir":    g.genInputDir.String(),
+			"genDir":      g.genOutputDir.String(),
+			"packagePath": g.properties.PackagePath,
+		},
+	})
+}
+
+func (g *vtscRule) GeneratedSourceFiles() android.Paths {
+	return g.genOutputs.Paths()
+}
+
+func (g *vtscRule) Srcs() android.Paths {
+	return g.genOutputs.Paths()
+}
+
+func (g *vtscRule) GeneratedDeps() android.Paths {
+	return g.genOutputs.Paths()
+}
+
+func (g *vtscRule) GeneratedHeaderDirs() android.Paths {
+	return android.Paths{g.genOutputDir}
+}
+
+func (g *vtscRule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), nil, g.properties.SpecName)
+}
+
+func vtscFactory() android.Module {
+	g := &vtscRule{}
+	g.AddProperties(&g.properties)
+	android.InitAndroidModule(g)
+	return g
+}
+
 type hidlInterfaceProperties struct {
 	// Vndk properties for interface library only.
 	cc.VndkProperties
@@ -315,6 +410,7 @@
 	// explicitly true if not specified to give early warning to devs
 	shouldGenerateJava := i.properties.Gen_java == nil || *i.properties.Gen_java
 	shouldGenerateJavaConstants := i.properties.Gen_java_constants
+	shouldGenerateVts := shouldGenerateLibrary
 
 	var libraryIfExists []string
 	if shouldGenerateLibrary {
@@ -506,6 +602,85 @@
 		}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
 		Group_static_libs: proptools.BoolPtr(true),
 	}, &i.inheritCommonProperties)
+
+	if shouldGenerateVts {
+		vtsSpecs := concat(wrap(name.dir(), interfaces, ".vts"), wrap(name.dir(), types, ".vts"))
+
+		mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+			Name: proptools.StringPtr(name.vtsSpecName()),
+		}, &hidlGenProperties{
+			Language:   "vts",
+			FqName:     name.string(),
+			Root:       i.properties.Root,
+			Interfaces: i.properties.Interfaces,
+			Inputs:     i.properties.Srcs,
+			Outputs:    vtsSpecs,
+		}, &i.inheritCommonProperties)
+
+		mctx.CreateModule(android.ModuleFactoryAdaptor(vtscFactory), &nameProperties{
+			Name: proptools.StringPtr(name.vtsDriverSourcesName()),
+		}, &vtscProperties{
+			Mode:        "DRIVER",
+			Type:        "SOURCE",
+			SpecName:    name.vtsSpecName(),
+			Outputs:     wrap("", vtsSpecs, ".cpp"),
+			PackagePath: name.dir(),
+		}, &i.inheritCommonProperties)
+		mctx.CreateModule(android.ModuleFactoryAdaptor(vtscFactory), &nameProperties{
+			Name: proptools.StringPtr(name.vtsDriverHeadersName()),
+		}, &vtscProperties{
+			Mode:        "DRIVER",
+			Type:        "HEADER",
+			SpecName:    name.vtsSpecName(),
+			Outputs:     wrap("", vtsSpecs, ".h"),
+			PackagePath: name.dir(),
+		}, &i.inheritCommonProperties)
+		mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
+			Name:                      proptools.StringPtr(name.vtsDriverName()),
+			Defaults:                  []string{"VtsHalDriverDefaults"},
+			Generated_sources:         []string{name.vtsDriverSourcesName()},
+			Generated_headers:         []string{name.vtsDriverHeadersName()},
+			Export_generated_headers:  []string{name.vtsDriverHeadersName()},
+			Shared_libs:               wrap("", cppDependencies, "-vts.driver"),
+			Export_shared_lib_headers: wrap("", cppDependencies, "-vts.driver"),
+			Static_libs:               concat(cppDependencies, libraryIfExists),
+
+			// TODO(b/126244142)
+			Cflags: []string{"-Wno-unused-variable"},
+		}, &i.inheritCommonProperties)
+
+		mctx.CreateModule(android.ModuleFactoryAdaptor(vtscFactory), &nameProperties{
+			Name: proptools.StringPtr(name.vtsProfilerSourcesName()),
+		}, &vtscProperties{
+			Mode:        "PROFILER",
+			Type:        "SOURCE",
+			SpecName:    name.vtsSpecName(),
+			Outputs:     wrap("", vtsSpecs, ".cpp"),
+			PackagePath: name.dir(),
+		}, &i.inheritCommonProperties)
+		mctx.CreateModule(android.ModuleFactoryAdaptor(vtscFactory), &nameProperties{
+			Name: proptools.StringPtr(name.vtsProfilerHeadersName()),
+		}, &vtscProperties{
+			Mode:        "PROFILER",
+			Type:        "HEADER",
+			SpecName:    name.vtsSpecName(),
+			Outputs:     wrap("", vtsSpecs, ".h"),
+			PackagePath: name.dir(),
+		}, &i.inheritCommonProperties)
+		mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
+			Name:                      proptools.StringPtr(name.vtsProfilerName()),
+			Defaults:                  []string{"VtsHalProfilerDefaults"},
+			Generated_sources:         []string{name.vtsProfilerSourcesName()},
+			Generated_headers:         []string{name.vtsProfilerHeadersName()},
+			Export_generated_headers:  []string{name.vtsProfilerHeadersName()},
+			Shared_libs:               wrap("", cppDependencies, "-vts.profiler"),
+			Export_shared_lib_headers: wrap("", cppDependencies, "-vts.profiler"),
+			Static_libs:               concat(cppDependencies, libraryIfExists),
+
+			// TODO(b/126244142)
+			Cflags: []string{"-Wno-unused-variable"},
+		}, &i.inheritCommonProperties)
+	}
 }
 
 func (h *hidlInterface) Name() string {
@@ -579,3 +754,37 @@
 	}
 	return false
 }
+
+// TODO(b/126383715): centralize this logic/support filtering in core VTS build
+var coreVtsSpecs = []string{
+	"android.frameworks.",
+	"android.hardware.",
+	"android.hidl.",
+	"android.system.",
+}
+
+func isVtsSpecPackage(name string) bool {
+	for _, pkgname := range coreVtsSpecs {
+		if strings.HasPrefix(name, pkgname) {
+			return true
+		}
+	}
+	return false
+}
+
+var vtsListKey = android.NewOnceKey("vtsList")
+
+func vtsList(config android.Config) *android.Paths {
+	return config.Once(vtsListKey, func() interface{} {
+		return &android.Paths{}
+	}).(*android.Paths)
+}
+
+var vtsListMutex sync.Mutex
+
+func makeVarsProvider(ctx android.MakeVarsContext) {
+	vtsList := vtsList(ctx.Config()).Strings()
+	sort.Strings(vtsList)
+
+	ctx.Strict("VTS_SPEC_FILE_LIST", strings.Join(vtsList, " "))
+}
diff --git a/build/properties.go b/build/properties.go
index a08e0bd..349beea 100644
--- a/build/properties.go
+++ b/build/properties.go
@@ -39,6 +39,7 @@
 	Export_static_lib_headers []string
 	Export_generated_headers  []string
 	Double_loadable           *bool
+	Cflags                    []string
 }
 
 type javaProperties struct {