Merge "Add PLATFORM_SYSTEMSDK_VERSIONS and BOARD_SYSTEMSDK_VERSIONS"
diff --git a/OWNERS b/OWNERS
index 004d638..c0c3762 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,7 +1,9 @@
 ccross@android.com
 dwillemsen@google.com
+nanzhang@google.com
 
 per-file * = ccross@android.com
 per-file * = dwillemsen@google.com
+per-file * = nanzhang@google.com
 per-file *gen_stub_libs.py = danalbert@google.com
 per-file ndk_*.go = danalbert@google.com
diff --git a/cc/builder.go b/cc/builder.go
index fcc4318..fe35d5c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -38,7 +38,6 @@
 
 var (
 	abiCheckAllowFlags = []string{
-		"-allow-extensions",
 		"-allow-unreferenced-changes",
 		"-allow-unreferenced-elf-symbol-changes",
 	}
@@ -711,8 +710,18 @@
 }
 
 func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
-	baseName string) android.OptionalPath {
+	baseName, exportedHeaderFlags string, isVndkExt bool) android.OptionalPath {
+
 	outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
+
+	localAbiCheckAllowFlags := append([]string(nil), abiCheckAllowFlags...)
+	if exportedHeaderFlags == "" {
+		localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-advice-only")
+	}
+	if isVndkExt {
+		localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-allow-extensions")
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        sAbiDiff,
 		Description: "header-abi-diff " + outputFile.Base(),
@@ -723,7 +732,7 @@
 			"referenceDump": referenceDump.String(),
 			"libName":       baseName,
 			"arch":          ctx.Arch().ArchType.Name,
-			"allowFlags":    strings.Join(abiCheckAllowFlags, " "),
+			"allowFlags":    strings.Join(localAbiCheckAllowFlags, " "),
 		},
 	})
 	return android.OptionalPathForPath(outputFile)
diff --git a/cc/cc.go b/cc/cc.go
index e5a483d..9b1f220 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -205,9 +205,11 @@
 	useVndk() bool
 	isVndk() bool
 	isVndkSp() bool
+	isVndkExt() bool
 	createVndkSourceAbiDump() bool
 	selectedStl() string
 	baseModuleName() string
+	getVndkExtendsModuleName() string
 }
 
 type ModuleContext interface {
@@ -289,6 +291,7 @@
 	reuseObjTag           = dependencyTag{name: "reuse objects"}
 	ndkStubDepTag         = dependencyTag{name: "ndk stub", library: true}
 	ndkLateStubDepTag     = dependencyTag{name: "ndk late stub", library: true}
+	vndkExtDepTag         = dependencyTag{name: "vndk extends", library: true}
 )
 
 // Module contains the properties and members used by all C/C++ module types, and implements
@@ -398,12 +401,33 @@
 }
 
 func (c *Module) isVndk() bool {
-	if c.vndkdep != nil {
-		return c.vndkdep.isVndk()
+	if vndkdep := c.vndkdep; vndkdep != nil {
+		return vndkdep.isVndk()
 	}
 	return false
 }
 
+func (c *Module) isVndkSp() bool {
+	if vndkdep := c.vndkdep; vndkdep != nil {
+		return vndkdep.isVndkSp()
+	}
+	return false
+}
+
+func (c *Module) isVndkExt() bool {
+	if vndkdep := c.vndkdep; vndkdep != nil {
+		return vndkdep.isVndkExt()
+	}
+	return false
+}
+
+func (c *Module) getVndkExtendsModuleName() string {
+	if vndkdep := c.vndkdep; vndkdep != nil {
+		return vndkdep.getVndkExtendsModuleName()
+	}
+	return ""
+}
+
 // Returns true only when this module is configured to have core and vendor
 // variants.
 func (c *Module) hasVendorVariant() bool {
@@ -474,18 +498,20 @@
 	return ""
 }
 
-func (ctx *moduleContextImpl) isVndk() bool {
-	return ctx.mod.isVndk()
-}
 func (ctx *moduleContextImpl) useVndk() bool {
 	return ctx.mod.useVndk()
 }
 
+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
+	return ctx.mod.isVndkSp()
+}
+
+func (ctx *moduleContextImpl) isVndkExt() bool {
+	return ctx.mod.isVndkExt()
 }
 
 // Create source abi dumps if the module belongs to the list of VndkLibraries.
