Add header-abi-checker for Vndk abi checks.

header-abi-dumper: dumps abi exported by source files for Vndk.
header-abi-linker: links abi dumps produced by header-abi-dumper.
header-abi-diff: compares linked dumps.

Test: mm -j64 showcommands > make_log in bionic/libc.
      This produced linked dumps in out/soong/.intermediates.
      Copied these dumps to
      prebuilts/abi-dumps/ndk/current/arm64/source-based/.
      Changed the abi and re-ran mm -j64 showcommands > make_log
      confirmed that the build reported compatibility breakge without
      actually failing (advisory mode).

Change-Id: Iccad6908fe68a80f47230751671d156893b96ead
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 59a1db8..481dbb4 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -141,6 +141,13 @@
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
 		library.androidMkWriteExportedFlags(w)
+		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := ")
+		if library.sAbiOutputFile.Valid() {
+			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiOutputFile.String())
+			if library.sAbiDiff.Valid() && !library.static() {
+				fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiDiff.String())
+			}
+		}
 
 		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+outputFile.Ext())
 
diff --git a/cc/builder.go b/cc/builder.go
index 0694cb7..96b4158 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -168,6 +168,41 @@
 			Description: "yasm $out",
 		},
 		"asFlags")
+
+	_ = pctx.SourcePathVariable("sAbiDumper", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-dumper")
+
+	sAbiDump = pctx.AndroidStaticRule("sAbiDump",
+		blueprint.RuleParams{
+			Command:     "rm -f $out && $sAbiDumper -o ${out} $in $exportDirs -- $cFlags -Wno-packed -isystem ${config.RSIncludePath}",
+			CommandDeps: []string{"$sAbiDumper"},
+			Description: "header-abi-dumper $in -o $out $exportDirs",
+		},
+		"cFlags", "exportDirs")
+
+	_ = pctx.SourcePathVariable("sAbiLinker", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-linker")
+
+	sAbiLink = pctx.AndroidStaticRule("sAbiLink",
+		blueprint.RuleParams{
+			Command:        "$sAbiLinker -o ${out} $symbolFile -arch $arch -api $api $exportedHeaderFlags @${out}.rsp ",
+			CommandDeps:    []string{"$sAbiLinker"},
+			Description:    "header-abi-linker $in -o $out",
+			Rspfile:        "${out}.rsp",
+			RspfileContent: "${in}",
+		},
+		"symbolFile", "arch", "api", "exportedHeaderFlags")
+
+	_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
+	// The output file is different from what the build system knows about.
+	// This is done since we have to create a report file even when builds
+	// fail in this case. Abidiff check turned on in advice-only mode. Builds
+	// will not fail on abi incompatibilties / extensions.
+	sAbiDiff = pctx.AndroidStaticRule("sAbiDiff",
+		blueprint.RuleParams{
+			Command:     "$sAbiDiffer -advice-only -o ${out}s -new $in -old $referenceDump",
+			CommandDeps: []string{"$sAbiDiffer"},
+			Description: "header-abi-diff -o ${out} -new $in -old $referenceDump",
+		},
+		"referenceDump")
 )
 
 func init() {
@@ -194,12 +229,14 @@
 	yaccFlags   string
 	protoFlags  string
 	tidyFlags   string
+	sAbiFlags   string
 	yasmFlags   string
 	aidlFlags   string
 	toolchain   config.Toolchain
 	clang       bool
 	tidy        bool
 	coverage    bool
+	sAbiDump    bool
 
 	systemIncludeFlags string
 
@@ -214,6 +251,7 @@
 	objFiles      android.Paths
 	tidyFiles     android.Paths
 	coverageFiles android.Paths
+	sAbiDumpFiles android.Paths
 }
 
 func (a Objects) Copy() Objects {
@@ -221,6 +259,7 @@
 		objFiles:      append(android.Paths{}, a.objFiles...),
 		tidyFiles:     append(android.Paths{}, a.tidyFiles...),
 		coverageFiles: append(android.Paths{}, a.coverageFiles...),
+		sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...),
 	}
 }
 
@@ -229,6 +268,7 @@
 		objFiles:      append(a.objFiles, b.objFiles...),
 		tidyFiles:     append(a.tidyFiles, b.tidyFiles...),
 		coverageFiles: append(a.coverageFiles, b.coverageFiles...),
