Merge "Have pom2mk list all duplicates modules" into pi-dev
diff --git a/android/androidmk.go b/android/androidmk.go
index 0ea7564..81de415 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -72,7 +72,7 @@
 
 	sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
 
-	transMk := PathForOutput(ctx, "Android"+String(ctx.Config().ProductVariables.Make_suffix)+".mk")
+	transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk")
 	if ctx.Failed() {
 		return
 	}
diff --git a/android/api_levels.go b/android/api_levels.go
index a519117..b1b954c 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -65,6 +65,8 @@
 		"N":     24,
 		"N-MR1": 25,
 		"O":     26,
+		"O-MR1": 27,
+		"P":     28,
 	}
 	for i, codename := range ctx.Config().PlatformVersionCombinedCodenames() {
 		apiLevelsMap[codename] = baseApiLevel + i
diff --git a/android/arch.go b/android/arch.go
index fd80eec..3990d7b 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -821,7 +821,7 @@
 
 // Convert the arch product variables into a list of targets for each os class structs
 func decodeTargetProductVariables(config *config) (map[OsClass][]Target, error) {
-	variables := config.ProductVariables
+	variables := config.productVariables
 
 	targets := make(map[OsClass][]Target)
 	var targetErr error
diff --git a/android/config.go b/android/config.go
index db833ec..549abe9 100644
--- a/android/config.go
+++ b/android/config.go
@@ -65,9 +65,26 @@
 	*deviceConfig
 }
 
+type VendorConfig interface {
+	// Bool interprets the variable named `name` as a boolean, returning true if, after
+	// lowercasing, it matches one of "1", "y", "yes", "on", or "true". Unset, or any other
+	// value will return false.
+	Bool(name string) bool
+
+	// String returns the string value of `name`. If the variable was not set, it will
+	// return the empty string.
+	String(name string) string
+
+	// IsSet returns whether the variable `name` was set by Make.
+	IsSet(name string) bool
+}
+
 type config struct {
 	FileConfigurableOptions
-	ProductVariables productVariables
+	productVariables productVariables
+
+	// Only available on configs created by TestConfig
+	TestProductVariables *productVariables
 
 	PrimaryBuilder           string
 	ConfigFileName           string
@@ -104,6 +121,8 @@
 	OncePer
 }
 
+type vendorConfig map[string]string
+
 type jsonConfigurable interface {
 	SetDefaultConfig()
 }
@@ -114,7 +133,7 @@
 		return err
 	}
 
-	return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName)
+	return loadFromConfigFile(&config.productVariables, config.ProductVariablesFileName)
 }
 
 // loads configuration options from a JSON file in the cwd.
