Merge "Include headers and props to VNDK snapshot"
diff --git a/android/config.go b/android/config.go
index 61370a0..72372ef 100644
--- a/android/config.go
+++ b/android/config.go
@@ -848,6 +848,10 @@
 	return ExistentPathForSource(ctx, "frameworks", "base").Valid()
 }
 
+func (c *config) VndkSnapshotBuildArtifacts() bool {
+	return Bool(c.productVariables.VndkSnapshotBuildArtifacts)
+}
+
 func (c *deviceConfig) Arches() []Arch {
 	var arches []Arch
 	for _, target := range c.config.Targets[Android] {
diff --git a/android/variable.go b/android/variable.go
index bfff81c..8886bae 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -261,7 +261,8 @@
 
 	PgoAdditionalProfileDirs []string `json:",omitempty"`
 
-	VndkUseCoreVariant *bool `json:",omitempty"`
+	VndkUseCoreVariant         *bool `json:",omitempty"`
+	VndkSnapshotBuildArtifacts *bool `json:",omitempty"`
 
 	BoardVendorSepolicyDirs      []string `json:",omitempty"`
 	BoardOdmSepolicyDirs         []string `json:",omitempty"`
diff --git a/cc/library.go b/cc/library.go
index b193ab7..893fc66 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -508,6 +508,7 @@
 type libraryInterface interface {
 	getWholeStaticMissingDeps() []string
 	static() bool
+	shared() bool
 	objs() Objects
 	reuseObjs() (Objects, exportedFlagsProducer)
 	toc() android.OptionalPath
diff --git a/cc/vndk.go b/cc/vndk.go
index 2c78047..2a86f5b 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -15,8 +15,8 @@
 package cc
 
 import (
+	"encoding/json"
 	"errors"
-	"fmt"
 	"path/filepath"
 	"sort"
 	"strings"
@@ -206,16 +206,9 @@
 	modulePathsKey                   = android.NewOnceKey("modulePaths")
 	vndkSnapshotOutputsKey           = android.NewOnceKey("vndkSnapshotOutputs")
 	vndkLibrariesLock                sync.Mutex
-)
 
-type vndkSnapshotOutputPaths struct {
-	configs         android.Paths
-	notices         android.Paths
-	vndkCoreLibs    android.Paths
-	vndkCoreLibs2nd android.Paths
-	vndkSpLibs      android.Paths
-	vndkSpLibs2nd   android.Paths
-}
+	headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
+)
 
 func vndkCoreLibraries(config android.Config) *[]string {
 	return config.Once(vndkCoreLibrariesKey, func() interface{} {
@@ -253,10 +246,10 @@
 	}).(map[string]string)
 }
 
-func vndkSnapshotOutputs(config android.Config) *vndkSnapshotOutputPaths {
+func vndkSnapshotOutputs(config android.Config) *android.RuleBuilderInstalls {
 	return config.Once(vndkSnapshotOutputsKey, func() interface{} {
-		return &vndkSnapshotOutputPaths{}
-	}).(*vndkSnapshotOutputPaths)
+		return &android.RuleBuilderInstalls{}
+	}).(*android.RuleBuilderInstalls)
 }
 
 func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
@@ -357,13 +350,7 @@
 	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
 		outputs := vndkSnapshotOutputs(ctx.Config())
-
-		ctx.Strict("SOONG_VNDK_SNAPSHOT_CONFIGS", strings.Join(outputs.configs.Strings(), " "))
-		ctx.Strict("SOONG_VNDK_SNAPSHOT_NOTICES", strings.Join(outputs.notices.Strings(), " "))
-		ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS", strings.Join(outputs.vndkCoreLibs.Strings(), " "))
-		ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS", strings.Join(outputs.vndkSpLibs.Strings(), " "))
-		ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS_2ND", strings.Join(outputs.vndkCoreLibs2nd.Strings(), " "))
-		ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS_2ND", strings.Join(outputs.vndkSpLibs2nd.Strings(), " "))
+		ctx.Strict("SOONG_VNDK_SNAPSHOT_FILES", outputs.String())
 	})
 }
 
@@ -373,26 +360,6 @@
 
 type vndkSnapshotSingleton struct{}
 