+		sAbiDumpFiles: append(a.sAbiDumpFiles, b.sAbiDumpFiles...),
 	}
 }
 
@@ -265,6 +305,10 @@
 		flags.systemIncludeFlags,
 		flags.asFlags,
 	}, " ")
+	var sAbiDumpFiles android.Paths
+	if flags.sAbiDump && flags.clang {
+		sAbiDumpFiles = make(android.Paths, 0, len(srcFiles))
+	}
 
 	if flags.clang {
 		cflags += " ${config.NoOverrideClangGlobalCflags}"
@@ -296,6 +340,7 @@
 		var ccCmd string
 		tidy := flags.tidy && flags.clang
 		coverage := flags.coverage
+		dump := flags.sAbiDump && flags.clang
 
 		switch srcFile.Ext() {
 		case ".S", ".s":
@@ -303,6 +348,7 @@
 			moduleCflags = asflags
 			tidy = false
 			coverage = false
+			dump = false
 		case ".c":
 			ccCmd = "gcc"
 			moduleCflags = cflags
@@ -366,12 +412,29 @@
 			})
 		}
 
+		if dump {
+			sAbiDumpFile := android.ObjPathWithExt(ctx, subdir, srcFile, "sdump")
+			sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile)
+
+			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+				Rule:     sAbiDump,
+				Output:   sAbiDumpFile,
+				Input:    srcFile,
+				Implicit: objFile,
+				Args: map[string]string{
+					"cFlags":     moduleCflags,
+					"exportDirs": flags.sAbiFlags,
+				},
+			})
+		}
+
 	}
 
 	return Objects{
 		objFiles:      objFiles,
 		tidyFiles:     tidyFiles,
 		coverageFiles: coverageFiles,
+		sAbiDumpFiles: sAbiDumpFiles,
 	}
 }
 
@@ -554,6 +617,47 @@
 	})
 }
 
+// Generate a rule to combine .dump sAbi dump files from multiple source files
+// into a single .ldump sAbi dump file
+func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths,
+	symbolFile android.OptionalPath, apiLevel, baseName, exportedHeaderFlags string) android.OptionalPath {
+	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
+	var symbolFileStr string
+	var linkedDumpDep android.Path
+	if symbolFile.Valid() {
+		symbolFileStr = "-v " + symbolFile.Path().String()
+		linkedDumpDep = symbolFile.Path()
+	}
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:     sAbiLink,
+		Output:   outputFile,
+		Inputs:   sAbiDumps,
+		Implicit: linkedDumpDep,
+		Args: map[string]string{
+			"symbolFile": symbolFileStr,
+			"arch":       ctx.Arch().ArchType.Name,
+			"api":        apiLevel,
+			"exportedHeaderFlags": exportedHeaderFlags,
+		},
+	})
+	return android.OptionalPathForPath(outputFile)
+}
+
+func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
+	baseName string) android.OptionalPath {
+	outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:     sAbiDiff,
+		Output:   outputFile,
+		Input:    inputDump,
+		Implicit: referenceDump,
+		Args: map[string]string{
+			"referenceDump": referenceDump.String(),
+		},
+	})
+	return android.OptionalPathForPath(outputFile)
+}
+
 // Generate a rule for extract a table of contents from a shared library (.so)
 func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.WritablePath,
 	outputFile android.WritablePath, flags builderFlags) {
diff --git a/cc/cc.go b/cc/cc.go
index 63caf3a..6e2f6a5 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -49,6 +49,7 @@
 		ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel()
 
 		ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
+		ctx.TopDown("vndk_deps", sabiDepsMutator)
 	})
 
 	pctx.Import("android/soong/cc/config")
@@ -108,6 +109,7 @@
 	LdFlags     []string // Flags that apply to linker command lines
 	libFlags    []string // Flags to add libraries early to the link order
 	TidyFlags   []string // Flags that apply to clang-tidy
+	SAbiFlags   []string // Flags that apply to header-abi-dumper
 	YasmFlags   []string // Flags that apply to yasm assembly source files
 
 	// Global include flags that apply to C, C++, and assembly source files
@@ -118,6 +120,7 @@
 	Clang     bool
 	Tidy      bool
 	Coverage  bool