@@ -181,7 +200,7 @@
 // TestConfig returns a Config object suitable for using for tests
 func TestConfig(buildDir string, env map[string]string) Config {
 	config := &config{
-		ProductVariables: productVariables{
+		productVariables: productVariables{
 			DeviceName:           stringPtr("test_device"),
 			Platform_sdk_version: intPtr(26),
 			AAPTConfig:           &[]string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
@@ -197,6 +216,7 @@
 	config.deviceConfig = &deviceConfig{
 		config: config,
 	}
+	config.TestProductVariables = &config.productVariables
 
 	if err := config.fromEnv(); err != nil {
 		panic(err)
@@ -428,59 +448,71 @@
 }
 
 func (c *config) BuildId() string {
-	return String(c.ProductVariables.BuildId)
+	return String(c.productVariables.BuildId)
 }
 
 func (c *config) BuildNumberFromFile() string {
-	return String(c.ProductVariables.BuildNumberFromFile)
+	return String(c.productVariables.BuildNumberFromFile)
 }
 
 // DeviceName returns the name of the current device target
 // TODO: take an AndroidModuleContext to select the device name for multi-device builds
 func (c *config) DeviceName() string {
-	return *c.ProductVariables.DeviceName
+	return *c.productVariables.DeviceName
 }
 
 func (c *config) ResourceOverlays() []string {
-	if c.ProductVariables.ResourceOverlays == nil {
+	if c.productVariables.ResourceOverlays == nil {
 		return nil
 	}
-	return *c.ProductVariables.ResourceOverlays
+	return *c.productVariables.ResourceOverlays
 }
 
 func (c *config) PlatformSdkVersionInt() int {
-	return *c.ProductVariables.Platform_sdk_version
+	return *c.productVariables.Platform_sdk_version
 }
 
 func (c *config) PlatformSdkVersion() string {
 	return strconv.Itoa(c.PlatformSdkVersionInt())
 }
 
+func (c *config) PlatformSdkCodename() string {
+	return String(c.productVariables.Platform_sdk_codename)
+}
+
 func (c *config) MinSupportedSdkVersion() int {
 	return 14
 }
 
 func (c *config) DefaultAppTargetSdkInt() int {
-	if Bool(c.ProductVariables.Platform_sdk_final) {
+	if Bool(c.productVariables.Platform_sdk_final) {
 		return c.PlatformSdkVersionInt()
 	} else {
 		return FutureApiLevel
 	}
 }
 
+func (c *config) DefaultAppTargetSdk() string {
+	if Bool(c.productVariables.Platform_sdk_final) {
+		return c.PlatformSdkVersion()
+	} else {
+		return c.PlatformSdkCodename()
+	}
+}
+
 func (c *config) AppsDefaultVersionName() string {
-	return String(c.ProductVariables.AppsDefaultVersionName)
+	return String(c.productVariables.AppsDefaultVersionName)
 }
 
 // Codenames that are active in the current lunch target.
 func (c *config) PlatformVersionActiveCodenames() []string {
-	return c.ProductVariables.Platform_version_active_codenames
+	return c.productVariables.Platform_version_active_codenames
 }
 
 // Codenames that are available in the branch but not included in the current
 // lunch target.
 func (c *config) PlatformVersionFutureCodenames() []string {
-	return c.ProductVariables.Platform_version_future_codenames
+	return c.productVariables.Platform_version_future_codenames
 }
 
 // All possible codenames in the current branch. NB: Not named AllCodenames
@@ -494,23 +526,23 @@
 }
 
 func (c *config) ProductAAPTConfig() []string {
-	return stringSlice(c.ProductVariables.AAPTConfig)
+	return stringSlice(c.productVariables.AAPTConfig)
 }
 
 func (c *config) ProductAAPTPreferredConfig() string {
-	return String(c.ProductVariables.AAPTPreferredConfig)
+	return String(c.productVariables.AAPTPreferredConfig)
 }
 
 func (c *config) ProductAAPTCharacteristics() string {
-	return String(c.ProductVariables.AAPTCharacteristics)
+	return String(c.productVariables.AAPTCharacteristics)
 }
 
 func (c *config) ProductAAPTPrebuiltDPI() []string {
-	return stringSlice(c.ProductVariables.AAPTPrebuiltDPI)
+	return stringSlice(c.productVariables.AAPTPrebuiltDPI)
 }
 
 func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
-	defaultCert := String(c.ProductVariables.DefaultAppCertificate)
+	defaultCert := String(c.productVariables.DefaultAppCertificate)
 	if defaultCert != "" {
 		return PathForSource(ctx, filepath.Dir(defaultCert))
 	} else {
@@ -519,7 +551,7 @@
 }
 
 func (c *config) DefaultAppCertificate(ctx PathContext) (pem, key SourcePath) {
-	defaultCert := String(c.ProductVariables.DefaultAppCertificate)
+	defaultCert := String(c.productVariables.DefaultAppCertificate)
 	if defaultCert != "" {
 		return PathForSource(ctx, defaultCert+".x509.pem"), PathForSource(ctx, defaultCert+".pk8")
 	} else {
@@ -529,23 +561,23 @@
 }
 
 func (c *config) AllowMissingDependencies() bool {
-	return Bool(c.ProductVariables.Allow_missing_dependencies)
+	return Bool(c.productVariables.Allow_missing_dependencies)
 }
 
 func (c *config) UnbundledBuild() bool {
-	return Bool(c.ProductVariables.Unbundled_build)
+	return Bool(c.productVariables.Unbundled_build)
 }
 
 func (c *config) IsPdkBuild() bool {
-	return Bool(c.ProductVariables.Pdk)
+	return Bool(c.productVariables.Pdk)
 }
 
 func (c *config) MinimizeJavaDebugInfo() bool {
-	return Bool(c.ProductVariables.MinimizeJavaDebugInfo) && !Bool(c.ProductVariables.Eng)
+	return Bool(c.productVariables.MinimizeJavaDebugInfo) && !Bool(c.productVariables.Eng)
 }
 
 func (c *config) DevicePrefer32BitExecutables() bool {
-	return Bool(c.ProductVariables.DevicePrefer32BitExecutables)
+	return Bool(c.productVariables.DevicePrefer32BitExecutables)
 }
 
 func (c *config) SkipDeviceInstall() bool {
@@ -558,26 +590,26 @@
 }
 
 func (c *config) SanitizeHost() []string {
-	return append([]string(nil), c.ProductVariables.SanitizeHost...)
+	return append([]string(nil), c.productVariables.SanitizeHost...)
 }
 
 func (c *config) SanitizeDevice() []string {
-	return append([]string(nil), c.ProductVariables.SanitizeDevice...)
+	return append([]string(nil), c.productVariables.SanitizeDevice...)
 }
 
 func (c *config) SanitizeDeviceDiag() []string {
-	return append([]string(nil), c.ProductVariables.SanitizeDeviceDiag...)
+	return append([]string(nil), c.productVariables.SanitizeDeviceDiag...)
 }
 
 func (c *config) SanitizeDeviceArch() []string {
-	return append([]string(nil), c.ProductVariables.SanitizeDeviceArch...)
+	return append([]string(nil), c.productVariables.SanitizeDeviceArch...)
 }
 
 func (c *config) EnableCFI() bool {
-	if c.ProductVariables.EnableCFI == nil {
+	if c.productVariables.EnableCFI == nil {
 		return true
 	} else {
-		return *c.ProductVariables.EnableCFI
+		return *c.productVariables.EnableCFI
 	}
 }
 
@@ -596,7 +628,7 @@
 }
 
 func (c *config) UseGoma() bool {
-	return Bool(c.ProductVariables.UseGoma)
+	return Bool(c.productVariables.UseGoma)
 }
 
 // Returns true if OpenJDK9 prebuilts are being used
@@ -610,14 +642,14 @@
 }
 
 func (c *config) ClangTidy() bool {
-	return Bool(c.ProductVariables.ClangTidy)
+	return Bool(c.productVariables.ClangTidy)
 }
 
 func (c *config) TidyChecks() string {
-	if c.ProductVariables.TidyChecks == nil {
+	if c.productVariables.TidyChecks == nil {
 		return ""
 	}
-	return *c.ProductVariables.TidyChecks
+	return *c.productVariables.TidyChecks
 }
 
 func (c *config) LibartImgHostBaseAddress() string {
@@ -638,7 +670,38 @@
 }
 
 func (c *config) ArtUseReadBarrier() bool {
-	return Bool(c.ProductVariables.ArtUseReadBarrier)
+	return Bool(c.productVariables.ArtUseReadBarrier)
+}
+
+func (c *config) EnforceRROForModule(name string) bool {
+	enforceList := c.productVariables.EnforceRROTargets
+	if enforceList != nil {
+		if len(*enforceList) == 1 && (*enforceList)[0] == "*" {
+			return true
+		}
+		return InList(name, *enforceList)
+	}
+	return false
+}
+
+func (c *config) EnforceRROExcludedOverlay(path string) bool {
+	excluded := c.productVariables.EnforceRROExcludedOverlays
+	if excluded != nil {
+		for _, exclude := range *excluded {
+			if strings.HasPrefix(path, exclude) {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func (c *config) ExportedNamespaces() []string {
+	return append([]string(nil), c.productVariables.NamespacesToExport...)
+}
+
+func (c *config) HostStaticBinaries() bool {
+	return Bool(c.productVariables.HostStaticBinaries)
 }
 
 func (c *deviceConfig) Arches() []Arch {
@@ -650,7 +713,7 @@
 }
 
 func (c *deviceConfig) BinderBitness() string {
-	is32BitBinder := c.config.ProductVariables.Binder32bit
+	is32BitBinder := c.config.productVariables.Binder32bit
 	if is32BitBinder != nil && *is32BitBinder {
 		return "32"
 	}
@@ -658,70 +721,70 @@
 }
 
 func (c *deviceConfig) VendorPath() string {
-	if c.config.ProductVariables.VendorPath != nil {
-		return *c.config.ProductVariables.VendorPath
+	if c.config.productVariables.VendorPath != nil {
+		return *c.config.productVariables.VendorPath
 	}
 	return "vendor"
 }
 
 func (c *deviceConfig) VndkVersion() string {
-	return String(c.config.ProductVariables.DeviceVndkVersion)
+	return String(c.config.productVariables.DeviceVndkVersion)
 }
 
 func (c *deviceConfig) PlatformVndkVersion() string {
-	return String(c.config.ProductVariables.Platform_vndk_version)
+	return String(c.config.productVariables.Platform_vndk_version)
 }
 
 func (c *deviceConfig) ExtraVndkVersions() []string {
-	return c.config.ProductVariables.ExtraVndkVersions
+	return c.config.productVariables.ExtraVndkVersions
 }
 
 func (c *deviceConfig) SystemSdkVersions() []string {
-	if c.config.ProductVariables.DeviceSystemSdkVersions == nil {
+	if c.config.productVariables.DeviceSystemSdkVersions == nil {
 		return nil
 	}
-	return *c.config.ProductVariables.DeviceSystemSdkVersions
+	return *c.config.productVariables.DeviceSystemSdkVersions
 }
 
 func (c *deviceConfig) PlatformSystemSdkVersions() []string {
-	return c.config.ProductVariables.Platform_systemsdk_versions
+	return c.config.productVariables.Platform_systemsdk_versions
 }
 
 func (c *deviceConfig) OdmPath() string {
-	if c.config.ProductVariables.OdmPath != nil {
-		return *c.config.ProductVariables.OdmPath
+	if c.config.productVariables.OdmPath != nil {
+		return *c.config.productVariables.OdmPath
 	}
 	return "odm"
 }
 
 func (c *deviceConfig) ProductPath() string {
-	if c.config.ProductVariables.ProductPath != nil {
-		return *c.config.ProductVariables.ProductPath
+	if c.config.productVariables.ProductPath != nil {
+		return *c.config.productVariables.ProductPath
 	}
 	return "product"
 }
 
 func (c *deviceConfig) BtConfigIncludeDir() string {
-	return String(c.config.ProductVariables.BtConfigIncludeDir)
+	return String(c.config.productVariables.BtConfigIncludeDir)
 }
 
 func (c *deviceConfig) DeviceKernelHeaderDirs() []string {
-	return c.config.ProductVariables.DeviceKernelHeaders
+	return c.config.productVariables.DeviceKernelHeaders
 }
 
 func (c *deviceConfig) NativeCoverageEnabled() bool {
-	return Bool(c.config.ProductVariables.NativeCoverage)
+	return Bool(c.config.productVariables.NativeCoverage)
 }
 
 func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
 	coverage := false
-	if c.config.ProductVariables.CoveragePaths != nil {
-		if PrefixInList(path, *c.config.ProductVariables.CoveragePaths) {
+	if c.config.productVariables.CoveragePaths != nil {
+		if PrefixInList(path, *c.config.productVariables.CoveragePaths) {
 			coverage = true
 		}
 	}
-	if coverage && c.config.ProductVariables.CoverageExcludePaths != nil {
-		if PrefixInList(path, *c.config.ProductVariables.CoverageExcludePaths) {
+	if coverage && c.config.productVariables.CoverageExcludePaths != nil {
+		if PrefixInList(path, *c.config.productVariables.CoverageExcludePaths) {
 			coverage = false
 		}
 	}
@@ -729,28 +792,46 @@
 }
 
 func (c *deviceConfig) PgoAdditionalProfileDirs() []string {
-	return c.config.ProductVariables.PgoAdditionalProfileDirs
+	return c.config.productVariables.PgoAdditionalProfileDirs
 }
 
 func (c *config) IntegerOverflowDisabledForPath(path string) bool {
-	if c.ProductVariables.IntegerOverflowExcludePaths == nil {
+	if c.productVariables.IntegerOverflowExcludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, *c.ProductVariables.IntegerOverflowExcludePaths)
+	return PrefixInList(path, *c.productVariables.IntegerOverflowExcludePaths)
 }
 
 func (c *config) CFIDisabledForPath(path string) bool {
-	if c.ProductVariables.CFIExcludePaths == nil {
+	if c.productVariables.CFIExcludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, *c.ProductVariables.CFIExcludePaths)
+	return PrefixInList(path, *c.productVariables.CFIExcludePaths)
 }
 
 func (c *config) CFIEnabledForPath(path string) bool {
-	if c.ProductVariables.CFIIncludePaths == nil {
+	if c.productVariables.CFIIncludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, *c.ProductVariables.CFIIncludePaths)
+	return PrefixInList(path, *c.productVariables.CFIIncludePaths)
+}
+
+func (c *config) VendorConfig(name string) VendorConfig {
+	return vendorConfig(c.productVariables.VendorVars[name])
+}
+
+func (c vendorConfig) Bool(name string) bool {
+	v := strings.ToLower(c[name])
+	return v == "1" || v == "y" || v == "yes" || v == "on" || v == "true"
+}
+
+func (c vendorConfig) String(name string) string {
+	return c[name]
+}
+
+func (c vendorConfig) IsSet(name string) bool {
+	_, ok := c[name]
+	return ok
 }
 
 func stringSlice(s *[]string) []string {
diff --git a/android/config_test.go b/android/config_test.go
index 5eb6ed5..72942eb 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -84,3 +84,10 @@
 		t.Errorf(err.Error())
 	}
 }
+
+func TestMissingVendorConfig(t *testing.T) {
+	c := &config{}
+	if c.VendorConfig("test").Bool("not_set") {
+		t.Errorf("Expected false")
+	}
+}
diff --git a/android/makevars.go b/android/makevars.go
index b6cd571..3094a48 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -36,6 +36,7 @@
 // Interface for other packages to use to declare make variables
 type MakeVarsContext interface {
 	Config() Config
+	DeviceConfig() DeviceConfig
 	SingletonContext() SingletonContext
 
 	// Verify the make variable matches the Soong version, fail the build
@@ -110,7 +111,7 @@
 		return
 	}
 
-	outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().ProductVariables.Make_suffix)+".mk").String()
+	outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
 
 	if ctx.Failed() {
 		return
@@ -231,6 +232,10 @@
 	return c.config
 }
 
+func (c *makeVarsContext) DeviceConfig() DeviceConfig {
+	return DeviceConfig{c.config.deviceConfig}
+}
+
 func (c *makeVarsContext) SingletonContext() SingletonContext {
 	return c.ctx
 }
diff --git a/android/namespace.go b/android/namespace.go
index 1f8ef5a..0230524 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -255,22 +255,7 @@
 }
 
 func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
-	oldNs := r.findNamespace(oldName)
-	newNs := r.findNamespace(newName)
-	if oldNs != newNs {
-		return []error{fmt.Errorf("cannot rename %v to %v because the destination is outside namespace %v", oldName, newName, oldNs.Path)}
-	}
-
-	oldName, err := filepath.Rel(oldNs.Path, oldName)
-	if err != nil {
-		panic(err)
-	}
-	newName, err = filepath.Rel(newNs.Path, newName)
-	if err != nil {
-		panic(err)
-	}
-
-	return oldNs.moduleContainer.Rename(oldName, newName, nil)
+	return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace)
 }
 
 // resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
diff --git a/android/namespace_test.go b/android/namespace_test.go
index 8bec0ad..9a791a5 100644
--- a/android/namespace_test.go
+++ b/android/namespace_test.go
@@ -582,6 +582,25 @@
 	}
 }
 
+// so that the generated .ninja file will have consistent names
+func TestRename(t *testing.T) {
+	_ = setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+				deps: ["c"],
+			}
+			test_module {
+				name: "b",
+				rename: "c",
+			}
+		`})
+	// setupTest will report any errors
+}
+
 // some utils to support the tests
 
 func mockFiles(bps map[string]string) (files map[string][]byte) {
@@ -607,6 +626,9 @@
 	ctx.RegisterModuleType("test_module", ModuleFactoryAdaptor(newTestModule))
 	ctx.RegisterModuleType("soong_namespace", ModuleFactoryAdaptor(NamespaceFactory))
 	ctx.PreArchMutators(RegisterNamespaceMutator)
+	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("rename", renameMutator)
+	})
 	ctx.Register()
 
 	_, errs = ctx.ParseBlueprintsFiles("Android.bp")
@@ -672,12 +694,16 @@
 type testModule struct {
 	ModuleBase
 	properties struct {
-		Deps []string
-		Id   string
+		Rename string
+		Deps   []string
+		Id     string
 	}
 }
 
 func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
+	if m.properties.Rename != "" {
+		ctx.Rename(m.properties.Rename)
+	}
 	for _, d := range m.properties.Deps {
 		ctx.AddDependency(ctx.Module(), nil, d)
 	}
@@ -686,6 +712,14 @@
 func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
 }
 
+func renameMutator(ctx BottomUpMutatorContext) {
+	if m, ok := ctx.Module().(*testModule); ok {
+		if m.properties.Rename != "" {
+			ctx.Rename(m.properties.Rename)
+		}
+	}
+}
+
 func newTestModule() Module {
 	m := &testModule{}
 	m.AddProperties(&m.properties)
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 849eb72..e228bba 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -47,6 +47,9 @@
 
 var _ PathContext = &configErrorWrapper{}
 var _ errorfContext = &configErrorWrapper{}
+var _ PackageVarContext = &configErrorWrapper{}
+var _ PackagePoolContext = &configErrorWrapper{}
+var _ PackageRuleContext = &configErrorWrapper{}
 
 func (e *configErrorWrapper) Config() Config {
 	return e.config
@@ -62,33 +65,56 @@
 	return nil
 }
 
+type PackageVarContext interface {
+	PathContext
+	errorfContext
+}
+
+type PackagePoolContext PackageVarContext
+type PackageRuleContext PackageVarContext
+
 // VariableFunc wraps blueprint.PackageContext.VariableFunc, converting the interface{} config
-// argument to a Config.
+// argument to a PackageVarContext.
 func (p PackageContext) VariableFunc(name string,
-	f func(Config) (string, error)) blueprint.Variable {
+	f func(PackageVarContext) string) blueprint.Variable {
 
 	return p.PackageContext.VariableFunc(name, func(config interface{}) (string, error) {
-		return f(config.(Config))
+		ctx := &configErrorWrapper{p, config.(Config), nil}
+		ret := f(ctx)
+		if len(ctx.errors) > 0 {
+			return "", ctx.errors[0]
+		}
+		return ret, nil
 	})
 }
 
 // PoolFunc wraps blueprint.PackageContext.PoolFunc, converting the interface{} config
-// argument to a Config.
+// argument to a Context that supports Config().
 func (p PackageContext) PoolFunc(name string,
-	f func(Config) (blueprint.PoolParams, error)) blueprint.Pool {
+	f func(PackagePoolContext) blueprint.PoolParams) blueprint.Pool {
 
 	return p.PackageContext.PoolFunc(name, func(config interface{}) (blueprint.PoolParams, error) {
-		return f(config.(Config))
+		ctx := &configErrorWrapper{p, config.(Config), nil}
+		params := f(ctx)
+		if len(ctx.errors) > 0 {
+			return params, ctx.errors[0]
+		}
+		return params, nil
 	})
 }
 
 // RuleFunc wraps blueprint.PackageContext.RuleFunc, converting the interface{} config
-// argument to a Config.
+// argument to a Context that supports Config().
 func (p PackageContext) RuleFunc(name string,
-	f func(Config) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
+	f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule {
 
 	return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
-		return f(config.(Config))
+		ctx := &configErrorWrapper{p, config.(Config), nil}
+		params := f(ctx)
+		if len(ctx.errors) > 0 {
+			return params, ctx.errors[0]
+		}
+		return params, nil
 	}, argNames...)
 }
 
@@ -97,13 +123,8 @@
 // initialization - either from the init() function or as part of a
 // package-scoped variable's initialization.
 func (p PackageContext) SourcePathVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		ctx := &configErrorWrapper{p, config, []error{}}
-		p := safePathForSource(ctx, path)
-		if len(ctx.errors) > 0 {
-			return "", ctx.errors[0]
-		}
-		return p.String(), nil
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
+		return safePathForSource(ctx, path).String()
 	})
 }
 
@@ -112,17 +133,13 @@
 // called during a Go package's initialization - either from the init()
 // function or as part of a package-scoped variable's initialization.
 func (p PackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		ctx := &configErrorWrapper{p, config, []error{}}
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
 		var ret []string
 		for _, path := range paths {
 			p := safePathForSource(ctx, path)
-			if len(ctx.errors) > 0 {
-				return "", ctx.errors[0]
-			}
 			ret = append(ret, p.String())
 		}
-		return strings.Join(ret, separator), nil
+		return strings.Join(ret, separator)
 	})
 }
 
@@ -132,13 +149,9 @@
 // It may only be called during a Go package's initialization - either from the init() function or
 // as part of a package-scoped variable's initialization.
 func (p PackageContext) SourcePathVariableWithEnvOverride(name, path, env string) blueprint.Variable {
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		ctx := &configErrorWrapper{p, config, []error{}}
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
 		p := safePathForSource(ctx, path)
-		if len(ctx.errors) > 0 {
-			return "", ctx.errors[0]
-		}
-		return config.GetenvWithDefault(env, p.String()), nil
+		return ctx.Config().GetenvWithDefault(env, p.String())
 	})
 }
 
@@ -147,22 +160,13 @@
 // package's initialization - either from the init() function or as part of a
 // package-scoped variable's initialization.
 func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		po, err := p.HostBinToolPath(config, path)
-		if err != nil {
-			return "", err
-		}
-		return po.String(), nil
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
+		return p.HostBinToolPath(ctx, path).String()
 	})
 }
 
-func (p PackageContext) HostBinToolPath(config Config, path string) (Path, error) {
-	ctx := &configErrorWrapper{p, config, []error{}}
-	pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path)
-	if len(ctx.errors) > 0 {
-		return nil, ctx.errors[0]
-	}
-	return pa, nil
+func (p PackageContext) HostBinToolPath(ctx PackageVarContext, path string) Path {
+	return PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin", path)
 }
 
 // HostJNIToolVariable returns a Variable whose value is the path to a host tool
@@ -170,26 +174,17 @@
 // package's initialization - either from the init() function or as part of a
 // package-scoped variable's initialization.
 func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		po, err := p.HostJNIToolPath(config, path)
-		if err != nil {
-			return "", err
-		}
-		return po.String(), nil
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
+		return p.HostJNIToolPath(ctx, path).String()
 	})
 }
 
-func (p PackageContext) HostJNIToolPath(config Config, path string) (Path, error) {
-	ctx := &configErrorWrapper{p, config, []error{}}
+func (p PackageContext) HostJNIToolPath(ctx PackageVarContext, path string) Path {
 	ext := ".so"
 	if runtime.GOOS == "darwin" {
 		ext = ".dylib"
 	}
-	pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "lib64", path+ext)
-	if len(ctx.errors) > 0 {
-		return nil, ctx.errors[0]
-	}
-	return pa, nil
+	return PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "lib64", path+ext)
 }
 
 // HostJavaToolVariable returns a Variable whose value is the path to a host
@@ -197,23 +192,13 @@
 // during a Go package's initialization - either from the init() function or as
 // part of a package-scoped variable's initialization.
 func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		ctx := &configErrorWrapper{p, config, []error{}}
-		p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
-		if len(ctx.errors) > 0 {
-			return "", ctx.errors[0]
-		}
-		return p.String(), nil
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
+		return p.HostJavaToolPath(ctx, path).String()
 	})
 }
 
-func (p PackageContext) HostJavaToolPath(config Config, path string) (Path, error) {
-	ctx := &configErrorWrapper{p, config, []error{}}
-	pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
-	if len(ctx.errors) > 0 {
-		return nil, ctx.errors[0]
-	}
-	return pa, nil
+func (p PackageContext) HostJavaToolPath(ctx PackageVarContext, path string) Path {
+	return PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", path)
 }
 
 // IntermediatesPathVariable returns a Variable whose value is the intermediate
@@ -221,13 +206,8 @@
 // package's initialization - either from the init() function or as part of a
 // package-scoped variable's initialization.
 func (p PackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		ctx := &configErrorWrapper{p, config, []error{}}
-		p := PathForIntermediates(ctx, path)
-		if len(ctx.errors) > 0 {
-			return "", ctx.errors[0]
-		}
-		return p.String(), nil
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
+		return PathForIntermediates(ctx, path).String()
 	})
 }
 
@@ -238,21 +218,17 @@
 func (p PackageContext) PrefixedExistentPathsForSourcesVariable(
 	name, prefix string, paths []string) blueprint.Variable {
 
-	return p.VariableFunc(name, func(config Config) (string, error) {
-		ctx := &configErrorWrapper{p, config, []error{}}
+	return p.VariableFunc(name, func(ctx PackageVarContext) string {
 		paths := ExistentPathsForSources(ctx, paths)
-		if len(ctx.errors) > 0 {
-			return "", ctx.errors[0]
-		}
-		return JoinWithPrefix(paths.Strings(), prefix), nil
+		return JoinWithPrefix(paths.Strings(), prefix)
 	})
 }
 
 // AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified
 func (p PackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
-	return p.AndroidRuleFunc(name, func(Config) (blueprint.RuleParams, error) {
-		return params, nil
+	return p.AndroidRuleFunc(name, func(PackageRuleContext) blueprint.RuleParams {
+		return params
 	}, argNames...)
 }
 
@@ -263,14 +239,14 @@
 }
 
 func (p PackageContext) AndroidRuleFunc(name string,
-	f func(Config) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
-	return p.RuleFunc(name, func(config Config) (blueprint.RuleParams, error) {
-		params, err := f(config)
-		if config.UseGoma() && params.Pool == nil {
+	f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule {
+	return p.RuleFunc(name, func(ctx PackageRuleContext) blueprint.RuleParams {
+		params := f(ctx)
+		if ctx.Config().UseGoma() && params.Pool == nil {
 			// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
 			// local parallelism value
 			params.Pool = localPool
 		}
-		return params, err
+		return params
 	}, argNames...)
 }
diff --git a/android/paths.go b/android/paths.go
index 3605dcf..91dd9a6 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -308,6 +308,18 @@
 	return list[totalSkip:]
 }
 
+// ReversePaths returns a copy of a Paths in reverse order.
+func ReversePaths(list Paths) Paths {
+	if list == nil {
+		return nil
+	}
+	ret := make(Paths, len(list))
+	for i := range list {
+		ret[i] = list[len(list)-1-i]
+	}
+	return ret
+}
+
 func indexPathList(s Path, list []Path) int {
 	for i, l := range list {
 		if l == s {
@@ -693,6 +705,46 @@
 	return PathForOutput(ctx, ".intermediates", path)
 }
 
+// DistPath is a Path representing a file path rooted from the dist directory
+type DistPath struct {
+	basePath
+}
+
+func (p DistPath) withRel(rel string) DistPath {
+	p.basePath = p.basePath.withRel(rel)
+	return p
+}
+
+var _ Path = DistPath{}
+
+// PathForDist joins the provided paths and returns a DistPath that is
+// validated to not escape the dist dir.
+// On error, it will return a usable, but invalid DistPath, and report a ModuleError.
+func PathForDist(ctx PathContext, pathComponents ...string) DistPath {
+	path, err := validatePath(pathComponents...)
+	if err != nil {
+		reportPathError(ctx, err)
+	}
+	return DistPath{basePath{path, ctx.Config(), ""}}
+}
+
+func (p DistPath) writablePath() {}
+
+func (p DistPath) Valid() bool {
+	return p.config.productVariables.DistDir != nil && *p.config.productVariables.DistDir != ""
+}
+
+func (p DistPath) String() string {
+	if !p.Valid() {
+		panic("Requesting an invalid path")
+	}
+	return filepath.Join(*p.config.productVariables.DistDir, p.path)
+}
+
+func (p DistPath) RelPathString() string {
+	return p.path
+}
+
 // ModuleSrcPath is a Path representing a file rooted from a module's local source dir
 type ModuleSrcPath struct {
 	SourcePath
diff --git a/android/paths_test.go b/android/paths_test.go
index 0075798..cd9fbfd 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -474,10 +474,7 @@
 	}
 
 	paths := makePaths()
-	reversePaths := make(Paths, len(paths))
-	for i, v := range paths {
-		reversePaths[len(paths)-i-1] = v
-	}
+	reversePaths := ReversePaths(paths)
 
 	sortedPaths := PathsToDirectorySortedPaths(paths)
 	reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
diff --git a/android/variable.go b/android/variable.go
index 01a8122..9d9830e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -128,6 +128,7 @@
 	DateFromFile        *string `json:",omitempty"`
 
 	Platform_sdk_version              *int     `json:",omitempty"`
+	Platform_sdk_codename             *string  `json:",omitempty"`
 	Platform_sdk_final                *bool    `json:",omitempty"`
 	Platform_version_active_codenames []string `json:",omitempty"`
 	Platform_version_future_codenames []string `json:",omitempty"`
@@ -226,6 +227,8 @@
 	NamespacesToExport []string `json:",omitempty"`
 
 	PgoAdditionalProfileDirs []string `json:",omitempty"`
+
+	VendorVars map[string]map[string]string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -293,7 +296,7 @@
 		property := "product_variables." + proptools.PropertyNameForField(name)
 
 		// Check that the variable was set for the product
-		val := reflect.ValueOf(mctx.Config().ProductVariables).FieldByName(name)
+		val := reflect.ValueOf(mctx.Config().productVariables).FieldByName(name)
 		if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() {
 			continue
 		}
diff --git a/cc/binary.go b/cc/binary.go
index c3e899a..9e7b70b 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -192,7 +192,7 @@
 
 	if !ctx.toolchain().Bionic() {
 		if ctx.Os() == android.Linux {
-			if binary.Properties.Static_executable == nil && Bool(ctx.Config().ProductVariables.HostStaticBinaries) {
+			if binary.Properties.Static_executable == nil && ctx.Config().HostStaticBinaries() {
 				binary.Properties.Static_executable = BoolPtr(true)
 			}
 		} else {
diff --git a/cc/builder.go b/cc/builder.go
index 59a8cc8..73a9168 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -196,18 +196,19 @@
 	_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
 
 	sAbiDiff = pctx.AndroidRuleFunc("sAbiDiff",
-		func(config android.Config) (blueprint.RuleParams, error) {
+		func(ctx android.PackageRuleContext) blueprint.RuleParams {
 
 			commandStr := "($sAbiDiffer $allowFlags -lib $libName -arch $arch -check-all-apis -o ${out} -new $in -old $referenceDump)"
-			distDir := config.ProductVariables.DistDir
-			if distDir != nil && *distDir != "" {
-				distAbiDiffDir := *distDir + "/abidiffs/"
-				commandStr += "  || (mkdir -p " + distAbiDiffDir + " && cp ${out} " + distAbiDiffDir + " && exit 1)"
+			distAbiDiffDir := android.PathForDist(ctx, "abidiffs")
+			commandStr += "|| (echo ' ---- Please update abi references by running platform/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l ${libName} ----'"
+			if distAbiDiffDir.Valid() {
+				commandStr += " && (mkdir -p " + distAbiDiffDir.String() + " && cp ${out} " + distAbiDiffDir.String() + ")"
 			}
+			commandStr += " && exit 1)"
 			return blueprint.RuleParams{
 				Command:     commandStr,
 				CommandDeps: []string{"$sAbiDiffer"},
-			}, nil
+			}
 		},
 		"allowFlags", "referenceDump", "libName", "arch")
 
@@ -738,7 +739,7 @@
 		Implicit:    referenceDump,
 		Args: map[string]string{
 			"referenceDump": referenceDump.String(),
-			"libName":       baseName,
+			"libName":       baseName[0:(len(baseName) - len(filepath.Ext(baseName)))],
 			"arch":          ctx.Arch().ArchType.Name,
 			"allowFlags":    strings.Join(localAbiCheckAllowFlags, " "),
 		},
diff --git a/cc/cc.go b/cc/cc.go
index e5eb8d8..50766fa 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -539,13 +539,14 @@
 
 // Create source abi dumps if the module belongs to the list of VndkLibraries.
 func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
+	skipAbiChecks := ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS")
 	isUnsanitizedVariant := true
 	sanitize := ctx.mod.sanitize
 	if sanitize != nil {
 		isUnsanitizedVariant = sanitize.isUnsanitizedVariant()
 	}
 	vendorAvailable := Bool(ctx.mod.VendorProperties.Vendor_available)
-	return isUnsanitizedVariant && ctx.ctx.Device() && ((ctx.useVndk() && ctx.isVndk() && vendorAvailable) || inList(ctx.baseModuleName(), llndkLibraries))
+	return !skipAbiChecks && isUnsanitizedVariant && ctx.ctx.Device() && ((ctx.useVndk() && ctx.isVndk() && vendorAvailable) || inList(ctx.baseModuleName(), llndkLibraries))
 }
 
 func (ctx *moduleContextImpl) selectedStl() string {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index f315b1d..a4e2534 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -188,8 +188,8 @@
 func testCc(t *testing.T, bp string) *android.TestContext {
 	t.Helper()
 	config := android.TestArchConfig(buildDir, nil)
-	config.ProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
 
 	return testCcWithConfig(t, bp, config)
 }
@@ -197,7 +197,7 @@
 func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
 	t.Helper()
 	config := android.TestArchConfig(buildDir, nil)
-	config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
 
 	return testCcWithConfig(t, bp, config)
 }
@@ -205,8 +205,8 @@
 func testCcError(t *testing.T, pattern string, bp string) {
 	t.Helper()
 	config := android.TestArchConfig(buildDir, nil)
-	config.ProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
 
 	ctx := createTestContext(t, config, bp)
 
diff --git a/cc/compiler.go b/cc/compiler.go
index 6154758..1b0eb4e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -377,10 +377,6 @@
 			fmt.Sprintf("${config.%sGlobalCflags}", hod))
 	}
 
-	if Bool(ctx.Config().ProductVariables.Brillo) {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-D__BRILLO__")
-	}
-
 	if ctx.Device() {
 		if Bool(compiler.Properties.Rtti) {
 			flags.CppFlags = append(flags.CppFlags, "-frtti")
diff --git a/cc/config/global.go b/cc/config/global.go
index 7df5de4..7a2aa80 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -180,26 +180,26 @@
 		[]string{"libnativehelper/include_jni"})
 
 	pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
-	pctx.VariableFunc("ClangBase", func(config android.Config) (string, error) {
-		if override := config.Getenv("LLVM_PREBUILTS_BASE"); override != "" {
-			return override, nil
+	pctx.VariableFunc("ClangBase", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("LLVM_PREBUILTS_BASE"); override != "" {
+			return override
 		}
-		return "${ClangDefaultBase}", nil
+		return "${ClangDefaultBase}"
 	})
-	pctx.VariableFunc("ClangVersion", func(config android.Config) (string, error) {
-		if override := config.Getenv("LLVM_PREBUILTS_VERSION"); override != "" {
-			return override, nil
+	pctx.VariableFunc("ClangVersion", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("LLVM_PREBUILTS_VERSION"); override != "" {
+			return override
 		}
-		return ClangDefaultVersion, nil
+		return ClangDefaultVersion
 	})
 	pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
 	pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
 
-	pctx.VariableFunc("ClangShortVersion", func(config android.Config) (string, error) {
-		if override := config.Getenv("LLVM_RELEASE_VERSION"); override != "" {
-			return override, nil
+	pctx.VariableFunc("ClangShortVersion", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("LLVM_RELEASE_VERSION"); override != "" {
+			return override
 		}
-		return ClangDefaultShortVersion, nil
+		return ClangDefaultShortVersion
 	})
 	pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib64/clang/${ClangShortVersion}/lib/linux")
 	if runtime.GOOS == "darwin" {
@@ -222,11 +222,11 @@
 			"frameworks/rs/script_api/include",
 		})
 
-	pctx.VariableFunc("CcWrapper", func(config android.Config) (string, error) {
-		if override := config.Getenv("CC_WRAPPER"); override != "" {
-			return override + " ", nil
+	pctx.VariableFunc("CcWrapper", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("CC_WRAPPER"); override != "" {
+			return override + " "
 		}
-		return "", nil
+		return ""
 	})
 }
 
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index 76a5f9e..a20d556 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -15,9 +15,8 @@
 package config
 
 import (
-	"strings"
-
 	"android/soong/android"
+	"strings"
 )
 
 func init() {
@@ -25,9 +24,9 @@
 	// Global tidy checks include only google*, performance*,
 	// and misc-macro-parentheses, but not google-readability*
 	// or google-runtime-references.
-	pctx.VariableFunc("TidyDefaultGlobalChecks", func(config android.Config) (string, error) {
-		if override := config.Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
-			return override, nil
+	pctx.VariableFunc("TidyDefaultGlobalChecks", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
+			return override
 		}
 		return strings.Join([]string{
 			"-*",
@@ -36,14 +35,14 @@
 			"performance*",
 			"-google-readability*",
 			"-google-runtime-references",
-		}, ","), nil
+		}, ",")
 	})
 
 	// There are too many clang-tidy warnings in external and vendor projects.
 	// Enable only some google checks for these projects.
-	pctx.VariableFunc("TidyExternalVendorChecks", func(config android.Config) (string, error) {
-		if override := config.Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
-			return override, nil
+	pctx.VariableFunc("TidyExternalVendorChecks", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
+			return override
 		}
 		return strings.Join([]string{
 			"-*",
@@ -54,7 +53,7 @@
 			"-google-readability*",
 			"-google-runtime-int",
 			"-google-runtime-references",
-		}, ","), nil
+		}, ",")
 	})
 
 	// Give warnings to header files only in selected directories.
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index dbaa6fa..cae9757 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -15,7 +15,6 @@
 package config
 
 import (
-	"fmt"
 	"os/exec"
 	"path/filepath"
 	"strings"
@@ -107,26 +106,28 @@
 )
 
 func init() {
-	pctx.VariableFunc("macSdkPath", func(config android.Config) (string, error) {
-		xcodeselect := config.HostSystemTool("xcode-select")
+	pctx.VariableFunc("macSdkPath", func(ctx android.PackageVarContext) string {
+		xcodeselect := ctx.Config().HostSystemTool("xcode-select")
 		bytes, err := exec.Command(xcodeselect, "--print-path").Output()
-		return strings.TrimSpace(string(bytes)), err
+		if err != nil {
+			ctx.Errorf("xcode-select failed with: %q", err.Error())
+		}
+		return strings.TrimSpace(string(bytes))
 	})
-	pctx.VariableFunc("macSdkRoot", func(config android.Config) (string, error) {
-		return xcrunSdk(config, "--show-sdk-path")
+	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
+		return xcrunSdk(ctx, "--show-sdk-path")
 	})
 	pctx.StaticVariable("macMinVersion", "10.8")
-	pctx.VariableFunc("MacArPath", func(config android.Config) (string, error) {
-		return xcrun(config, "--find", "ar")
+	pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
+		return xcrun(ctx, "--find", "ar")
 	})
 
-	pctx.VariableFunc("MacStripPath", func(config android.Config) (string, error) {
-		return xcrun(config, "--find", "strip")
+	pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
+		return xcrun(ctx, "--find", "strip")
 	})
 
-	pctx.VariableFunc("MacToolPath", func(config android.Config) (string, error) {
-		path, err := xcrun(config, "--find", "ld")
-		return filepath.Dir(path), err
+	pctx.VariableFunc("MacToolPath", func(ctx android.PackageVarContext) string {
+		return filepath.Dir(xcrun(ctx, "--find", "ld"))
 	})
 
 	pctx.StaticVariable("DarwinGccVersion", darwinGccVersion)
@@ -156,33 +157,38 @@
 	pctx.StaticVariable("DarwinX8664YasmFlags", "-f macho -m amd64")
 }
 
-func xcrun(config android.Config, args ...string) (string, error) {
-	xcrun := config.HostSystemTool("xcrun")
+func xcrun(ctx android.PackageVarContext, args ...string) string {
+	xcrun := ctx.Config().HostSystemTool("xcrun")
 	bytes, err := exec.Command(xcrun, args...).Output()
-	return strings.TrimSpace(string(bytes)), err
+	if err != nil {
+		ctx.Errorf("xcrun failed with: %q", err.Error())
+	}
+	return strings.TrimSpace(string(bytes))
 }
 
-func xcrunSdk(config android.Config, arg string) (string, error) {
-	xcrun := config.HostSystemTool("xcrun")
-	if selected := config.Getenv("MAC_SDK_VERSION"); selected != "" {
+func xcrunSdk(ctx android.PackageVarContext, arg string) string {
+	xcrun := ctx.Config().HostSystemTool("xcrun")
+	if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" {
 		if !inList(selected, darwinSupportedSdkVersions) {
-			return "", fmt.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+			ctx.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+			return ""
 		}
 
 		bytes, err := exec.Command(xcrun, "--sdk", "macosx"+selected, arg).Output()
-		if err == nil {
-			return strings.TrimSpace(string(bytes)), err
+		if err != nil {
+			ctx.Errorf("MAC_SDK_VERSION %s is not installed", selected)
 		}
-		return "", fmt.Errorf("MAC_SDK_VERSION %s is not installed", selected)
+		return strings.TrimSpace(string(bytes))
 	}
 
 	for _, sdk := range darwinSupportedSdkVersions {
 		bytes, err := exec.Command(xcrun, "--sdk", "macosx"+sdk, arg).Output()
 		if err == nil {
-			return strings.TrimSpace(string(bytes)), err
+			return strings.TrimSpace(string(bytes))
 		}
 	}
-	return "", fmt.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
+	ctx.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
+	return ""
 }
 
 type toolchainDarwin struct {
diff --git a/cc/makevars.go b/cc/makevars.go
index 479e019..3bb00a1 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -89,11 +89,7 @@
 	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("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
 
 	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(vndkCoreLibraries, " "))
 	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(vndkSpLibraries, " "))
@@ -211,10 +207,7 @@
 		hod = "Device"
 	}
 
-	if target.Os.Class == android.Device && Bool(ctx.Config().ProductVariables.Brillo) {
-		productExtraCflags += "-D__BRILLO__"
-	}
-	if target.Os.Class == android.Host && Bool(ctx.Config().ProductVariables.HostStaticBinaries) {
+	if target.Os.Class == android.Host && ctx.Config().HostStaticBinaries() {
 		productExtraLdflags += "-static"
 	}
 
diff --git a/cc/proto.go b/cc/proto.go
index c53dcf4..42bb536 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -115,7 +115,7 @@
 	flags.protoFlags = android.ProtoFlags(ctx, p)
 
 	if proptools.String(p.Proto.Type) == "lite" {
-		flags.protoOutParams = []string{"lite"}
+		flags.protoOutParams = append(flags.protoOutParams, "lite")
 	}
 
 	return flags
diff --git a/cc/util.go b/cc/util.go
index aaf0f71..1e4a0c0 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -67,7 +67,7 @@
 		cppFlags:       strings.Join(in.CppFlags, " "),
 		yaccFlags:      strings.Join(in.YaccFlags, " "),
 		protoFlags:     strings.Join(in.protoFlags, " "),
-		protoOutParams: strings.Join(in.protoOutParams, ":"),
+		protoOutParams: strings.Join(in.protoOutParams, ","),
 		aidlFlags:      strings.Join(in.aidlFlags, " "),
 		rsFlags:        strings.Join(in.rsFlags, " "),
 		ldFlags:        strings.Join(in.LdFlags, " "),
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 40beab8..a4c6898 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -36,7 +36,7 @@
 func newNameResolver(config android.Config) *android.NameResolver {
 	namespacePathsToExport := make(map[string]bool)
 
-	for _, namespaceName := range config.ProductVariables.NamespacesToExport {
+	for _, namespaceName := range config.ExportedNamespaces() {
 		namespacePathsToExport[namespaceName] = true
 	}
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 3658636..13966ed 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -195,7 +195,9 @@
 				}
 
 				if len(app.rroDirs) > 0 {
-					fmt.Fprintln(w, "LOCAL_SOONG_RRO_DIRS :=", strings.Join(app.rroDirs.Strings(), " "))
+					// Reverse the order, Soong stores rroDirs in aapt2 order (low to high priority), but Make
+					// expects it in LOCAL_RESOURCE_DIRS order (high to low priority).
+					fmt.Fprintln(w, "LOCAL_SOONG_RRO_DIRS :=", strings.Join(android.ReversePaths(app.rroDirs).Strings(), " "))
 				}
 
 				if Bool(app.appProperties.Export_package_resources) {
diff --git a/java/app.go b/java/app.go
index ac88df7..0db48e7 100644
--- a/java/app.go
+++ b/java/app.go
@@ -283,7 +283,7 @@
 	sdkVersion := String(a.deviceProperties.Sdk_version)
 	switch sdkVersion {
 	case "", "current", "system_current", "test_current":
-		sdkVersion = proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
+		sdkVersion = proptools.NinjaEscape([]string{ctx.Config().DefaultAppTargetSdk()})[0]
 	}
 
 	linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
@@ -362,15 +362,7 @@
 	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
 
 	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
-	rroEnabled := false
-	enforceRROTargets := ctx.Config().ProductVariables.EnforceRROTargets
-	if enforceRROTargets != nil {
-		if len(*enforceRROTargets) == 1 && (*enforceRROTargets)[0] == "*" {
-			rroEnabled = true
-		} else if inList(ctx.ModuleName(), *enforceRROTargets) {
-			rroEnabled = true
-		}
-	}
+	rroEnabled := ctx.Config().EnforceRROForModule(ctx.ModuleName())
 
 	for _, data := range overlayData {
 		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
@@ -400,13 +392,6 @@
 type overlaySingleton struct{}
 
 func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
-
-	// Specific overlays may be excluded from Runtime Resource Overlays by the product config
-	var rroExcludedOverlays []string
-	if ctx.Config().ProductVariables.EnforceRROExcludedOverlays != nil {
-		rroExcludedOverlays = *ctx.Config().ProductVariables.EnforceRROExcludedOverlays
-	}
-
 	var overlayData []overlayGlobResult
 	overlayDirs := ctx.Config().ResourceOverlays()
 	for i := range overlayDirs {
@@ -417,11 +402,8 @@
 		result.dir = overlay
 
 		// Mark overlays that will not have Runtime Resource Overlays enforced on them
-		for _, exclude := range rroExcludedOverlays {
-			if strings.HasPrefix(overlay, exclude) {
-				result.excludeFromRRO = true
-			}
-		}
+		// based on the product config
+		result.excludeFromRRO = ctx.Config().EnforceRROExcludedOverlay(overlay)
 
 		files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
 		if err != nil {
diff --git a/java/app_test.go b/java/app_test.go
index d3216bf..2e53130 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -16,8 +16,10 @@
 
 import (
 	"android/soong/android"
+	"fmt"
 	"reflect"
 	"sort"
+	"strings"
 	"testing"
 )
 
@@ -188,12 +190,12 @@
 	for _, testCase := range testEnforceRROTests {
 		t.Run(testCase.name, func(t *testing.T) {
 			config := testConfig(nil)
-			config.ProductVariables.ResourceOverlays = &resourceOverlays
+			config.TestProductVariables.ResourceOverlays = &resourceOverlays
 			if testCase.enforceRROTargets != nil {
-				config.ProductVariables.EnforceRROTargets = &testCase.enforceRROTargets
+				config.TestProductVariables.EnforceRROTargets = &testCase.enforceRROTargets
 			}
 			if testCase.enforceRROExcludedOverlays != nil {
-				config.ProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays
+				config.TestProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays
 			}
 
 			ctx := testAppContext(config, bp, fs)
@@ -237,3 +239,94 @@
 		})
 	}
 }
+
+func TestAppSdkVersion(t *testing.T) {
+	testCases := []struct {
+		name                  string
+		sdkVersion            string
+		platformSdkInt        int
+		platformSdkCodename   string
+		platformSdkFinal      bool
+		expectedMinSdkVersion string
+	}{
+		{
+			name:                  "current final SDK",
+			sdkVersion:            "current",
+			platformSdkInt:        27,
+			platformSdkCodename:   "REL",
+			platformSdkFinal:      true,
+			expectedMinSdkVersion: "27",
+		},
+		{
+			name:                  "current non-final SDK",
+			sdkVersion:            "current",
+			platformSdkInt:        27,
+			platformSdkCodename:   "OMR1",
+			platformSdkFinal:      false,
+			expectedMinSdkVersion: "OMR1",
+		},
+		{
+			name:                  "default final SDK",
+			sdkVersion:            "",
+			platformSdkInt:        27,
+			platformSdkCodename:   "REL",
+			platformSdkFinal:      true,
+			expectedMinSdkVersion: "27",
+		},
+		{
+			name:                  "default non-final SDK",
+			sdkVersion:            "",
+			platformSdkInt:        27,
+			platformSdkCodename:   "OMR1",
+			platformSdkFinal:      false,
+			expectedMinSdkVersion: "OMR1",
+		},
+		{
+			name:                  "14",
+			sdkVersion:            "14",
+			expectedMinSdkVersion: "14",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			bp := fmt.Sprintf(`android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "%s",
+				}`, test.sdkVersion)
+
+			config := testConfig(nil)
+			config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
+			config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
+			config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
+
+			ctx := testAppContext(config, bp, nil)
+
+			run(t, ctx, config)
+
+			foo := ctx.ModuleForTests("foo", "android_common")
+			link := foo.Output("package-res.apk")
+			linkFlags := strings.Split(link.Args["flags"], " ")
+			min := android.IndexList("--min-sdk-version", linkFlags)
+			target := android.IndexList("--target-sdk-version", linkFlags)
+
+			if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
+				t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
+			}
+
+			gotMinSdkVersion := linkFlags[min+1]
+			gotTargetSdkVersion := linkFlags[target+1]
+
+			if gotMinSdkVersion != test.expectedMinSdkVersion {
+				t.Errorf("incorrect --min-sdk-version, expected %q got %q",
+					test.expectedMinSdkVersion, gotMinSdkVersion)
+			}
+
+			if gotTargetSdkVersion != test.expectedMinSdkVersion {
+				t.Errorf("incorrect --target-sdk-version, expected %q got %q",
+					test.expectedMinSdkVersion, gotTargetSdkVersion)
+			}
+		})
+	}
+}
diff --git a/java/config/config.go b/java/config/config.go
index 37f6528..5587a16 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -68,9 +68,9 @@
 
 	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
 
-	pctx.VariableFunc("JavaHome", func(config android.Config) (string, error) {
+	pctx.VariableFunc("JavaHome", func(ctx android.PackageVarContext) string {
 		// This is set up and guaranteed by soong_ui
-		return config.Getenv("ANDROID_JAVA_HOME"), nil
+		return ctx.Config().Getenv("ANDROID_JAVA_HOME")
 	})
 
 	pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
@@ -91,38 +91,27 @@
 	pctx.HostBinToolVariable("MergeZipsCmd", "merge_zips")
 	pctx.HostBinToolVariable("Zip2ZipCmd", "zip2zip")
 	pctx.HostBinToolVariable("ZipSyncCmd", "zipsync")
-	pctx.VariableFunc("DxCmd", func(config android.Config) (string, error) {
+	pctx.VariableFunc("DxCmd", func(ctx android.PackageVarContext) string {
+		config := ctx.Config()
 		if config.IsEnvFalse("USE_D8") {
 			if config.UnbundledBuild() || config.IsPdkBuild() {
-				return "prebuilts/build-tools/common/bin/dx", nil
+				return "prebuilts/build-tools/common/bin/dx"
 			} else {
-				path, err := pctx.HostBinToolPath(config, "dx")
-				if err != nil {
-					return "", err
-				}
-				return path.String(), nil
+				return pctx.HostBinToolPath(ctx, "dx").String()
 			}
 		} else {
-			path, err := pctx.HostBinToolPath(config, "d8-compat-dx")
-			if err != nil {
-				return "", err
-			}
-			return path.String(), nil
+			return pctx.HostBinToolPath(ctx, "d8-compat-dx").String()
 		}
 	})
 	pctx.HostBinToolVariable("D8Cmd", "d8")
 	pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard")
 
-	pctx.VariableFunc("TurbineJar", func(config android.Config) (string, error) {
+	pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
 		turbine := "turbine.jar"
-		if config.UnbundledBuild() {
-			return "prebuilts/build-tools/common/framework/" + turbine, nil
+		if ctx.Config().UnbundledBuild() {
+			return "prebuilts/build-tools/common/framework/" + turbine
 		} else {
-			path, err := pctx.HostJavaToolPath(config, turbine)
-			if err != nil {
-				return "", err
-			}
-			return path.String(), nil
+			return pctx.HostJavaToolPath(ctx, turbine).String()
 		}
 	})
 
@@ -133,25 +122,21 @@
 
 	pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")
 
-	pctx.VariableFunc("JavacWrapper", func(config android.Config) (string, error) {
-		if override := config.Getenv("JAVAC_WRAPPER"); override != "" {
-			return override + " ", nil
+	pctx.VariableFunc("JavacWrapper", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("JAVAC_WRAPPER"); override != "" {
+			return override + " "
 		}
-		return "", nil
+		return ""
 	})
 
 	pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
 
 	hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
-		pctx.VariableFunc(name, func(config android.Config) (string, error) {
-			if config.UnbundledBuild() || config.IsPdkBuild() {
-				return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool), nil
+		pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
+			if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+				return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool)
 			} else {
-				if path, err := pctx.HostBinToolPath(config, tool); err != nil {
-					return "", err
-				} else {
-					return path.String(), nil
-				}
+				return pctx.HostBinToolPath(ctx, tool).String()
 			}
 		})
 	}
diff --git a/java/config/error_prone.go b/java/config/error_prone.go
index 862217f..f203234 100644
--- a/java/config/error_prone.go
+++ b/java/config/error_prone.go
@@ -27,8 +27,8 @@
 
 // Wrapper that grabs value of val late so it can be initialized by a later module's init function
 func errorProneVar(name string, val *string) {
-	pctx.VariableFunc(name, func(config android.Config) (string, error) {
-		return *val, nil
+	pctx.VariableFunc(name, func(android.PackageVarContext) string {
+		return *val
 	})
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index 6ef406f..015c233 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -60,7 +60,7 @@
 		env["ANDROID_JAVA8_HOME"] = "jdk8"
 	}
 	config := android.TestArchConfig(buildDir, env)
-	config.ProductVariables.DeviceSystemSdkVersions = &[]string{"14", "15"}
+	config.TestProductVariables.DeviceSystemSdkVersions = &[]string{"14", "15"}
 	return config
 
 }