Split /system and /vendor modules, allow multi-installation

Nothing changes if BOARD_VNDK_VERSION isn't set.

When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split
/system and /vendor modules into two different variant spaces that can't
link to each other. There are a few interfaces between the two variant
spaces:

The `llndk_library` stubs will be available in the /vendor variant, but
won't be installed, so at runtime the /system variant will be used.

Setting `vendor_available: true` will split a module into both variants.
The /system (or "core") variant will compile just like today. The
/vendor ("vendor") variant will compile against everything else in the
vendor space (so LL-NDK instead of libc/liblog/etc). There will be two
copies of these libraries installed onto the final device.

Since the available runtime interfaces for vendor modules may be
reduced, and your dependencies may not expose their private interfaces,
we allow the vendor variants to reduce their compilation set, and export
a different set of headers:

  cc_library {
      name: "libfoo",
      srcs: ["common.cpp", "private_impl.cpp"],
      export_include_dirs: ["include"],
      target: {
          vendor: {
	      export_include_dirs: ["include_vndk"],
	      exclude_srcs: ["private_impl.cpp"],
	      srcs: ["vendor_only.cpp"],
	  },
      },
  }

So the "core" variant would compile with both "common.cpp" and
"private_impl.cpp", and export "include".

The "vendor" variant would compile "common.cpp" and "vendor_only.cpp",
and export "include_vndk".

Bug: 36426473
Bug: 36079834
Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and
      .llndk -> .vendor
Test: attempt to compile with BOARD_VNDK_VERSION:=current
Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
diff --git a/cc/androidmk.go b/cc/androidmk.go
index fa7ce42..59a1db8 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -26,6 +26,7 @@
 type AndroidMkContext interface {
 	Target() android.Target
 	subAndroidMk(*android.AndroidMkData, interface{})
+	vndk() bool
 }
 
 type subAndroidMkProvider interface {
@@ -56,13 +57,16 @@
 		if len(c.Properties.AndroidMkSharedLibs) > 0 {
 			fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(c.Properties.AndroidMkSharedLibs, " "))
 		}
-		if c.Target().Os == android.Android && c.Properties.Sdk_version != "" {
+		if c.Target().Os == android.Android && c.Properties.Sdk_version != "" && !c.vndk() {
 			fmt.Fprintln(w, "LOCAL_SDK_VERSION := "+c.Properties.Sdk_version)
 			fmt.Fprintln(w, "LOCAL_NDK_STL_VARIANT := none")
 		} else {
 			// These are already included in LOCAL_SHARED_LIBRARIES
 			fmt.Fprintln(w, "LOCAL_CXX_STL := none")
 		}
+		if c.vndk() {
+			fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+		}
 		return nil
 	})
 
@@ -74,6 +78,10 @@
 	c.subAndroidMk(&ret, c.linker)
 	c.subAndroidMk(&ret, c.installer)
 
+	if c.vndk() {
+		ret.SubName += ".vendor"
+	}
+
 	return ret, nil
 }
 
@@ -118,6 +126,8 @@
 			if host {
 				fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", ctx.Target().Os.String())
 				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
+			} else if ctx.vndk() {
+				fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
 			}
 
 			library.androidMkWriteExportedFlags(w)
@@ -301,7 +311,7 @@
 
 func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	ret.Class = "SHARED_LIBRARIES"
-	ret.SubName = llndkLibrarySuffix
+	ret.SubName = ".vendor"
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
 		c.libraryDecorator.androidMkWriteExportedFlags(w)
@@ -311,6 +321,7 @@
 		fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=")
 		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+		fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
 
 		return nil
 	})
