Install VNDK libs in /system instead of /vendor

If BOARD_VNDK_VERSION is set, and a module is set to
`vendor_available: true` it is installed in /system and /vendor.

However, if the module is a VNDK library, it must be
installed at `/system/${LIB}/vndk` instead of /vendor/${LIB}.
For those modules, need following to set.

vendor_available: true,
vndk: {
    enabled: true,
    support_system_process: true,
},

`support_system_process` is optional to define.
If it is defined to true, the module is regarded as vndk-sp.

link-type check for VNDK modules is added to make sure that VNDK
modules only link to other VNDK shared libraries or LL-NDKs.

move the ABI checks to VNDK from all of vendor_available.

Bug: 38304436
Test: attempt to compile with BOARD_VNDK_VERSION:=current
Test: Use `vendor_available_vndk: true` for VNDK modules and compile
      with BOARD_VNDK_VERSION:=current
Change-Id: I409268e0b7f05a9d01697bf9f9f4726b5aac631f
diff --git a/cc/cc.go b/cc/cc.go
index c17b95e..8fc0ebd 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -183,6 +183,8 @@
 	sdk() bool
 	sdkVersion() string
 	vndk() bool
+	isVndk() bool
+	isVndkSp() bool
 	createVndkSourceAbiDump() bool
 	selectedStl() string
 	baseModuleName() string
@@ -291,6 +293,7 @@
 	sanitize  *sanitize
 	coverage  *coverage
 	sabi      *sabi
+	vndkdep   *vndkdep
 
 	androidMkSharedLibDeps []string
 
@@ -327,6 +330,9 @@
 	if c.sabi != nil {
 		c.AddProperties(c.sabi.props()...)
 	}
+	if c.vndkdep != nil {
+		c.AddProperties(c.vndkdep.props()...)
+	}
 	for _, feature := range c.features {
 		c.AddProperties(feature.props()...)
 	}
@@ -353,6 +359,13 @@
 	return c.Properties.UseVndk
 }
 
+func (c *Module) isVndk() bool {
+	if c.vndkdep != nil {
+		return c.vndkdep.isVndk()
+	}
+	return false
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
@@ -368,10 +381,10 @@
 	moduleContextImpl
 }
 
-// Vendor returns true for vendor modules so that they get installed onto the
-// correct partition
+// Vendor returns true for vendor modules excluding VNDK libraries so that
+// they get installed onto the correct partition
 func (ctx *moduleContext) Vendor() bool {
-	return ctx.ModuleContext.Vendor() || ctx.moduleContextImpl.mod.Properties.UseVndk
+	return ctx.ModuleContext.Vendor() || (ctx.mod.vndk() && !ctx.mod.isVndk())
 }
 
 type moduleContextImpl struct {
@@ -431,9 +444,20 @@
 	return ctx.mod.vndk()
 }
 
+func (ctx *moduleContextImpl) isVndk() bool {
+	return ctx.mod.isVndk()
+}
+
+func (ctx *moduleContextImpl) isVndkSp() bool {
+	if vndk := ctx.mod.vndkdep; vndk != nil {
+		return vndk.isVndkSp()
+	}
+	return false
+}
+
 // Create source abi dumps if the module belongs to the list of VndkLibraries.
 func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
-	return ctx.ctx.Device() && ((Bool(ctx.mod.Properties.Vendor_available)) || (inList(ctx.baseModuleName(), config.LLndkLibraries())))
+	return ctx.ctx.Device() && (ctx.mod.isVndk() || inList(ctx.baseModuleName(), config.LLndkLibraries()))
 }
 
 func (ctx *moduleContextImpl) selectedStl() string {
@@ -463,6 +487,7 @@
 	module.sanitize = &sanitize{}
 	module.coverage = &coverage{}
 	module.sabi = &sabi{}
+	module.vndkdep = &vndkdep{}
 	return module
 }
 
@@ -591,6 +616,9 @@
 	if c.sabi != nil {
 		c.sabi.begin(ctx)
 	}
