Merge "Remove myself from the OWNERS"
diff --git a/android/config.go b/android/config.go
index ef5eadf..c10ad09 100644
--- a/android/config.go
+++ b/android/config.go
@@ -232,7 +232,7 @@
 
 	// Copy the real PATH value to the test environment, it's needed by
 	// NonHermeticHostSystemTool() used in x86_darwin_host.go
-	envCopy["PATH"] = originalEnv["PATH"]
+	envCopy["PATH"] = os.Getenv("PATH")
 
 	config := &config{
 		productVariables: productVariables{
diff --git a/android/env.go b/android/env.go
index a8c7777..58ad0b6 100644
--- a/android/env.go
+++ b/android/env.go
@@ -17,7 +17,6 @@
 import (
 	"fmt"
 	"os"
-	"os/exec"
 	"strings"
 	"syscall"
 
@@ -34,37 +33,27 @@
 var originalEnv map[string]string
 var soongDelveListen string
 var soongDelvePath string
-var soongDelveEnv []string
+var isDebugging bool
 
-func init() {
-	// Delve support needs to read this environment variable very early, before NewConfig has created a way to
-	// access originalEnv with dependencies.  Store the value where soong_build can find it, it will manually
-	// ensure the dependencies are created.
-	soongDelveListen = os.Getenv("SOONG_DELVE")
-	soongDelvePath = os.Getenv("SOONG_DELVE_PATH")
-	if soongDelvePath == "" {
-		soongDelvePath, _ = exec.LookPath("dlv")
+func InitEnvironment(envFile string) {
+	var err error
+	originalEnv, err = shared.EnvFromFile(envFile)
+	if err != nil {
+		panic(err)
 	}
 
-	originalEnv = make(map[string]string)
-	soongDelveEnv = []string{}
-	for _, env := range os.Environ() {
-		idx := strings.IndexRune(env, '=')
-		if idx != -1 {
-			originalEnv[env[:idx]] = env[idx+1:]
-			if env[:idx] != "SOONG_DELVE" && env[:idx] != "SOONG_DELVE_PATH" {
-				soongDelveEnv = append(soongDelveEnv, env)
-			}
-		}
-	}
-
-	// Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment
-	// variable values.  The environment is available through ctx.Config().Getenv, ctx.Config().IsEnvTrue, etc.
-	os.Clearenv()
+	soongDelveListen = originalEnv["SOONG_DELVE"]
+	soongDelvePath = originalEnv["SOONG_DELVE_PATH"]
 }
 
+// Returns whether the current process is running under Delve due to
+// ReexecWithDelveMaybe().
+func IsDebugging() bool {
+	return isDebugging
+}
 func ReexecWithDelveMaybe() {
-	if soongDelveListen == "" {
+	isDebugging = os.Getenv("SOONG_DELVE_REEXECUTED") == "true"
+	if isDebugging || soongDelveListen == "" {
 		return
 	}
 
@@ -72,6 +61,17 @@
 		fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
 		os.Exit(1)
 	}
+
+	soongDelveEnv := []string{}
+	for _, env := range os.Environ() {
+		idx := strings.IndexRune(env, '=')
+		if idx != -1 {
+			soongDelveEnv = append(soongDelveEnv, env)
+		}
+	}
+
+	soongDelveEnv = append(soongDelveEnv, "SOONG_DELVE_REEXECUTED=true")
+
 	dlvArgv := []string{
 		soongDelvePath,
 		"--listen=:" + soongDelveListen,
@@ -88,17 +88,6 @@
 	os.Exit(1)
 }
 
-// getenv checks either os.Getenv or originalEnv so that it works before or after the init()
-// function above.  It doesn't add any dependencies on the environment variable, so it should
-// only be used for values that won't change.  For values that might change use ctx.Config().Getenv.
-func getenv(key string) string {
-	if originalEnv == nil {
-		return os.Getenv(key)
-	} else {
-		return originalEnv[key]
-	}
-}
-
 func EnvSingleton() Singleton {
 	return &envSingleton{}
 }
@@ -108,7 +97,7 @@
 func (c *envSingleton) GenerateBuildActions(ctx SingletonContext) {
 	envDeps := ctx.Config().EnvDeps()
 
-	envFile := PathForOutput(ctx, ".soong.environment")
+	envFile := PathForOutput(ctx, "soong.environment.used")
 	if ctx.Failed() {
 		return
 	}
diff --git a/android/fixture.go b/android/fixture.go
index 0efe329..ae24b91 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -182,7 +182,13 @@
 	// Create a Fixture.
 	Fixture(t *testing.T, preparers ...FixturePreparer) Fixture
 
-	// Run the test, expecting no errors, returning a TestResult instance.
+	// Set the error handler that will be used to check any errors reported by the test.
+	//
+	// The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any
+	// errors are reported.
+	SetErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory
+
+	// Run the test, checking any errors reported and returning a TestResult instance.
 	//
 	// Shorthand for Fixture(t, preparers...).RunTest()
 	RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult
@@ -202,6 +208,9 @@
 	return &fixtureFactory{
 		buildDirSupplier: buildDirSupplier,
 		preparers:        dedupAndFlattenPreparers(nil, preparers),
+
+		// Set the default error handler.
+		errorHandler: FixtureExpectsNoErrors,
 	}
 }
 
@@ -352,9 +361,84 @@
 	return &simpleFixturePreparer{function: preparer}
 }
 
+// FixtureErrorHandler determines how to respond to errors reported by the code under test.
+//
+// Some possible responses:
+// * Fail the test if any errors are reported, see FixtureExpectsNoErrors.
+// * Fail the test if at least one error that matches a pattern is not reported see
+//   FixtureExpectsAtLeastOneErrorMatchingPattern
+// * Fail the test if any unexpected errors are reported.
+//
+// Although at the moment all the error handlers are implemented as simply a wrapper around a
+// function this is defined as an interface to allow future enhancements, e.g. provide different
+// ways other than patterns to match an error and to combine handlers together.
+type FixtureErrorHandler interface {
+	// CheckErrors checks the errors reported.
+	//
+	// The supplied result can be used to access the state of the code under test just as the main
+	// body of the test would but if any errors other than ones expected are reported the state may
+	// be indeterminate.
+	CheckErrors(result *TestResult, errs []error)
+}
+
+type simpleErrorHandler struct {
+	function func(result *TestResult, errs []error)
+}
+
+func (h simpleErrorHandler) CheckErrors(result *TestResult, errs []error) {
+	h.function(result, errs)
+}
+
+// The default fixture error handler.
+//
+// Will fail the test immediately if any errors are reported.
+var FixtureExpectsNoErrors = FixtureCustomErrorHandler(
+	func(result *TestResult, errs []error) {
+		FailIfErrored(result.T, errs)
+	},
+)
+
+// FixtureExpectsAtLeastOneMatchingError returns an error handler that will cause the test to fail
+// if at least one error that matches the regular expression is not found.
+//
+// The test will be failed if:
+// * No errors are reported.
+// * One or more errors are reported but none match the pattern.
+//
+// The test will not fail if:
+// * Multiple errors are reported that do not match the pattern as long as one does match.
+func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler {
+	return FixtureCustomErrorHandler(func(result *TestResult, errs []error) {
+		FailIfNoMatchingErrors(result.T, pattern, errs)
+	})
+}
+
+// FixtureExpectsOneErrorToMatchPerPattern returns an error handler that will cause the test to fail
+// if there are any unexpected errors.
+//
+// The test will be failed if:
+// * The number of errors reported does not exactly match the patterns.
+// * One or more of the reported errors do not match a pattern.
+// * No patterns are provided and one or more errors are reported.
+//
+// The test will not fail if:
+// * One or more of the patterns does not match an error.
+func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler {
+	return FixtureCustomErrorHandler(func(result *TestResult, errs []error) {
+		CheckErrorsAgainstExpectations(result.T, errs, patterns)
+	})
+}
+
+// FixtureCustomErrorHandler creates a custom error handler
+func FixtureCustomErrorHandler(function func(result *TestResult, errs []error)) FixtureErrorHandler {
+	return simpleErrorHandler{
+		function: function,
+	}
+}
+
 // Fixture defines the test environment.
 type Fixture interface {
-	// Run the test, expecting no errors, returning a TestResult instance.
+	// Run the test, checking any errors reported and returning a TestResult instance.
 	RunTest() *TestResult
 }
 
@@ -454,25 +538,29 @@
 type fixtureFactory struct {
 	buildDirSupplier *string
 	preparers        []*simpleFixturePreparer
+	errorHandler     FixtureErrorHandler
 }
 
 func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixtureFactory {
 	all := append(f.preparers, dedupAndFlattenPreparers(f.preparers, preparers)...)
-	return &fixtureFactory{
-		buildDirSupplier: f.buildDirSupplier,
-		preparers:        all,
-	}
+	// Copy the existing factory.
+	extendedFactory := &fixtureFactory{}
+	*extendedFactory = *f
+	// Use the extended list of preparers.
+	extendedFactory.preparers = all
+	return extendedFactory
 }
 
 func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
 	config := TestConfig(*f.buildDirSupplier, nil, "", nil)
 	ctx := NewTestContext(config)
 	fixture := &fixture{
-		factory: f,
-		t:       t,
-		config:  config,
-		ctx:     ctx,
-		mockFS:  make(MockFS),
+		factory:      f,
+		t:            t,
+		config:       config,
+		ctx:          ctx,
+		mockFS:       make(MockFS),
+		errorHandler: f.errorHandler,
 	}
 
 	for _, preparer := range f.preparers {
@@ -486,6 +574,11 @@
 	return fixture
 }
 
+func (f *fixtureFactory) SetErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory {
+	f.errorHandler = errorHandler
+	return f
+}
+
 func (f *fixtureFactory) RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult {
 	t.Helper()
 	fixture := f.Fixture(t, preparers...)
@@ -498,11 +591,23 @@
 }
 
 type fixture struct {
+	// The factory used to create this fixture.
 	factory *fixtureFactory
-	t       *testing.T
-	config  Config
-	ctx     *TestContext
-	mockFS  MockFS
+
+	// The gotest state of the go test within which this was created.
+	t *testing.T
+
+	// The configuration prepared for this fixture.
+	config Config
+
+	// The test context prepared for this fixture.
+	ctx *TestContext
+
+	// The mock filesystem prepared for this fixture.
+	mockFS MockFS
+
+	// The error handler used to check the errors, if any, that are reported.
+	errorHandler FixtureErrorHandler
 }
 
 func (f *fixture) RunTest() *TestResult {
@@ -525,9 +630,9 @@
 
 	ctx.Register()
 	_, errs := ctx.ParseBlueprintsFiles("ignored")
-	FailIfErrored(f.t, errs)
-	_, errs = ctx.PrepareBuildActions(f.config)
-	FailIfErrored(f.t, errs)
+	if len(errs) == 0 {
+		_, errs = ctx.PrepareBuildActions(f.config)
+	}
 
 	result := &TestResult{
 		TestHelper:  TestHelper{T: f.t},
@@ -535,6 +640,9 @@
 		fixture:     f,
 		Config:      f.config,
 	}
+
+	f.errorHandler.CheckErrors(result, errs)
+
 	return result
 }
 
diff --git a/android/module.go b/android/module.go
index f0e17ba..9f923e2 100644
--- a/android/module.go
+++ b/android/module.go
@@ -753,7 +753,7 @@
 	// Whether this module is installed to vendor ramdisk
 	Vendor_ramdisk *bool
 
-	// Whether this module is built for non-native architecures (also known as native bridge binary)
+	// Whether this module is built for non-native architectures (also known as native bridge binary)
 	Native_bridge_supported *bool `android:"arch_variant"`
 
 	// init.rc files to be installed if this module is installed
@@ -1832,6 +1832,18 @@
 			return
 		}
 
+		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+		rcDir := PathForModuleInstall(ctx, "etc", "init")
+		for _, src := range m.initRcPaths {
+			ctx.PackageFile(rcDir, filepath.Base(src.String()), src)
+		}
+
+		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
+		vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
+		for _, src := range m.vintfFragmentsPaths {
+			ctx.PackageFile(vintfDir, filepath.Base(src.String()), src)
+		}
+
 		// Create the set of tagged dist files after calling GenerateAndroidBuildActions
 		// as GenerateTaggedDistFiles() calls OutputFiles(tag) and so relies on the
 		// output paths being set which must be done before or during
@@ -1844,8 +1856,6 @@
 		m.installFiles = append(m.installFiles, ctx.installFiles...)
 		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
 		m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...)
-		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
-		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
 		for k, v := range ctx.phonies {
 			m.phonies[k] = append(m.phonies[k], v...)
 		}
diff --git a/android/package.go b/android/package.go
index 7012fc7..878e4c4 100644
--- a/android/package.go
+++ b/android/package.go
@@ -23,6 +23,8 @@
 	RegisterPackageBuildComponents(InitRegistrationContext)
 }
 
+var PrepareForTestWithPackageModule = FixtureRegisterWithContext(RegisterPackageBuildComponents)
+
 // Register the package module type.
 func RegisterPackageBuildComponents(ctx RegistrationContext) {
 	ctx.RegisterModuleType("package", PackageFactory)
diff --git a/android/paths.go b/android/paths.go
index ada4da6..3f4d3f2 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1662,9 +1662,9 @@
 			// on a device without a dedicated recovery partition, install the
 			// recovery variant.
 			if ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() {
-				partition = "vendor-ramdisk/first_stage_ramdisk"
+				partition = "vendor_ramdisk/first_stage_ramdisk"
 			} else {
-				partition = "vendor-ramdisk"
+				partition = "vendor_ramdisk"
 			}
 			if !ctx.InstallInRoot() {
 				partition += "/system"
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 164b1bc..32af5df 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -388,6 +388,8 @@
 	ctx.PostDepsMutators(RegisterOverridePostDepsMutators)
 }
 
+var prepareForTestWithFakePrebuiltModules = FixtureRegisterWithContext(registerTestPrebuiltModules)
+
 func registerTestPrebuiltModules(ctx RegistrationContext) {
 	ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
 	ctx.RegisterModuleType("source", newSourceModule)
diff --git a/android/sandbox.go b/android/sandbox.go
index ed022fb..28e903a 100644
--- a/android/sandbox.go
+++ b/android/sandbox.go
@@ -14,29 +14,8 @@
 
 package android
 
-import (
-	"fmt"
-	"os"
-)
-
-func init() {
-	// Stash the working directory in a private variable and then change the working directory
-	// to "/", which will prevent untracked accesses to files by Go Soong plugins. The
-	// SOONG_SANDBOX_SOONG_BUILD environment variable is set by soong_ui, and is not
-	// overrideable on the command line.
-
-	orig, err := os.Getwd()
-	if err != nil {
-		panic(fmt.Errorf("failed to get working directory: %s", err))
-	}
-	absSrcDir = orig
-
-	if getenv("SOONG_SANDBOX_SOONG_BUILD") == "true" {
-		err = os.Chdir("/")
-		if err != nil {
-			panic(fmt.Errorf("failed to change working directory to '/': %s", err))
-		}
-	}
+func InitSandbox(topDir string) {
+	absSrcDir = topDir
 }
 
 // DO NOT USE THIS FUNCTION IN NEW CODE.
diff --git a/android/visibility.go b/android/visibility.go
index 7eac471..631e88f 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -202,6 +202,18 @@
 	ExcludeFromVisibilityEnforcement()
 }
 
+var PrepareForTestWithVisibilityRuleChecker = FixtureRegisterWithContext(func(ctx RegistrationContext) {
+	ctx.PreArchMutators(RegisterVisibilityRuleChecker)
+})
+
+var PrepareForTestWithVisibilityRuleGatherer = FixtureRegisterWithContext(func(ctx RegistrationContext) {
+	ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
+})
+
+var PrepareForTestWithVisibilityRuleEnforcer = FixtureRegisterWithContext(func(ctx RegistrationContext) {
+	ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
+})
+
 // The rule checker needs to be registered before defaults expansion to correctly check that
 // //visibility:xxx isn't combined with other packages in the same list in any one module.
 func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) {
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 87a295e..30cdcbf 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -9,13 +9,13 @@
 
 var visibilityTests = []struct {
 	name                string
-	fs                  map[string][]byte
+	fs                  MockFS
 	expectedErrors      []string
 	effectiveVisibility map[qualifiedModuleName][]string
 }{
 	{
 		name: "invalid visibility: empty list",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -26,7 +26,7 @@
 	},
 	{
 		name: "invalid visibility: empty rule",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -37,7 +37,7 @@
 	},
 	{
 		name: "invalid visibility: unqualified",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -48,7 +48,7 @@
 	},
 	{
 		name: "invalid visibility: empty namespace",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -59,7 +59,7 @@
 	},
 	{
 		name: "invalid visibility: empty module",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -70,7 +70,7 @@
 	},
 	{
 		name: "invalid visibility: empty namespace and module",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -81,7 +81,7 @@
 	},
 	{
 		name: "//visibility:unknown",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -92,7 +92,7 @@
 	},
 	{
 		name: "//visibility:xxx mixed",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -113,7 +113,7 @@
 	},
 	{
 		name: "//visibility:legacy_public",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -129,7 +129,7 @@
 		// Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
 		// the current directory, a nested directory and a directory in a separate tree.
 		name: "//visibility:public",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -156,7 +156,7 @@
 		// Verify that //visibility:private allows the module to be referenced from the current
 		// directory only.
 		name: "//visibility:private",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -188,7 +188,7 @@
 	{
 		// Verify that :__pkg__ allows the module to be referenced from the current directory only.
 		name: ":__pkg__",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -221,7 +221,7 @@
 		// Verify that //top/nested allows the module to be referenced from the current directory and
 		// the top/nested directory only, not a subdirectory of top/nested and not peak directory.
 		name: "//top/nested",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -259,7 +259,7 @@
 		// Verify that :__subpackages__ allows the module to be referenced from the current directory
 		// and sub directories but nowhere else.
 		name: ":__subpackages__",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -290,7 +290,7 @@
 		// Verify that //top/nested:__subpackages__ allows the module to be referenced from the current
 		// directory and sub directories but nowhere else.
 		name: "//top/nested:__subpackages__",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -321,7 +321,7 @@
 		// Verify that ["//top/nested", "//peak:__subpackages"] allows the module to be referenced from
 		// the current directory, top/nested and peak and all its subpackages.
 		name: `["//top/nested", "//peak:__subpackages__"]`,
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -347,7 +347,7 @@
 	{
 		// Verify that //vendor... cannot be used outside vendor apart from //vendor:__subpackages__
 		name: `//vendor`,
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -381,7 +381,7 @@
 	{
 		// Check that visibility is the union of the defaults modules.
 		name: "defaults union, basic",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -419,7 +419,7 @@
 	},
 	{
 		name: "defaults union, multiple defaults",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults_1",
@@ -460,7 +460,7 @@
 	},
 	{
 		name: "//visibility:public mixed with other in defaults",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -478,7 +478,7 @@
 	},
 	{
 		name: "//visibility:public overriding defaults",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -501,7 +501,7 @@
 	},
 	{
 		name: "//visibility:public mixed with other from different defaults 1",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults_1",
@@ -524,7 +524,7 @@
 	},
 	{
 		name: "//visibility:public mixed with other from different defaults 2",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults_1",
@@ -547,7 +547,7 @@
 	},
 	{
 		name: "//visibility:private in defaults",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -581,7 +581,7 @@
 	},
 	{
 		name: "//visibility:private mixed with other in defaults",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -599,7 +599,7 @@
 	},
 	{
 		name: "//visibility:private overriding defaults",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -618,7 +618,7 @@
 	},
 	{
 		name: "//visibility:private in defaults overridden",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -637,7 +637,7 @@
 	},
 	{
 		name: "//visibility:private override //visibility:public",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -655,7 +655,7 @@
 	},
 	{
 		name: "//visibility:public override //visibility:private",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -673,7 +673,7 @@
 	},
 	{
 		name: "//visibility:override must be first in the list",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_library {
 					name: "libexample",
@@ -686,7 +686,7 @@
 	},
 	{
 		name: "//visibility:override discards //visibility:private",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -707,7 +707,7 @@
 	},
 	{
 		name: "//visibility:override discards //visibility:public",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -736,7 +736,7 @@
 	},
 	{
 		name: "//visibility:override discards defaults supplied rules",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -765,7 +765,7 @@
 	},
 	{
 		name: "//visibility:override can override //visibility:public with //visibility:private",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -788,7 +788,7 @@
 	},
 	{
 		name: "//visibility:override can override //visibility:private with //visibility:public",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults",
@@ -808,7 +808,7 @@
 	},
 	{
 		name: "//visibility:private mixed with itself",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "libexample_defaults_1",
@@ -838,7 +838,7 @@
 	// Defaults module's defaults_visibility tests
 	{
 		name: "defaults_visibility invalid",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_defaults {
 					name: "top_defaults",
@@ -851,7 +851,7 @@
 	},
 	{
 		name: "defaults_visibility overrides package default",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: ["//visibility:private"],
@@ -871,7 +871,7 @@
 	// Package default_visibility tests
 	{
 		name: "package default_visibility property is checked",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: ["//visibility:invalid"],
@@ -882,7 +882,7 @@
 	{
 		// This test relies on the default visibility being legacy_public.
 		name: "package default_visibility property used when no visibility specified",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: ["//visibility:private"],
@@ -904,7 +904,7 @@
 	},
 	{
 		name: "package default_visibility public does not override visibility private",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: ["//visibility:public"],
@@ -927,7 +927,7 @@
 	},
 	{
 		name: "package default_visibility private does not override visibility public",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: ["//visibility:private"],
@@ -946,7 +946,7 @@
 	},
 	{
 		name: "package default_visibility :__subpackages__",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: [":__subpackages__"],
@@ -973,7 +973,7 @@
 	},
 	{
 		name: "package default_visibility inherited to subpackages",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: ["//outsider"],
@@ -1001,7 +1001,7 @@
 	},
 	{
 		name: "package default_visibility inherited to subpackages",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				package {
 					default_visibility: ["//visibility:private"],
@@ -1031,7 +1031,7 @@
 	},
 	{
 		name: "verify that prebuilt dependencies are ignored for visibility reasons (not preferred)",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"prebuilts/Blueprints": []byte(`
 				prebuilt {
 					name: "module",
@@ -1053,7 +1053,7 @@
 	},
 	{
 		name: "verify that prebuilt dependencies are ignored for visibility reasons (preferred)",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"prebuilts/Blueprints": []byte(`
 				prebuilt {
 					name: "module",
@@ -1076,7 +1076,7 @@
 	},
 	{
 		name: "ensure visibility properties are checked for correctness",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_parent {
 					name: "parent",
@@ -1093,7 +1093,7 @@
 	},
 	{
 		name: "invalid visibility added to child detected during gather phase",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_parent {
 					name: "parent",
@@ -1115,7 +1115,7 @@
 	},
 	{
 		name: "automatic visibility inheritance enabled",
-		fs: map[string][]byte{
+		fs: MockFS{
 			"top/Blueprints": []byte(`
 				mock_parent {
 					name: "parent",
@@ -1142,55 +1142,43 @@
 func TestVisibility(t *testing.T) {
 	for _, test := range visibilityTests {
 		t.Run(test.name, func(t *testing.T) {
-			ctx, errs := testVisibility(buildDir, test.fs)
-
-			CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
+			result := emptyTestFixtureFactory.Extend(
+				FixtureRegisterWithContext(func(ctx RegistrationContext) {
+					ctx.RegisterModuleType("mock_library", newMockLibraryModule)
+					ctx.RegisterModuleType("mock_parent", newMockParentFactory)
+					ctx.RegisterModuleType("mock_defaults", defaultsFactory)
+				}),
+				prepareForTestWithFakePrebuiltModules,
+				PrepareForTestWithPackageModule,
+				// Order of the following method calls is significant as they register mutators.
+				PrepareForTestWithArchMutator,
+				PrepareForTestWithPrebuilts,
+				PrepareForTestWithOverrides,
+				PrepareForTestWithVisibilityRuleChecker,
+				PrepareForTestWithDefaults,
+				PrepareForTestWithVisibilityRuleGatherer,
+				PrepareForTestWithVisibilityRuleEnforcer,
+				// Add additional files to the mock filesystem
+				test.fs.AddToFixture(),
+			).
+				SetErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
+				RunTest(t)
 
 			if test.effectiveVisibility != nil {
-				checkEffectiveVisibility(t, ctx, test.effectiveVisibility)
+				checkEffectiveVisibility(result, test.effectiveVisibility)
 			}
 		})
 	}
 }
 
-func checkEffectiveVisibility(t *testing.T, ctx *TestContext, effectiveVisibility map[qualifiedModuleName][]string) {
+func checkEffectiveVisibility(result *TestResult, effectiveVisibility map[qualifiedModuleName][]string) {
 	for moduleName, expectedRules := range effectiveVisibility {
-		rule := effectiveVisibilityRules(ctx.config, moduleName)
+		rule := effectiveVisibilityRules(result.Config, moduleName)
 		stringRules := rule.Strings()
-		if !reflect.DeepEqual(expectedRules, stringRules) {
-			t.Errorf("effective rules mismatch: expected %q, found %q", expectedRules, stringRules)
-		}
+		result.AssertDeepEquals("effective rules mismatch", expectedRules, stringRules)
 	}
 }
 
-func testVisibility(buildDir string, fs map[string][]byte) (*TestContext, []error) {
-
-	// Create a new config per test as visibility information is stored in the config.
-	config := TestArchConfig(buildDir, nil, "", fs)
-
-	ctx := NewTestArchContext(config)
-	ctx.RegisterModuleType("mock_library", newMockLibraryModule)
-	ctx.RegisterModuleType("mock_parent", newMockParentFactory)
-	ctx.RegisterModuleType("mock_defaults", defaultsFactory)
-
-	// Order of the following method calls is significant.
-	RegisterPackageBuildComponents(ctx)
-	registerTestPrebuiltBuildComponents(ctx)
-	ctx.PreArchMutators(RegisterVisibilityRuleChecker)
-	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
-	ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
-	ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
-	ctx.Register()
-
-	_, errs := ctx.ParseBlueprintsFiles(".")
-	if len(errs) > 0 {
-		return ctx, errs
-	}
-
-	_, errs = ctx.PrepareBuildActions(config)
-	return ctx, errs
-}
-
 type mockLibraryProperties struct {
 	Deps []string
 }
diff --git a/android/writedocs.go b/android/writedocs.go
index 91c2318..6417690 100644
--- a/android/writedocs.go
+++ b/android/writedocs.go
@@ -34,7 +34,8 @@
 type docsSingleton struct{}
 
 func primaryBuilderPath(ctx SingletonContext) Path {
-	primaryBuilder, err := filepath.Rel(ctx.Config().BuildDir(), os.Args[0])
+	buildDir := absolutePath(ctx.Config().BuildDir())
+	primaryBuilder, err := filepath.Rel(buildDir, os.Args[0])
 	if err != nil {
 		ctx.Errorf("path to primary builder %q is not in build dir %q",
 			os.Args[0], ctx.Config().BuildDir())
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 78b84f0..476ac4a 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -361,6 +361,7 @@
 libmedia_headers(minSdkVersion:29)
 libmedia_helper_headers(minSdkVersion:29)
 libmedia_midiiowrapper(minSdkVersion:29)
+libmediaparser-jni(minSdkVersion:29)
 libmidiextractor(minSdkVersion:29)
 libminijail(minSdkVersion:29)
 libminijail_gen_constants(minSdkVersion:(no version))
@@ -635,6 +636,7 @@
 Tethering(minSdkVersion:current)
 TetheringApiCurrentLib(minSdkVersion:30)
 TetheringApiCurrentLib(minSdkVersion:current)
+TetheringGoogle(minSdkVersion:30)
 TetheringGoogle(minSdkVersion:current)
 textclassifier-statsd(minSdkVersion:current)
 TextClassifierNotificationLibNoManifest(minSdkVersion:29)
diff --git a/apex/apex.go b/apex/apex.go
index a4bdc63..8f388c4 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -121,7 +121,7 @@
 	// Whether this APEX is considered updatable or not. When set to true, this will enforce
 	// additional rules for making sure that the APEX is truly updatable. To be updatable,
 	// min_sdk_version should be set as well. This will also disable the size optimizations like
-	// symlinking to the system libs. Default is false.
+	// symlinking to the system libs. Default is true.
 	Updatable *bool
 
 	// Whether this APEX is installable to one of the partitions like system, vendor, etc.
@@ -1232,7 +1232,7 @@
 
 // Implements android.ApexBudleDepsInfoIntf
 func (a *apexBundle) Updatable() bool {
-	return proptools.Bool(a.properties.Updatable)
+	return proptools.BoolDefault(a.properties.Updatable, true)
 }
 
 // getCertString returns the name of the cert that should be used to sign this APEX. This is
diff --git a/apex/apex_test.go b/apex/apex_test.go
index a2992df..aa68378 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -144,17 +144,18 @@
 	bp = bp + java.GatherRequiredDepsForTest()
 
 	fs := map[string][]byte{
-		"a.java":                                              nil,
-		"PrebuiltAppFoo.apk":                                  nil,
-		"PrebuiltAppFooPriv.apk":                              nil,
-		"build/make/target/product/security":                  nil,
-		"apex_manifest.json":                                  nil,
-		"AndroidManifest.xml":                                 nil,
-		"system/sepolicy/apex/myapex-file_contexts":           nil,
-		"system/sepolicy/apex/myapex.updatable-file_contexts": nil,
-		"system/sepolicy/apex/myapex2-file_contexts":          nil,
-		"system/sepolicy/apex/otherapex-file_contexts":        nil,
-		"system/sepolicy/apex/com.android.vndk-file_contexts": nil,
+		"a.java":                                                      nil,
+		"PrebuiltAppFoo.apk":                                          nil,
+		"PrebuiltAppFooPriv.apk":                                      nil,
+		"build/make/target/product/security":                          nil,
+		"apex_manifest.json":                                          nil,
+		"AndroidManifest.xml":                                         nil,
+		"system/sepolicy/apex/myapex-file_contexts":                   nil,
+		"system/sepolicy/apex/myapex.updatable-file_contexts":         nil,
+		"system/sepolicy/apex/myapex2-file_contexts":                  nil,
+		"system/sepolicy/apex/otherapex-file_contexts":                nil,
+		"system/sepolicy/apex/com.android.vndk-file_contexts":         nil,
+		"system/sepolicy/apex/com.android.vndk.current-file_contexts": nil,
 		"mylib.cpp":                                  nil,
 		"mytest.cpp":                                 nil,
 		"mytest1.cpp":                                nil,
@@ -377,6 +378,7 @@
 				"myjar",
 				"myjar_dex",
 			],
+			updatable: false,
 		}
 
 		apex {
@@ -477,6 +479,7 @@
 			binaries: ["foo"],
 			key: "myapex.key",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		cc_library_shared {
@@ -670,6 +673,7 @@
 			apps: ["AppFoo"],
 			rros: ["rro"],
 			bpfs: ["bpf"],
+			updatable: false,
 		}
 
 		prebuilt_etc {
@@ -738,6 +742,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 		}
 
 		apex_key {
@@ -761,6 +766,7 @@
 			key: "myapex.key",
 			payload_type: "zip",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -810,6 +816,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib", "mylib3"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1076,6 +1083,7 @@
 			name: "myapex2",
 			key: "myapex2.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1171,6 +1179,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1233,6 +1242,7 @@
 			name: "com.android.runtime",
 			key: "com.android.runtime.key",
 			native_shared_libs: ["libc"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1296,6 +1306,7 @@
 			name: "com.android.runtime",
 			key: "com.android.runtime.key",
 			native_shared_libs: ["libc"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1381,6 +1392,7 @@
 				key: "myapex.key",
 				use_vendor: true,
 				native_shared_libs: ["mylib"],
+				updatable: false,
 				`+tc.minSdkVersion+`
 			}
 
@@ -1446,6 +1458,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1672,6 +1685,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["libx"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1717,6 +1731,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["libx"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -1943,6 +1958,7 @@
 					name: "myapex",
 					java_libs: ["myjar"],
 					key: "myapex.key",
+					updatable: false,
 				}
 				apex_key {
 					name: "myapex.key",
@@ -2253,6 +2269,7 @@
 			binaries: ["mybin"],
 			prebuilts: ["myetc"],
 			compile_multilib: "both",
+			updatable: false,
 		}
 
 		apex_key {
@@ -2319,6 +2336,7 @@
 			},
 			compile_multilib: "both",
 			native_bridge_supported: true,
+			updatable: false,
 		}
 
 		apex_key {
@@ -2371,6 +2389,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
 			use_vendor: true,
+			updatable: false,
 		}
 
 		apex_key {
@@ -2439,6 +2458,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			use_vendor: true,
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -2457,6 +2477,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
 			use_vendor: true,
+			updatable: false,
 		}
 
 		apex_key {
@@ -2481,6 +2502,7 @@
 			key: "myapex.key",
 			binaries: ["mybin"],
 			vendor: true,
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -2512,7 +2534,8 @@
 	var builder strings.Builder
 	data.Custom(&builder, name, prefix, "", data)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`)
+	installPath := path.Join(buildDir, "../target/product/test_device/vendor/apex")
+	ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath)
 
 	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
 	requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
@@ -2527,6 +2550,7 @@
 			binaries: ["mybin"],
 			vendor: true,
 			use_vndk_as_stable: true,
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -2588,6 +2612,7 @@
 					name: "myapex",
 					key: "myapex.key",
 					prebuilts: ["myfirmware"],
+					updatable: false,
 					`+tc.additionalProp+`
 				}
 				apex_key {
@@ -2616,6 +2641,7 @@
 			key: "myapex.key",
 			use_vendor: true,
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -2650,6 +2676,7 @@
 			key: "myapex.key",
 			vendor: true,
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -2681,6 +2708,7 @@
 			key: "myapex.key",
 			vintf_fragments: ["fragment.xml"],
 			init_rc: ["init.rc"],
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -2709,6 +2737,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -2755,6 +2784,7 @@
 			certificate: ":myapex.certificate",
 			native_shared_libs: ["mylib"],
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		cc_library {
@@ -2809,6 +2839,7 @@
 			apex {
 				name: "myapex",
 				key: "myapex.key",
+				updatable: false,
 			}
 			apex_key {
 				name: "myapex.key",
@@ -2827,6 +2858,7 @@
 				name: "myapex_keytest",
 				key: "myapex.key",
 				file_contexts: ":myapex-file_contexts",
+				updatable: false,
 			}
 			apex_key {
 				name: "myapex.key",
@@ -2849,6 +2881,7 @@
 				name: "myapex",
 				key: "myapex.key",
 				certificate: ":myapex.certificate",
+				updatable: false,
 			}
 			apex_key {
 				name: "myapex.key",
@@ -2872,6 +2905,7 @@
 				key: "myapex.key",
 				file_contexts: ":myapex-file_contexts",
 				certificate: ":myapex.certificate",
+				updatable: false,
 			}
 			apex_key {
 				name: "myapex.key",
@@ -2894,6 +2928,7 @@
 				name: "myapex",
 				key: "myapex.key",
 				certificate: "testkey",
+				updatable: false,
 			}
 			apex_key {
 				name: "myapex.key",
@@ -2913,6 +2948,7 @@
 				key: "myapex.key",
 				file_contexts: ":myapex-file_contexts",
 				certificate: "testkey",
+				updatable: false,
 			}
 			apex_key {
 				name: "myapex.key",
@@ -2937,6 +2973,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib", "mylib2"],
+			updatable: false,
 		}
 
 		apex {
@@ -3064,6 +3101,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -3204,12 +3242,13 @@
 func TestVndkApexCurrent(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex",
-			key: "myapex.key",
+			name: "com.android.vndk.current",
+			key: "com.android.vndk.current.key",
+			updatable: false,
 		}
 
 		apex_key {
-			name: "myapex.key",
+			name: "com.android.vndk.current.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
@@ -3224,7 +3263,7 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex" ],
+			apex_available: [ "com.android.vndk.current" ],
 		}
 
 		cc_library {
@@ -3238,11 +3277,11 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex" ],
+			apex_available: [ "com.android.vndk.current" ],
 		}
 	`+vndkLibrariesTxtFiles("current"))
 
-	ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
 		"lib/libvndk.so",
 		"lib/libvndksp.so",
 		"lib/libc++.so",
@@ -3260,12 +3299,13 @@
 func TestVndkApexWithPrebuilt(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex",
-			key: "myapex.key",
+			name: "com.android.vndk.current",
+			key: "com.android.vndk.current.key",
+			updatable: false,
 		}
 
 		apex_key {
-			name: "myapex.key",
+			name: "com.android.vndk.current.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
@@ -3280,7 +3320,7 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex" ],
+			apex_available: [ "com.android.vndk.current" ],
 		}
 
 		cc_prebuilt_library_shared {
@@ -3299,15 +3339,14 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex" ],
+			apex_available: [ "com.android.vndk.current" ],
 		}
 		`+vndkLibrariesTxtFiles("current"),
 		withFiles(map[string][]byte{
 			"libvndk.so":     nil,
 			"libvndk.arm.so": nil,
 		}))
-
-	ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
 		"lib/libvndk.so",
 		"lib/libvndk.arm.so",
 		"lib64/libvndk.so",
@@ -3344,10 +3383,11 @@
 func TestVndkApexVersion(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex_v27",
+			name: "com.android.vndk.v27",
 			key: "myapex.key",
 			file_contexts: ":myapex-file_contexts",
 			vndk_version: "27",
+			updatable: false,
 		}
 
 		apex_key {
@@ -3373,7 +3413,7 @@
 					srcs: ["libvndk27_arm64.so"],
 				},
 			},
-			apex_available: [ "myapex_v27" ],
+			apex_available: [ "com.android.vndk.v27" ],
 		}
 
 		vndk_prebuilt_shared {
@@ -3402,73 +3442,27 @@
 			"libvndk27_x86_64.so": nil,
 		}))
 
-	ensureExactContents(t, ctx, "myapex_v27", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{
 		"lib/libvndk27_arm.so",
 		"lib64/libvndk27_arm64.so",
 		"etc/*",
 	})
 }
 
-func TestVndkApexErrorWithDuplicateVersion(t *testing.T) {
-	testApexError(t, `module "myapex_v27.*" .*: vndk_version: 27 is already defined in "myapex_v27.*"`, `
-		apex_vndk {
-			name: "myapex_v27",
-			key: "myapex.key",
-			file_contexts: ":myapex-file_contexts",
-			vndk_version: "27",
-		}
-		apex_vndk {
-			name: "myapex_v27_other",
-			key: "myapex.key",
-			file_contexts: ":myapex-file_contexts",
-			vndk_version: "27",
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "libvndk",
-			srcs: ["mylib.cpp"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-		}
-
-		vndk_prebuilt_shared {
-			name: "libvndk",
-			version: "27",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			srcs: ["libvndk.so"],
-		}
-	`, withFiles(map[string][]byte{
-		"libvndk.so": nil,
-	}))
-}
-
 func TestVndkApexNameRule(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex",
+			name: "com.android.vndk.current",
 			key: "myapex.key",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 		apex_vndk {
-			name: "myapex_v28",
+			name: "com.android.vndk.v28",
 			key: "myapex.key",
 			file_contexts: ":myapex-file_contexts",
 			vndk_version: "28",
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -3484,20 +3478,21 @@
 		}
 	}
 
-	assertApexName("com.android.vndk.vVER", "myapex")
-	assertApexName("com.android.vndk.v28", "myapex_v28")
+	assertApexName("com.android.vndk.vVER", "com.android.vndk.current")
+	assertApexName("com.android.vndk.v28", "com.android.vndk.v28")
 }
 
 func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex",
-			key: "myapex.key",
+			name: "com.android.vndk.current",
+			key: "com.android.vndk.current.key",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		apex_key {
-			name: "myapex.key",
+			name: "com.android.vndk.current.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
@@ -3514,11 +3509,12 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex" ],
+			apex_available: [ "com.android.vndk.current" ],
 		}
-		`+vndkLibrariesTxtFiles("current"), withNativeBridgeEnabled)
+		`+vndkLibrariesTxtFiles("current"),
+		withNativeBridgeEnabled)
 
-	ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
 		"lib/libvndk.so",
 		"lib64/libvndk.so",
 		"lib/libc++.so",
@@ -3528,16 +3524,16 @@
 }
 
 func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) {
-	testApexError(t, `module "myapex" .*: native_bridge_supported: .* doesn't support native bridge binary`, `
+	testApexError(t, `module "com.android.vndk.current" .*: native_bridge_supported: .* doesn't support native bridge binary`, `
 		apex_vndk {
-			name: "myapex",
-			key: "myapex.key",
+			name: "com.android.vndk.current",
+			key: "com.android.vndk.current.key",
 			file_contexts: ":myapex-file_contexts",
 			native_bridge_supported: true,
 		}
 
 		apex_key {
-			name: "myapex.key",
+			name: "com.android.vndk.current.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
@@ -3561,10 +3557,11 @@
 func TestVndkApexWithBinder32(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex_v27",
+			name: "com.android.vndk.v27",
 			key: "myapex.key",
 			file_contexts: ":myapex-file_contexts",
 			vndk_version: "27",
+			updatable: false,
 		}
 
 		apex_key {
@@ -3604,7 +3601,7 @@
 					srcs: ["libvndk27binder32.so"],
 				}
 			},
-			apex_available: [ "myapex_v27" ],
+			apex_available: [ "com.android.vndk.v27" ],
 		}
 		`+vndkLibrariesTxtFiles("27"),
 		withFiles(map[string][]byte{
@@ -3620,7 +3617,7 @@
 		}),
 	)
 
-	ensureExactContents(t, ctx, "myapex_v27", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{
 		"lib/libvndk27binder32.so",
 		"etc/*",
 	})
@@ -3629,13 +3626,14 @@
 func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex",
-			key: "myapex.key",
+			name: "com.android.vndk.current",
+			key: "com.android.vndk.current.key",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		apex_key {
-			name: "myapex.key",
+			name: "com.android.vndk.current.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
@@ -3656,7 +3654,7 @@
 		"libz.map.txt": nil,
 	}))
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_image").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common_image").Rule("apexManifestRule")
 	provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
 }
@@ -3669,6 +3667,7 @@
 			native_shared_libs: ["lib_nodep"],
 			compile_multilib: "both",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		apex {
@@ -3677,6 +3676,7 @@
 			native_shared_libs: ["lib_dep"],
 			compile_multilib: "both",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		apex {
@@ -3685,6 +3685,7 @@
 			native_shared_libs: ["libfoo"],
 			compile_multilib: "both",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		apex {
@@ -3693,6 +3694,7 @@
 			native_shared_libs: ["lib_dep", "libfoo"],
 			compile_multilib: "both",
 			file_contexts: ":myapex-file_contexts",
+			updatable: false,
 		}
 
 		apex_key {
@@ -3772,6 +3774,7 @@
 			key: "myapex.key",
 			apex_name: "com.android.myapex",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -3815,6 +3818,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib_common"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -3867,6 +3871,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib_common_test"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -3914,6 +3919,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 			multilib: {
 				first: {
 					native_shared_libs: ["mylib_common"],
@@ -4004,6 +4010,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 			arch: {
 				arm64: {
 					native_shared_libs: ["mylib.arm64"],
@@ -4063,6 +4070,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			binaries: ["myscript"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -4102,6 +4110,7 @@
 				apex {
 					name: "myapex",
 					key: "myapex.key",
+					updatable: false,
 					`+tc.propName+`
 				}
 
@@ -4134,6 +4143,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 		}
 
 		apex_key {
@@ -4153,6 +4163,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			file_contexts: "my_own_file_contexts",
+			updatable: false,
 		}
 
 		apex_key {
@@ -4172,6 +4183,7 @@
 			key: "myapex.key",
 			product_specific: true,
 			file_contexts: "product_specific_file_contexts",
+			updatable: false,
 		}
 
 		apex_key {
@@ -4187,6 +4199,7 @@
 			key: "myapex.key",
 			product_specific: true,
 			file_contexts: "product_specific_file_contexts",
+			updatable: false,
 		}
 
 		apex_key {
@@ -4209,6 +4222,7 @@
 			key: "myapex.key",
 			product_specific: true,
 			file_contexts: ":my-file-contexts",
+			updatable: false,
 		}
 
 		apex_key {
@@ -4682,6 +4696,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["libfoo", "libbar"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -4817,6 +4832,7 @@
 		apex_test {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 			tests: [
 				"mytest",
 				"mytests",
@@ -4928,6 +4944,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -4998,6 +5015,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["myjavaimport"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5029,6 +5047,7 @@
 				"AppFoo",
 				"AppFooPriv",
 			],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5107,6 +5126,7 @@
 				"AppFooPrebuilt",
 				"AppFooPrivPrebuilt",
 			],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5154,6 +5174,7 @@
 			apps: [
 				"AppFoo",
 			],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5195,6 +5216,7 @@
 			apps: [
 				"TesterHelpAppFoo",
 			],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5225,6 +5247,7 @@
 		name: "myapex",
 		key: "myapex.key",
 		native_shared_libs: ["libfoo"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5237,6 +5260,7 @@
 		name: "otherapex",
 		key: "myapex.key",
 		native_shared_libs: ["libfoo"],
+		updatable: false,
 	}
 
 	cc_defaults {
@@ -5259,6 +5283,7 @@
 		name: "myapex",
 		key: "myapex.key",
 		native_shared_libs: ["libfoo"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5271,6 +5296,7 @@
 		name: "otherapex",
 		key: "otherapex.key",
 		native_shared_libs: ["libfoo"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5300,6 +5326,7 @@
 		name: "myapex",
 		key: "myapex.key",
 		native_shared_libs: ["libfoo"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5337,6 +5364,7 @@
 		name: "myapex",
 		key: "myapex.key",
 		native_shared_libs: ["libfoo"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5357,6 +5385,7 @@
 		name: "myapex",
 		key: "myapex.key",
 		native_shared_libs: ["libfoo", "libbar"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5396,6 +5425,7 @@
 		name: "myapex",
 		key: "myapex.key",
 		native_shared_libs: ["libbar", "libbaz"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5458,6 +5488,7 @@
 		name: "myapex",
 		key: "myapex.key",
 		native_shared_libs: ["libfoo"],
+		updatable: false,
 	}
 
 	apex_key {
@@ -5493,6 +5524,7 @@
 			key: "myapex.key",
 			apps: ["app"],
 			overrides: ["oldapex"],
+			updatable: false,
 		}
 
 		override_apex {
@@ -5635,6 +5667,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["foo"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5672,6 +5705,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["foo", "bar"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5724,6 +5758,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["foo"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5786,6 +5821,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["foo", "bar"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5863,6 +5899,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["foo"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5890,6 +5927,7 @@
 			key: "myapex.key",
 			prebuilts: ["myjar-platform-compat-config"],
 			java_libs: ["myjar"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5923,6 +5961,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			java_libs: ["myjar"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5948,6 +5987,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -5987,6 +6027,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
 			java_libs: ["myjar"],
+			updatable: false,
 		}
 
 		apex {
@@ -6115,6 +6156,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -6166,6 +6208,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			jni_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -6206,6 +6249,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -6228,6 +6272,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			apps: ["AppFoo"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -6258,6 +6303,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			apps: ["AppSet"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -6364,6 +6410,7 @@
 			name: "some-non-updatable-apex",
 			key: "some-non-updatable-apex.key",
 			java_libs: ["some-non-updatable-apex-lib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -6487,6 +6534,21 @@
 	`)
 }
 
+func TestUpdatableDefault_should_set_min_sdk_version(t *testing.T) {
+	testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+}
+
 func TestNoUpdatableJarsInBootImage(t *testing.T) {
 	var err string
 	var transform func(*dexpreopt.GlobalConfig)
@@ -6701,6 +6763,7 @@
 					name: "myapex",
 					key: "myapex.key",
 					java_libs: ["bcp_lib1", "nonbcp_lib2"],
+					updatable: false,
 				}`,
 			bootJars: []string{"bcp_lib1"},
 			modulesPackages: map[string][]string{
@@ -6733,6 +6796,7 @@
 					name: "myapex",
 					key: "myapex.key",
 					java_libs: ["bcp_lib1", "bcp_lib2"],
+					updatable: false,
 				}
 			`,
 			bootJars: []string{"bcp_lib1", "bcp_lib2"},
@@ -6757,6 +6821,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib", "myprivlib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -6881,6 +6946,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -6916,6 +6982,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			updatable: false,
 		}
 
 		apex_key {
@@ -6958,6 +7025,7 @@
 			key: "myapex.key",
 			apps: ["app"],
 			allowed_files: "allowed.txt",
+			updatable: false,
 		}
 
 		apex_key {
@@ -7012,6 +7080,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -7047,6 +7116,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			compressible: true,
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -7081,6 +7151,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -7132,6 +7203,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 
 		apex_key {
@@ -7181,6 +7253,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			updatable: false,
 		}
 		apex_key {
 			name: "myapex.key",
@@ -7199,6 +7272,7 @@
 			enabled: %s,
 			key: "myapex.key",
 			native_shared_libs: ["stublib"],
+			updatable: false,
 		}
 	`
 
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index 27a1562..ff779e1 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -48,6 +48,7 @@
 				"baz",
 				"quuz",
 			],
+			updatable: false,
 		}
 
 		apex_key {
@@ -187,6 +188,7 @@
 			boot_images: [
 				"mybootimage",
 			],
+			updatable: false,
 		}
 
 		apex_key {
diff --git a/apex/vndk.go b/apex/vndk.go
index f4b12b5..75c0fb0 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -17,7 +17,6 @@
 import (
 	"path/filepath"
 	"strings"
-	"sync"
 
 	"android/soong/android"
 	"android/soong/cc"
@@ -60,17 +59,6 @@
 	Vndk_version *string
 }
 
-var (
-	vndkApexListKey   = android.NewOnceKey("vndkApexList")
-	vndkApexListMutex sync.Mutex
-)
-
-func vndkApexList(config android.Config) map[string]string {
-	return config.Once(vndkApexListKey, func() interface{} {
-		return map[string]string{}
-	}).(map[string]string)
-}
-
 func apexVndkMutator(mctx android.TopDownMutatorContext) {
 	if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex {
 		if ab.IsNativeBridgeSupported() {
@@ -80,15 +68,6 @@
 		vndkVersion := ab.vndkVersion(mctx.DeviceConfig())
 		// Ensure VNDK APEX mount point is formatted as com.android.vndk.v###
 		ab.properties.Apex_name = proptools.StringPtr(vndkApexNamePrefix + vndkVersion)
-
-		// vndk_version should be unique
-		vndkApexListMutex.Lock()
-		defer vndkApexListMutex.Unlock()
-		vndkApexList := vndkApexList(mctx.Config())
-		if other, ok := vndkApexList[vndkVersion]; ok {
-			mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other)
-		}
-		vndkApexList[vndkVersion] = mctx.ModuleName()
 	}
 }
 
@@ -99,9 +78,16 @@
 		if vndkVersion == "" {
 			vndkVersion = mctx.DeviceConfig().PlatformVndkVersion()
 		}
-		vndkApexList := vndkApexList(mctx.Config())
-		if vndkApex, ok := vndkApexList[vndkVersion]; ok {
-			mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApex)
+		if vndkVersion == mctx.DeviceConfig().PlatformVndkVersion() {
+			vndkVersion = "current"
+		} else {
+			vndkVersion = "v" + vndkVersion
+		}
+
+		vndkApexName := "com.android.vndk." + vndkVersion
+
+		if mctx.OtherModuleExists(vndkApexName) {
+			mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApexName)
 		}
 	} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
 		vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index ccf4e57..5e9a11f 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -11,12 +11,13 @@
 func TestVndkApexForVndkLite(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
-			name: "myapex",
-			key: "myapex.key",
+			name: "com.android.vndk.current",
+			key: "com.android.vndk.current.key",
+			updatable: false,
 		}
 
 		apex_key {
-			name: "myapex.key",
+			name: "com.android.vndk.current.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
@@ -31,7 +32,7 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex" ],
+			apex_available: [ "com.android.vndk.current" ],
 		}
 
 		cc_library {
@@ -45,13 +46,13 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
-			apex_available: [ "myapex" ],
+			apex_available: [ "com.android.vndk.current" ],
 		}
 	`+vndkLibrariesTxtFiles("current"), func(fs map[string][]byte, config android.Config) {
 		config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("")
 	})
 	// VNDK-Lite contains only core variants of VNDK-Sp libraries
-	ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
 		"lib/libvndksp.so",
 		"lib/libc++.so",
 		"lib64/libvndksp.so",
@@ -67,8 +68,9 @@
 func TestVndkApexUsesVendorVariant(t *testing.T) {
 	bp := `
 		apex_vndk {
-			name: "myapex",
+			name: "com.android.vndk.current",
 			key: "mykey",
+			updatable: false,
 		}
 		apex_key {
 			name: "mykey",
@@ -94,7 +96,7 @@
 				return
 			}
 		}
-		t.Fail()
+		t.Errorf("expected path %q not found", path)
 	}
 
 	t.Run("VNDK lib doesn't have an apex variant", func(t *testing.T) {
@@ -106,7 +108,7 @@
 		}
 
 		// VNDK APEX doesn't create apex variant
-		files := getFiles(t, ctx, "myapex", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
 	})
 
@@ -116,7 +118,7 @@
 			config.TestProductVariables.ProductVndkVersion = proptools.StringPtr("current")
 		})
 
-		files := getFiles(t, ctx, "myapex", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
 	})
 
@@ -126,10 +128,10 @@
 			config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
 		})
 
-		files := getFiles(t, ctx, "myapex", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
 
-		files = getFiles(t, ctx, "myapex", "android_common_cov_image")
+		files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov_image")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared_cov/libfoo.so")
 	})
 }
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 3a6feca..e7f995f 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -21,6 +21,7 @@
 	"path/filepath"
 	"strings"
 
+	"android/soong/shared"
 	"github.com/google/blueprint/bootstrap"
 
 	"android/soong/android"
@@ -28,11 +29,15 @@
 )
 
 var (
+	topDir            string
+	outDir            string
 	docFile           string
 	bazelQueryViewDir string
 )
 
 func init() {
+	flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree")
+	flag.StringVar(&outDir, "out", "", "Soong output directory (usually $TOP/out/soong)")
 	flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
 	flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory")
 }
@@ -80,15 +85,22 @@
 }
 
 func main() {
-	android.ReexecWithDelveMaybe()
 	flag.Parse()
 
+	android.InitSandbox(topDir)
+	android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available"))
+	android.ReexecWithDelveMaybe()
+
 	// The top-level Blueprints file is passed as the first argument.
 	srcDir := filepath.Dir(flag.Arg(0))
 	var ctx *android.Context
 	configuration := newConfig(srcDir)
 	extraNinjaDeps := []string{configuration.ProductVariablesFileName}
 
+	// These two are here so that we restart a non-debugged soong_build when the
+	// user sets SOONG_DELVE the first time.
+	configuration.Getenv("SOONG_DELVE")
+	configuration.Getenv("SOONG_DELVE_PATH")
 	// Read the SOONG_DELVE again through configuration so that there is a dependency on the environment variable
 	// and soong_build will rerun when it is set for the first time.
 	if listen := configuration.Getenv("SOONG_DELVE"); listen != "" {
diff --git a/java/java.go b/java/java.go
index e471f0d..b5988fc 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2515,6 +2515,11 @@
 }
 
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if j.testProperties.Test_options.Unit_test == nil && ctx.Host() {
+		// TODO(b/): Clean temporary heuristic to avoid unexpected onboarding.
+		defaultUnitTest := !inList("tradefed", j.properties.Static_libs) && !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites) && !inList("robolectric-host-android_all", j.properties.Static_libs) && !inList("robolectric-host-android_all", j.properties.Libs)
+		j.testProperties.Test_options.Unit_test = proptools.BoolPtr(defaultUnitTest)
+	}
 	j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
 		j.testProperties.Test_suites, j.testProperties.Auto_gen_config, j.testProperties.Test_options.Unit_test)
 
@@ -2675,6 +2680,7 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	InitJavaModuleMultiTargets(module, android.HostSupported)
+
 	return module
 }
 
diff --git a/java/rro_test.go b/java/rro_test.go
index edbf170..061d9d3 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -20,6 +20,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/shared"
 )
 
 func TestRuntimeResourceOverlay(t *testing.T) {
@@ -105,7 +106,7 @@
 
 	// Check device location.
 	path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath = []string{"/tmp/target/product/test_device/product/overlay"}
+	expectedPath = []string{shared.JoinPath(buildDir, "../target/product/test_device/product/overlay")}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
 	}
@@ -114,7 +115,7 @@
 	m = ctx.ModuleForTests("foo_themed", "android_common")
 	androidMkEntries = android.AndroidMkEntriesForTest(t, ctx, m.Module())[0]
 	path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath = []string{"/tmp/target/product/test_device/product/overlay/faza"}
+	expectedPath = []string{shared.JoinPath(buildDir, "../target/product/test_device/product/overlay/faza")}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
 	}
@@ -160,7 +161,7 @@
 
 	// Check device location.
 	path := android.AndroidMkEntriesForTest(t, ctx, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath := []string{"/tmp/target/product/test_device/product/overlay/default_theme"}
+	expectedPath := []string{shared.JoinPath(buildDir, "../target/product/test_device/product/overlay/default_theme")}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %q, expected: %q", path, expectedPath)
 	}
@@ -179,7 +180,7 @@
 
 	// Check device location.
 	path = android.AndroidMkEntriesForTest(t, ctx, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath = []string{"/tmp/target/product/test_device/system/overlay"}
+	expectedPath = []string{shared.JoinPath(buildDir, "../target/product/test_device/system/overlay")}
 	if !reflect.DeepEqual(path, expectedPath) {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
 	}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 997d2f6..3591777 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -251,6 +251,7 @@
 			uses_sdks: ["mysdk@1"],
 			key: "myapex.key",
 			certificate: ":myapex.cert",
+			updatable: false,
 		}
 
 		apex {
@@ -259,6 +260,7 @@
 			uses_sdks: ["mysdk@2"],
 			key: "myapex.key",
 			certificate: ":myapex.cert",
+			updatable: false,
 		}
 
 		apex {
@@ -266,6 +268,7 @@
 			native_shared_libs: ["sdkmember"],
 			key: "myapex.key",
 			certificate: ":myapex.cert",
+			updatable: false,
 		}
 	`)
 
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 17a6ca9..111b22c 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -211,6 +211,7 @@
 			uses_sdks: ["mysdk@1"],
 			key: "myapex.key",
 			certificate: ":myapex.cert",
+			updatable: false,
 		}
 
 		apex {
@@ -219,6 +220,7 @@
 			uses_sdks: ["mysdk@2"],
 			key: "myapex.key",
 			certificate: ":myapex.cert",
+			updatable: false,
 		}
 	`)
 
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index fb7ab13..f48f7fb 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -3,6 +3,7 @@
 import (
 	"io/ioutil"
 	"os"
+	"path"
 	"path/filepath"
 	"reflect"
 	"testing"
@@ -73,7 +74,8 @@
 
 	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
 
-	expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo_test"
+	expectedPath := path.Join(buildDir,
+		"../target/product/test_device/data/nativetest64/foo_test")
 	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
 	if expectedPath != actualPath {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
@@ -97,7 +99,8 @@
 
 	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
 
-	expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo"
+	expectedPath := path.Join(buildDir,
+		"../target/product/test_device/data/nativetest64/foo")
 	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
 	if expectedPath != actualPath {
 		t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
diff --git a/shared/Android.bp b/shared/Android.bp
index c79bc2b..deb17f8 100644
--- a/shared/Android.bp
+++ b/shared/Android.bp
@@ -8,6 +8,10 @@
     srcs: [
         "env.go",
         "paths.go",
+        "debug.go",
+    ],
+    testSrcs: [
+        "paths_test.go",
     ],
     deps: [
         "soong-bazel",
diff --git a/shared/debug.go b/shared/debug.go
new file mode 100644
index 0000000..0c9ba4f
--- /dev/null
+++ b/shared/debug.go
@@ -0,0 +1,17 @@
+package shared
+
+import (
+	"os"
+	"os/exec"
+)
+
+// Finds the Delve binary to use. Either uses the SOONG_DELVE_PATH environment
+// variable or if that is unset, looks at $PATH.
+func ResolveDelveBinary() string {
+	result := os.Getenv("SOONG_DELVE_PATH")
+	if result == "" {
+		result, _ = exec.LookPath("dlv")
+	}
+
+	return result
+}
diff --git a/shared/env.go b/shared/env.go
index 7900daa..152729b 100644
--- a/shared/env.go
+++ b/shared/env.go
@@ -91,6 +91,28 @@
 	return false, nil
 }
 
+// Deserializes and environment serialized by EnvFileContents() and returns it
+// as a map[string]string.
+func EnvFromFile(envFile string) (map[string]string, error) {
+	result := make(map[string]string)
+	data, err := ioutil.ReadFile(envFile)
+	if err != nil {
+		return result, err
+	}
+
+	var contents envFileData
+	err = json.Unmarshal(data, &contents)
+	if err != nil {
+		return result, err
+	}
+
+	for _, entry := range contents {
+		result[entry.Key] = entry.Value
+	}
+
+	return result, nil
+}
+
 // Implements sort.Interface so that we can use sort.Sort on envFileData arrays.
 func (e envFileData) Len() int {
 	return len(e)
diff --git a/shared/paths.go b/shared/paths.go
index 1b9ff60..fca8b4c 100644
--- a/shared/paths.go
+++ b/shared/paths.go
@@ -30,6 +30,21 @@
 	BazelMetricsDir() string
 }
 
+// Joins the path strings in the argument list, taking absolute paths into
+// account. That is, if one of the strings is an absolute path, the ones before
+// are ignored.
+func JoinPath(base string, rest ...string) string {
+	result := base
+	for _, next := range rest {
+		if filepath.IsAbs(next) {
+			result = next
+		} else {
+			result = filepath.Join(result, next)
+		}
+	}
+	return result
+}
+
 // Given the out directory, returns the root of the temp directory (to be cleared at the start of each execution of Soong)
 func TempDirForOutDir(outDir string) (tempPath string) {
 	return filepath.Join(outDir, ".temp")
diff --git a/shared/paths_test.go b/shared/paths_test.go
new file mode 100644
index 0000000..018d55f
--- /dev/null
+++ b/shared/paths_test.go
@@ -0,0 +1,32 @@
+// Copyright 2021 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 shared
+
+import (
+	"testing"
+)
+
+func assertEqual(t *testing.T, expected, actual string) {
+	t.Helper()
+	if expected != actual {
+		t.Errorf("expected %q != got %q", expected, actual)
+	}
+}
+
+func TestJoinPath(t *testing.T) {
+	assertEqual(t, "/a/b", JoinPath("c/d", "/a/b"))
+	assertEqual(t, "a/b", JoinPath("a", "b"))
+	assertEqual(t, "/a/b", JoinPath("x", "/a", "b"))
+}
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index b1f8551..6ba497c 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -124,7 +124,7 @@
 		productOut("obj/PACKAGING"),
 		productOut("ramdisk"),
 		productOut("debug_ramdisk"),
-		productOut("vendor-ramdisk"),
+		productOut("vendor_ramdisk"),
 		productOut("vendor_debug_ramdisk"),
 		productOut("test_harness_ramdisk"),
 		productOut("recovery"),
diff --git a/ui/build/environment.go b/ui/build/environment.go
index 6d8a28f..50d059f 100644
--- a/ui/build/environment.go
+++ b/ui/build/environment.go
@@ -33,6 +33,19 @@
 	return &env
 }
 
+// Returns a copy of the environment as a map[string]string.
+func (e *Environment) AsMap() map[string]string {
+	result := make(map[string]string)
+
+	for _, envVar := range *e {
+		if k, v, ok := decodeKeyValue(envVar); ok {
+			result[k] = v
+		}
+	}
+
+	return result
+}
+
 // Get returns the value associated with the key, and whether it exists.
 // It's equivalent to the os.LookupEnv function, but with this copy of the
 // Environment.
diff --git a/ui/build/paths/logs_test.go b/ui/build/paths/logs_test.go
index 3b1005f..067f3f3 100644
--- a/ui/build/paths/logs_test.go
+++ b/ui/build/paths/logs_test.go
@@ -26,6 +26,9 @@
 )
 
 func TestSendLog(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode, sometimes hangs")
+	}
 	t.Run("Short name", func(t *testing.T) {
 		d, err := ioutil.TempDir("", "s")
 		if err != nil {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 125dbcc..fc43663 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -21,6 +21,7 @@
 	"strconv"
 
 	"android/soong/shared"
+
 	soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
 
 	"github.com/golang/protobuf/proto"
@@ -30,6 +31,15 @@
 	"android/soong/ui/status"
 )
 
+func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string) error {
+	data, err := shared.EnvFileContents(envDeps)
+	if err != nil {
+		return err
+	}
+
+	return ioutil.WriteFile(envFile, data, 0644)
+}
+
 // This uses Android.bp files and various tools to generate <builddir>/build.ninja.
 //
 // However, the execution of <builddir>/build.ninja happens later in build/soong/ui/build/build.go#Build()
@@ -47,6 +57,12 @@
 	ctx.BeginTrace(metrics.RunSoong, "soong")
 	defer ctx.EndTrace()
 
+	// We have two environment files: .available is the one with every variable,
+	// .used with the ones that were actually used. The latter is used to
+	// determine whether Soong needs to be re-run since why re-run it if only
+	// unused variables were changed?
+	envFile := filepath.Join(config.SoongOutDir(), "soong.environment.available")
+
 	// Use an anonymous inline function for tracing purposes (this pattern is used several times below).
 	func() {
 		ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
@@ -61,6 +77,7 @@
 		}
 
 		cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", args...)
+
 		cmd.Environment.Set("BLUEPRINTDIR", "./build/blueprint")
 		cmd.Environment.Set("BOOTSTRAP", "./build/blueprint/bootstrap.bash")
 		cmd.Environment.Set("BUILDDIR", config.SoongOutDir())
@@ -74,11 +91,32 @@
 		cmd.RunAndPrintOrFatal()
 	}()
 
+	soongBuildEnv := config.Environment().Copy()
+	soongBuildEnv.Set("TOP", os.Getenv("TOP"))
+	// These two dependencies are read from bootstrap.go, but also need to be here
+	// so that soong_build can declare a dependency on them
+	soongBuildEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
+	soongBuildEnv.Set("SOONG_DELVE_PATH", os.Getenv("SOONG_DELVE_PATH"))
+	soongBuildEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
+	// For Bazel mixed builds.
+	soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel")
+	soongBuildEnv.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
+	soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
+	soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
+	soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
+
+	if os.Getenv("SOONG_DELVE") != "" {
+		// SOONG_DELVE is already in cmd.Environment
+		soongBuildEnv.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary())
+	}
+
+	writeEnvironmentFile(ctx, envFile, soongBuildEnv.AsMap())
+
 	func() {
 		ctx.BeginTrace(metrics.RunSoong, "environment check")
 		defer ctx.EndTrace()
 
-		envFile := filepath.Join(config.SoongOutDir(), ".soong.environment")
+		envFile := filepath.Join(config.SoongOutDir(), "soong.environment.used")
 		getenv := func(k string) string {
 			v, _ := config.Environment().Get(k)
 			return v
@@ -134,14 +172,7 @@
 			"--frontend_file", fifo,
 			"-f", filepath.Join(config.SoongOutDir(), file))
 
-		// For Bazel mixed builds.
-		cmd.Environment.Set("BAZEL_PATH", "./tools/bazel")
-		cmd.Environment.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
-		cmd.Environment.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
-		cmd.Environment.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
-		cmd.Environment.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
-
-		cmd.Environment.Set("SOONG_SANDBOX_SOONG_BUILD", "true")
+		cmd.Environment.Set("SOONG_OUTDIR", config.SoongOutDir())
 		cmd.Sandbox = soongSandbox
 		cmd.RunAndStreamOrFatal()
 	}