Merge changes from topic "remove_ndk_platform"

* changes:
  *-ndk.so libraries are added to VndkMustUseVendorVariantList
  Reland: Add more target-specific properties
diff --git a/android/bazel.go b/android/bazel.go
index d40e650..f72fd40 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -127,11 +127,22 @@
 
 var (
 	// Keep any existing BUILD files (and do not generate new BUILD files) for these directories
+	// in the synthetic Bazel workspace.
 	bp2buildKeepExistingBuildFile = map[string]bool{
 		// This is actually build/bazel/build.BAZEL symlinked to ./BUILD
 		".":/*recursive = */ false,
 
-		"build/bazel":/* recursive = */ true,
+		// build/bazel/examples/apex/... BUILD files should be generated, so
+		// build/bazel is not recursive. Instead list each subdirectory under
+		// build/bazel explicitly.
+		"build/bazel":/* recursive = */ false,
+		"build/bazel/examples/android_app":/* recursive = */ true,
+		"build/bazel/bazel_skylib":/* recursive = */ true,
+		"build/bazel/rules":/* recursive = */ true,
+		"build/bazel/rules_cc":/* recursive = */ true,
+		"build/bazel/tests":/* recursive = */ true,
+		"build/bazel/platforms":/* recursive = */ true,
+		"build/bazel/product_variables":/* recursive = */ true,
 		"build/pesto":/* recursive = */ true,
 
 		// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
diff --git a/android/config.go b/android/config.go
index 9addf5d..b3b8f3c 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1851,16 +1851,16 @@
 func (c *config) BootJars() []string {
 	return c.Once(earlyBootJarsKey, func() interface{} {
 		list := c.productVariables.BootJars.CopyOfJars()
-		return append(list, c.productVariables.UpdatableBootJars.CopyOfJars()...)
+		return append(list, c.productVariables.ApexBootJars.CopyOfJars()...)
 	}).([]string)
 }
 
-func (c *config) NonUpdatableBootJars() ConfiguredJarList {
+func (c *config) NonApexBootJars() ConfiguredJarList {
 	return c.productVariables.BootJars
 }
 
-func (c *config) UpdatableBootJars() ConfiguredJarList {
-	return c.productVariables.UpdatableBootJars
+func (c *config) ApexBootJars() ConfiguredJarList {
+	return c.productVariables.ApexBootJars
 }
 
 func (c *config) RBEWrapper() string {
diff --git a/android/variable.go b/android/variable.go
index d32debe..0fb9078 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -253,8 +253,8 @@
 	UncompressPrivAppDex             *bool    `json:",omitempty"`
 	ModulesLoadedByPrivilegedModules []string `json:",omitempty"`
 
-	BootJars          ConfiguredJarList `json:",omitempty"`
-	UpdatableBootJars ConfiguredJarList `json:",omitempty"`
+	BootJars     ConfiguredJarList `json:",omitempty"`
+	ApexBootJars ConfiguredJarList `json:",omitempty"`
 
 	IntegerOverflowExcludePaths []string `json:",omitempty"`
 
@@ -441,8 +441,8 @@
 		Malloc_pattern_fill_contents: boolPtr(false),
 		Safestack:                    boolPtr(false),
 
-		BootJars:          ConfiguredJarList{apexes: []string{}, jars: []string{}},
-		UpdatableBootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}},
+		BootJars:     ConfiguredJarList{apexes: []string{}, jars: []string{}},
+		ApexBootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}},
 	}
 
 	if runtime.GOOS == "linux" {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d6c7142..f58bf6c 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7264,7 +7264,7 @@
 	})
 }
 
