Add basic VNDK support in Soong

Export a list of libraries in the VNDK, which is currently empty.

Take in Make's global BOARD_VNDK_VERSION, and use that as the SDK
version for modules that specify use_vndk: true.

Modules that use the vndk have some configuration as if they were
building against the NDK (the absence of globally defined headers), but
in other cases look like platform modules (using the platform libc++,
for now).

This change does not attempt to enforce any linking constraints, that
will come in a later patch.

Test: out/soong/build.ninja doesn't change
Change-Id: I3be206b67015ac5177b7eef4a451c579e3dc903f
diff --git a/android/config.go b/android/config.go
index 725f43d..fdc7375 100644
--- a/android/config.go
+++ b/android/config.go
@@ -424,3 +424,10 @@
 	}
 	return arches
 }
+
+func (c *deviceConfig) VndkVersion() string {
+	if c.config.ProductVariables.DeviceVndkVersion == nil {
+		return ""
+	}
+	return *c.config.ProductVariables.DeviceVndkVersion
+}
diff --git a/android/variable.go b/android/variable.go
index c1948b0..3436a75 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -87,6 +87,7 @@
 	DeviceCpuVariant  *string   `json:",omitempty"`
 	DeviceAbi         *[]string `json:",omitempty"`
 	DeviceUsesClang   *bool     `json:",omitempty"`
+	DeviceVndkVersion *string   `json:",omitempty"`
 
 	DeviceSecondaryArch        *string   `json:",omitempty"`
 	DeviceSecondaryArchVariant *string   `json:",omitempty"`
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 6387ff1..5d9f1b4 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -77,6 +77,7 @@
 	"LOCAL_NO_STANDARD_LIBRARIES":   {"no_standard_libraries", bpparser.BoolType},
 	"LOCAL_PACK_MODULE_RELOCATIONS": {"pack_relocations", bpparser.BoolType},
 	"LOCAL_TIDY":                    {"tidy", bpparser.BoolType},