diff --git a/cc/binary.go b/cc/binary.go
index 2578311..b4610ed 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -108,7 +108,7 @@
 	deps = binary.baseLinker.linkerDeps(ctx, deps)
 	if ctx.toolchain().Bionic() {
 		if !Bool(binary.baseLinker.Properties.Nocrt) {
-			if !ctx.sdk() && !ctx.vndk() {
+			if !ctx.sdk() {
 				if binary.static() {
 					deps.CrtBegin = "crtbegin_static"
 				} else {
diff --git a/cc/cc.go b/cc/cc.go
index ae203a3..63caf3a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -35,6 +35,7 @@
 
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("link", linkageMutator).Parallel()
+		ctx.BottomUp("image", vendorMutator).Parallel()
 		ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
 		ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
 		ctx.BottomUp("begin", beginMutator).Parallel()
@@ -143,9 +144,24 @@
 	// cppflags, conlyflags, ldflags, or include_dirs
 	No_default_compiler_flags *bool
 
+	// whether this module should be allowed to install onto /vendor as
+	// well as /system. The two variants will be built separately, one
+	// like normal, and the other limited to the set of libraries and
+	// headers that are exposed to /vendor modules.
+	//
+	// The vendor variant may be used with a different (newer) /system,
+	// so it shouldn't have any unversioned runtime dependencies, or
+	// make assumptions about the system that may not be true in the
+	// future.
+	//
+	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
+	Vendor_available *bool
+
 	AndroidMkSharedLibs []string `blueprint:"mutated"`
 	HideFromMake        bool     `blueprint:"mutated"`
 	PreventInstall      bool     `blueprint:"mutated"`
+
+	UseVndk bool `blueprint:"mutated"`
 }
 
 type UnusedProperties struct {
@@ -320,6 +336,10 @@
 	return false
 }
 
+func (c *Module) vndk() bool {
+	return c.Properties.UseVndk
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
@@ -335,6 +355,12 @@
 	moduleContextImpl
 }
 
+// Vendor returns true for vendor modules so that they get installed onto the
+// correct partition
+func (ctx *moduleContext) Vendor() bool {
+	return ctx.ModuleContext.Vendor() || ctx.moduleContextImpl.mod.Properties.UseVndk
+}
+
 type moduleContextImpl struct {
 	mod *Module
 	ctx BaseModuleContext
@@ -371,7 +397,7 @@
 }
 
 func (ctx *moduleContextImpl) sdk() bool {
-	if ctx.ctx.Device() {
+	if ctx.ctx.Device() && !ctx.vndk() {
 		return ctx.mod.Properties.Sdk_version != ""
 	}
 	return false
@@ -389,7 +415,7 @@
 }
 
 func (ctx *moduleContextImpl) vndk() bool {
-	return ctx.ctx.Os() == android.Android && ctx.ctx.Vendor() && ctx.ctx.DeviceConfig().CompileVndk()
+	return ctx.mod.vndk()
 }
 
 func (ctx *moduleContextImpl) selectedStl() string {
@@ -772,6 +798,10 @@
 			// Host code is not restricted
 			return
 		}
+		if from.Properties.UseVndk {
+			// Vendor code is already limited by the vendor mutator
+			return
+		}
 		if from.Properties.Sdk_version == "" {
 			// Platform code can link to anything
 			return
@@ -1060,6 +1090,57 @@
 	return android.InitDefaultsModule(module, module, props...)
 }
 
+const (
+	// coreMode is the variant used for framework-private libraries, or
+	// SDK libraries. (which framework-private libraries can use)
+	coreMode = "core"
+
+	// vendorMode is the variant used for /vendor code that compiles
+	// against the VNDK.
+	vendorMode = "vendor"
+)
+
+func vendorMutator(mctx android.BottomUpMutatorContext) {
+	if mctx.Os() != android.Android {
+		return
+	}
+
+	m, ok := mctx.Module().(*Module)
+	if !ok {
+		return
+	}
+
+	// Sanity check
+	if Bool(m.Properties.Vendor_available) && mctx.Vendor() {
+		mctx.PropertyErrorf("vendor_available",
+			"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
+		return
+	}
+
+	if !mctx.DeviceConfig().CompileVndk() {
+		// If the device isn't compiling against the VNDK, we always
+		// use the core mode.
+		mctx.CreateVariations(coreMode)
+	} else if _, ok := m.linker.(*llndkStubDecorator); ok {
+		// LL-NDK stubs only exist in the vendor variant, since the
+		// real libraries will be used in the core variant.
+		mctx.CreateVariations(vendorMode)
+	} else if Bool(m.Properties.Vendor_available) {
+		// This will be available in both /system and /vendor
+		mod := mctx.CreateVariations(coreMode, vendorMode)
+		mod[1].(*Module).Properties.UseVndk = true
+	} else if mctx.Vendor() && m.Properties.Sdk_version == "" {
+		// This will be available in /vendor only
+		mod := mctx.CreateVariations(vendorMode)
+		mod[0].(*Module).Properties.UseVndk = true
+	} else {
+		// This is either in /system (or similar: /data), or is a
+		// modules built with the NDK. Modules built with the NDK
+		// will be restricted using the existing link type checks.
+		mctx.CreateVariations(coreMode)
+	}
+}
+
 // lastUniqueElements returns all unique elements of a slice, keeping the last copy of each
 // modifies the slice contents in place, and returns a subslice of the original slice
 func lastUniqueElements(list []string) []string {
diff --git a/cc/compiler.go b/cc/compiler.go
index 9fc2747..aed4480 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -113,6 +113,18 @@
 		// release builds
 		Cflags []string `android:"arch_variant"`
 	} `android:"arch_variant"`
+
+	Target struct {
+		Vendor struct {
+			// list of source files that should only be used in the
+			// vendor variant of the C/C++ module.
+			Srcs []string
+
+			// list of source files that should not be used to
+			// build the vendor variant of the C/C++ module.
+			Exclude_srcs []string
+		}
+	}
 }
 
 func NewBaseCompiler() *baseCompiler {
@@ -429,6 +441,14 @@
 	pathDeps := deps.GeneratedHeaders
 	pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
 
+	if ctx.vndk() {
+		compiler.Properties.Srcs = append(compiler.Properties.Srcs,
+			compiler.Properties.Target.Vendor.Srcs...)
+
+		compiler.Properties.Exclude_srcs = append(compiler.Properties.Exclude_srcs,
+			compiler.Properties.Target.Vendor.Exclude_srcs...)
+	}
+
 	srcs := ctx.ExpandSources(compiler.Properties.Srcs, compiler.Properties.Exclude_srcs)
 	srcs = append(srcs, deps.GeneratedSources...)
 
diff --git a/cc/installer.go b/cc/installer.go
index c4de589..112a7ea 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -68,6 +68,9 @@
 	if !ctx.Host() && !ctx.Arch().Native {
 		subDir = filepath.Join(subDir, ctx.Arch().ArchType.String())
 	}
+	if installer.location == InstallInData && ctx.vndk() {
+		subDir = filepath.Join(subDir, "vendor")
+	}
 	return android.PathForModuleInstall(ctx, subDir, installer.Properties.Relative_install_path, installer.relative)
 }
 
diff --git a/cc/library.go b/cc/library.go
index e9e796e..0ba7088 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -84,6 +84,16 @@
 	// be added to the include path (using -I) for this module and any module that links
 	// against this module
 	Export_include_dirs []string `android:"arch_variant"`
+
+	Target struct {
+		Vendor struct {
+			// list of exported include directories, like
+			// export_include_dirs, that will be applied to the
+			// vendor variant of this library. This will overwrite
+			// any other declarations.
+			Export_include_dirs []string
+		}
+	}
 }
 
 func init() {
@@ -144,8 +154,16 @@
 	flagsDeps android.Paths
 }
 
+func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths {
+	if ctx.Vendor() && 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)
+	}
+}
+
 func (f *flagExporter) exportIncludes(ctx ModuleContext, inc string) {
-	includeDirs := android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs)
+	includeDirs := f.exportedIncludes(ctx)
 	for _, dir := range includeDirs.Strings() {
 		f.flags = append(f.flags, inc+dir)
 	}
@@ -277,7 +295,7 @@
 }
 
 func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
-	exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs)
+	exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 	if len(exportIncludeDirs) > 0 {
 		flags.GlobalFlags = append(flags.GlobalFlags, includeDirsToFlags(exportIncludeDirs))
 	}