-func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) {
+func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, bootJars []string, rules []android.Rule) {
 	t.Helper()
 	bp += `
 	apex_key {
@@ -7289,11 +7289,11 @@
 		PrepareForTestWithApexBuildComponents,
 		android.PrepareForTestWithNeverallowRules(rules),
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			updatableBootJars := make([]string, 0, len(apexBootJars))
-			for _, apexBootJar := range apexBootJars {
-				updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar)
+			apexBootJars := make([]string, 0, len(bootJars))
+			for _, apexBootJar := range bootJars {
+				apexBootJars = append(apexBootJars, "myapex:"+apexBootJar)
 			}
-			variables.UpdatableBootJars = android.CreateTestConfiguredJarList(updatableBootJars)
+			variables.ApexBootJars = android.CreateTestConfiguredJarList(apexBootJars)
 		}),
 		fs.AddToFixture(),
 	).
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 5cd3eab..6098989 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -748,7 +748,7 @@
 		prepareForTestWithMyapex,
 		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
 		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
-		java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
+		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
 		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
 		// is disabled.
 		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 7209c02..eaee20d 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -173,7 +173,7 @@
 		prepareForTestWithMyapex,
 		// Configure some libraries in the art and framework boot images.
 		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo"),
-		java.FixtureConfigureUpdatableBootJars("myapex:bar"),
+		java.FixtureConfigureApexBootJars("myapex:bar"),
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo"),
 	).RunTestWithBp(t, `
@@ -288,7 +288,7 @@
 		"com.android.art:quuz",
 		"platform:foo",
 
-		// The configured contents of UpdatableBootJars.
+		// The configured contents of ApexBootJars.
 		"myapex:bar",
 	})
 
@@ -313,7 +313,7 @@
 		`com.android.art:quuz`,
 		`platform:foo`,
 
-		// The configured contents of UpdatableBootJars.
+		// The configured contents of ApexBootJars.
 		`myapex:bar`,
 
 		// The fragments.
@@ -348,7 +348,7 @@
 		// if the dependency on myapex:foo is filtered out because of either of those conditions then
 		// the dependencies resolved by the platform_bootclasspath will not match the configured list
 		// and so will fail the test.