+	if c.vndkdep != nil {
+		c.vndkdep.begin(ctx)
+	}
 	for _, feature := range c.features {
 		feature.begin(ctx)
 	}
@@ -624,6 +652,9 @@
 	if c.sabi != nil {
 		deps = c.sabi.deps(ctx, deps)
 	}
+	if c.vndkdep != nil {
+		deps = c.vndkdep.deps(ctx, deps)
+	}
 	for _, feature := range c.features {
 		deps = feature.deps(ctx, deps)
 	}
@@ -828,7 +859,12 @@
 			return
 		}
 		if from.Properties.UseVndk {
-			// Vendor code is already limited by the vendor mutator
+			// Though vendor code is limited by the vendor mutator,
+			// each vendor-available module needs to check
+			// link-type for VNDK.
+			if from.vndkdep != nil {
+				from.vndkdep.vndkCheckLinkType(ctx, to)
+			}
 			return
 		}
 		if from.Properties.Sdk_version == "" {
@@ -1169,6 +1205,18 @@
 			"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
 		return
 	}
+	if vndk := m.vndkdep; vndk != nil {
+		if vndk.isVndk() && !Bool(m.Properties.Vendor_available) {
+			mctx.PropertyErrorf("vndk",
+				"has to define `vendor_available: true` to enable vndk")
+			return
+		}
+		if !vndk.isVndk() && vndk.isVndkSp() {
+			mctx.PropertyErrorf("vndk",
+				"must set `enabled: true` to set `support_system_process: true`")
+			return
+		}
+	}
 
 	if !mctx.DeviceConfig().CompileVndk() {
 		// If the device isn't compiling against the VNDK, we always
@@ -1180,6 +1228,7 @@
 		mctx.CreateVariations(vendorMode)
 	} else if Bool(m.Properties.Vendor_available) {
 		// This will be available in both /system and /vendor
+		// or a /system directory that is available to vendor.
 		mod := mctx.CreateVariations(coreMode, vendorMode)
 		mod[1].(*Module).Properties.UseVndk = true
 	} else if mctx.Vendor() && m.Properties.Sdk_version == "" {
diff --git a/cc/installer.go b/cc/installer.go
index 112a7ea..7bedc56 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -48,6 +48,7 @@
 
 	dir      string
 	dir64    string
+	subDir   string
 	relative string
 	location installLocation
 
@@ -61,17 +62,17 @@
 }
 
 func (installer *baseInstaller) installDir(ctx ModuleContext) android.OutputPath {
-	subDir := installer.dir
+	dir := installer.dir
 	if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
-		subDir = installer.dir64
+		dir = installer.dir64
 	}
 	if !ctx.Host() && !ctx.Arch().Native {
-		subDir = filepath.Join(subDir, ctx.Arch().ArchType.String())
+		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
 	if installer.location == InstallInData && ctx.vndk() {
-		subDir = filepath.Join(subDir, "vendor")
+		dir = filepath.Join(dir, "vendor")
 	}
-	return android.PathForModuleInstall(ctx, subDir, installer.Properties.Relative_install_path, installer.relative)
+	return android.PathForModuleInstall(ctx, dir, installer.subDir, installer.Properties.Relative_install_path, installer.relative)
 }
 
 func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) {
diff --git a/cc/library.go b/cc/library.go
index c7c1142..3d463bd 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -156,7 +156,7 @@
 }
 
 func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths {
-	if ctx.Vendor() && f.Properties.Target.Vendor.Export_include_dirs != nil {
+	if ctx.vndk() && f.Properties.Target.Vendor.Export_include_dirs != nil {
 		return android.PathsForModuleSrc(ctx, f.Properties.Target.Vendor.Export_include_dirs)
 	} else {
 		return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs)
@@ -351,7 +351,7 @@
 		}
 		return Objects{}
 	}