@@ -504,6 +530,10 @@
 	return ctx.mod.ModuleBase.BaseModuleName()
 }
 
+func (ctx *moduleContextImpl) getVndkExtendsModuleName() string {
+	return ctx.mod.getVndkExtendsModuleName()
+}
+
 func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	return &Module{
 		hod:      hod,
@@ -935,6 +965,18 @@
 		{"ndk_api", version}, {"link", "shared"}}, ndkStubDepTag, variantNdkLibs...)
 	actx.AddVariationDependencies([]blueprint.Variation{
 		{"ndk_api", version}, {"link", "shared"}}, ndkLateStubDepTag, variantLateNdkLibs...)
+
+	if vndkdep := c.vndkdep; vndkdep != nil {
+		if vndkdep.isVndkExt() {
+			baseModuleMode := vendorMode
+			if actx.DeviceConfig().VndkVersion() == "" {
+				baseModuleMode = coreMode
+			}
+			actx.AddVariationDependencies([]blueprint.Variation{
+				{"image", baseModuleMode}, {"link", "shared"}}, vndkExtDepTag,
+				vndkdep.getVndkExtendsModuleName())
+		}
+	}
 }
 
 func beginMutator(ctx android.BottomUpMutatorContext) {
@@ -959,7 +1001,7 @@
 
 // Whether a module can link to another module, taking into
 // account NDK linking.
-func checkLinkType(ctx android.ModuleContext, from *Module, to *Module) {
+func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag dependencyTag) {
 	if from.Target().Os != android.Android {
 		// Host code is not restricted
 		return
@@ -969,7 +1011,7 @@
 		// each vendor-available module needs to check
 		// link-type for VNDK.
 		if from.vndkdep != nil {
-			from.vndkdep.vndkCheckLinkType(ctx, to)
+			from.vndkdep.vndkCheckLinkType(ctx, to, tag)
 		}
 		return
 	}
@@ -1151,7 +1193,7 @@
 				}
 			}
 
-			checkLinkType(ctx, c, ccDep)
+			checkLinkType(ctx, c, ccDep, t)
 		}
 
 		var ptr *android.Paths
@@ -1411,21 +1453,47 @@
 	}
 
 	// Sanity check