-		java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
+		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
@@ -490,7 +490,7 @@
 	result := android.GroupFixturePreparers(
 		prepareForTestWithPlatformBootclasspath,
 		prepareForTestWithMyapex,
-		java.FixtureConfigureUpdatableBootJars("myapex:foo"),
+		java.FixtureConfigureApexBootJars("myapex:foo"),
 		android.FixtureWithRootAndroidBp(`
 			platform_bootclasspath {
 				name: "platform-bootclasspath",
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 22922c0..02c5229 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -16,6 +16,7 @@
 
 import (
 	"context"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -34,6 +35,11 @@
 	"android/soong/ui/tracer"
 )
 
+const (
+	configDir  = "vendor/google/tools/soong_config"
+	jsonSuffix = "json"
+)
+
 // A command represents an operation to be executed in the soong build
 // system.
 type command struct {
@@ -110,6 +116,34 @@
 	return indexList(s, list) != -1
 }
 
+func loadEnvConfig() error {
+	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
+	if bc == "" {
+		return nil
+	}
+	cfgFile := filepath.Join(os.Getenv("TOP"), configDir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
+
+	envVarsJSON, err := ioutil.ReadFile(cfgFile)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "\033[33mWARNING:\033[0m failed to open config file %s: %s\n", cfgFile, err.Error())
+		return nil
+	}
+
+	var envVars map[string]map[string]string
+	if err := json.Unmarshal(envVarsJSON, &envVars); err != nil {
+		return fmt.Errorf("env vars config file: %s did not parse correctly: %s", cfgFile, err.Error())
+	}
+	for k, v := range envVars["env"] {
+		if os.Getenv(k) != "" {
+			continue
+		}
+		if err := os.Setenv(k, v); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // Main execution of soong_ui. The command format is as follows:
 //
 //    soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
@@ -171,6 +205,11 @@
 		Status:  stat,
 	}}
 
+	if err := loadEnvConfig(); err != nil {
+		fmt.Fprintf(os.Stderr, "failed to parse env config files: %v", err)
+		os.Exit(1)
+	}
+
 	config := c.config(buildCtx, args...)
 
 	build.SetupOutDir(buildCtx, config)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 0bcec17..d4ab4bc 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -44,8 +44,8 @@
 	DisableGenerateProfile bool   // don't generate profiles
 	ProfileDir             string // directory to find profiles in
 
-	BootJars          android.ConfiguredJarList // modules for jars that form the boot class path
-	UpdatableBootJars android.ConfiguredJarList // jars within apex that form the boot class path
+	BootJars     android.ConfiguredJarList // modules for jars that form the boot class path
+	ApexBootJars android.ConfiguredJarList // jars within apex that form the boot class path
 
 	ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX
 
@@ -531,7 +531,7 @@
 	return config, nil
 }
 
-// checkBootJarsConfigConsistency checks the consistency of BootJars and UpdatableBootJars fields in
+// checkBootJarsConfigConsistency checks the consistency of BootJars and ApexBootJars fields in
 // DexpreoptGlobalConfig and Config.productVariables.
 func checkBootJarsConfigConsistency(ctx android.SingletonContext, dexpreoptConfig *GlobalConfig, config android.Config) {
 	compareBootJars := func(property string, dexpreoptJars, variableJars android.ConfiguredJarList) {
@@ -545,8 +545,8 @@
 		}
 	}
 
-	compareBootJars("BootJars", dexpreoptConfig.BootJars, config.NonUpdatableBootJars())
-	compareBootJars("UpdatableBootJars", dexpreoptConfig.UpdatableBootJars, config.UpdatableBootJars())
+	compareBootJars("BootJars", dexpreoptConfig.BootJars, config.NonApexBootJars())
+	compareBootJars("ApexBootJars", dexpreoptConfig.ApexBootJars, config.ApexBootJars())
 }
 
 func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -614,7 +614,7 @@
 		DisableGenerateProfile:             false,
 		ProfileDir:                         "",
 		BootJars:                           android.EmptyConfiguredJarList(),
-		UpdatableBootJars:                  android.EmptyConfiguredJarList(),
+		ApexBootJars:                       android.EmptyConfiguredJarList(),
 		ArtApexJars:                        android.EmptyConfiguredJarList(),
 		SystemServerJars:                   android.EmptyConfiguredJarList(),
 		SystemServerApps:                   nil,
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index c0ba5ca..2f99655 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -118,10 +118,10 @@
 	})
 }
 
-// FixtureSetUpdatableBootJars sets the UpdatableBootJars property in the global config.
-func FixtureSetUpdatableBootJars(bootJars ...string) android.FixturePreparer {
+// FixtureSetApexBootJars sets the ApexBootJars property in the global config.
+func FixtureSetApexBootJars(bootJars ...string) android.FixturePreparer {
 	return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
-		dexpreoptConfig.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars)
+		dexpreoptConfig.ApexBootJars = android.CreateTestConfiguredJarList(bootJars)
 	})
 }
 
diff --git a/java/app_test.go b/java/app_test.go
index a99ac62..7997f7a 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2471,7 +2471,7 @@
 				PrepareForTestWithJavaSdkLibraryFiles,
 				FixtureWithLastReleaseApis("runtime-library", "foo", "bar"),
 				dexpreopt.FixtureSetBootJars("platform:foo"),
-				dexpreopt.FixtureSetUpdatableBootJars("platform:bar"),
+				dexpreopt.FixtureSetApexBootJars("platform:bar"),
 				dexpreopt.FixtureSetPreoptWithUpdatableBcp(test.with),
 			).RunTestWithBp(t, bp)
 
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 1ce9911..107d34a 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -537,15 +537,11 @@
 
 	global := dexpreopt.GetGlobalConfig(ctx)
 
-	possibleUpdatableModules := gatherPossibleUpdatableModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
-
-	// Only create configs for updatable boot jars. Non-updatable boot jars must be part of the
-	// platform_bootclasspath's classpath proto config to guarantee that they come before any
-	// updatable jars at runtime.
-	jars := global.UpdatableBootJars.Filter(possibleUpdatableModules)
+	possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
+	jars := global.ApexBootJars.Filter(possibleUpdatableModules)
 
 	// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
-	// config. However, any test specific jars would not be present in UpdatableBootJars. Instead,
+	// config. However, any test specific jars would not be present in ApexBootJars. Instead,
 	// we should check if we are creating a config for apex_test via ApexInfo and amend the values.
 	// This is an exception to support end-to-end test for SdkExtensions, until such support exists.
 	if android.InList("test_framework-sdkextensions", possibleUpdatableModules) {
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 12bb711..f63d81d 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -91,8 +91,8 @@
 	maxSdkVersion int32
 }
 
-// gatherPossibleUpdatableModuleNamesAndStems returns a set of module and stem names from the
-// supplied contents that may be in the updatable boot jars.
+// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
+// supplied contents that may be in the apex boot jars.
 //
 // The module names are included because sometimes the stem is set to just change the name of
 // the installed file and it expects the configuration to still use the actual module name.
@@ -100,7 +100,7 @@
 // The stem names are included because sometimes the stem is set to change the effective name of the
 // module that is used in the configuration as well,e .g. when a test library is overriding an
 // actual boot jar
-func gatherPossibleUpdatableModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
+func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
 	set := map[string]struct{}{}
 	for _, name := range contents {
 		dep := ctx.GetDirectDepWithTag(name, tag)
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 2c78d73..1019b4c 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -167,10 +167,10 @@
 // regardless which APEX goes into the product. See also android.ApexInfo.ApexVariationName and
 // apex.apexBundleProperties.Apex_name.
 //
-// A related variable PRODUCT_UPDATABLE_BOOT_JARS contains bootclasspath libraries that are in
-// APEXes. They are not included in the boot image. The only exception here is core-icu4j.jar that
-// has been historically part of the boot image and is now in a non updatable apex; it is treated
-// as being part of PRODUCT_BOOT_JARS and is in the boot image.
+// A related variable PRODUCT_APEX_BOOT_JARS contains bootclasspath libraries that are in APEXes.
+// They are not included in the boot image. The only exception here are ART jars and core-icu4j.jar
+// that have been historically part of the boot image and are now in apexes; they are in boot images
+// and core-icu4j.jar is generally treated as being part of PRODUCT_BOOT_JARS.
 //
 // One exception to the above rules are "coverage" builds (a special build flavor which requires
 // setting environment variable EMMA_INSTRUMENT_FRAMEWORK=true). In coverage builds the Java code in
@@ -810,10 +810,10 @@
 
 // generateUpdatableBcpPackagesRule generates the rule to create the updatable-bcp-packages.txt file
 // and returns a path to the generated file.
-func generateUpdatableBcpPackagesRule(ctx android.ModuleContext, image *bootImageConfig, updatableModules []android.Module) android.WritablePath {
+func generateUpdatableBcpPackagesRule(ctx android.ModuleContext, image *bootImageConfig, apexModules []android.Module) android.WritablePath {
 	// Collect `permitted_packages` for updatable boot jars.
 	var updatablePackages []string
-	for _, module := range updatableModules {
+	for _, module := range apexModules {
 		if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
 			pp := j.PermittedPackagesForUpdatableBootJars()
 			if len(pp) > 0 {
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 1507aaf..415a1d4 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -142,14 +142,14 @@
 	return genBootImageConfigs(ctx)[frameworkBootImageName]
 }
 
-// Updatable boot config allows to access build/install paths of updatable boot jars without going
+// Apex boot config allows to access build/install paths of apex boot jars without going
 // through the usual trouble of registering dependencies on those modules and extracting build paths
 // from those dependencies.
-type updatableBootConfig struct {
-	// A list of updatable boot jars.
+type apexBootConfig struct {
+	// A list of apex boot jars.
 	modules android.ConfiguredJarList
 
-	// A list of predefined build paths to updatable boot jars. They are configured very early,
+	// A list of predefined build paths to apex boot jars. They are configured very early,
 	// before the modules for these jars are processed and the actual paths are generated, and
 	// later on a singleton adds commands to copy actual jars to the predefined paths.
 	dexPaths android.WritablePaths
@@ -161,21 +161,21 @@
 	dexLocations []string
 }
 
-var updatableBootConfigKey = android.NewOnceKey("updatableBootConfig")
+var updatableBootConfigKey = android.NewOnceKey("apexBootConfig")
 
-// Returns updatable boot config.
-func GetUpdatableBootConfig(ctx android.PathContext) updatableBootConfig {
+// Returns apex boot config.
+func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
 	return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
-		updatableBootJars := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
+		apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
 
-		dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "updatable_bootjars")
-		dexPaths := updatableBootJars.BuildPaths(ctx, dir)
-		dexPathsByModuleName := updatableBootJars.BuildPathsByModule(ctx, dir)
+		dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "apex_bootjars")
+		dexPaths := apexBootJars.BuildPaths(ctx, dir)
+		dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
 
-		dexLocations := updatableBootJars.DevicePaths(ctx.Config(), android.Android)
+		dexLocations := apexBootJars.DevicePaths(ctx.Config(), android.Android)
 
-		return updatableBootConfig{updatableBootJars, dexPaths, dexPathsByModuleName, dexLocations}
-	}).(updatableBootConfig)
+		return apexBootConfig{apexBootJars, dexPaths, dexPathsByModuleName, dexLocations}
+	}).(apexBootConfig)
 }
 
 // Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be
@@ -188,10 +188,10 @@
 	dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
 
 	if withUpdatable {
-		// Updatable boot jars (they are used only in dexpreopt, but not in the boot image).
-		updBootConfig := GetUpdatableBootConfig(ctx)
-		dexPaths = append(dexPaths, updBootConfig.dexPaths...)
-		dexLocations = append(dexLocations, updBootConfig.dexLocations...)
+		// Apex boot jars (they are used only in dexpreopt, but not in the boot image).
+		apexBootConfig := GetApexBootConfig(ctx)
+		dexPaths = append(dexPaths, apexBootConfig.dexPaths...)
+		dexLocations = append(dexLocations, apexBootConfig.dexLocations...)
 	}
 
 	return dexPaths, dexLocations
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index f901434..30683da 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -118,11 +118,11 @@
 }
 
 func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Module) bool {
-	// Get the configured non-updatable and updatable boot jars.
-	nonUpdatableBootJars := ctx.Config().NonUpdatableBootJars()
-	updatableBootJars := ctx.Config().UpdatableBootJars()
-	active := isModuleInConfiguredList(ctx, module, nonUpdatableBootJars) ||
-		isModuleInConfiguredList(ctx, module, updatableBootJars)
+	// Get the configured platform and apex boot jars.
+	nonApexBootJars := ctx.Config().NonApexBootJars()
+	apexBootJars := ctx.Config().ApexBootJars()
+	active := isModuleInConfiguredList(ctx, module, nonApexBootJars) ||
+		isModuleInConfiguredList(ctx, module, apexBootJars)
 	return active
 }
 
diff --git a/java/java.go b/java/java.go
index e38a714..b6e2a54 100644
--- a/java/java.go
+++ b/java/java.go
@@ -457,7 +457,7 @@
 
 var _ android.ApexModule = (*Library)(nil)
 
-// Provides access to the list of permitted packages from updatable boot jars.
+// Provides access to the list of permitted packages from apex boot jars.
 type PermittedPackagesForUpdatableBootJars interface {
 	PermittedPackagesForUpdatableBootJars() []string
 }
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 8bed3e9..3ff4c77 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -32,9 +32,9 @@
 // The tags used for the dependencies between the platform bootclasspath and any configured boot
 // jars.
 var (
-	platformBootclasspathArtBootJarDepTag          = bootclasspathDependencyTag{name: "art-boot-jar"}
-	platformBootclasspathNonUpdatableBootJarDepTag = bootclasspathDependencyTag{name: "non-updatable-boot-jar"}
-	platformBootclasspathUpdatableBootJarDepTag    = bootclasspathDependencyTag{name: "updatable-boot-jar"}
+	platformBootclasspathArtBootJarDepTag  = bootclasspathDependencyTag{name: "art-boot-jar"}
+	platformBootclasspathBootJarDepTag     = bootclasspathDependencyTag{name: "platform-boot-jar"}
+	platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"}
 )
 
 type platformBootclasspathModule struct {
@@ -131,11 +131,11 @@
 	// Add dependencies on all the non-updatable module configured in the "boot" boot image. That does
 	// not include modules configured in the "art" boot image.
 	bootImageConfig := b.getImageConfig(ctx)
-	addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathNonUpdatableBootJarDepTag)
+	addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathBootJarDepTag)
 
-	// Add dependencies on all the updatable modules.
-	updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
-	addDependenciesOntoBootImageModules(ctx, updatableModules, platformBootclasspathUpdatableBootJarDepTag)
+	// Add dependencies on all the apex jars.
+	apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
+	addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
 
 	// Add dependencies on all the fragments.
 	b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
@@ -163,16 +163,16 @@
 }
 
 func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// Gather all the dependencies from the art, updatable and non-updatable boot jars.
+	// Gather all the dependencies from the art, platform, and apex boot jars.
 	artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag)
-	nonUpdatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathNonUpdatableBootJarDepTag)
-	updatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathUpdatableBootJarDepTag)
+	platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag)
+	apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag)
 
 	// Concatenate them all, in order as they would appear on the bootclasspath.
 	var allModules []android.Module
 	allModules = append(allModules, artModules...)
-	allModules = append(allModules, nonUpdatableModules...)
-	allModules = append(allModules, updatableModules...)
+	allModules = append(allModules, platformModules...)
+	allModules = append(allModules, apexModules...)
 	b.configuredModules = allModules
 
 	// Gather all the fragments dependencies.
@@ -180,8 +180,8 @@
 
 	// Check the configuration of the boot modules.
 	// ART modules are checked by the art-bootclasspath-fragment.
-	b.checkNonUpdatableModules(ctx, nonUpdatableModules)
-	b.checkUpdatableModules(ctx, updatableModules)
+	b.checkPlatformModules(ctx, platformModules)
+	b.checkApexModules(ctx, apexModules)
 
 	b.generateClasspathProtoBuildActions(ctx)
 
@@ -193,7 +193,7 @@
 		return
 	}
 
-	b.generateBootImageBuildActions(ctx, nonUpdatableModules, updatableModules)
+	b.generateBootImageBuildActions(ctx, platformModules, apexModules)
 }
 
 // Generate classpaths.proto config
@@ -209,7 +209,7 @@
 	jars := b.getImageConfig(ctx).modules
 
 	// Include jars from APEXes that don't populate their classpath proto config.
-	remainingJars := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
+	remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
 	for _, fragment := range b.fragments {
 		info := ctx.OtherModuleProvider(fragment, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
 		if info.ClasspathFragmentProtoGenerated {
@@ -223,9 +223,10 @@
 	return jars
 }
 
-// checkNonUpdatableModules ensures that the non-updatable modules supplied are not part of an
-// updatable module.
-func (b *platformBootclasspathModule) checkNonUpdatableModules(ctx android.ModuleContext, modules []android.Module) {
+// checkPlatformModules ensures that the non-updatable modules supplied are not part of an
+// apex module.
+func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) {
+	// TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here.
 	for _, m := range modules {
 		apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
 		fromUpdatableApex := apexInfo.Updatable
@@ -238,8 +239,8 @@
 	}
 }
 
-// checkUpdatableModules ensures that the updatable modules supplied are not from the platform.
-func (b *platformBootclasspathModule) checkUpdatableModules(ctx android.ModuleContext, modules []android.Module) {
+// checkApexModules ensures that the apex modules supplied are not from the platform.
+func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) {
 	for _, m := range modules {
 		apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
 		fromUpdatableApex := apexInfo.Updatable
@@ -255,12 +256,12 @@
 				//  modules is complete.
 				if !ctx.Config().AlwaysUsePrebuiltSdks() {
 					// error: this jar is part of the platform
-					ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+					ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name)
 				}
 			} else {
 				// TODO(b/177892522): Treat this as an error.
 				// Cannot do that at the moment because framework-wifi and framework-tethering are in the
-				// PRODUCT_UPDATABLE_BOOT_JARS but not marked as updatable in AOSP.
+				// PRODUCT_APEX_BOOT_JARS but not marked as updatable in AOSP.
 			}
 		}
 	}
@@ -405,7 +406,7 @@
 }
 
 // generateBootImageBuildActions generates ninja rules related to the boot image creation.
-func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, nonUpdatableModules, updatableModules []android.Module) {
+func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, platformModules, apexModules []android.Module) {
 	// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
 	// GenerateSingletonBuildActions method as it cannot create it for itself.
 	dexpreopt.GetGlobalSoongConfig(ctx)
@@ -428,17 +429,17 @@
 	// TODO(b/193889859): Remove when the prebuilts have been updated.
 	if !ctx.Config().AlwaysUsePrebuiltSdks() {
 		// Generate the updatable bootclasspath packages rule.
-		generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
+		generateUpdatableBcpPackagesRule(ctx, imageConfig, apexModules)
 	}
 
-	// Copy non-updatable module dex jars to their predefined locations.
-	nonUpdatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, nonUpdatableModules)
-	copyBootJarsToPredefinedLocations(ctx, nonUpdatableBootDexJarsByModule, imageConfig.dexPathsByModule)
+	// Copy platform module dex jars to their predefined locations.
+	platformBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, platformModules)
+	copyBootJarsToPredefinedLocations(ctx, platformBootDexJarsByModule, imageConfig.dexPathsByModule)
 
-	// Copy updatable module dex jars to their predefined locations.
-	config := GetUpdatableBootConfig(ctx)
-	updatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, updatableModules)
-	copyBootJarsToPredefinedLocations(ctx, updatableBootDexJarsByModule, config.dexPathsByModule)
+	// Copy apex module dex jars to their predefined locations.
+	config := GetApexBootConfig(ctx)
+	apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
+	copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
 
 	// Build a profile for the image config and then use that to build the boot image.
 	profile := bootImageProfileRule(ctx, imageConfig)
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 28a5a2c..dfe90ba 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -106,11 +106,7 @@
 func (s *SystemServerClasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
 	global := dexpreopt.GetGlobalConfig(ctx)
 
-	possibleUpdatableModules := gatherPossibleUpdatableModuleNamesAndStems(ctx, s.properties.Contents, systemServerClasspathFragmentContentDepTag)
-
-	// Only create configs for updatable boot jars. Non-updatable system server jars must be part of the
-	// platform_systemserverclasspath's classpath proto config to guarantee that they come before any
-	// updatable jars at runtime.
+	possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Contents, systemServerClasspathFragmentContentDepTag)
 	return global.UpdatableSystemServerJars.Filter(possibleUpdatableModules)
 }
 
diff --git a/java/testing.go b/java/testing.go
index e2ff5cd..8860b45 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -214,15 +214,15 @@
 	)
 }
 
-// FixtureConfigureUpdatableBootJars configures the updatable boot jars in both the
+// FixtureConfigureApexBootJars configures the apex boot jars in both the
 // dexpreopt.GlobalConfig and Config.productVariables structs. As a side effect that enables
 // dexpreopt.
-func FixtureConfigureUpdatableBootJars(bootJars ...string) android.FixturePreparer {
+func FixtureConfigureApexBootJars(bootJars ...string) android.FixturePreparer {
 	return android.GroupFixturePreparers(
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars)
+			variables.ApexBootJars = android.CreateTestConfiguredJarList(bootJars)
 		}),
-		dexpreopt.FixtureSetUpdatableBootJars(bootJars...),
+		dexpreopt.FixtureSetApexBootJars(bootJars...),
 
 		// Add a fake dex2oatd module.
 		dexpreopt.PrepareForTestWithFakeDex2oatd,
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 55a35e9..0e9e6fe 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -93,13 +93,14 @@
 	"is-vendor-board-platform":            {"!is-vendor-board-platform", starlarkTypeBool},
 	callLoadAlways:                        {"!inherit-product", starlarkTypeVoid},
 	callLoadIf:                            {"!inherit-product-if-exists", starlarkTypeVoid},
+	"patsubst":                            {baseName + ".mkpatsubst", starlarkTypeString},
 	"produce_copy_files":                  {baseName + ".produce_copy_files", starlarkTypeList},
 	"require-artifacts-in-path":           {baseName + ".require_artifacts_in_path", starlarkTypeVoid},
 	"require-artifacts-in-path-relaxed":   {baseName + ".require_artifacts_in_path_relaxed", starlarkTypeVoid},
 	// TODO(asmundak): remove it once all calls are removed from configuration makefiles. see b/183161002
 	"shell":    {baseName + ".shell", starlarkTypeString},
 	"strip":    {baseName + ".mkstrip", starlarkTypeString},
-	"subst":    {baseName + ".subst", starlarkTypeString},
+	"subst":    {baseName + ".mksubst", starlarkTypeString},
 	"warning":  {baseName + ".mkwarning", starlarkTypeVoid},
 	"word":     {baseName + "!word", starlarkTypeString},
 	"wildcard": {baseName + ".expand_wildcard", starlarkTypeList},
@@ -509,13 +510,7 @@
 		}
 		inferred_type := asgn.value.typ()
 		if inferred_type != starlarkTypeUnknown {
-			if ogv, ok := lhs.(*otherGlobalVariable); ok {
-				ogv.typ = inferred_type
-			} else if pcv, ok := lhs.(*productConfigVariable); ok {
-				pcv.typ = inferred_type
-			} else {
-				panic(fmt.Errorf("cannot assign new type to a variable %s, its flavor is %T", lhs.name(), lhs))
-			}
+			lhs.setValueType(inferred_type)
 		}
 	}
 	if lhs.valueType() == starlarkTypeList {
@@ -1085,8 +1080,8 @@
 	switch expr.name {
 	case "word":
 		return ctx.parseWordFunc(node, args)
-	case "subst":
-		return ctx.parseSubstFunc(node, args)
+	case "subst", "patsubst":
+		return ctx.parseSubstFunc(node, expr.name, args)
 	default:
 		for _, arg := range args.Split(",") {
 			arg.TrimLeftSpaces()
@@ -1101,24 +1096,33 @@
 	return expr
 }
 
-func (ctx *parseContext) parseSubstFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+func (ctx *parseContext) parseSubstFunc(node mkparser.Node, fname string, args *mkparser.MakeString) starlarkExpr {
 	words := args.Split(",")
 	if len(words) != 3 {
-		return ctx.newBadExpr(node, "subst function should have 3 arguments")
+		return ctx.newBadExpr(node, "%s function should have 3 arguments", fname)
 	}
 	if !words[0].Const() || !words[1].Const() {
-		return ctx.newBadExpr(node, "subst function's from and to arguments should be constant")
+		return ctx.newBadExpr(node, "%s function's from and to arguments should be constant", fname)
 	}
 	from := words[0].Strings[0]
 	to := words[1].Strings[0]
 	words[2].TrimLeftSpaces()
 	words[2].TrimRightSpaces()
 	obj := ctx.parseMakeString(node, words[2])
+	typ := obj.typ()
+	if typ == starlarkTypeString && fname == "subst" {
+		// Optimization: if it's $(subst from, to, string), emit string.replace(from, to)
+		return &callExpr{
+			object:     obj,
+			name:       "replace",
+			args:       []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}},
+			returnType: typ,
+		}
+	}
 	return &callExpr{
-		object:     obj,
-		name:       "replace",
-		args:       []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}},
-		returnType: starlarkTypeString,
+		name:       fname,
+		args:       []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}, obj},
+		returnType: obj.typ(),
 	}
 }
 
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 54263b8..240d0b8 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -628,6 +628,7 @@
 PRODUCT_COPY_FILES := $(addprefix pfx-,a b c)
 PRODUCT_COPY_FILES := $(addsuffix .sff, a b c)
 PRODUCT_NAME := $(word 1, $(subst ., ,$(TARGET_BOARD_PLATFORM)))
+$(info $(patsubst %.pub,%,$(PRODUCT_ADB_KEYS)))
 
 `,
 		expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -637,6 +638,23 @@
   cfg["PRODUCT_COPY_FILES"] = rblf.addprefix("pfx-", "a b c")
   cfg["PRODUCT_COPY_FILES"] = rblf.addsuffix(".sff", "a b c")
   cfg["PRODUCT_NAME"] = ((g.get("TARGET_BOARD_PLATFORM", "")).replace(".", " ")).split()[0]
+  rblf.mkinfo("product.mk", rblf.mkpatsubst("%.pub", "%", g.get("PRODUCT_ADB_KEYS", "")))
+`,
+	},
+	{
+		desc:   "subst in list",
+		mkname: "product.mk",
+		in: `
+files = $(call find-copy-subdir-files,*,from,to)
+PRODUCT_COPY_FILES += $(subst foo,bar,$(files))
+`,
+		expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+  cfg = rblf.cfg(handle)
+  _files = rblf.find_and_copy("*", "from", "to")
+  rblf.setdefault(handle, "PRODUCT_COPY_FILES")
+  cfg["PRODUCT_COPY_FILES"] += rblf.mksubst("foo", "bar", _files)
 `,
 	},
 	{
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index 56db192..a650453 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -26,6 +26,7 @@
 	emitSet(gctx *generationContext, asgn *assignmentNode)
 	emitDefined(gctx *generationContext)
 	valueType() starlarkType
+	setValueType(t starlarkType)
 	defaultValueString() string
 	isPreset() bool
 }
@@ -44,6 +45,10 @@
 	return v.typ
 }
 