+	"LOCAL_USE_VNDK":                {"use_vndk", bpparser.BoolType},
 
 	"LOCAL_EXPORT_PACKAGE_RESOURCES": {"export_package_resources", bpparser.BoolType},
 }
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 50c183e..709ac59 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -59,6 +59,9 @@
 		if c.Target().Os == android.Android && c.Properties.Sdk_version != "" {
 			fmt.Fprintln(w, "LOCAL_SDK_VERSION := "+c.Properties.Sdk_version)
 			fmt.Fprintln(w, "LOCAL_NDK_STL_VARIANT := none")
+		} else if c.Target().Os == android.Android && c.Properties.Use_vndk {
+			fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+			fmt.Fprintln(w, "LOCAL_NDK_STL_VARIANT := none")
 		} else {
 			// These are already included in LOCAL_SHARED_LIBRARIES
 			fmt.Fprintln(w, "LOCAL_CXX_STL := none")
diff --git a/cc/binary.go b/cc/binary.go
index 2b77514..1aba6eb 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -93,7 +93,7 @@
 	deps = binary.baseLinker.linkerDeps(ctx, deps)
 	if ctx.toolchain().Bionic() {
 		if !Bool(binary.baseLinker.Properties.Nocrt) {
-			if !ctx.sdk() {
+			if !ctx.sdk() && !ctx.vndk() {
 				if binary.static() {
 					deps.CrtBegin = "crtbegin_static"
 				} else {
diff --git a/cc/cc.go b/cc/cc.go
index ddeede9..9062b00 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -125,6 +125,9 @@
 	// Minimum sdk version supported when compiling against the ndk
 	Sdk_version string
 
+	// Whether to compile against the VNDK
+	Use_vndk bool
+
 	// don't insert default compiler flags into asflags, cflags,
 	// cppflags, conlyflags, ldflags, or include_dirs
 	No_default_compiler_flags *bool
@@ -132,6 +135,7 @@
 	AndroidMkSharedLibs []string `blueprint:"mutated"`
 	HideFromMake        bool     `blueprint:"mutated"`
 	PreventInstall      bool     `blueprint:"mutated"`
+	Vndk_version        string   `blueprint:"mutated"`
 }
 
 type UnusedProperties struct {
@@ -147,6 +151,7 @@
 	noDefaultCompilerFlags() bool
 	sdk() bool
 	sdkVersion() string
+	vndk() bool
 	selectedStl() string
 	baseModuleName() string
 }
@@ -345,11 +350,22 @@
 
 func (ctx *moduleContextImpl) sdkVersion() string {
 	if ctx.ctx.Device() {
-		return ctx.mod.Properties.Sdk_version
+		if ctx.mod.Properties.Use_vndk {
+			return ctx.mod.Properties.Vndk_version
+		} else {
+			return ctx.mod.Properties.Sdk_version
+		}
 	}
 	return ""
 }
 
+func (ctx *moduleContextImpl) vndk() bool {
+	if ctx.ctx.Device() {
+		return ctx.mod.Properties.Use_vndk
+	}
+	return false
+}
+
 func (ctx *moduleContextImpl) selectedStl() string {
 	if stl := ctx.mod.stl; stl != nil {
 		return stl.Properties.SelectedStl
@@ -493,11 +509,22 @@
 		feature.begin(ctx)
 	}
 	if ctx.sdk() {
+		if ctx.vndk() {
+			ctx.PropertyErrorf("use_vndk",
+				"sdk_version and use_vndk cannot be used at the same time")
+		}
+
 		version, err := normalizeNdkApiLevel(ctx.sdkVersion(), ctx.Arch())
 		if err != nil {
 			ctx.PropertyErrorf("sdk_version", err.Error())
 		}
 		c.Properties.Sdk_version = version
+	} else if ctx.vndk() {
+		version, err := normalizeNdkApiLevel(ctx.DeviceConfig().VndkVersion(), ctx.Arch())
+		if err != nil {
+			ctx.ModuleErrorf("Bad BOARD_VNDK_VERSION: %s", err.Error())
+		}
+		c.Properties.Vndk_version = version
 	}
 }
 
@@ -579,7 +606,7 @@
 
 	variantNdkLibs := []string{}
 	variantLateNdkLibs := []string{}
-	if ctx.sdk() {
+	if ctx.sdk() || ctx.vndk() {
 		version := ctx.sdkVersion()
 
 		// Rewrites the names of shared libraries into the names of the NDK
diff --git a/cc/compiler.go b/cc/compiler.go
index 285bb69..def8d58 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -160,7 +160,7 @@
 	}
 
 	if !ctx.noDefaultCompilerFlags() {
-		if !ctx.sdk() || ctx.Host() {
+		if !(ctx.sdk() || ctx.vndk()) || ctx.Host() {
 			flags.GlobalFlags = append(flags.GlobalFlags,
 				"${config.CommonGlobalIncludes}",
 				"${config.CommonGlobalSystemIncludes}",
@@ -171,7 +171,7 @@
 		flags.GlobalFlags = append(flags.GlobalFlags, "-I"+android.PathForModuleSrc(ctx).String())
 	}
 
-	if ctx.sdk() {
+	if ctx.sdk() || ctx.vndk() {
 		// The NDK headers are installed to a common sysroot. While a more
 		// typical Soong approach would be to only make the headers for the
 		// library you're using available, we're trying to emulate the NDK
@@ -354,7 +354,7 @@
 var gnuToCReplacer = strings.NewReplacer("gnu", "c")
 
 func ndkPathDeps(ctx ModuleContext) android.Paths {
-	if ctx.sdk() {
+	if ctx.sdk() || ctx.vndk() {
 		// The NDK sysroot timestamp file depends on all the NDK sysroot files
 		// (headers and libraries).
 		return android.Paths{getNdkSysrootTimestampFile(ctx)}
diff --git a/cc/config/global.go b/cc/config/global.go
index e454c16..71c0da4 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -163,3 +163,7 @@
 		"-isystem bionic/libc/kernel/android/uapi",
 	}, " ")
 }
+
+func VndkLibraries() []string {
+	return []string{}
+}
diff --git a/cc/library.go b/cc/library.go
index 35d0089..7b7ac95 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -331,7 +331,7 @@
 		deps.SharedLibs = append(deps.SharedLibs, library.Properties.Static.Shared_libs...)
 	} else {
 		if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
-			if !ctx.sdk() {
+			if !ctx.sdk() && !ctx.vndk() {
 				deps.CrtBegin = "crtbegin_so"
 				deps.CrtEnd = "crtend_so"
 			} else {
diff --git a/cc/makevars.go b/cc/makevars.go
index 7f1063f..fe3440c 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -45,6 +45,13 @@
 	ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "")
 	ctx.Strict("NDK_PREBUILT_SHARED_LIBRARIES", strings.Join(ndkPrebuiltSharedLibs, " "))
 
+	if ctx.Config().ProductVariables.DeviceVndkVersion != nil {
+		ctx.Strict("BOARD_VNDK_VERSION", *ctx.Config().ProductVariables.DeviceVndkVersion)
+	} else {
+		ctx.Strict("BOARD_VNDK_VERSION", "")
+	}
+	ctx.Strict("VNDK_LIBRARIES", strings.Join(config.VndkLibraries(), " "))
+
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", asanCflags)
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", asanLdflags)
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", asanLibs)