@@ -369,7 +387,7 @@
 		deps.SharedLibs = append(deps.SharedLibs, library.Properties.Static.Shared_libs...)
 	} else if library.shared() {
 		if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
-			if !ctx.sdk() && !ctx.vndk() {
+			if !ctx.sdk() {
 				deps.CrtBegin = "crtbegin_so"
 				deps.CrtEnd = "crtend_so"
 			} else {
diff --git a/cc/linker.go b/cc/linker.go
index 4d21d99..5a3b478 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -143,7 +143,7 @@
 			if linker.Properties.System_shared_libs != nil {
 				deps.LateSharedLibs = append(deps.LateSharedLibs,
 					linker.Properties.System_shared_libs...)
-			} else if !ctx.sdk() {
+			} else if !ctx.sdk() && !ctx.vndk() {
 				deps.LateSharedLibs = append(deps.LateSharedLibs, "libc", "libm")
 			}
 		}
@@ -154,6 +154,9 @@
 				"libm",
 			)
 		}
+		if ctx.vndk() {
+			deps.LateSharedLibs = append(deps.LateSharedLibs, "libc", "libm")
+		}
 	}
 
 	if ctx.Windows() {
diff --git a/cc/makevars.go b/cc/makevars.go
index cad76f9..ce2ac5a 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -57,8 +57,6 @@
 	} else {
 		ctx.Strict("BOARD_VNDK_VERSION", "")
 	}
-	ctx.Strict("VNDK_LIBRARIES", strings.Join(config.VndkLibraries(), " "))
-	ctx.Strict("LLNDK_LIBRARIES", strings.Join(config.LLndkLibraries(), " "))
 
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", asanCflags)
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", asanLdflags)