-func installVndkSnapshotLib(ctx android.SingletonContext, name string, module *Module, dir string) android.Path {
-	if !module.outputFile.Valid() {
-		panic(fmt.Errorf("module %s has no outputFile\n", name))
-	}
-
-	out := android.PathForOutput(ctx, dir, name+".so")
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cp,
-		Input:       module.outputFile.Path(),
-		Output:      out,
-		Description: "vndk snapshot " + dir + "/" + name + ".so",
-		Args: map[string]string{
-			"cpFlags": "-f -L",
-		},
-	})
-
-	return out
-}
-
 func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
 	if ctx.DeviceConfig().VndkVersion() != "current" {
@@ -411,30 +378,58 @@
 
 	snapshotDir := "vndk-snapshot"
 
-	var vndkLibPath, vndkLib2ndPath string
+	vndkLibDir := make(map[android.ArchType]string)
 
-	snapshotVariantPath := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
-	if ctx.DeviceConfig().BinderBitness() == "32" {
-		vndkLibPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
-			"arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
-		vndkLib2ndPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
-			"arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
-	} else {
-		vndkLibPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
-			"arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
-		vndkLib2ndPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
-			"arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
+	snapshotVariantDir := ctx.DeviceConfig().DeviceArch()
+	for _, target := range ctx.Config().Targets[android.Android] {
+		dir := snapshotVariantDir
+		if ctx.DeviceConfig().BinderBitness() == "32" {
+			dir = filepath.Join(dir, "binder32")
+		}
+		arch := "arch-" + target.Arch.ArchType.String()
+		if target.Arch.ArchVariant != "" {
+			arch += "-" + target.Arch.ArchVariant
+		}
+		dir = filepath.Join(dir, arch)
+		vndkLibDir[target.Arch.ArchType] = dir
 	}
-
-	vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
-	vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
-	vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
-	vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
-	noticePath := filepath.Join(snapshotVariantPath, "NOTICE_FILES")
+	configsDir := filepath.Join(snapshotVariantDir, "configs")
+	noticeDir := filepath.Join(snapshotVariantDir, "NOTICE_FILES")
+	includeDir := filepath.Join(snapshotVariantDir, "include")
 	noticeBuilt := make(map[string]bool)
 
+	installSnapshotFileFromPath := func(path android.Path, out string) {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        android.Cp,
+			Input:       path,
+			Output:      android.PathForOutput(ctx, snapshotDir, out),
+			Description: "vndk snapshot " + out,
+			Args: map[string]string{
+				"cpFlags": "-f -L",
+			},
+		})
+		*outputs = append(*outputs, android.RuleBuilderInstall{
+			From: android.PathForOutput(ctx, snapshotDir, out),
+			To:   out,
+		})
+	}
+	installSnapshotFileFromContent := func(content, out string) {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        android.WriteFile,
+			Output:      android.PathForOutput(ctx, snapshotDir, out),
+			Description: "vndk snapshot " + out,
+			Args: map[string]string{
+				"content": content,
+			},
+		})
+		*outputs = append(*outputs, android.RuleBuilderInstall{
+			From: android.PathForOutput(ctx, snapshotDir, out),
+			To:   out,
+		})
+	}
+
 	tryBuildNotice := func(m *Module) {
-		name := ctx.ModuleName(m)
+		name := ctx.ModuleName(m) + ".so.txt"
 
 		if _, ok := noticeBuilt[name]; ok {
 			return
@@ -443,17 +438,7 @@
 		noticeBuilt[name] = true
 
 		if m.NoticeFile().Valid() {
-			out := android.PathForOutput(ctx, noticePath, name+".so.txt")
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        android.Cp,
-				Input:       m.NoticeFile().Path(),
-				Output:      out,
-				Description: "vndk snapshot notice " + name + ".so.txt",
-				Args: map[string]string{
-					"cpFlags": "-f -L",
-				},
-			})
-			outputs.notices = append(outputs.notices, out)
+			installSnapshotFileFromPath(m.NoticeFile().Path(), filepath.Join(noticeDir, name))
 		}
 	}
 
@@ -461,84 +446,160 @@
 	vndkSpLibraries := vndkSpLibraries(ctx.Config())
 	vndkPrivateLibraries := vndkPrivateLibraries(ctx.Config())
 
