Merge changes from topic "sdk_repo_license"

* changes:
  Generate sdk_repo notice files from license metadata
  Annotate more java dependencies for licensing
  Track transitive packaged license deps of containers
diff --git a/README.md b/README.md
index 127c52c..18c6604 100644
--- a/README.md
+++ b/README.md
@@ -188,7 +188,7 @@
 
 #### Namespaces
 
-A presense of the `soong_namespace {..}` in an Android.bp file defines a
+The presence of the `soong_namespace {..}` in an Android.bp file defines a
 **namespace**. For instance, having
 
 ```
diff --git a/android/bazel.go b/android/bazel.go
index 528c7b1..0940205 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -217,7 +217,6 @@
 		"external/bazelbuild-rules_android":/* recursive = */ true,
 		"external/bazel-skylib":/* recursive = */ true,
 		"external/guava":/* recursive = */ true,
-		"external/error_prone":/* recursive = */ true,
 		"external/jsr305":/* recursive = */ true,
 		"frameworks/ex/common":/* recursive = */ true,
 
@@ -292,6 +291,7 @@
 		"external/bouncycastle":                              Bp2BuildDefaultTrue,
 		"external/brotli":                                    Bp2BuildDefaultTrue,
 		"external/conscrypt":                                 Bp2BuildDefaultTrue,
+		"external/error_prone":                               Bp2BuildDefaultTrue,
 		"external/fmtlib":                                    Bp2BuildDefaultTrueRecursively,
 		"external/google-benchmark":                          Bp2BuildDefaultTrueRecursively,
 		"external/googletest":                                Bp2BuildDefaultTrueRecursively,
@@ -341,6 +341,7 @@
 		"packages/screensavers/Basic":                        Bp2BuildDefaultTrue,
 		"packages/services/Car/tests/SampleRearViewCamera":   Bp2BuildDefaultTrue,
 		"prebuilts/clang/host/linux-x86":                     Bp2BuildDefaultTrueRecursively,
+		"prebuilts/tools/common/m2":                          Bp2BuildDefaultTrue,
 		"system/apex":                                        Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
 		"system/apex/proto":                                  Bp2BuildDefaultTrueRecursively,
 		"system/apex/libs":                                   Bp2BuildDefaultTrueRecursively,
@@ -469,10 +470,11 @@
 		"libdexfiled", // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette
 
 		// go deps:
-		"apex-protos",               // depends on soong_zip, a go binary
-		"robolectric_tzdata",        // depends on soong_zip, a go binary
-		"host_bionic_linker_asm",    // depends on extract_linker, a go binary.
-		"host_bionic_linker_script", // depends on extract_linker, a go binary.
+		"apex-protos",                    // depends on soong_zip, a go binary
+		"robolectric_tzdata",             // depends on soong_zip, a go binary
+		"robolectric-sqlite4java-native", // depends on soong_zip, a go binary
+		"host_bionic_linker_asm",         // depends on extract_linker, a go binary.
+		"host_bionic_linker_script",      // depends on extract_linker, a go binary.
 
 		// java deps
 		"bin2c_fastdeployagent", // depends on deployagent, a java binary
diff --git a/android/module.go b/android/module.go
index 0e69f27..00aed95 100644
--- a/android/module.go
+++ b/android/module.go
@@ -267,7 +267,7 @@
 	//
 	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
 	// invalidated by future mutators.
-	WalkDeps(visit func(Module, Module) bool)
+	WalkDeps(visit func(child, parent Module) bool)
 
 	// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
 	// tree in top down order.  visit may be called multiple times for the same (child, parent)
diff --git a/android/mutator.go b/android/mutator.go
index fa6f2be8..739e4ee 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -323,13 +323,13 @@
 	// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
 	// argument to select which variant of the dependency to use.  It returns a slice of modules for
 	// each dependency (some entries may be nil).  A variant of the dependency must exist that matches
-	// the all of the non-local variations of the current module, plus the variations argument.
+	// all the non-local variations of the current module, plus the variations argument.
 	//
 	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
 	// new dependencies have had the current mutator called on them.  If the mutator is not
 	// parallel this method does not affect the ordering of the current mutator pass, but will
 	// be ordered correctly for all future mutator passes.
-	AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []blueprint.Module
+	AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) []blueprint.Module
 
 	// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
 	// variations argument to select which variant of the dependency to use.  It returns a slice of
diff --git a/android/namespace.go b/android/namespace.go
index 4f727e1..fc7bc29 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -74,7 +74,7 @@
 
 // A NameResolver implements blueprint.NameInterface, and implements the logic to
 // find a module from namespaces based on a query string.
-// A query string can be a module name or can be be "//namespace_path:module_path"
+// A query string can be a module name or can be "//namespace_path:module_path"
 type NameResolver struct {
 	rootNamespace *Namespace
 
diff --git a/android/register.go b/android/register.go
index 1ac4440..10e14e0 100644
--- a/android/register.go
+++ b/android/register.go
@@ -31,7 +31,7 @@
 type sortableComponent interface {
 	// componentName returns the name of the component.
 	//
-	// Uniquely identifies the components within the set of components used at runtimr and during
+	// Uniquely identifies the components within the set of components used at runtime and during
 	// tests.
 	componentName() string
 
diff --git a/android/variable.go b/android/variable.go
index 40dd2d8..ff77fef 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -129,7 +129,7 @@
 			Exclude_srcs []string
 		}
 
-		// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
+		// eng is true for -eng builds, and can be used to turn on additional heavyweight debugging
 		// features.
 		Eng struct {
 			Cflags   []string
diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go
new file mode 100644
index 0000000..2f7211c
--- /dev/null
+++ b/bp2build/java_import_conversion_test.go
@@ -0,0 +1,52 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/java"
+
+	"testing"
+)
+
+func runJavaImportTestCase(t *testing.T, tc bp2buildTestCase) {
+	t.Helper()
+	runBp2BuildTestCase(t, registerJavaImportModuleTypes, tc)
+}
+
+func registerJavaImportModuleTypes(ctx android.RegistrationContext) {
+}
+
+func TestMinimalJavaImport(t *testing.T) {
+	runJavaImportTestCase(t, bp2buildTestCase{
+		description:                "Java import - simple example",
+		moduleTypeUnderTest:        "java_import",
+		moduleTypeUnderTestFactory: java.ImportFactory,
+		filesystem: map[string]string{
+			"import.jar": "",
+		},
+		blueprint: `
+java_import {
+        name: "example_import",
+        jars: ["import.jar"],
+        bazel_module: { bp2build_available: true },
+}
+`,
+		expectedBazelTargets: []string{
+			makeBazelTarget("java_import", "example_import", attrNameToString{
+				"jars": `["import.jar"]`,
+			}),
+		}})
+}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index d8cb47a..13b20f4 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -16,7 +16,6 @@
 
 import (
 	"context"
-	"encoding/json"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -36,11 +35,6 @@
 	"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 {
@@ -67,7 +61,7 @@
 }
 
 // list of supported commands (flags) supported by soong ui
-var commands []command = []command{
+var commands = []command{
 	{
 		flag:        "--make-mode",
 		description: "build the modules by the target name (i.e. soong_docs)",
@@ -117,43 +111,6 @@
 	return indexList(s, list) != -1
 }
 
-func loadEnvConfig(config build.Config) error {
-	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
-	if bc == "" {
-		return nil
-	}
-	configDirs := []string{
-		os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
-		config.OutDir(),
-		configDir,
-	}
-	var cfgFile string
-	for _, dir := range configDirs {
-		cfgFile = filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
-		if _, err := os.Stat(cfgFile); err == nil {
-			break
-		}
-	}
-
-	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
-		}
-		config.Environment().Set(k, v)
-	}
-	return nil
-}
-
 // Main execution of soong_ui. The command format is as follows:
 //
 //    soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
@@ -218,11 +175,6 @@
 
 	config := c.config(buildCtx, args...)
 
-	if err := loadEnvConfig(config); err != nil {
-		fmt.Fprintf(os.Stderr, "failed to parse env config files: %v", err)
-		os.Exit(1)
-	}
-
 	build.SetupOutDir(buildCtx, config)
 
 	if config.UseBazel() && config.Dist() {
@@ -571,7 +523,11 @@
 	}
 
 	// command not found
-	return nil, nil, fmt.Errorf("Command not found: %q", args)
+	flags := make([]string, len(commands))
+	for i, c := range commands {
+		flags[i] = c.flag
+	}
+	return nil, nil, fmt.Errorf("Command not found: %q\nDid you mean one of these: %q", args, flags)
 }
 
 // For Bazel support, this moves files and directories from e.g. out/dist/$f to DIST_DIR/$f if necessary.
diff --git a/java/OWNERS b/java/OWNERS
index 5242712..5b71b1e 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1,4 @@
 per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,skvadrik@google.com
+
+# For metalava team to disable lint checks in platform
+per-file droidstubs.go = aurimas@google.com,emberrose@google.com,sjgilbert@google.com
\ No newline at end of file
diff --git a/java/config/config.go b/java/config/config.go
index 30c6f91..ea2f934 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -60,7 +60,7 @@
 
 const (
 	JavaVmFlags  = `-XX:OnError="cat hs_err_pid%p.log" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads`
-	JavacVmFlags = `-J-XX:OnError="cat hs_err_pid%p.log" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads`
+	JavacVmFlags = `-J-XX:OnError="cat hs_err_pid%p.log" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1`
 )
 
 func init() {
diff --git a/java/java.go b/java/java.go
index 35b6a4f..fef9912 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1333,6 +1333,7 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
+	android.BazelModuleBase
 	prebuilt android.Prebuilt
 	android.SdkBase
 
@@ -1688,6 +1689,7 @@
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	android.InitApexModule(module)
 	android.InitSdkAwareModule(module)
+	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
@@ -2106,3 +2108,21 @@
 	// Create the BazelTargetModule.
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
 }
+
+type bazelJavaImportAttributes struct {
+	Jars bazel.LabelListAttribute
+}
+
+// java_import bp2Build converter.
+func (i *Import) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	//TODO(b/209577426): Support multiple arch variants
+	jars := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, i.properties.Jars, []string(nil)))
+
+	attrs := &bazelJavaImportAttributes{
+		Jars: jars,
+	}
+	props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"}
+
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: android.RemoveOptionalPrebuiltPrefix(i.Name())}, attrs)
+
+}
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 5b764dc..8db001f 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -18,6 +18,11 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+filegroup {
+    name: "Apache-2.0-License-Text",
+    srcs: ["LICENSE"],
+}
+
 license {
     name: "Android-Apache-2.0",
     package_name: "Android",
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index d62882d..c4f7da3 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -1048,8 +1048,8 @@
   cfg = rblf.cfg(handle)
   g["MY_PATH"] = "foo"
   _entry = {
-    "vendor/foo1/cfg.mk": ("_cfg", _cfg_init),
-    "vendor/bar/baz/cfg.mk": ("_cfg1", _cfg1_init),
+    "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
+    "vendor/bar/baz/cfg.mk": ("vendor/bar/baz/cfg", _cfg1_init),
   }.get("vendor/%s/cfg.mk" % g["MY_PATH"])
   (_varmod, _varmod_init) = _entry if _entry else (None, None)
   if not _varmod_init:
@@ -1073,7 +1073,7 @@
   g["MY_PATH"] = "foo"
   #RBC# include_top vendor/foo1
   _entry = {
-    "vendor/foo1/cfg.mk": ("_cfg", _cfg_init),
+    "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
   }.get("%s/cfg.mk" % g["MY_PATH"])
   (_varmod, _varmod_init) = _entry if _entry else (None, None)
   if not _varmod_init:
@@ -1099,7 +1099,7 @@
   g["MY_PATH"] = "foo"
   #RBC# include_top vendor/foo1
   _entry = {
-    "vendor/foo1/cfg.mk": ("_cfg", _cfg_init),
+    "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
   }.get("%s/cfg.mk" % g["MY_PATH"])
   (_varmod, _varmod_init) = _entry if _entry else (None, None)
   if not _varmod_init:
@@ -1107,7 +1107,7 @@
   rblf.inherit(handle, _varmod, _varmod_init)
   #RBC# include_top vendor/foo1
   _entry = {
-    "vendor/foo1/cfg.mk": ("_cfg", _cfg_init),
+    "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
   }.get("%s/cfg.mk" % g["MY_PATH"])
   (_varmod, _varmod_init) = _entry if _entry else (None, None)
   if not _varmod_init:
@@ -1137,7 +1137,7 @@
 def init(g, handle):
   cfg = rblf.cfg(handle)
   _entry = {
-    "foo/font.mk": ("_font", _font_init),
+    "foo/font.mk": ("foo/font", _font_init),
   }.get("%s/font.mk" % g.get("MY_VAR", ""))
   (_varmod, _varmod_init) = _entry if _entry else (None, None)
   if not _varmod_init:
@@ -1146,7 +1146,7 @@
   #RBC# include_top foo
   # There's some space and even this comment between the include_top and the inherit-product
   _entry = {
-    "foo/font.mk": ("_font", _font_init),
+    "foo/font.mk": ("foo/font", _font_init),
   }.get("%s/font.mk" % g.get("MY_VAR", ""))
   (_varmod, _varmod_init) = _entry if _entry else (None, None)
   if not _varmod_init:
diff --git a/mk2rbc/node.go b/mk2rbc/node.go
index 333a8da..4f7c4f0 100644
--- a/mk2rbc/node.go
+++ b/mk2rbc/node.go
@@ -54,6 +54,10 @@
 	return im.moduleLocalName + "_init"
 }
 
+func (mi moduleInfo) name() string {
+	return fmt.Sprintf("%q", MakePath2ModuleName(mi.originalPath))
+}
+
 type inheritedModule interface {
 	name() string
 	entryName() string
@@ -67,10 +71,6 @@
 	loadAlways bool
 }
 
-func (im inheritedStaticModule) name() string {
-	return fmt.Sprintf("%q", MakePath2ModuleName(im.originalPath))
-}
-
 func (im inheritedStaticModule) emitSelect(_ *generationContext) {
 }
 
@@ -102,7 +102,7 @@
 	gctx.indentLevel++
 	for _, mi := range i.candidateModules {
 		gctx.newLine()
-		gctx.writef(`"%s": (%q, %s),`, mi.originalPath, mi.moduleLocalName, mi.entryName())
+		gctx.writef(`"%s": (%s, %s),`, mi.originalPath, mi.name(), mi.entryName())
 	}
 	gctx.indentLevel--
 	gctx.newLine()
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index f318507..0962168 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -19,6 +19,7 @@
 		"frameworks/native/libs/binder/rust",
 		"frameworks/proto_logging/stats",
 		"hardware/interfaces/security",
+		"hardware/interfaces/uwb",
 		"packages/modules/Bluetooth",
 		"packages/modules/DnsResolver",
 		"packages/modules/Uwb",
diff --git a/snapshot/host_snapshot.go b/snapshot/host_snapshot.go
index 252cef8..09a382e 100644
--- a/snapshot/host_snapshot.go
+++ b/snapshot/host_snapshot.go
@@ -58,7 +58,7 @@
 	android.ModuleBase
 	android.PackagingBase
 
-	zipFile    android.OptionalPath
+	outputFile android.OutputPath
 	installDir android.InstallPath
 }
 
@@ -141,7 +141,7 @@
 	// Create a zip file for the binaries, and a zip of the meta data, then merge zips
 	depsZipFile := android.PathForModuleOut(ctx, f.Name()+"_deps.zip").OutputPath
 	modsZipFile := android.PathForModuleOut(ctx, f.Name()+"_mods.zip").OutputPath
-	outputFile := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
+	f.outputFile = android.PathForModuleOut(ctx, f.installFileName()).OutputPath
 
 	f.installDir = android.PathForModuleInstall(ctx)
 
@@ -158,26 +158,21 @@
 
 	builder.Command().
 		BuiltTool("merge_zips").
-		Output(outputFile).
+		Output(f.outputFile).
 		Input(metaZipFile).
 		Input(modsZipFile)
 
 	builder.Build("manifest", fmt.Sprintf("Adding manifest %s", f.installFileName()))
-	zip := ctx.InstallFile(f.installDir, f.installFileName(), outputFile)
-	f.zipFile = android.OptionalPathForPath(zip)
+	ctx.InstallFile(f.installDir, f.installFileName(), f.outputFile)
 
 }
 
 // Implements android.AndroidMkEntriesProvider
 func (f *hostSnapshot) AndroidMkEntries() []android.AndroidMkEntries {
-	if !f.zipFile.Valid() {
-		return []android.AndroidMkEntries{}
-	}
-
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "ETC",
-		OutputFile: f.zipFile,
-		DistFiles:  android.MakeDefaultDistFiles(f.zipFile.Path()),
+		OutputFile: android.OptionalPathForPath(f.outputFile),
+		DistFiles:  android.MakeDefaultDistFiles(f.outputFile),
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				entries.SetString("LOCAL_MODULE_PATH", f.installDir.String())
diff --git a/ui/build/config.go b/ui/build/config.go
index 57a8849..1dd948c 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -15,8 +15,12 @@
 package build
 
 import (
+	"context"
+	"encoding/json"
 	"fmt"
+	"io/ioutil"
 	"os"
+	"os/exec"
 	"path/filepath"
 	"runtime"
 	"strconv"
@@ -30,6 +34,14 @@
 	smpb "android/soong/ui/metrics/metrics_proto"
 )
 
+const (
+	envConfigDir  = "vendor/google/tools/soong_config"
+	jsonSuffix    = "json"
+
+	configFetcher = "vendor/google/tools/soong/expconfigfetcher"
+	envConfigFetchTimeout = 10 * time.Second
+)
+
 type Config struct{ *configImpl }
 
 type configImpl struct {
@@ -128,6 +140,85 @@
 	}
 }
 
+// fetchEnvConfig optionally fetches environment config from an
+// experiments system to control Soong features dynamically.
+func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
+	s, err := os.Stat(configFetcher)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+	if s.Mode()&0111 == 0 {
+		return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode())
+	}
+
+	configExists := false
+	outConfigFilePath := filepath.Join(config.OutDir(), envConfigName + jsonSuffix)
+	if _, err := os.Stat(outConfigFilePath); err == nil {
+		configExists = true
+	}
+
+	tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout)
+	defer cancel()
+	cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir())
+	if err := cmd.Start(); err != nil {
+		return err
+	}
+
+	// If a config file already exists, return immediately and run the config file
+	// fetch in the background. Otherwise, wait for the config file to be fetched.
+	if configExists {
+		go cmd.Wait()
+		return nil
+	}
+	if err := cmd.Wait(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func loadEnvConfig(ctx Context, config *configImpl) error {
+	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
+	if bc == "" {
+		return nil
+	}
+
+	if err := fetchEnvConfig(ctx, config, bc); err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to fetch config file: %v", err)
+	}
+
+	configDirs := []string{
+		config.OutDir(),
+		os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
+		envConfigDir,
+	}
+	for _, dir := range configDirs {
+		cfgFile := filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
+		envVarsJSON, err := ioutil.ReadFile(cfgFile)
+		if err != nil {
+			continue
+		}
+		ctx.Verbosef("Loading config file %v\n", cfgFile)
+		var envVars map[string]map[string]string
+		if err := json.Unmarshal(envVarsJSON, &envVars); err != nil {
+			fmt.Fprintf(os.Stderr, "Env vars config file %s did not parse correctly: %s", cfgFile, err.Error())
+			continue
+		}
+		for k, v := range envVars["env"] {
+			if os.Getenv(k) != "" {
+				continue
+			}
+			config.environ.Set(k, v)
+		}
+		ctx.Verbosef("Finished loading config file %v\n", cfgFile)
+		break
+	}
+
+	return nil
+}
+
 func NewConfig(ctx Context, args ...string) Config {
 	ret := &configImpl{
 		environ:       OsEnvironment(),
@@ -157,6 +248,12 @@
 		ret.environ.Set("OUT_DIR", outDir)
 	}
 
+	// loadEnvConfig needs to know what the OUT_DIR is, so it should
+	// be called after we determine the appropriate out directory.
+	if err := loadEnvConfig(ctx, ret); err != nil {
+		ctx.Fatalln("Failed to parse env config files: %v", err)
+	}
+
 	if distDir, ok := ret.environ.Get("DIST_DIR"); ok {
 		ret.distDir = filepath.Clean(distDir)
 	} else {
@@ -992,7 +1089,7 @@
 }
 
 func (c *configImpl) UseRBE() bool {
-	if v, ok := c.environ.Get("USE_RBE"); ok {
+	if v, ok := c.Environment().Get("USE_RBE"); ok {
 		v = strings.TrimSpace(v)
 		if v != "" && v != "false" {
 			return true