-	if m.VendorProperties.Vendor_available != nil && (mctx.SocSpecific() || mctx.DeviceSpecific()) {
+	vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+
+	if m.VendorProperties.Vendor_available != nil && vendorSpecific {
 		mctx.PropertyErrorf("vendor_available",
 			"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
 		return
 	}
-	if vndk := m.vndkdep; vndk != nil {
-		if vndk.isVndk() && m.VendorProperties.Vendor_available == nil {
-			mctx.PropertyErrorf("vndk",
-				"vendor_available must be set to either true or false when `vndk: {enabled: true}`")
-			return
-		}
-		if !vndk.isVndk() && vndk.isVndkSp() {
-			mctx.PropertyErrorf("vndk",
-				"must set `enabled: true` to set `support_system_process: true`")
-			return
+
+	if vndkdep := m.vndkdep; vndkdep != nil {
+		if vndkdep.isVndk() {
+			if vendorSpecific {
+				if !vndkdep.isVndkExt() {
+					mctx.PropertyErrorf("vndk",
+						"must set `extends: \"...\"` to vndk extension")
+					return
+				}
+			} else {
+				if vndkdep.isVndkExt() {
+					mctx.PropertyErrorf("vndk",
+						"must set `vendor: true` to set `extends: %q`",
+						m.getVndkExtendsModuleName())
+					return
+				}
+				if m.VendorProperties.Vendor_available == nil {
+					mctx.PropertyErrorf("vndk",
+						"vendor_available must be set to either true or false when `vndk: {enabled: true}`")
+					return
+				}
+			}
+		} else {
+			if vndkdep.isVndkSp() {
+				mctx.PropertyErrorf("vndk",
+					"must set `enabled: true` to set `support_system_process: true`")
+				return
+			}
+			if vndkdep.isVndkExt() {
+				mctx.PropertyErrorf("vndk",
+					"must set `enabled: true` to set `extends: %q`",
+					m.getVndkExtendsModuleName())
+				return
+			}
 		}
 	}
 
@@ -1442,20 +1510,25 @@
 		mod := mctx.CreateVariations(vendorMode)
 		vendor := mod[0].(*Module)
 		vendor.Properties.UseVndk = true
-	} else if _, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+	} else if prebuilt, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
 		mod := mctx.CreateVariations(vendorMode)
 		vendor := mod[0].(*Module)
 		vendor.Properties.UseVndk = true
-	} else if m.hasVendorVariant() {
+		arches := mctx.DeviceConfig().Arches()
+		if len(arches) == 0 || arches[0].ArchType.String() != prebuilt.arch() {
+			vendor.Properties.PreventInstall = true
+			vendor.Properties.HideFromMake = true
+		}
+	} else if m.hasVendorVariant() && !vendorSpecific {
 		// This will be available in both /system and /vendor
 		// or a /system directory that is available to vendor.
 		mod := mctx.CreateVariations(coreMode, vendorMode)
 		vendor := mod[1].(*Module)
 		vendor.Properties.UseVndk = true
 		squashVendorSrcs(vendor)
-	} else if (mctx.SocSpecific() || mctx.DeviceSpecific()) && String(m.Properties.Sdk_version) == "" {
+	} else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
 		// This will be available in /vendor (or /odm) only
 		mod := mctx.CreateVariations(vendorMode)
 		vendor := mod[0].(*Module)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 4d8c4fb..19e4703 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -22,6 +22,7 @@
 	"io/ioutil"
 	"os"
 	"reflect"
+	"regexp"
 	"sort"
 	"strings"
 	"testing"
@@ -52,10 +53,7 @@
 	os.Exit(run())
 }
 