+	var generatedHeaders android.Paths
+	includeDirs := make(map[string]bool)
+
+	type vndkSnapshotLibraryInterface interface {
+		exportedFlagsProducer
+		libraryInterface
+	}
+
+	var _ vndkSnapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
+	var _ vndkSnapshotLibraryInterface = (*libraryDecorator)(nil)
+
+	installVndkSnapshotLib := func(m *Module, l vndkSnapshotLibraryInterface, dir string) bool {
+		name := ctx.ModuleName(m)
+		libOut := filepath.Join(dir, name+".so")
+
+		installSnapshotFileFromPath(m.outputFile.Path(), libOut)
+		tryBuildNotice(m)
+
+		if ctx.Config().VndkSnapshotBuildArtifacts() {
+			prop := struct {
+				ExportedDirs        []string `json:",omitempty"`
+				ExportedSystemDirs  []string `json:",omitempty"`
+				ExportedFlags       []string `json:",omitempty"`
+				RelativeInstallPath string   `json:",omitempty"`
+			}{}
+			prop.ExportedFlags = l.exportedFlags()
+			prop.ExportedDirs = l.exportedDirs()
+			prop.ExportedSystemDirs = l.exportedSystemDirs()
+			prop.RelativeInstallPath = m.RelativeInstallPath()
+
+			propOut := libOut + ".json"
+
+			j, err := json.Marshal(prop)
+			if err != nil {
+				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
+				return false
+			}
+
+			installSnapshotFileFromContent(string(j), propOut)
+		}
+		return true
+	}
+
+	isVndkSnapshotLibrary := func(m *Module) (i vndkSnapshotLibraryInterface, libDir string, isVndkSnapshotLib bool) {
+		if m.Target().NativeBridge == android.NativeBridgeEnabled {
+			return nil, "", false
+		}
+		if !m.useVndk() || !m.IsForPlatform() || !m.installable() {
+			return nil, "", false
+		}
+		l, ok := m.linker.(vndkSnapshotLibraryInterface)
+		if !ok || !l.shared() {
+			return nil, "", false
+		}
+		name := ctx.ModuleName(m)
+		if inList(name, *vndkCoreLibraries) {
+			return l, filepath.Join("shared", "vndk-core"), true
+		} else if inList(name, *vndkSpLibraries) {
+			return l, filepath.Join("shared", "vndk-sp"), true
+		} else {
+			return nil, "", false
+		}
+	}
+
 	ctx.VisitAllModules(func(module android.Module) {
 		m, ok := module.(*Module)
-		if !ok || !m.Enabled() || !m.useVndk() || !m.installable() {
+		if !ok || !m.Enabled() {
 			return
 		}
 
-		if m.Target().NativeBridge == android.NativeBridgeEnabled {
+		baseDir, ok := vndkLibDir[m.Target().Arch.ArchType]
+		if !ok {
 			return
 		}
 
-		lib, is_lib := m.linker.(*libraryDecorator)
-		prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
-
-		if !(is_lib && lib.shared()) && !(is_prebuilt_lib && prebuilt_lib.shared()) {
+		l, libDir, ok := isVndkSnapshotLibrary(m)
+		if !ok {
 			return
 		}
 
-		is_2nd := m.Target().Arch.ArchType != ctx.Config().DevicePrimaryArchType()
+		if !installVndkSnapshotLib(m, l, filepath.Join(baseDir, libDir)) {
+			return
+		}
 
-		name := ctx.ModuleName(module)
+		generatedHeaders = append(generatedHeaders, l.exportedDeps()...)
+		for _, dir := range append(l.exportedDirs(), l.exportedSystemDirs()...) {
+			includeDirs[dir] = true
+		}
+	})
 
-		if inList(name, *vndkCoreLibraries) {
-			if is_2nd {
-				out := installVndkSnapshotLib(ctx, name, m, vndkCoreLib2ndPath)
-				outputs.vndkCoreLibs2nd = append(outputs.vndkCoreLibs2nd, out)
-			} else {
-				out := installVndkSnapshotLib(ctx, name, m, vndkCoreLibPath)
-				outputs.vndkCoreLibs = append(outputs.vndkCoreLibs, out)
+	if ctx.Config().VndkSnapshotBuildArtifacts() {
+		headers := make(map[string]bool)
+
+		for _, dir := range android.SortedStringKeys(includeDirs) {
+			// workaround to determine if dir is under output directory
+			if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
+				continue
 			}
-			tryBuildNotice(m)
-		} else if inList(name, *vndkSpLibraries) {
-			if is_2nd {
-				out := installVndkSnapshotLib(ctx, name, m, vndkSpLib2ndPath)
-				outputs.vndkSpLibs2nd = append(outputs.vndkSpLibs2nd, out)
-			} else {
-				out := installVndkSnapshotLib(ctx, name, m, vndkSpLibPath)
-				outputs.vndkSpLibs = append(outputs.vndkSpLibs, out)
+			exts := headerExts
+			// Glob all files under this special directory, because of C++ headers.
+			if strings.HasPrefix(dir, "external/libcxx/include") {
+				exts = []string{""}
 			}
-			tryBuildNotice(m)
+			for _, ext := range exts {
+				glob, err := ctx.GlobWithDeps(dir+"/**/*"+ext, nil)
+				if err != nil {
+					ctx.Errorf("%#v\n", err)
+					return
+				}
+				for _, header := range glob {
+					if strings.HasSuffix(header, "/") {
+						continue
+					}
+					headers[header] = true
+				}
+			}
 		}
-	})
 
-	configsPath := filepath.Join(snapshotVariantPath, "configs")
-	vndkCoreTxt := android.PathForOutput(ctx, configsPath, "vndkcore.libraries.txt")
-	vndkPrivateTxt := android.PathForOutput(ctx, configsPath, "vndkprivate.libraries.txt")
-	modulePathTxt := android.PathForOutput(ctx, configsPath, "module_paths.txt")
+		for _, header := range android.SortedStringKeys(headers) {
+			installSnapshotFileFromPath(android.PathForSource(ctx, header),
+				filepath.Join(includeDir, header))
+		}
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      vndkCoreTxt,
-		Description: "vndk snapshot vndkcore.libraries.txt",
-		Args: map[string]string{
-			"content": android.JoinWithSuffix(*vndkCoreLibraries, ".so", "\\n"),
-		},
-	})
-	outputs.configs = append(outputs.configs, vndkCoreTxt)
+		isHeader := func(path string) bool {
+			for _, ext := range headerExts {
+				if strings.HasSuffix(path, ext) {
+					return true
+				}
+			}
+			return false
+		}
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      vndkPrivateTxt,
-		Description: "vndk snapshot vndkprivate.libraries.txt",
-		Args: map[string]string{
-			"content": android.JoinWithSuffix(*vndkPrivateLibraries, ".so", "\\n"),
-		},
-	})
-	outputs.configs = append(outputs.configs, vndkPrivateTxt)
+		for _, path := range android.PathsToDirectorySortedPaths(android.FirstUniquePaths(generatedHeaders)) {
+			header := path.String()
+
+			if !isHeader(header) {
+				continue
+			}
+
+			installSnapshotFileFromPath(path, filepath.Join(includeDir, header))
+		}
+	}
+
+	installSnapshotFileFromContent(android.JoinWithSuffix(*vndkCoreLibraries, ".so", "\\n"),
+		filepath.Join(configsDir, "vndkcore.libraries.txt"))
+	installSnapshotFileFromContent(android.JoinWithSuffix(*vndkPrivateLibraries, ".so", "\\n"),
+		filepath.Join(configsDir, "vndkprivate.libraries.txt"))
 
 	var modulePathTxtBuilder strings.Builder
 
 	modulePaths := modulePaths(ctx.Config())
