Check against xsd for building all matrices

Test: builds
Fixes: 149929588

Change-Id: Id08cfe41af59bb336889f9edeaf35dc484892997
diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go
index e48f993..2772ba3 100644
--- a/compatibility_matrices/build/vintf_compatibility_matrix.go
+++ b/compatibility_matrices/build/vintf_compatibility_matrix.go
@@ -40,7 +40,15 @@
 		Description: "assemble_vintf -i ${inputs}",
 	}, "inputs")
 
-	kernelConfigTag = dependencyTag{name: "kernel-config"}
+	xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{
+		Command:     `$XmlLintCmd --schema $xsd $in > /dev/null && touch -a $out`,
+		CommandDeps: []string{"$XmlLintCmd"},
+		Restat:      true,
+	}, "xsd")
+
+	kernelConfigTag  = dependencyTag{name: "kernel-config"}
+	schemaTag        = dependencyTag{name: "matrix-schema"}
+	schemaModuleName = "compatibility_matrix_schema"
 )
 
 const (
@@ -62,11 +70,13 @@
 	android.ModuleBase
 	properties vintfCompatibilityMatrixProperties
 
-	genFile android.WritablePath
+	genFile                android.WritablePath
+	additionalDependencies android.WritablePaths
 }
 
 func init() {
 	pctx.HostBinToolVariable("assembleVintfCmd", "assemble_vintf")
+	pctx.HostBinToolVariable("XmlLintCmd", "xmllint")
 	android.RegisterModuleType("vintf_compatibility_matrix", vintfCompatibilityMatrixFactory)
 }
 
@@ -82,6 +92,42 @@
 func (g *vintfCompatibilityMatrixRule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	android.ExtractSourcesDeps(ctx, g.properties.Srcs)
 	ctx.AddDependency(ctx.Module(), kernelConfigTag, g.properties.Kernel_configs...)
+	ctx.AddDependency(ctx.Module(), schemaTag, schemaModuleName)
+}
+
+func (g *vintfCompatibilityMatrixRule) timestampFilePath(ctx android.ModuleContext, path android.Path) android.WritablePath {
+	return android.GenPathWithExt(ctx, "vintf-xmllint", path, "ts")
+}
+
+func (g *vintfCompatibilityMatrixRule) generateValidateBuildAction(ctx android.ModuleContext, path android.Path, schema android.Path) {
+	timestamp := g.timestampFilePath(ctx, path)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        xmllintXsd,
+		Description: "xmllint-xsd",
+		Input:       path,
+		Output:      timestamp,
+		Implicit:    schema,
+		Args: map[string]string{
+			"xsd": schema.String(),
+		},
+	})
+	g.additionalDependencies = append(g.additionalDependencies, timestamp)
+}
+
+func (g *vintfCompatibilityMatrixRule) getSchema(ctx android.ModuleContext) android.OptionalPath {
+	schemaModule := ctx.GetDirectDepWithTag(schemaModuleName, schemaTag)
+	sfp, ok := schemaModule.(android.SourceFileProducer)
+	if !ok {
+		ctx.ModuleErrorf("Implicit dependency %q has no srcs", ctx.OtherModuleName(schemaModule))
+		return android.OptionalPath{}
+	}
+
+	schemaSrcs := sfp.Srcs()
+	if len(schemaSrcs) != 1 {
+		ctx.PropertyErrorf(`srcs of implicit dependency %q has length %d != 1`, ctx.OtherModuleName(schemaModule), len(schemaSrcs))
+		return android.OptionalPath{}
+	}
+	return android.OptionalPathForPath(schemaSrcs[0])
 }
 
 func (g *vintfCompatibilityMatrixRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -91,7 +137,18 @@
 		outputFilename = g.Name()
 	}
 
+	schema := g.getSchema(ctx)
+	if !schema.Valid() {
+		return
+	}
+
 	inputPaths := android.PathsForModuleSrc(ctx, g.properties.Srcs)
+	for _, srcPath := range inputPaths {
+		g.generateValidateBuildAction(ctx, srcPath, schema.Path())
+	}
+
+	// No need to validate matrices from kernel configs because they are generated by
+	// assemble_vintf.
 	ctx.VisitDirectDepsWithTag(kernelConfigTag, func(m android.Module) {
 		if k, ok := m.(*configs.KernelConfigRule); ok {
 			inputPaths = append(inputPaths, k.OutputPath())
@@ -112,6 +169,7 @@
 			"inputs": strings.Join(inputPaths.Strings(), ":"),
 		},
 	})
+	g.generateValidateBuildAction(ctx, g.genFile, schema.Path())
 
 	ctx.InstallFile(android.PathForModuleInstall(ctx, "etc", relpath), outputFilename, g.genFile)
 }
@@ -126,6 +184,9 @@
 				if proptools.String(g.properties.Stem) != "" {
 					fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", proptools.String(g.properties.Stem))
 				}
+				for _, path := range g.additionalDependencies {
+					fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", path.String())
+				}
 			},
 		},
 	}