-func testCc(t *testing.T, bp string) *android.TestContext {
-	config := android.TestArchConfig(buildDir, nil)
-	config.ProductVariables.DeviceVndkVersion = StringPtr("current")
-
+func createTestContext(t *testing.T, config android.Config, bp string) *android.TestContext {
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
@@ -90,8 +88,8 @@
 
 		cc_library {
 			name: "libc",
-			no_libgcc : true,
-			nocrt : true,
+			no_libgcc: true,
+			nocrt: true,
 			system_shared_libs: [],
 		}
 		llndk_library {
@@ -100,8 +98,8 @@
 		}
 		cc_library {
 			name: "libm",
-			no_libgcc : true,
-			nocrt : true,
+			no_libgcc: true,
+			nocrt: true,
 			system_shared_libs: [],
 		}
 		llndk_library {
@@ -110,8 +108,8 @@
 		}
 		cc_library {
 			name: "libdl",
-			no_libgcc : true,
-			nocrt : true,
+			no_libgcc: true,
+			nocrt: true,
 			system_shared_libs: [],
 		}
 		llndk_library {
@@ -142,6 +140,12 @@
 		"my_include": nil,
 	})
 
+	return ctx
+}
+
+func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.TestContext {
+	ctx := createTestContext(t, config, bp)
+
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	failIfErrored(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
@@ -150,14 +154,56 @@
 	return ctx
 }
 
+func testCc(t *testing.T, bp string) *android.TestContext {
+	config := android.TestArchConfig(buildDir, nil)
+	config.ProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+
+	return testCcWithConfig(t, bp, config)
+}
+
+func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
+	config := android.TestArchConfig(buildDir, nil)
+	config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+
+	return testCcWithConfig(t, bp, config)
+}
+
+func testCcError(t *testing.T, pattern string, bp string) {
+	config := android.TestArchConfig(buildDir, nil)
+	config.ProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+
+	ctx := createTestContext(t, config, bp)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	if len(errs) > 0 {
+		failIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+
+	_, errs = ctx.PrepareBuildActions(config)
+	if len(errs) > 0 {
+		failIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+
+	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+const (
+	coreVariant   = "android_arm64_armv8-a_core_shared"
+	vendorVariant = "android_arm64_armv8-a_vendor_shared"
+)
+
 func TestVendorSrc(t *testing.T) {
 	ctx := testCc(t, `
 		cc_library {
 			name: "libTest",
 			srcs: ["foo.c"],
-			no_libgcc : true,
-			nocrt : true,
-			system_shared_libs : [],
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
 			vendor_available: true,
 			target: {
 				vendor: {
@@ -167,7 +213,7 @@
 		}
 	`)
 
-	ld := ctx.ModuleForTests("libTest", "android_arm_armv7-a-neon_vendor_shared").Rule("ld")
+	ld := ctx.ModuleForTests("libTest", vendorVariant).Rule("ld")
 	var objs []string
 	for _, o := range ld.Inputs {
 		objs = append(objs, o.Base())
@@ -177,6 +223,524 @@
 	}
 }
 
+func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string,
+	isVndkSp bool, extends string) {
+
+	mod := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
+	if !mod.hasVendorVariant() {
+		t.Error("%q must have vendor variant", name)
+	}
+
+	// Check library properties.
+	lib, ok := mod.compiler.(*libraryDecorator)
+	if !ok {
+		t.Errorf("%q must have libraryDecorator", name)
+	} else if lib.baseInstaller.subDir != subDir {
+		t.Errorf("%q must use %q as subdir but it is using %q", name, subDir,
+			lib.baseInstaller.subDir)
+	}
+
+	// Check VNDK properties.
+	if mod.vndkdep == nil {
+		t.Fatalf("%q must have `vndkdep`", name)
+	}
+	if !mod.isVndk() {
+		t.Errorf("%q isVndk() must equal to true", name)
+	}
+	if mod.isVndkSp() != isVndkSp {
+		t.Errorf("%q isVndkSp() must equal to %t", name, isVndkSp)
+	}
+
+	// Check VNDK extension properties.
+	isVndkExt := extends != ""
+	if mod.isVndkExt() != isVndkExt {
+		t.Errorf("%q isVndkExt() must equal to %t", name, isVndkExt)
+	}
+
+	if actualExtends := mod.getVndkExtendsModuleName(); actualExtends != extends {
+		t.Errorf("%q must extend from %q but get %q", name, extends, actualExtends)
+	}
+}
+
+func TestVndk(t *testing.T) {
+	ctx := testCc(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_private",
+			vendor_available: false,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp_private",
+			vendor_available: false,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+	`)
+
+	checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
+	checkVndkModule(t, ctx, "libvndk_private", "vndk-VER", false, "")
+	checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
+	checkVndkModule(t, ctx, "libvndk_sp_private", "vndk-sp-VER", true, "")
+}
+
+func TestVndkExt(t *testing.T) {
+	// This test checks the VNDK-Ext properties.
+	ctx := testCc(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			nocrt: true,
+		}
+	`)
+
+	checkVndkModule(t, ctx, "libvndk_ext", "vndk", false, "libvndk")
+}
+
+func TestVndkExtNoVndk(t *testing.T) {
+	// This test checks the VNDK-Ext properties when BOARD_VNDK_VERSION is not set.
+	ctx := testCcNoVndk(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			nocrt: true,
+		}
+	`)
+
+	// Ensures that the core variant of "libvndk_ext" can be found.
+	mod := ctx.ModuleForTests("libvndk_ext", coreVariant).Module().(*Module)
+	if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
+		t.Errorf("\"libvndk_ext\" must extend from \"libvndk\" but get %q", extends)
+	}
+}
+
+func TestVndkExtError(t *testing.T) {
+	// This test ensures an error is emitted in ill-formed vndk-ext definition.
+	testCcError(t, "must set `vendor: true` to set `extends: \".*\"`", `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			nocrt: true,
+		}
+	`)
+
+	testCcError(t, "must set `extends: \"\\.\\.\\.\"` to vndk extension", `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+	`)
+}
+
+func TestVndkExtInconsistentSupportSystemProcessError(t *testing.T) {
+	// This test ensures an error is emitted for inconsistent support_system_process.
+	testCcError(t, "module \".*\" with mismatched support_system_process", `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+	`)
+
+	testCcError(t, "module \".*\" with mismatched support_system_process", `
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk_sp",
+			},
+			nocrt: true,
+		}
+	`)
+}
+
+func TestVndkExtVendorAvailableFalseError(t *testing.T) {
+	// This test ensures an error is emitted when a vndk-ext library extends a vndk library
+	// with `vendor_available: false`.
+	testCcError(t, "`extends` refers module \".*\" which does not have `vendor_available: true`", `
+		cc_library {
+			name: "libvndk",
+			vendor_available: false,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			nocrt: true,
+		}
+	`)
+}
+
+func TestVendorModuleUsesVndkExt(t *testing.T) {
+	// This test ensures a vendor module can depend on a vndk-ext library.
+	testCc(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk_sp",
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvendor",
+			vendor: true,
+			shared_libs: ["libvndk_ext", "libvndk_sp_ext"],
+			nocrt: true,
+		}
+	`)
+}
+
+func TestVndkExtUsesVendorLib(t *testing.T) {
+	// This test ensures a vndk-ext library can depend on a vendor library.
+	testCc(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			shared_libs: ["libvendor"],
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvendor",
+			vendor: true,
+			nocrt: true,
+		}
+	`)
+}
+
+func TestVndkSpExtUsesVendorLibError(t *testing.T) {
+	// This test ensures an error is emitted if a vndk-sp-ext library depends on a vendor
+	// library.
+	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk_sp",
+				support_system_process: true,
+			},
+			shared_libs: ["libvendor"],  // Cause an error
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvendor",
+			vendor: true,
+			nocrt: true,
+		}
+	`)
+}
+
+func TestVndkUsesVndkExtError(t *testing.T) {
+	// This test ensures an error is emitted if a vndk/vndk-sp library depends on a
+	// vndk-ext/vndk-sp-ext library.
+	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk2",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			shared_libs: ["libvndk_ext"],
+			nocrt: true,
+		}
+	`)
+
+	// The pattern should be "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\""
+	// but target.vendor.shared_libs has not been supported yet.
+	testCcError(t, "unrecognized property \"target.vendor.shared_libs\"", `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk",
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk2",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			target: {
+				vendor: {
+					shared_libs: ["libvndk_ext"],
+				},
+			},
+			nocrt: true,
+		}
+	`)
+
+	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk_sp",
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp_2",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			shared_libs: ["libvndk_sp_ext"],
+			nocrt: true,
+		}
+	`)
+
+	// The pattern should be "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\""
+	// but target.vendor.shared_libs has not been supported yet.
+	testCcError(t, "unrecognized property \"target.vendor.shared_libs\"", `
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp_ext",
+			vendor: true,
+			vndk: {
+				enabled: true,
+				extends: "libvndk_sp",
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp2",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			target: {
+				vendor: {
+					shared_libs: ["libvndk_sp_ext"],
+				},
+			},
+			nocrt: true,
+		}
+	`)
+}
+
 var (
 	str11 = "01234567891"
 	str10 = str11[:10]
@@ -499,6 +1063,7 @@
 		}
 	}
 }
+
 func failIfErrored(t *testing.T, errs []error) {
 	if len(errs) > 0 {
 		for _, err := range errs {
@@ -508,6 +1073,29 @@
 	}
 }
 
+func failIfNoMatchingErrors(t *testing.T, pattern string, errs []error) {
+	matcher, err := regexp.Compile(pattern)
+	if err != nil {
+		t.Errorf("failed to compile regular expression %q because %s", pattern, err)
+	}
+
+	found := false
+
+	for _, err := range errs {
+		if matcher.FindStringIndex(err.Error()) != nil {
+			found = true
+			break
+		}
+	}
+
+	if !found {
+		t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs))
+		for i, err := range errs {
+			t.Errorf("errs[%d] = %s", i, err)
+		}
+	}
+}
+
 func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
 	for _, moduleName := range moduleNames {
 		module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
@@ -597,8 +1185,8 @@
 		shared_libs: ["libllndk"],
 		vendor: true,
 		srcs: ["foo.c"],
-		no_libgcc : true,
-		nocrt : true,
+		no_libgcc: true,
+		nocrt: true,
 	}
 	`)
 