+	SAbiDump  bool
 
 	RequiredInstructionSet string
 	DynamicLinker          string
@@ -177,6 +180,7 @@
 	sdk() bool
 	sdkVersion() string
 	vndk() bool
+	createVndkSourceAbiDump() bool
 	selectedStl() string
 	baseModuleName() string
 }
@@ -283,6 +287,7 @@
 	stl       *stl
 	sanitize  *sanitize
 	coverage  *coverage
+	sabi      *sabi
 
 	androidMkSharedLibDeps []string
 
@@ -316,6 +321,9 @@
 	if c.coverage != nil {
 		props = append(props, c.coverage.props()...)
 	}
+	if c.sabi != nil {
+		props = append(props, c.sabi.props()...)
+	}
 	for _, feature := range c.features {
 		props = append(props, feature.props()...)
 	}
@@ -418,6 +426,12 @@
 	return ctx.mod.vndk()
 }
 
+// Create source abi dumps if the module belongs to the list of VndkLibraries.
+func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
+	return ctx.ctx.Device() && (inList(ctx.baseModuleName(), config.LLndkLibraries())) ||
+		(inList(ctx.baseModuleName(), config.VndkLibraries()))
+}
+
 func (ctx *moduleContextImpl) selectedStl() string {
 	if stl := ctx.mod.stl; stl != nil {
 		return stl.Properties.SelectedStl
@@ -444,6 +458,7 @@
 	module.stl = &stl{}
 	module.sanitize = &sanitize{}
 	module.coverage = &coverage{}
+	module.sabi = &sabi{}
 	return module
 }
 
@@ -492,6 +507,9 @@
 	if c.coverage != nil {
 		flags = c.coverage.flags(ctx, flags)
 	}
+	if c.sabi != nil {
+		flags = c.sabi.flags(ctx, flags)
+	}
 	for _, feature := range c.features {
 		flags = feature.flags(ctx, flags)
 	}
@@ -566,6 +584,9 @@
 	if c.coverage != nil {
 		c.coverage.begin(ctx)
 	}
+	if c.sabi != nil {
+		c.sabi.begin(ctx)
+	}
 	for _, feature := range c.features {
 		feature.begin(ctx)
 	}
@@ -596,6 +617,9 @@
 	if c.coverage != nil {
 		deps = c.coverage.deps(ctx, deps)
 	}
+	if c.sabi != nil {
+		deps = c.sabi.deps(ctx, deps)
+	}
 	for _, feature := range c.features {
 		deps = feature.deps(ctx, deps)
 	}
@@ -999,9 +1023,12 @@
 			}
 
 			// When combining coverage files for shared libraries and executables, coverage files
-			// in static libraries act as if they were whole static libraries.
+			// in static libraries act as if they were whole static libraries. The same goes for
+			// source based Abi dump files.
 			depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
 				staticLib.objs().coverageFiles...)
+			depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
+				staticLib.objs().sAbiDumpFiles...)
 		}
 
 		if ptr != nil {
@@ -1085,6 +1112,7 @@
 		&InstallerProperties{},
 		&TidyProperties{},
 		&CoverageProperties{},
+		&SAbiProperties{},
 	)
 
 	return android.InitDefaultsModule(module, module, props...)
diff --git a/cc/library.go b/cc/library.go
index cb85bd3..e2ec584 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -21,6 +21,7 @@
 	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
+	"android/soong/cc/config"
 )
 
 type LibraryProperties struct {
@@ -220,9 +221,17 @@
 
 	sanitize *sanitize
 
+	sabi *sabi
+
 	// Output archive of gcno coverage information files
 	coverageOutputFile android.OptionalPath
 
+	// linked Source Abi Dump
+	sAbiOutputFile android.OptionalPath
+
+	// Source Abi Diff
+	sAbiDiff android.OptionalPath
+
 	// Decorated interafaces
 	*baseCompiler
 	*baseLinker
@@ -316,7 +325,20 @@
 		}
 		return Objects{}
 	}