+func (v *baseVariable) setValueType(t starlarkType) {
+	v.typ = t
+}
+
 func (v baseVariable) isPreset() bool {
 	return v.preset
 }
@@ -279,7 +284,7 @@
 		} else if name == strings.ToLower(name) {
 			// Heuristics: if variable's name is all lowercase, consider it local
 			// string variable.
-			v = &localVariable{baseVariable{nam: name, typ: starlarkTypeString}}
+			v = &localVariable{baseVariable{nam: name, typ: starlarkTypeUnknown}}
 		} else {
 			vt := starlarkTypeUnknown
 			if strings.HasPrefix(name, "LOCAL_") {
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index efd2b5b..c7ad798 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -224,7 +224,7 @@
 		java.PrepareForTestWithJavaDefaultModules,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
-		java.FixtureConfigureUpdatableBootJars("myapex:mybootlib", "myapex:myothersdklibrary"),
+		java.FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:myothersdklibrary"),
 		prepareForSdkTestWithApex,
 
 		// Add a platform_bootclasspath that depends on the fragment.
@@ -728,7 +728,7 @@
 		java.PrepareForTestWithJavaDefaultModules,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("mysdklibrary"),
-		java.FixtureConfigureUpdatableBootJars("myapex:mybootlib"),
+		java.FixtureConfigureApexBootJars("myapex:mybootlib"),
 		prepareForSdkTestWithApex,
 
 		// Add a platform_bootclasspath that depends on the fragment.