diff --git a/cc/config/global.go b/cc/config/global.go
index ef710c8..5e99cde 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -112,7 +112,7 @@
 	ExperimentalCStdVersion   = "gnu11"
 	ExperimentalCppStdVersion = "gnu++1z"
 
-	NdkMaxPrebuiltVersionInt = 24
+	NdkMaxPrebuiltVersionInt = 27
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
diff --git a/cc/library.go b/cc/library.go
index adbd6b5..00282fc 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -416,6 +416,10 @@
 		name = ctx.baseModuleName()
 	}
 
+	if ctx.isVndkExt() {
+		name = ctx.getVndkExtendsModuleName()
+	}
+
 	if ctx.Host() && Bool(library.Properties.Unique_host_soname) {
 		if !strings.HasSuffix(name, "-host") {
 			name = name + "-host"
@@ -619,7 +623,12 @@
 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() {
-		refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, "current", fileName, vndkVsNdk(ctx), true)
+		vndkVersion := "current"
+		if ver := ctx.DeviceConfig().VndkVersion(); ver != "" {
+			vndkVersion = ver
+		}
+
+		refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, vndkVsNdk(ctx), true)
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
@@ -632,7 +641,8 @@
 		library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags)
 		if refSourceDumpFile.Valid() {
 			unzippedRefDump := UnzipRefDump(ctx, refSourceDumpFile.Path(), fileName)
-			library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(), unzippedRefDump, fileName)
+			library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
+				unzippedRefDump, fileName, exportedHeaderFlags, ctx.isVndkExt())
 		}
 	}
 }