-	var libs []string
-	for lib := range modulePaths {
-		libs = append(libs, lib)
-	}
-	sort.Strings(libs)
 
 	first := true
-	for _, lib := range libs {
+	for _, lib := range android.SortedStringKeys(modulePaths) {
 		if first {
 			first = false
 		} else {
@@ -549,13 +610,6 @@
 		modulePathTxtBuilder.WriteString(modulePaths[lib])
 	}
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      modulePathTxt,
-		Description: "vndk snapshot module_paths.txt",
-		Args: map[string]string{
-			"content": modulePathTxtBuilder.String(),
-		},
-	})
-	outputs.configs = append(outputs.configs, modulePathTxt)
+	installSnapshotFileFromContent(modulePathTxtBuilder.String(),
+		filepath.Join(configsDir, "module_paths.txt"))
 }
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 0ecf566..c8ff87f 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -61,6 +61,13 @@
 	// Prebuilt files for each arch.
 	Srcs []string `android:"arch_variant"`
 
+	// list of directories relative to the Blueprints file that will be added to the include
+	// path (using -isystem) for any module that links against this module.
+	Export_system_include_dirs []string `android:"arch_variant"`
+
+	// list of flags that will be used for any module that links against this module.
+	Export_flags []string `android:"arch_variant"`
+
 	// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols,
 	// etc).
 	Check_elf_files *bool
@@ -123,6 +130,9 @@
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 	if len(p.properties.Srcs) > 0 && p.shared() {
+		p.libraryDecorator.exportIncludes(ctx)
+		p.libraryDecorator.reexportSystemDirs(p.properties.Export_system_include_dirs...)
+		p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
 		// current VNDK prebuilts are only shared libs.
 		return p.singleSourcePath(ctx)
 	}