-	if (ctx.createVndkSourceAbiDump() || (library.sabi.Properties.CreateSAbiDumps && ctx.Device())) && !ctx.Vendor() {
+	if ctx.createVndkSourceAbiDump() {
 		exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
@@ -596,7 +596,7 @@
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
 	//Also take into account object re-use.
-	if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() && !ctx.Vendor() {
+	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
@@ -699,6 +699,15 @@
 
 func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if library.shared() {
+		if ctx.Device() {
+			if ctx.vndk() {
+				if ctx.isVndkSp() {
+					library.baseInstaller.subDir = "vndk-sp"
+				} else if ctx.isVndk() {
+					library.baseInstaller.subDir = "vndk"
+				}
+			}
+		}
 		library.baseInstaller.install(ctx, file)
 	}
 }
diff --git a/cc/sabi.go b/cc/sabi.go
index 9aff738..318d198 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -72,7 +72,7 @@
 
 func sabiDepsMutator(mctx android.TopDownMutatorContext) {
 	if c, ok := mctx.Module().(*Module); ok &&
-		(Bool(c.Properties.Vendor_available) || (inList(c.Name(), config.LLndkLibraries())) ||
+		(c.isVndk() || inList(c.Name(), config.LLndkLibraries()) ||
 			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
 		mctx.VisitDirectDeps(func(m blueprint.Module) {
 			tag := mctx.OtherModuleDependencyTag(m)
diff --git a/cc/vndk.go b/cc/vndk.go
new file mode 100644
index 0000000..fd1bdcb
--- /dev/null
+++ b/cc/vndk.go
@@ -0,0 +1,98 @@
+// 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"
+)
+
+type VndkProperties struct {
+	Vndk struct {
+		// declared as a VNDK or VNDK-SP module. The vendor variant
+		// will be installed in /system instead of /vendor partition.
+		//
+		// `vendor_available: true` must set to together for VNDK
+		// modules.
+		Enabled *bool
+
+		// declared as a VNDK-SP module, which is a subset of VNDK.
+		//
+		// `vndk: { enabled: true }` must set together.
+		//
+		// All these modules are allowed to link to VNDK-SP or LL-NDK
+		// modules only. Other dependency will cause link-type errors.
+		//
+		// If `support_system_process` is not set or set to false,
+		// the module is VNDK-core and can link to other VNDK-core,
+		// VNDK-SP or LL-NDK modules only.
+		Support_system_process *bool
+	}
+}
+
+type vndkdep struct {
+	Properties VndkProperties
+}
+
+func (vndk *vndkdep) props() []interface{} {
+	return []interface{}{&vndk.Properties}
+}
+
+func (vndk *vndkdep) begin(ctx BaseModuleContext) {}
+
+func (vndk *vndkdep) deps(ctx BaseModuleContext, deps Deps) Deps {
+	return deps
+}
+
+func (vndk *vndkdep) isVndk() bool {
+	return Bool(vndk.Properties.Vndk.Enabled)
+}
+
+func (vndk *vndkdep) isVndkSp() bool {
+	return Bool(vndk.Properties.Vndk.Support_system_process)
+}
+
+func (vndk *vndkdep) typeName() string {
+	if !vndk.isVndk() {
+		return "native:vendor"
+	}
+	if !vndk.isVndkSp() {
+		return "native:vendor:vndk"
+	}
+	return "native:vendor:vndksp"
+}
+
+func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module) {
+	if to.linker == nil {
+		return
+	}
+	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
+		// Check only shared libraries.
+		// Other (static and LL-NDK) libraries are allowed to link.
+		return
+	}
+	if !to.Properties.UseVndk {
+		ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
+			vndk.typeName(), to.Name())
+		return
+	}
+	if to.vndkdep == nil {
+		return
+	}
+	if (vndk.isVndk() && !to.vndkdep.isVndk()) || (vndk.isVndkSp() && !to.vndkdep.isVndkSp()) {
+		ctx.ModuleErrorf("(%s) should not link to %q(%s)",
+			vndk.typeName(), to.Name(), to.vndkdep.typeName())
+		return
+	}
+}