@@ -721,15 +731,21 @@
 			} else if ctx.isVndk() {
 				library.baseInstaller.subDir = "vndk"
 			}
-			if ctx.isVndk() && ctx.DeviceConfig().PlatformVndkVersion() != "current" {
-				library.baseInstaller.subDir += "-" + ctx.DeviceConfig().PlatformVndkVersion()
+
+			// Append a version to vndk or vndk-sp directories on the system partition.
+			if ctx.isVndk() && !ctx.isVndkExt() {
+				vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
+				if vndkVersion != "current" && vndkVersion != "" {
+					library.baseInstaller.subDir += "-" + vndkVersion
+				}
 			}
 		}
 		library.baseInstaller.install(ctx, file)
 	}
 
 	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
-		!ctx.useVndk() && ctx.Device() {
+		!ctx.useVndk() && ctx.Device() &&
+		library.sanitize.isUnsanitizedVariant() {
 		installPath := getNdkSysrootBase(ctx).Join(
 			ctx, "usr/lib", ctx.toolchain().ClangTriple(), file.Base())
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 1afec26..02aedc8 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -514,6 +514,12 @@
 	}
 }
 
+func (sanitize *sanitize) isUnsanitizedVariant() bool {
+	return !sanitize.isSanitizerEnabled(asan) &&
+		!sanitize.isSanitizerEnabled(tsan) &&
+		!sanitize.isSanitizerEnabled(cfi)
+}
+
 func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
 	switch t {
 	case asan:
diff --git a/cc/vndk.go b/cc/vndk.go
index a61b74c..d417bea 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -42,6 +42,9 @@
 		// the module is VNDK-core and can link to other VNDK-core,
 		// VNDK-SP or LL-NDK modules only.
 		Support_system_process *bool
+
+		// Extending another module
+		Extends *string
 	}
 }
 