+	if ctx.createVndkSourceAbiDump() || (library.sabi.Properties.CreateSAbiDumps && ctx.Device()) {
+		exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+		var SourceAbiFlags []string
+		for _, dir := range exportIncludeDirs.Strings() {
+			SourceAbiFlags = append(SourceAbiFlags, "-I "+dir)
+		}
 
+		flags.SAbiFlags = SourceAbiFlags
+		total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + len(library.Properties.Shared.Srcs) +
+			len(library.Properties.Static.Srcs)
+		if total_length > 0 {
+			flags.SAbiDump = true
+		}
+	}
 	objs := library.baseCompiler.compile(ctx, flags, deps)
 	library.reuseObjects = objs
 	buildFlags := flagsToBuilderFlags(flags)
@@ -534,11 +556,45 @@
 
 	objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
 	objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
+
+	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.StaticLibObjs.sAbiDumpFiles...)
+	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...)
+
 	library.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, library.getLibName(ctx))
+	library.linkSAbiDumpFiles(ctx, objs, fileName)
 
 	return ret
 }
 
+func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string) {
+	//Also take into account object re-use.
+	if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() {
+		refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, "current", fileName, vndkVsNdk(ctx), true)
+		versionScript := android.OptionalPathForModuleSrc(ctx, library.Properties.Version_script)
+		var symbolFile android.OptionalPath
+		if versionScript.Valid() {
+			symbolFile = versionScript
+		}
+		exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+		var SourceAbiFlags []string
+		for _, dir := range exportIncludeDirs.Strings() {
+			SourceAbiFlags = append(SourceAbiFlags, "-I "+dir)
+		}
+		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
+		library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, symbolFile, "current", fileName, exportedHeaderFlags)
+		if refSourceDumpFile.Valid() {
+			library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(), refSourceDumpFile.Path(), fileName)
+		}
+	}
+}
+
+func vndkVsNdk(ctx ModuleContext) bool {
+	if inList(ctx.baseModuleName(), config.LLndkLibraries()) {
+		return false
+	}
+	return true
+}
+
 func (library *libraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
@@ -656,6 +712,7 @@
 		baseLinker:    NewBaseLinker(),
 		baseInstaller: NewBaseInstaller("lib", "lib64", InstallInSystem),
 		sanitize:      module.sanitize,
+		sabi:          module.sabi,
 	}
 
 	module.compiler = library
diff --git a/cc/sabi.go b/cc/sabi.go
new file mode 100644
index 0000000..7ae31c9
--- /dev/null
+++ b/cc/sabi.go
@@ -0,0 +1,63 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+	"github.com/google/blueprint"
+
+	"android/soong/cc/config"
+)
+
+type SAbiProperties struct {
+	CreateSAbiDumps bool `blueprint:"mutated"`
+}
+
+type sabi struct {
+	Properties SAbiProperties
+}
+
+func (sabimod *sabi) props() []interface{} {
+	return []interface{}{&sabimod.Properties}
+}
+
+func (sabimod *sabi) begin(ctx BaseModuleContext) {}
+
+func (sabimod *sabi) deps(ctx BaseModuleContext, deps Deps) Deps {
+	return deps
+}
+
+func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags {
+	return flags
+}
+
+func sabiDepsMutator(mctx android.TopDownMutatorContext) {
+	if c, ok := mctx.Module().(*Module); ok &&
+		((inList(c.Name(), config.VndkLibraries())) || (inList(c.Name(), config.LLndkLibraries())) ||
+			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
+		mctx.VisitDirectDeps(func(m blueprint.Module) {
+			tag := mctx.OtherModuleDependencyTag(m)
+			switch tag {
+			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
+
+				cc, _ := m.(*Module)
+				if cc == nil {
+					return
+				}
+				cc.sabi.Properties.CreateSAbiDumps = true
+			}
+		})
+	}
+}
diff --git a/cc/util.go b/cc/util.go
index 36d8dd2..18ad8a6 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -99,11 +99,13 @@
 		ldFlags:     strings.Join(in.LdFlags, " "),
 		libFlags:    strings.Join(in.libFlags, " "),
 		tidyFlags:   strings.Join(in.TidyFlags, " "),
+		sAbiFlags:   strings.Join(in.SAbiFlags, " "),
 		yasmFlags:   strings.Join(in.YasmFlags, " "),
 		toolchain:   in.Toolchain,
 		clang:       in.Clang,
 		coverage:    in.Coverage,
 		tidy:        in.Tidy,
+		sAbiDump:    in.SAbiDump,
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),