@@ -67,17 +70,31 @@
 	return Bool(vndk.Properties.Vndk.Support_system_process)
 }
 
+func (vndk *vndkdep) isVndkExt() bool {
+	return vndk.Properties.Vndk.Extends != nil
+}
+
+func (vndk *vndkdep) getVndkExtendsModuleName() string {
+	return String(vndk.Properties.Vndk.Extends)
+}
+
 func (vndk *vndkdep) typeName() string {
 	if !vndk.isVndk() {
 		return "native:vendor"
 	}
-	if !vndk.isVndkSp() {
-		return "native:vendor:vndk"
+	if !vndk.isVndkExt() {
+		if !vndk.isVndkSp() {
+			return "native:vendor:vndk"
+		}
+		return "native:vendor:vndksp"
 	}
-	return "native:vendor:vndksp"
+	if !vndk.isVndkSp() {
+		return "native:vendor:vndkext"
+	}
+	return "native:vendor:vndkspext"
 }
 
-func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module) {
+func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag dependencyTag) {
 	if to.linker == nil {
 		return
 	}
@@ -109,11 +126,43 @@
 			vndk.typeName(), to.Name())
 		return
 	}
+	if tag == vndkExtDepTag {
+		// Ensure `extends: "name"` property refers a vndk module that has vendor_available
+		// and has identical vndk properties.
+		if to.vndkdep == nil || !to.vndkdep.isVndk() {
+			ctx.ModuleErrorf("`extends` refers a non-vndk module %q", to.Name())
+			return
+		}
+		if vndk.isVndkSp() != to.vndkdep.isVndkSp() {
+			ctx.ModuleErrorf(
+				"`extends` refers a module %q with mismatched support_system_process",
+				to.Name())
+			return
+		}
+		if !Bool(to.VendorProperties.Vendor_available) {
+			ctx.ModuleErrorf(
+				"`extends` refers module %q which does not have `vendor_available: true`",
+				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-core and VNDK-SP must not depend on VNDK extensions.
+	if (vndk.isVndk() || vndk.isVndkSp()) && !vndk.isVndkExt() && to.vndkdep.isVndkExt() {
+		ctx.ModuleErrorf("(%s) should not link to %q (%s)",
+			vndk.typeName(), to.Name(), to.vndkdep.typeName())
+		return
+	}
+
+	// VNDK-core must be only depend on VNDK-SP or LL-NDK. VNDK-SP must only depend on
+	// LL-NDK, regardless the extension status. VNDK-Ext may depend on vendor libraries, but
+	// VNDK-SP-Ext must remain self-contained.
+	if (vndk.isVndk() && !to.vndkdep.isVndk() && !vndk.isVndkExt()) ||
+		(vndk.isVndkSp() && !to.vndkdep.isVndkSp()) {
+		ctx.ModuleErrorf("(%s) should not link to %q (%s)",
 			vndk.typeName(), to.Name(), to.vndkdep.typeName())
 		return
 	}
@@ -149,7 +198,7 @@
 			prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
 			if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
 				name := strings.TrimPrefix(m.Name(), "prebuilt_")
-				if m.vndkdep.isVndk() {
+				if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
 					vndkLibrariesLock.Lock()
 					defer vndkLibrariesLock.Unlock()
 					if m.vndkdep.isVndkSp() {
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index b4fcb57..99e35f3 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -111,12 +111,10 @@
 
 func (p *vndkPrebuiltLibraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if p.shared() {
-		if ctx.Device() && ctx.useVndk() {
-			if ctx.isVndkSp() {
-				p.baseInstaller.subDir = "vndk-sp-" + p.version()
-			} else if ctx.isVndk() {
-				p.baseInstaller.subDir = "vndk-" + p.version()
-			}
+		if ctx.isVndkSp() {
+			p.baseInstaller.subDir = "vndk-sp-" + p.version()
+		} else if ctx.isVndk() {
+			p.baseInstaller.subDir = "vndk-" + p.version()
 		}
 		p.baseInstaller.install(ctx, file)
 	}
diff --git a/ui/build/config.go b/ui/build/config.go
index 0c37724..363121f 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -168,6 +168,8 @@
 	}()
 	absJavaHome := absPath(ctx, javaHome)
 
+	ret.configureLocale(ctx)
+
 	newPath := []string{filepath.Join(absJavaHome, "bin")}
 	if path, ok := ret.environ.Get("PATH"); ok && path != "" {
 		newPath = append(newPath, path)
@@ -228,6 +230,52 @@
 	}
 }
 
+func (c *configImpl) configureLocale(ctx Context) {
+	cmd := Command(ctx, Config{c}, "locale", "locale", "-a")
+	output, err := cmd.Output()
+
+	var locales []string
+	if err == nil {
+		locales = strings.Split(string(output), "\n")
+	} else {
+		// If we're unable to list the locales, let's assume en_US.UTF-8
+		locales = []string{"en_US.UTF-8"}
+		ctx.Verbosef("Failed to list locales (%q), falling back to %q", err, locales)
+	}
+
+	// gettext uses LANGUAGE, which is passed directly through
+
+	// For LANG and LC_*, only preserve the evaluated version of
+	// LC_MESSAGES
+	user_lang := ""
+	if lc_all, ok := c.environ.Get("LC_ALL"); ok {
+		user_lang = lc_all
+	} else if lc_messages, ok := c.environ.Get("LC_MESSAGES"); ok {
+		user_lang = lc_messages
+	} else if lang, ok := c.environ.Get("LANG"); ok {
+		user_lang = lang
+	}
+
+	c.environ.UnsetWithPrefix("LC_")
+
+	if user_lang != "" {
+		c.environ.Set("LC_MESSAGES", user_lang)
+	}
+
+	// The for LANG, use C.UTF-8 if it exists (Debian currently, proposed
+	// for others)
+	if inList("C.UTF-8", locales) {
+		c.environ.Set("LANG", "C.UTF-8")
+	} else if inList("en_US.UTF-8", locales) {
+		c.environ.Set("LANG", "en_US.UTF-8")
+	} else if inList("en_US.utf8", locales) {
+		// These normalize to the same thing
+		c.environ.Set("LANG", "en_US.UTF-8")
+	} else {
+		ctx.Fatalln("System doesn't support either C.UTF-8 or en_US.UTF-8")
+	}
+}
+
 // Lunch configures the environment for a specific product similarly to the
 // `lunch` bash function.
 func (c *configImpl) Lunch(ctx Context, product, variant string) {
diff --git a/ui/build/environment.go b/ui/build/environment.go
index baab101..8589937 100644
--- a/ui/build/environment.go
+++ b/ui/build/environment.go
@@ -63,6 +63,18 @@
 	*e = out
 }
 
+// UnsetWithPrefix removes all keys that start with prefix.
+func (e *Environment) UnsetWithPrefix(prefix string) {
+	out := (*e)[:0]
+	for _, env := range *e {
+		if key, _, ok := decodeKeyValue(env); ok && strings.HasPrefix(key, prefix) {
+			continue
+		}
+		out = append(out, env)
+	}
+	*e = out
+}
+
 // Environ returns the []string required for exec.Cmd.Env
 func (e *Environment) Environ() []string {
 	return []string(*e)