Merge "Remove .rustc ELF section from mini-debug-info."
diff --git a/android/android_test.go b/android/android_test.go
index 2a697fb..fb82e37 100644
--- a/android/android_test.go
+++ b/android/android_test.go
@@ -22,5 +22,3 @@
 func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
-
-var emptyTestFixtureFactory = NewFixtureFactory(nil)
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index 230b1ec..8eda9b2 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -141,14 +141,14 @@
 // bp module and then returns the config and the custom module called "foo".
 func buildContextAndCustomModuleFoo(t *testing.T, bp string) (*TestContext, *customModule) {
 	t.Helper()
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		// Enable androidmk Singleton
 		PrepareForTestWithAndroidMk,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("custom", customModuleFactory)
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	module := result.ModuleForTests("foo", "").Module().(*customModule)
 	return result.TestContext, module
diff --git a/android/apex.go b/android/apex.go
index 0d5cac8..a5ff442 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -140,9 +140,24 @@
 	// DepIsInSameApex tests if the other module 'dep' is considered as part of the same APEX as
 	// this module. For example, a static lib dependency usually returns true here, while a
 	// shared lib dependency to a stub library returns false.
+	//
+	// This method must not be called directly without first ignoring dependencies whose tags
+	// implement ExcludeFromApexContentsTag. Calls from within the func passed to WalkPayloadDeps()
+	// are fine as WalkPayloadDeps() will ignore those dependencies automatically. Otherwise, use
+	// IsDepInSameApex instead.
 	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
 }
 
+func IsDepInSameApex(ctx BaseModuleContext, module, dep Module) bool {
+	depTag := ctx.OtherModuleDependencyTag(dep)
+	if _, ok := depTag.(ExcludeFromApexContentsTag); ok {
+		// The tag defines a dependency that never requires the child module to be part of the same
+		// apex as the parent.
+		return false
+	}
+	return module.(DepIsInSameApex).DepIsInSameApex(ctx, dep)
+}
+
 // ApexModule is the interface that a module type is expected to implement if the module has to be
 // built differently depending on whether the module is destined for an APEX or not (i.e., installed
 // to one of the regular partitions).
@@ -260,6 +275,10 @@
 //
 // Unless the tag also implements the AlwaysRequireApexVariantTag this will prevent an apex variant
 // from being created for the module.
+//
+// At the moment the sdk.sdkRequirementsMutator relies on the fact that the existing tags which
+// implement this interface do not define dependencies onto members of an sdk_snapshot. If that
+// changes then sdk.sdkRequirementsMutator will need fixing.
 type ExcludeFromApexContentsTag interface {
 	blueprint.DependencyTag
 
diff --git a/android/arch_test.go b/android/arch_test.go
index 09cb523..633ddaa 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -358,12 +358,12 @@
 
 	for _, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			result := emptyTestFixtureFactory.RunTest(t,
+			result := GroupFixturePreparers(
 				prepareForArchTest,
 				// Test specific preparer
 				OptionalFixturePreparer(tt.preparer),
 				FixtureWithRootAndroidBp(bp),
-			)
+			).RunTest(t)
 			ctx := result.TestContext
 
 			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
@@ -441,7 +441,7 @@
 
 	for _, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			result := emptyTestFixtureFactory.RunTest(t,
+			result := GroupFixturePreparers(
 				prepareForArchTest,
 				// Test specific preparer
 				OptionalFixturePreparer(tt.preparer),
@@ -455,7 +455,7 @@
 					}
 				}),
 				FixtureWithRootAndroidBp(bp),
-			)
+			).RunTest(t)
 
 			ctx := result.TestContext
 
diff --git a/android/config.go b/android/config.go
index 19706f5..0de8928 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1389,7 +1389,10 @@
 }
 
 func (c *deviceConfig) BoardSepolicyVers() string {
-	return String(c.config.productVariables.BoardSepolicyVers)
+	if ver := String(c.config.productVariables.BoardSepolicyVers); ver != "" {
+		return ver
+	}
+	return c.PlatformSepolicyVersion()
 }
 
 func (c *deviceConfig) BoardReqdMaskPolicy() []string {
diff --git a/android/csuite_config_test.go b/android/csuite_config_test.go
index d30ff69..b8a176e 100644
--- a/android/csuite_config_test.go
+++ b/android/csuite_config_test.go
@@ -19,14 +19,14 @@
 )
 
 func TestCSuiteConfig(t *testing.T) {
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		PrepareForTestWithArchMutator,
 		FixtureRegisterWithContext(registerCSuiteBuildComponents),
 		FixtureWithRootAndroidBp(`
 			csuite_config { name: "plain"}
 			csuite_config { name: "with_manifest", test_config: "manifest.xml" }
 		`),
-	)
+	).RunTest(t)
 
 	variants := result.ModuleVariantsForTests("plain")
 	if len(variants) > 1 {
diff --git a/android/defaults_test.go b/android/defaults_test.go
index b33cb52..a7542ab 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -83,10 +83,10 @@
 		}
 	`
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		prepareForDefaultsTest,
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	foo := result.Module("foo", "").(*defaultsTestModule)
 
@@ -114,11 +114,11 @@
 		}
 	`
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		prepareForDefaultsTest,
 		PrepareForTestWithAllowMissingDependencies,
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	missingDefaults := result.ModuleForTests("missing_defaults", "").Output("out")
 	missingTransitiveDefaults := result.ModuleForTests("missing_transitive_defaults", "").Output("out")
diff --git a/android/deptag_test.go b/android/deptag_test.go
index 7f55896..eb4fa89 100644
--- a/android/deptag_test.go
+++ b/android/deptag_test.go
@@ -80,13 +80,13 @@
 		}
 	`
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		PrepareForTestWithArchMutator,
 		FixtureWithRootAndroidBp(bp),
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("test_module", testInstallDependencyTagModuleFactory)
 		}),
-	)
+	).RunTest(t)
 
 	config := result.Config
 
diff --git a/android/fixture.go b/android/fixture.go
index 4e445c0..6c9ea6b 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"strings"
 	"testing"
 )
 
@@ -29,8 +30,8 @@
 // first creating a base Fixture (which is essentially empty) and then applying FixturePreparer
 // instances to it to modify the environment.
 //
-// FixtureFactory
-// ==============
+// FixtureFactory (deprecated)
+// ===========================
 // These are responsible for creating fixtures. Factories are immutable and are intended to be
 // initialized once and reused to create multiple fixtures. Each factory has a list of fixture
 // preparers that prepare a fixture for running a test. Factories can also be used to create other
@@ -42,7 +43,9 @@
 // intended to be immutable and able to prepare multiple Fixture objects simultaneously without
 // them sharing any data.
 //
-// FixturePreparers are only ever invoked once per test fixture. Prior to invocation the list of
+// They provide the basic capabilities for running tests too.
+//
+// FixturePreparers are only ever applied once per test fixture. Prior to application the list of
 // FixturePreparers are flattened and deduped while preserving the order they first appear in the
 // list. This makes it easy to reuse, group and combine FixturePreparers together.
 //
@@ -118,14 +121,58 @@
 // Some files to use in tests in the java package.
 //
 // var javaMockFS = android.MockFS{
-//		"api/current.txt":        nil,
-//		"api/removed.txt":        nil,
+//    "api/current.txt":        nil,
+//    "api/removed.txt":        nil,
 //    ...
 // }
 //
-// A package private factory for use for testing java within the java package.
+// A package private preparer for use for testing java within the java package.
 //
-// var javaFixtureFactory = NewFixtureFactory(
+// var prepareForJavaTest = android.GroupFixturePreparers(
+//    PrepareForIntegrationTestWithJava,
+//    FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+//      ctx.RegisterModuleType("test_module", testModule)
+//    }),
+//    javaMockFS.AddToFixture(),
+//    ...
+// }
+//
+// func TestJavaStuff(t *testing.T) {
+//   result := android.GroupFixturePreparers(t,
+//       prepareForJavaTest,
+//       android.FixtureWithRootAndroidBp(`java_library {....}`),
+//       android.MockFS{...}.AddToFixture(),
+//   ).RunTest(t)
+//   ... test result ...
+// }
+//
+// package cc
+// var PrepareForTestWithCC = android.GroupFixturePreparers(
+//    android.PrepareForArchMutator,
+//    android.prepareForPrebuilts,
+//    FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
+//    ...
+// )
+//
+// package apex
+//
+// var PrepareForApex = GroupFixturePreparers(
+//    ...
+// )
+//
+// Use modules and mutators from java, cc and apex. Any duplicate preparers (like
+// android.PrepareForArchMutator) will be automatically deduped.
+//
+// var prepareForApexTest = android.GroupFixturePreparers(
+//    PrepareForJava,
+//    PrepareForCC,
+//    PrepareForApex,
+// )
+//
+// // FixtureFactory instances have been deprecated, this remains for informational purposes to
+// // help explain some of the existing code but will be removed along with FixtureFactory.
+//
+// var javaFixtureFactory = android.NewFixtureFactory(
 //    PrepareForIntegrationTestWithJava,
 //    FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
 //      ctx.RegisterModuleType("test_module", testModule)
@@ -145,7 +192,7 @@
 // package cc
 // var PrepareForTestWithCC = GroupFixturePreparers(
 //    android.PrepareForArchMutator,
-//	  android.prepareForPrebuilts,
+//    android.prepareForPrebuilts,
 //    FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
 //    ...
 // )
@@ -169,52 +216,10 @@
 //
 // This is configured with a set of FixturePreparer objects that are used to
 // initialize each Fixture instance this creates.
+//
+// deprecated: Use FixturePreparer instead.
 type FixtureFactory interface {
-
-	// Creates a copy of this instance and adds some additional preparers.
-	//
-	// Before the preparers are used they are combined with the preparers provided when the factory
-	// was created, any groups of preparers are flattened, and the list is deduped so that each
-	// preparer is only used once. See the file documentation in android/fixture.go for more details.
-	Extend(preparers ...FixturePreparer) FixtureFactory
-
-	// Create a Fixture.
-	Fixture(t *testing.T, preparers ...FixturePreparer) Fixture
-
-	// ExtendWithErrorHandler creates a new FixtureFactory that will use the supplied error handler
-	// to check the errors (may be 0) reported by the test.
-	//
-	// The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any
-	// errors are reported.
-	ExtendWithErrorHandler(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
-
-	// Run the test with the supplied Android.bp file.
-	//
-	// Shorthand for RunTest(t, android.FixtureWithRootAndroidBp(bp))
-	RunTestWithBp(t *testing.T, bp string) *TestResult
-
-	// RunTestWithConfig is a temporary method added to help ease the migration of existing tests to
-	// the test fixture.
-	//
-	// In order to allow the Config object to be customized separately to the TestContext a lot of
-	// existing test code has `test...WithConfig` funcs that allow the Config object to be supplied
-	// from the test and then have the TestContext created and configured automatically. e.g.
-	// testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc.
-	//
-	// This method allows those methods to be migrated to use the test fixture pattern without
-	// requiring that every test that uses those methods be migrated at the same time. That allows
-	// those tests to benefit from correctness in the order of registration quickly.
-	//
-	// This method discards the config (along with its mock file system, product variables,
-	// environment, etc.) that may have been set up by FixturePreparers.
-	//
-	// deprecated
-	RunTestWithConfig(t *testing.T, config Config) *TestResult
+	FixturePreparer
 }
 
 // Create a new FixtureFactory that will apply the supplied preparers.
@@ -223,14 +228,17 @@
 // the package level setUp method. It has to be a pointer to the variable as the variable will not
 // have been initialized at the time the factory is created. If it is nil then a test specific
 // temporary directory will be created instead.
+//
+// deprecated: The functionality provided by FixtureFactory will be merged into FixturePreparer
 func NewFixtureFactory(buildDirSupplier *string, preparers ...FixturePreparer) FixtureFactory {
-	return &fixtureFactory{
+	f := &fixtureFactory{
 		buildDirSupplier: buildDirSupplier,
-		preparers:        dedupAndFlattenPreparers(nil, preparers),
-
-		// Set the default error handler.
-		errorHandler: FixtureExpectsNoErrors,
+		compositeFixturePreparer: compositeFixturePreparer{
+			preparers: dedupAndFlattenPreparers(nil, preparers),
+		},
 	}
+	f.initBaseFixturePreparer(f)
+	return f
 }
 
 // A set of mock files to add to the mock file system.
@@ -241,6 +249,7 @@
 // Fails if the supplied map files with the same paths are present in both of them.
 func (fs MockFS) Merge(extra map[string][]byte) {
 	for p, c := range extra {
+		validateFixtureMockFSPath(p)
 		if _, ok := fs[p]; ok {
 			panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists", p))
 		}
@@ -248,10 +257,40 @@
 	}
 }
 
+// Ensure that tests cannot add paths into the mock file system which would not be allowed in the
+// runtime, e.g. absolute paths, paths relative to the 'out/' directory.
+func validateFixtureMockFSPath(path string) {
+	// This uses validateSafePath rather than validatePath because the latter prevents adding files
+	// that include a $ but there are tests that allow files with a $ to be used, albeit only by
+	// globbing.
+	validatedPath, err := validateSafePath(path)
+	if err != nil {
+		panic(err)
+	}
+
+	// Make sure that the path is canonical.
+	if validatedPath != path {
+		panic(fmt.Errorf("path %q is not a canonical path, use %q instead", path, validatedPath))
+	}
+
+	if path == "out" || strings.HasPrefix(path, "out/") {
+		panic(fmt.Errorf("cannot add output path %q to the mock file system", path))
+	}
+}
+
 func (fs MockFS) AddToFixture() FixturePreparer {
 	return FixtureMergeMockFs(fs)
 }
 
+// FixtureCustomPreparer allows for the modification of any aspect of the fixture.
+//
+// This should only be used if one of the other more specific preparers are not suitable.
+func FixtureCustomPreparer(mutator func(fixture Fixture)) FixturePreparer {
+	return newSimpleFixturePreparer(func(f *fixture) {
+		mutator(f)
+	})
+}
+
 // Modify the config
 func FixtureModifyConfig(mutator func(config Config)) FixturePreparer {
 	return newSimpleFixturePreparer(func(f *fixture) {
@@ -281,6 +320,11 @@
 func FixtureModifyMockFS(mutator func(fs MockFS)) FixturePreparer {
 	return newSimpleFixturePreparer(func(f *fixture) {
 		mutator(f.mockFS)
+
+		// Make sure that invalid paths were not added to the mock filesystem.
+		for p, _ := range f.mockFS {
+			validateFixtureMockFSPath(p)
+		}
 	})
 }
 
@@ -298,6 +342,7 @@
 // Fail if the filesystem already contains a file with that path, use FixtureOverrideFile instead.
 func FixtureAddFile(path string, contents []byte) FixturePreparer {
 	return FixtureModifyMockFS(func(fs MockFS) {
+		validateFixtureMockFSPath(path)
 		if _, ok := fs[path]; ok {
 			panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists, use FixtureOverride*File instead", path))
 		}
@@ -378,7 +423,8 @@
 // Before preparing the fixture the list of preparers is flattened by replacing each
 // instance of GroupFixturePreparers with its contents.
 func GroupFixturePreparers(preparers ...FixturePreparer) FixturePreparer {
-	return &compositeFixturePreparer{dedupAndFlattenPreparers(nil, preparers)}
+	all := dedupAndFlattenPreparers(nil, preparers)
+	return newFixturePreparer(all)
 }
 
 // NullFixturePreparer is a preparer that does nothing.
@@ -394,20 +440,57 @@
 	}
 }
 
-type simpleFixturePreparerVisitor func(preparer *simpleFixturePreparer)
-
-// FixturePreparer is an opaque interface that can change a fixture.
+// FixturePreparer provides the ability to create, modify and then run tests within a fixture.
 type FixturePreparer interface {
-	// visit calls the supplied visitor with each *simpleFixturePreparer instances in this preparer,
-	visit(simpleFixturePreparerVisitor)
-}
+	// Return the flattened and deduped list of simpleFixturePreparer pointers.
+	list() []*simpleFixturePreparer
 
-type fixturePreparers []FixturePreparer
+	// Creates a copy of this instance and adds some additional preparers.
+	//
+	// Before the preparers are used they are combined with the preparers provided when the factory
+	// was created, any groups of preparers are flattened, and the list is deduped so that each
+	// preparer is only used once. See the file documentation in android/fixture.go for more details.
+	//
+	// deprecated: Use GroupFixturePreparers() instead.
+	Extend(preparers ...FixturePreparer) FixturePreparer
 
-func (f fixturePreparers) visit(visitor simpleFixturePreparerVisitor) {
-	for _, p := range f {
-		p.visit(visitor)
-	}
+	// Create a Fixture.
+	Fixture(t *testing.T, preparers ...FixturePreparer) Fixture
+
+	// ExtendWithErrorHandler creates a new FixturePreparer that will use the supplied error handler
+	// to check the errors (may be 0) reported by the test.
+	//
+	// The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any
+	// errors are reported.
+	ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer
+
+	// 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
+
+	// Run the test with the supplied Android.bp file.
+	//
+	// Shorthand for RunTest(t, android.FixtureWithRootAndroidBp(bp))
+	RunTestWithBp(t *testing.T, bp string) *TestResult
+
+	// RunTestWithConfig is a temporary method added to help ease the migration of existing tests to
+	// the test fixture.
+	//
+	// In order to allow the Config object to be customized separately to the TestContext a lot of
+	// existing test code has `test...WithConfig` funcs that allow the Config object to be supplied
+	// from the test and then have the TestContext created and configured automatically. e.g.
+	// testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc.
+	//
+	// This method allows those methods to be migrated to use the test fixture pattern without
+	// requiring that every test that uses those methods be migrated at the same time. That allows
+	// those tests to benefit from correctness in the order of registration quickly.
+	//
+	// This method discards the config (along with its mock file system, product variables,
+	// environment, etc.) that may have been set up by FixturePreparers.
+	//
+	// deprecated
+	RunTestWithConfig(t *testing.T, config Config) *TestResult
 }
 
 // dedupAndFlattenPreparers removes any duplicates and flattens any composite FixturePreparer
@@ -420,48 +503,73 @@
 // preparers - a list of additional unflattened, undeduped preparers that will be applied after the
 //             base preparers.
 //
-// Returns a deduped and flattened list of the preparers minus any that exist in the base preparers.
-func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers fixturePreparers) []*simpleFixturePreparer {
-	var list []*simpleFixturePreparer
+// Returns a deduped and flattened list of the preparers starting with the ones in base with any
+// additional ones from the preparers list added afterwards.
+func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers []FixturePreparer) []*simpleFixturePreparer {
+	if len(preparers) == 0 {
+		return base
+	}
+
+	list := make([]*simpleFixturePreparer, len(base))
 	visited := make(map[*simpleFixturePreparer]struct{})
 
 	// Mark the already flattened and deduped preparers, if any, as having been seen so that
-	// duplicates of these in the additional preparers will be discarded.
-	for _, s := range base {
+	// duplicates of these in the additional preparers will be discarded. Add them to the output
+	// list.
+	for i, s := range base {
 		visited[s] = struct{}{}
+		list[i] = s
 	}
 
-	preparers.visit(func(preparer *simpleFixturePreparer) {
-		if _, seen := visited[preparer]; !seen {
-			visited[preparer] = struct{}{}
-			list = append(list, preparer)
+	for _, p := range preparers {
+		for _, s := range p.list() {
+			if _, seen := visited[s]; !seen {
+				visited[s] = struct{}{}
+				list = append(list, s)
+			}
 		}
-	})
+	}
+
 	return list
 }
 
 // compositeFixturePreparer is a FixturePreparer created from a list of fixture preparers.
 type compositeFixturePreparer struct {
+	baseFixturePreparer
+	// The flattened and deduped list of simpleFixturePreparer pointers encapsulated within this
+	// composite preparer.
 	preparers []*simpleFixturePreparer
 }
 
-func (c *compositeFixturePreparer) visit(visitor simpleFixturePreparerVisitor) {
-	for _, p := range c.preparers {
-		p.visit(visitor)
+func (c *compositeFixturePreparer) list() []*simpleFixturePreparer {
+	return c.preparers
+}
+
+func newFixturePreparer(preparers []*simpleFixturePreparer) FixturePreparer {
+	if len(preparers) == 1 {
+		return preparers[0]
 	}
+	p := &compositeFixturePreparer{
+		preparers: preparers,
+	}
+	p.initBaseFixturePreparer(p)
+	return p
 }
 
 // simpleFixturePreparer is a FixturePreparer that applies a function to a fixture.
 type simpleFixturePreparer struct {
+	baseFixturePreparer
 	function func(fixture *fixture)
 }
 
-func (s *simpleFixturePreparer) visit(visitor simpleFixturePreparerVisitor) {
-	visitor(s)
+func (s *simpleFixturePreparer) list() []*simpleFixturePreparer {
+	return []*simpleFixturePreparer{s}
 }
 
 func newSimpleFixturePreparer(preparer func(fixture *fixture)) FixturePreparer {
-	return &simpleFixturePreparer{function: preparer}
+	p := &simpleFixturePreparer{function: preparer}
+	p.initBaseFixturePreparer(p)
+	return p
 }
 
 // FixtureErrorHandler determines how to respond to errors reported by the code under test.
@@ -564,6 +672,15 @@
 
 // Fixture defines the test environment.
 type Fixture interface {
+	// Config returns the fixture's configuration.
+	Config() Config
+
+	// Context returns the fixture's test context.
+	Context() *TestContext
+
+	// MockFS returns the fixture's mock filesystem.
+	MockFS() MockFS
+
 	// Run the test, checking any errors reported and returning a TestResult instance.
 	RunTest() *TestResult
 }
@@ -588,82 +705,66 @@
 	NinjaDeps []string
 }
 
-var _ FixtureFactory = (*fixtureFactory)(nil)
+func createFixture(t *testing.T, buildDir string, base []*simpleFixturePreparer, extra []FixturePreparer) Fixture {
+	all := dedupAndFlattenPreparers(base, extra)
 
-type fixtureFactory struct {
-	buildDirSupplier *string
-	preparers        []*simpleFixturePreparer
-	errorHandler     FixtureErrorHandler
-}
-
-func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixtureFactory {
-	// Create a new slice to avoid accidentally sharing the preparers slice from this factory with
-	// the extending factories.
-	var all []*simpleFixturePreparer
-	all = append(all, f.preparers...)
-	all = append(all, dedupAndFlattenPreparers(f.preparers, preparers)...)
-	// 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 {
-	var buildDir string
-	if f.buildDirSupplier == nil {
-		// Create a new temporary directory for this run. It will be automatically cleaned up when the
-		// test finishes.
-		buildDir = t.TempDir()
-	} else {
-		// Retrieve the buildDir from the supplier.
-		buildDir = *f.buildDirSupplier
-	}
 	config := TestConfig(buildDir, nil, "", nil)
 	ctx := NewTestContext(config)
 	fixture := &fixture{
-		factory:      f,
-		t:            t,
-		config:       config,
-		ctx:          ctx,
-		mockFS:       make(MockFS),
-		errorHandler: f.errorHandler,
+		preparers: all,
+		t:         t,
+		config:    config,
+		ctx:       ctx,
+		mockFS:    make(MockFS),
+		// Set the default error handler.
+		errorHandler: FixtureExpectsNoErrors,
 	}
 
-	for _, preparer := range f.preparers {
-		preparer.function(fixture)
-	}
-
-	for _, preparer := range dedupAndFlattenPreparers(f.preparers, preparers) {
+	for _, preparer := range all {
 		preparer.function(fixture)
 	}
 
 	return fixture
 }
 
-func (f *fixtureFactory) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory {
-	newFactory := &fixtureFactory{}
-	*newFactory = *f
-	newFactory.errorHandler = errorHandler
-	return newFactory
+type baseFixturePreparer struct {
+	self FixturePreparer
 }
 
-func (f *fixtureFactory) RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult {
+func (b *baseFixturePreparer) initBaseFixturePreparer(self FixturePreparer) {
+	b.self = self
+}
+
+func (b *baseFixturePreparer) Extend(preparers ...FixturePreparer) FixturePreparer {
+	all := dedupAndFlattenPreparers(b.self.list(), preparers)
+	return newFixturePreparer(all)
+}
+
+func (b *baseFixturePreparer) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
+	return createFixture(t, t.TempDir(), b.self.list(), preparers)
+}
+
+func (b *baseFixturePreparer) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer {
+	return b.self.Extend(newSimpleFixturePreparer(func(fixture *fixture) {
+		fixture.errorHandler = errorHandler
+	}))
+}
+
+func (b *baseFixturePreparer) RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult {
 	t.Helper()
-	fixture := f.Fixture(t, preparers...)
+	fixture := b.self.Fixture(t, preparers...)
 	return fixture.RunTest()
 }
 
-func (f *fixtureFactory) RunTestWithBp(t *testing.T, bp string) *TestResult {
+func (b *baseFixturePreparer) RunTestWithBp(t *testing.T, bp string) *TestResult {
 	t.Helper()
-	return f.RunTest(t, FixtureWithRootAndroidBp(bp))
+	return b.RunTest(t, FixtureWithRootAndroidBp(bp))
 }
 
-func (f *fixtureFactory) RunTestWithConfig(t *testing.T, config Config) *TestResult {
+func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *TestResult {
 	t.Helper()
 	// Create the fixture as normal.
-	fixture := f.Fixture(t).(*fixture)
+	fixture := b.self.Fixture(t).(*fixture)
 
 	// Discard the mock filesystem as otherwise that will override the one in the config.
 	fixture.mockFS = nil
@@ -682,9 +783,49 @@
 	return fixture.RunTest()
 }
 
+var _ FixtureFactory = (*fixtureFactory)(nil)
+
+type fixtureFactory struct {
+	compositeFixturePreparer
+
+	buildDirSupplier *string
+}
+
+// Override to preserve the buildDirSupplier.
+func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixturePreparer {
+	// If there is no buildDirSupplier then just use the default implementation.
+	if f.buildDirSupplier == nil {
+		return f.baseFixturePreparer.Extend(preparers...)
+	}
+
+	all := dedupAndFlattenPreparers(f.preparers, preparers)
+
+	// Create a new factory which uses the same buildDirSupplier as the previous one.
+	extendedFactory := &fixtureFactory{
+		buildDirSupplier: f.buildDirSupplier,
+		compositeFixturePreparer: compositeFixturePreparer{
+			preparers: all,
+		},
+	}
+	extendedFactory.initBaseFixturePreparer(extendedFactory)
+	return extendedFactory
+}
+
+func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
+	// If there is no buildDirSupplier then just use the default implementation.
+	if f.buildDirSupplier == nil {
+		return f.baseFixturePreparer.Fixture(t, preparers...)
+	}
+
+	// Retrieve the buildDir from the supplier.
+	buildDir := *f.buildDirSupplier
+
+	return createFixture(t, buildDir, f.preparers, preparers)
+}
+
 type fixture struct {
-	// The factory used to create this fixture.
-	factory *fixtureFactory
+	// The preparers used to create this fixture.
+	preparers []*simpleFixturePreparer
 
 	// The gotest state of the go test within which this was created.
 	t *testing.T
@@ -702,6 +843,18 @@
 	errorHandler FixtureErrorHandler
 }
 
+func (f *fixture) Config() Config {
+	return f.config
+}
+
+func (f *fixture) Context() *TestContext {
+	return f.ctx
+}
+
+func (f *fixture) MockFS() MockFS {
+	return f.mockFS
+}
+
 func (f *fixture) RunTest() *TestResult {
 	f.t.Helper()
 
@@ -780,6 +933,21 @@
 	return result
 }
 
+// Preparer will return a FixturePreparer encapsulating all the preparers used to create the fixture
+// that produced this result.
+//
+// e.g. assuming that this result was created by running:
+//     factory.Extend(preparer1, preparer2).RunTest(t, preparer3, preparer4)
+//
+// Then this method will be equivalent to running:
+//     GroupFixturePreparers(preparer1, preparer2, preparer3, preparer4)
+//
+// This is intended for use by tests whose output is Android.bp files to verify that those files
+// are valid, e.g. tests of the snapshots produced by the sdk module type.
+func (r *TestResult) Preparer() FixturePreparer {
+	return newFixturePreparer(r.fixture.preparers)
+}
+
 // Module returns the module with the specific name and of the specified variant.
 func (r *TestResult) Module(name string, variant string) Module {
 	return r.ModuleForTests(name, variant).Module()
diff --git a/android/fixture_test.go b/android/fixture_test.go
index 0042e5b..681a034 100644
--- a/android/fixture_test.go
+++ b/android/fixture_test.go
@@ -14,7 +14,9 @@
 
 package android
 
-import "testing"
+import (
+	"testing"
+)
 
 // Make sure that FixturePreparer instances are only called once per fixture and in the order in
 // which they were added.
@@ -37,13 +39,47 @@
 
 	preparer2Then1 := GroupFixturePreparers(preparer2, preparer1)
 
-	buildDir := "build"
-	factory := NewFixtureFactory(&buildDir, preparer1, preparer2, preparer1, preparer1Then2)
+	group := GroupFixturePreparers(preparer1, preparer2, preparer1, preparer1Then2)
 
-	extension := factory.Extend(preparer4, preparer2)
+	extension := group.Extend(preparer4, preparer2)
 
 	extension.Fixture(t, preparer1, preparer2, preparer2Then1, preparer3)
 
 	AssertDeepEquals(t, "preparers called in wrong order",
 		[]string{"preparer1", "preparer2", "preparer4", "preparer3"}, list)
 }
+
+func TestFixtureValidateMockFS(t *testing.T) {
+	buildDir := "<unused>"
+	factory := NewFixtureFactory(&buildDir)
+
+	t.Run("absolute path", func(t *testing.T) {
+		AssertPanicMessageContains(t, "source path validation failed", "Path is outside directory: /abs/path/Android.bp", func() {
+			factory.Fixture(t, FixtureAddFile("/abs/path/Android.bp", nil))
+		})
+	})
+	t.Run("not canonical", func(t *testing.T) {
+		AssertPanicMessageContains(t, "source path validation failed", `path "path/with/../in/it/Android.bp" is not a canonical path, use "path/in/it/Android.bp" instead`, func() {
+			factory.Fixture(t, FixtureAddFile("path/with/../in/it/Android.bp", nil))
+		})
+	})
+	t.Run("FixtureAddFile", func(t *testing.T) {
+		AssertPanicMessageContains(t, "source path validation failed", `cannot add output path "out/Android.bp" to the mock file system`, func() {
+			factory.Fixture(t, FixtureAddFile("out/Android.bp", nil))
+		})
+	})
+	t.Run("FixtureMergeMockFs", func(t *testing.T) {
+		AssertPanicMessageContains(t, "source path validation failed", `cannot add output path "out/Android.bp" to the mock file system`, func() {
+			factory.Fixture(t, FixtureMergeMockFs(MockFS{
+				"out/Android.bp": nil,
+			}))
+		})
+	})
+	t.Run("FixtureModifyMockFS", func(t *testing.T) {
+		AssertPanicMessageContains(t, "source path validation failed", `cannot add output path "out/Android.bp" to the mock file system`, func() {
+			factory.Fixture(t, FixtureModifyMockFS(func(fs MockFS) {
+				fs["out/Android.bp"] = nil
+			}))
+		})
+	})
+}
diff --git a/android/license_kind_test.go b/android/license_kind_test.go
index 83e83ce..1f09568 100644
--- a/android/license_kind_test.go
+++ b/android/license_kind_test.go
@@ -97,13 +97,14 @@
 func TestLicenseKind(t *testing.T) {
 	for _, test := range licenseKindTests {
 		t.Run(test.name, func(t *testing.T) {
-			licenseTestFixtureFactory.
-				Extend(
-					FixtureRegisterWithContext(func(ctx RegistrationContext) {
-						ctx.RegisterModuleType("mock_license", newMockLicenseModule)
-					}),
-					test.fs.AddToFixture(),
-				).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
+			GroupFixturePreparers(
+				prepareForLicenseTest,
+				FixtureRegisterWithContext(func(ctx RegistrationContext) {
+					ctx.RegisterModuleType("mock_license", newMockLicenseModule)
+				}),
+				test.fs.AddToFixture(),
+			).
+				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
 				RunTest(t)
 		})
 	}
diff --git a/android/license_test.go b/android/license_test.go
index a564827..2b09a4f 100644
--- a/android/license_test.go
+++ b/android/license_test.go
@@ -5,7 +5,7 @@
 )
 
 // Common test set up for license tests.
-var licenseTestFixtureFactory = emptyTestFixtureFactory.Extend(
+var prepareForLicenseTest = GroupFixturePreparers(
 	// General preparers in alphabetical order.
 	PrepareForTestWithDefaults,
 	prepareForTestWithLicenses,
@@ -179,7 +179,8 @@
 	for _, test := range licenseTests {
 		t.Run(test.name, func(t *testing.T) {
 			// Customize the common license text fixture factory.
-			licenseTestFixtureFactory.Extend(
+			GroupFixturePreparers(
+				prepareForLicenseTest,
 				FixtureRegisterWithContext(func(ctx RegistrationContext) {
 					ctx.RegisterModuleType("rule", newMockRuleModule)
 				}),
diff --git a/android/licenses_test.go b/android/licenses_test.go
index a581932..913dc88 100644
--- a/android/licenses_test.go
+++ b/android/licenses_test.go
@@ -470,7 +470,8 @@
 	for _, test := range licensesTests {
 		t.Run(test.name, func(t *testing.T) {
 			// Customize the common license text fixture factory.
-			result := licenseTestFixtureFactory.Extend(
+			result := GroupFixturePreparers(
+				prepareForLicenseTest,
 				FixtureRegisterWithContext(func(ctx RegistrationContext) {
 					ctx.RegisterModuleType("mock_bad_module", newMockLicensesBadModule)
 					ctx.RegisterModuleType("mock_library", newMockLicensesLibraryModule)
diff --git a/android/module_test.go b/android/module_test.go
index 99bf30a..9ac9291 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -179,11 +179,9 @@
 		}
 	`
 
-	emptyTestFixtureFactory.
+	prepareForModuleTests.
 		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": depends on disabled module "bar"`)).
-		RunTest(t,
-			prepareForModuleTests,
-			FixtureWithRootAndroidBp(bp))
+		RunTestWithBp(t, bp)
 }
 
 func TestValidateCorrectBuildParams(t *testing.T) {
@@ -268,9 +266,7 @@
 		"\\QAndroid.bp:18:17: module \"foo\": dists[1].suffix: Suffix may not contain a '/' character.\\E",
 	}
 
-	emptyTestFixtureFactory.
+	prepareForModuleTests.
 		ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
-		RunTest(t,
-			prepareForModuleTests,
-			FixtureWithRootAndroidBp(bp))
+		RunTestWithBp(t, bp)
 }
diff --git a/android/mutator_test.go b/android/mutator_test.go
index 46d26d1..21eebd2 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -65,7 +65,7 @@
 		}
 	`
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		PrepareForTestWithAllowMissingDependencies,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("test", mutatorTestModuleFactory)
@@ -74,7 +74,7 @@
 			})
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	foo := result.ModuleForTests("foo", "").Module().(*mutatorTestModule)
 
@@ -90,7 +90,7 @@
 
 	var moduleStrings []string
 
-	emptyTestFixtureFactory.RunTest(t,
+	GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 
 			ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
@@ -128,7 +128,7 @@
 			ctx.RegisterModuleType("test", mutatorTestModuleFactory)
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	want := []string{
 		// Initial name.
@@ -187,7 +187,7 @@
 
 	finalGot := map[string]int{}
 
-	emptyTestFixtureFactory.RunTest(t,
+	GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			dep1Tag := struct {
 				blueprint.BaseDependencyTag
@@ -224,7 +224,7 @@
 			ctx.RegisterModuleType("test", mutatorTestModuleFactory)
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	finalWant := map[string]int{
 		"common_dep_1{variant:a}":                   1,
@@ -249,7 +249,7 @@
 		}
 	}
 
-	emptyTestFixtureFactory.RunTest(t,
+	GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
 				ctx.BottomUp("vars", func(ctx BottomUpMutatorContext) {
@@ -265,5 +265,5 @@
 			ctx.RegisterModuleType("test", mutatorTestModuleFactory)
 		}),
 		FixtureWithRootAndroidBp(`test {name: "foo"}`),
-	)
+	).RunTest(t)
 }
diff --git a/android/namespace_test.go b/android/namespace_test.go
index 1caf5a8..08e221a 100644
--- a/android/namespace_test.go
+++ b/android/namespace_test.go
@@ -633,21 +633,21 @@
 }
 
 func setupTestFromFiles(t *testing.T, bps MockFS) (ctx *TestContext, errs []error) {
-	result := emptyTestFixtureFactory.
+	result := GroupFixturePreparers(
+		FixtureModifyContext(func(ctx *TestContext) {
+			ctx.RegisterModuleType("test_module", newTestModule)
+			ctx.RegisterModuleType("soong_namespace", NamespaceFactory)
+			ctx.Context.RegisterModuleType("blueprint_test_module", newBlueprintTestModule)
+			ctx.PreArchMutators(RegisterNamespaceMutator)
+			ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+				ctx.BottomUp("rename", renameMutator)
+			})
+		}),
+		bps.AddToFixture(),
+	).
 		// Ignore errors for now so tests can check them later.
 		ExtendWithErrorHandler(FixtureIgnoreErrors).
-		RunTest(t,
-			FixtureModifyContext(func(ctx *TestContext) {
-				ctx.RegisterModuleType("test_module", newTestModule)
-				ctx.RegisterModuleType("soong_namespace", NamespaceFactory)
-				ctx.Context.RegisterModuleType("blueprint_test_module", newBlueprintTestModule)
-				ctx.PreArchMutators(RegisterNamespaceMutator)
-				ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-					ctx.BottomUp("rename", renameMutator)
-				})
-			}),
-			bps.AddToFixture(),
-		)
+		RunTest(t)
 
 	return result.TestContext, result.Errs
 }
@@ -697,7 +697,7 @@
 		testModule, ok := candidate.(*testModule)
 		if ok {
 			if testModule.properties.Id == id {
-				module = TestingModule{testModule}
+				module = newTestingModule(ctx.config, testModule)
 			}
 		}
 	}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 5ac97e7..b8ef0f5 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -299,18 +299,17 @@
 func TestNeverallow(t *testing.T) {
 	for _, test := range neverallowTests {
 		t.Run(test.name, func(t *testing.T) {
-			emptyTestFixtureFactory.
-				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
-				RunTest(t,
-					prepareForNeverAllowTest,
-					FixtureModifyConfig(func(config Config) {
-						// If the test has its own rules then use them instead of the default ones.
-						if test.rules != nil {
-							SetTestNeverallowRules(config, test.rules)
-						}
-					}),
-					test.fs.AddToFixture(),
-				)
+			GroupFixturePreparers(
+				prepareForNeverAllowTest,
+				FixtureModifyConfig(func(config Config) {
+					// If the test has its own rules then use them instead of the default ones.
+					if test.rules != nil {
+						SetTestNeverallowRules(config, test.rules)
+					}
+				}),
+				test.fs.AddToFixture(),
+			).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
+				RunTest(t)
 		})
 	}
 }
diff --git a/android/ninja_deps_test.go b/android/ninja_deps_test.go
index 7e5864d..947c257 100644
--- a/android/ninja_deps_test.go
+++ b/android/ninja_deps_test.go
@@ -57,13 +57,13 @@
 		"test_ninja_deps/exists": nil,
 	}
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterSingletonType("test_ninja_deps_singleton", testNinjaDepsSingletonFactory)
 			ctx.RegisterSingletonType("ninja_deps_singleton", ninjaDepsSingletonFactory)
 		}),
 		fs.AddToFixture(),
-	)
+	).RunTest(t)
 
 	// Verify that the ninja file has a dependency on the test_ninja_deps directory.
 	if g, w := result.NinjaDeps, "test_ninja_deps"; !InList(w, g) {
diff --git a/android/package_test.go b/android/package_test.go
index d5b4db4..3bd30cc 100644
--- a/android/package_test.go
+++ b/android/package_test.go
@@ -61,13 +61,13 @@
 func TestPackage(t *testing.T) {
 	for _, test := range packageTests {
 		t.Run(test.name, func(t *testing.T) {
-			emptyTestFixtureFactory.
+			GroupFixturePreparers(
+				PrepareForTestWithArchMutator,
+				PrepareForTestWithPackageModule,
+				test.fs.AddToFixture(),
+			).
 				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
-				RunTest(t,
-					PrepareForTestWithArchMutator,
-					PrepareForTestWithPackageModule,
-					test.fs.AddToFixture(),
-				)
+				RunTest(t)
 		})
 	}
 }
diff --git a/android/packaging.go b/android/packaging.go
index 9b901ce..72c0c17 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -59,7 +59,8 @@
 	packagingBase() *PackagingBase
 
 	// AddDeps adds dependencies to the `deps` modules. This should be called in DepsMutator.
-	// When adding the dependencies, depTag is used as the tag.
+	// When adding the dependencies, depTag is used as the tag. If `deps` modules are meant to
+	// be copied to a zip in CopyDepsToZip, `depTag` should implement PackagingItem marker interface.
 	AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag)
 
 	// CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and
@@ -167,6 +168,24 @@
 	return ret
 }
 
+// PackagingItem is a marker interface for dependency tags.
+// Direct dependencies with a tag implementing PackagingItem are packaged in CopyDepsToZip().
+type PackagingItem interface {
+	// IsPackagingItem returns true if the dep is to be packaged
+	IsPackagingItem() bool
+}
+
+// DepTag provides default implementation of PackagingItem interface.
+// PackagingBase-derived modules can define their own dependency tag by embedding this, which
+// can be passed to AddDeps() or AddDependencies().
+type PackagingItemAlwaysDepTag struct {
+}
+
+// IsPackagingItem returns true if the dep is to be packaged
+func (PackagingItemAlwaysDepTag) IsPackagingItem() bool {
+	return true
+}
+
 // See PackageModule.AddDeps
 func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) {
 	for _, t := range p.getSupportedTargets(ctx) {
@@ -182,16 +201,15 @@
 // See PackageModule.CopyDepsToZip
 func (p *PackagingBase) CopyDepsToZip(ctx ModuleContext, zipOut WritablePath) (entries []string) {
 	m := make(map[string]PackagingSpec)
-	ctx.WalkDeps(func(child Module, parent Module) bool {
-		if !IsInstallDepNeeded(ctx.OtherModuleDependencyTag(child)) {
-			return false
+	ctx.VisitDirectDeps(func(child Module) {
+		if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
+			return
 		}
-		for _, ps := range child.PackagingSpecs() {
+		for _, ps := range child.TransitivePackagingSpecs() {
 			if _, ok := m[ps.relPathInPackage]; !ok {
 				m[ps.relPathInPackage] = ps
 			}
 		}
-		return true
 	})
 
 	builder := NewRuleBuilder(pctx, ctx)
diff --git a/android/packaging_test.go b/android/packaging_test.go
index eb7f26f..f91dc5d 100644
--- a/android/packaging_test.go
+++ b/android/packaging_test.go
@@ -56,7 +56,9 @@
 type packageTestModule struct {
 	ModuleBase
 	PackagingBase
-
+	properties struct {
+		Install_deps []string `android:`
+	}
 	entries []string
 }
 
@@ -64,6 +66,7 @@
 	module := &packageTestModule{}
 	InitPackageModule(module)
 	InitAndroidMultiTargetsArchModule(module, DeviceSupported, MultilibCommon)
+	module.AddProperties(&module.properties)
 	return module
 }
 
@@ -71,11 +74,18 @@
 	module := &packageTestModule{}
 	InitPackageModule(module)
 	InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
+	module.AddProperties(&module.properties)
 	return module
 }
 
+type packagingDepTag struct {
+	blueprint.BaseDependencyTag
+	PackagingItemAlwaysDepTag
+}
+
 func (m *packageTestModule) DepsMutator(ctx BottomUpMutatorContext) {
-	m.AddDeps(ctx, installDepTag{})
+	m.AddDeps(ctx, packagingDepTag{})
+	ctx.AddDependency(ctx.Module(), installDepTag{}, m.properties.Install_deps...)
 }
 
 func (m *packageTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -96,14 +106,14 @@
 		moduleFactory = packageTestModuleFactory
 	}
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		PrepareForTestWithArchMutator,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("component", componentTestModuleFactory)
 			ctx.RegisterModuleType("package_module", moduleFactory)
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	p := result.Module("package", archVariant).(*packageTestModule)
 	actual := p.entries
@@ -337,4 +347,21 @@
 			},
 		}
 		`, []string{"lib64/foo", "lib64/bar"})
+
+	runPackagingTest(t, multiTarget,
+		`
+		component {
+			name: "foo",
+		}
+
+		component {
+			name: "bar",
+		}
+
+		package_module {
+			name: "package",
+			deps: ["foo"],
+			install_deps: ["bar"],
+		}
+		`, []string{"lib64/foo"})
 }
diff --git a/android/path_properties_test.go b/android/path_properties_test.go
index 8726ea7..568f868 100644
--- a/android/path_properties_test.go
+++ b/android/path_properties_test.go
@@ -157,14 +157,14 @@
 				}
 			`
 
-			result := emptyTestFixtureFactory.RunTest(t,
+			result := GroupFixturePreparers(
 				PrepareForTestWithArchMutator,
 				PrepareForTestWithFilegroup,
 				FixtureRegisterWithContext(func(ctx RegistrationContext) {
 					ctx.RegisterModuleType("test", pathDepsMutatorTestModuleFactory)
 				}),
 				FixtureWithRootAndroidBp(bp),
-			)
+			).RunTest(t)
 
 			m := result.Module("foo", "android_arm64_armv8-a").(*pathDepsMutatorTestModule)
 
diff --git a/android/paths_test.go b/android/paths_test.go
index c5fc10e..465ea3b 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -1005,14 +1005,14 @@
 				"foo/src_special/$": nil,
 			}
 
-			result := emptyTestFixtureFactory.RunTest(t,
+			result := GroupFixturePreparers(
 				FixtureRegisterWithContext(func(ctx RegistrationContext) {
 					ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory)
 					ctx.RegisterModuleType("output_file_provider", pathForModuleSrcOutputFileProviderModuleFactory)
 					ctx.RegisterModuleType("filegroup", FileGroupFactory)
 				}),
 				mockFS.AddToFixture(),
-			)
+			).RunTest(t)
 
 			m := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
 
@@ -1203,13 +1203,13 @@
 		}
 	`
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		PrepareForTestWithAllowMissingDependencies,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory)
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	foo := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
 
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 32af5df..ced37fe 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -284,7 +284,7 @@
 				t.Errorf("windows is assumed to be disabled by default")
 			}
 
-			result := emptyTestFixtureFactory.Extend(
+			result := GroupFixturePreparers(
 				PrepareForTestWithArchMutator,
 				PrepareForTestWithPrebuilts,
 				PrepareForTestWithOverrides,
diff --git a/android/register.go b/android/register.go
index c9e66e9..900edfa 100644
--- a/android/register.go
+++ b/android/register.go
@@ -263,8 +263,9 @@
 //   ctx := android.NewTestContext(config)
 //   RegisterBuildComponents(ctx)
 var InitRegistrationContext RegistrationContext = &initRegistrationContext{
-	moduleTypes:    make(map[string]ModuleFactory),
-	singletonTypes: make(map[string]SingletonFactory),
+	moduleTypes:       make(map[string]ModuleFactory),
+	singletonTypes:    make(map[string]SingletonFactory),
+	preSingletonTypes: make(map[string]SingletonFactory),
 }
 
 // Make sure the TestContext implements RegistrationContext.
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 3415aed..9cd60a2 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -542,11 +542,11 @@
 		}
 	`
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		prepareForRuleBuilderTest,
 		FixtureWithRootAndroidBp(bp),
 		fs.AddToFixture(),
-	)
+	).RunTest(t)
 
 	check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraImplicits, extraCmdDeps []string) {
 		t.Helper()
@@ -562,46 +562,44 @@
 		AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat)
 
 		wantImplicits := append([]string{"bar"}, extraImplicits...)
-		AssertArrayString(t, "Implicits", wantImplicits, params.Implicits.Strings())
+		AssertPathsRelativeToTopEquals(t, "Implicits", wantImplicits, params.Implicits)
 
-		AssertStringEquals(t, "Output", wantOutput, params.Output.String())
+		AssertPathRelativeToTopEquals(t, "Output", wantOutput, params.Output)
 
 		if len(params.ImplicitOutputs) != 0 {
 			t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings())
 		}
 
-		AssertStringEquals(t, "Depfile", wantDepfile, params.Depfile.String())
+		AssertPathRelativeToTopEquals(t, "Depfile", wantDepfile, params.Depfile)
 
 		if params.Deps != blueprint.DepsGCC {
 			t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
 		}
 	}
 
-	buildDir := result.Config.BuildDir()
-
 	t.Run("module", func(t *testing.T) {
-		outFile := filepath.Join(buildDir, ".intermediates", "foo", "gen", "foo")
-		check(t, result.ModuleForTests("foo", "").Rule("rule"),
+		outFile := "out/soong/.intermediates/foo/gen/foo"
+		check(t, result.ModuleForTests("foo", "").Rule("rule").RelativeToTop(),
 			"cp bar "+outFile,
 			outFile, outFile+".d", true, nil, nil)
 	})
 	t.Run("sbox", func(t *testing.T) {
-		outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox")
+		outDir := "out/soong/.intermediates/foo_sbox"
 		outFile := filepath.Join(outDir, "gen/foo_sbox")
 		depFile := filepath.Join(outDir, "gen/foo_sbox.d")
 		manifest := filepath.Join(outDir, "sbox.textproto")
-		sbox := filepath.Join(buildDir, "host", result.Config.PrebuiltOS(), "bin/sbox")
-		sandboxPath := shared.TempDirForOutDir(buildDir)
+		sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
+		sandboxPath := shared.TempDirForOutDir("out/soong")
 
 		cmd := `rm -rf ` + outDir + `/gen && ` +
 			sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest
 
-		check(t, result.ModuleForTests("foo_sbox", "").Output("gen/foo_sbox"),
+		check(t, result.ModuleForTests("foo_sbox", "").Output("gen/foo_sbox").RelativeToTop(),
 			cmd, outFile, depFile, false, []string{manifest}, []string{sbox})
 	})
 	t.Run("singleton", func(t *testing.T) {
-		outFile := filepath.Join(buildDir, "singleton/gen/baz")
-		check(t, result.SingletonForTests("rule_builder_test").Rule("rule"),
+		outFile := filepath.Join("out/soong/singleton/gen/baz")
+		check(t, result.SingletonForTests("rule_builder_test").Rule("rule").RelativeToTop(),
 			"cp bar "+outFile, outFile, outFile+".d", true, nil, nil)
 	})
 }
@@ -651,10 +649,10 @@
 		},
 	}
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		prepareForRuleBuilderTest,
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	for _, test := range testcases {
 		t.Run(test.name, func(t *testing.T) {
diff --git a/android/singleton_module_test.go b/android/singleton_module_test.go
index 41dd4bb..eb5554c 100644
--- a/android/singleton_module_test.go
+++ b/android/singleton_module_test.go
@@ -56,11 +56,10 @@
 			name: "test_singleton_module",
 		}
 	`
-	result := emptyTestFixtureFactory.
-		RunTest(t,
-			prepareForSingletonModuleTest,
-			FixtureWithRootAndroidBp(bp),
-		)
+	result := GroupFixturePreparers(
+		prepareForSingletonModuleTest,
+		FixtureWithRootAndroidBp(bp),
+	).RunTest(t)
 
 	ops := result.ModuleForTests("test_singleton_module", "").Module().(*testSingletonModule).ops
 	wantOps := []string{"GenerateAndroidBuildActions", "GenerateSingletonBuildActions", "MakeVars"}
@@ -78,19 +77,16 @@
 		}
 	`
 
-	emptyTestFixtureFactory.
+	prepareForSingletonModuleTest.
 		ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
 			`\QDuplicate SingletonModule "test_singleton_module", previously used in\E`,
-		})).RunTest(t,
-		prepareForSingletonModuleTest,
-		FixtureWithRootAndroidBp(bp),
-	)
+		})).RunTestWithBp(t, bp)
 }
 
 func TestUnusedSingletonModule(t *testing.T) {
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		prepareForSingletonModuleTest,
-	)
+	).RunTest(t)
 
 	singleton := result.SingletonForTests("test_singleton_module").Singleton()
 	sm := singleton.(*singletonModuleSingletonAdaptor).sm
@@ -113,17 +109,16 @@
 		}
 	`
 
-	emptyTestFixtureFactory.
+	GroupFixturePreparers(
+		prepareForSingletonModuleTest,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+				ctx.BottomUp("test_singleton_module_mutator", testVariantSingletonModuleMutator)
+			})
+		}),
+	).
 		ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
 			`\QGenerateAndroidBuildActions already called for variant\E`,
 		})).
-		RunTest(t,
-			prepareForSingletonModuleTest,
-			FixtureRegisterWithContext(func(ctx RegistrationContext) {
-				ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-					ctx.BottomUp("test_singleton_module_mutator", testVariantSingletonModuleMutator)
-				})
-			}),
-			FixtureWithRootAndroidBp(bp),
-		)
+		RunTestWithBp(t, bp)
 }
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index a72b160..8f252d9 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -278,7 +278,7 @@
 
 		for _, tc := range testCases {
 			t.Run(tc.name, func(t *testing.T) {
-				result := emptyTestFixtureFactory.RunTest(t,
+				result := GroupFixturePreparers(
 					tc.preparer,
 					PrepareForTestWithDefaults,
 					FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -291,7 +291,7 @@
 					}),
 					fs.AddToFixture(),
 					FixtureWithRootAndroidBp(bp),
-				)
+				).RunTest(t)
 
 				foo := result.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
 				AssertDeepEquals(t, "foo cflags", tc.fooExpectedFlags, foo.props.Cflags)
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 4b5e934..bfb88ab 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"fmt"
 	"reflect"
 	"strings"
 	"testing"
@@ -162,19 +163,24 @@
 	}
 }
 
-// AssertPanic checks that the supplied function panics as expected.
-func AssertPanic(t *testing.T, message string, funcThatShouldPanic func()) {
+// AssertPanicMessageContains checks that the supplied function panics as expected and the message
+// obtained by formatting the recovered value as a string contains the expected contents.
+func AssertPanicMessageContains(t *testing.T, message, expectedMessageContents string, funcThatShouldPanic func()) {
 	t.Helper()
 	panicked := false
+	var recovered interface{}
 	func() {
 		defer func() {
-			if x := recover(); x != nil {
+			if recovered = recover(); recovered != nil {
 				panicked = true
 			}
 		}()
 		funcThatShouldPanic()
 	}()
 	if !panicked {
-		t.Error(message)
+		t.Errorf("%s: did not panic", message)
 	}
+
+	panicMessage := fmt.Sprintf("%s", recovered)
+	AssertStringDoesContain(t, fmt.Sprintf("%s: panic message", message), panicMessage, expectedMessageContents)
 }
diff --git a/android/testing.go b/android/testing.go
index af360fa..f17de31 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -479,7 +479,7 @@
 		}
 	}
 
-	return TestingModule{module}
+	return newTestingModule(ctx.config, module)
 }
 
 func (ctx *TestContext) ModuleVariantsForTests(name string) []string {
@@ -499,8 +499,8 @@
 		n := ctx.SingletonName(s)
 		if n == name {
 			return TestingSingleton{
-				singleton: s.(*singletonAdaptor).Singleton,
-				provider:  s.(testBuildProvider),
+				baseTestingComponent: newBaseTestingComponent(ctx.config, s.(testBuildProvider)),
+				singleton:            s.(*singletonAdaptor).Singleton,
 			}
 		}
 		allSingletonNames = append(allSingletonNames, n)
@@ -522,62 +522,170 @@
 type TestingBuildParams struct {
 	BuildParams
 	RuleParams blueprint.RuleParams
+
+	config Config
 }
 
-func newTestingBuildParams(provider testBuildProvider, bparams BuildParams) TestingBuildParams {
+// RelativeToTop creates a new instance of this which has had any usages of the current test's
+// temporary and test specific build directory replaced with a path relative to the notional top.
+//
+// The parts of this structure which are changed are:
+// * BuildParams
+//   * Args
+//   * Path instances are intentionally not modified, use AssertPathRelativeToTopEquals or
+//     AssertPathsRelativeToTopEquals instead which do something similar.
+//
+// * RuleParams
+//   * Command
+//   * Depfile
+//   * Rspfile
+//   * RspfileContent
+//   * SymlinkOutputs
+//   * CommandDeps
+//   * CommandOrderOnly
+//
+// See PathRelativeToTop for more details.
+func (p TestingBuildParams) RelativeToTop() TestingBuildParams {
+	// If this is not a valid params then just return it back. That will make it easy to use with the
+	// Maybe...() methods.
+	if p.Rule == nil {
+		return p
+	}
+	if p.config.config == nil {
+		panic("cannot call RelativeToTop() on a TestingBuildParams previously returned by RelativeToTop()")
+	}
+	// Take a copy of the build params and replace any args that contains test specific temporary
+	// paths with paths relative to the top.
+	bparams := p.BuildParams
+	bparams.Args = normalizeStringMapRelativeToTop(p.config, bparams.Args)
+
+	// Ditto for any fields in the RuleParams.
+	rparams := p.RuleParams
+	rparams.Command = normalizeStringRelativeToTop(p.config, rparams.Command)
+	rparams.Depfile = normalizeStringRelativeToTop(p.config, rparams.Depfile)
+	rparams.Rspfile = normalizeStringRelativeToTop(p.config, rparams.Rspfile)
+	rparams.RspfileContent = normalizeStringRelativeToTop(p.config, rparams.RspfileContent)
+	rparams.SymlinkOutputs = normalizeStringArrayRelativeToTop(p.config, rparams.SymlinkOutputs)
+	rparams.CommandDeps = normalizeStringArrayRelativeToTop(p.config, rparams.CommandDeps)
+	rparams.CommandOrderOnly = normalizeStringArrayRelativeToTop(p.config, rparams.CommandOrderOnly)
+
 	return TestingBuildParams{
 		BuildParams: bparams,
-		RuleParams:  provider.RuleParamsForTests()[bparams.Rule],
+		RuleParams:  rparams,
 	}
 }
 
-func maybeBuildParamsFromRule(provider testBuildProvider, rule string) (TestingBuildParams, []string) {
+// baseTestingComponent provides functionality common to both TestingModule and TestingSingleton.
+type baseTestingComponent struct {
+	config   Config
+	provider testBuildProvider
+}
+
+func newBaseTestingComponent(config Config, provider testBuildProvider) baseTestingComponent {
+	return baseTestingComponent{config, provider}
+}
+
+// A function that will normalize a string containing paths, e.g. ninja command, by replacing
+// any references to the test specific temporary build directory that changes with each run to a
+// fixed path relative to a notional top directory.
+//
+// This is similar to StringPathRelativeToTop except that assumes the string is a single path
+// containing at most one instance of the temporary build directory at the start of the path while
+// this assumes that there can be any number at any position.
+func normalizeStringRelativeToTop(config Config, s string) string {
+	// The buildDir usually looks something like: /tmp/testFoo2345/001
+	//
+	// Replace any usage of the buildDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with
+	// "out/soong".
+	outSoongDir := filepath.Clean(config.buildDir)
+	re := regexp.MustCompile(`\Q` + outSoongDir + `\E\b`)
+	s = re.ReplaceAllString(s, "out/soong")
+
+	// Replace any usage of the buildDir/.. with out, e.g. replace "/tmp/testFoo2345" with
+	// "out". This must come after the previous replacement otherwise this would replace
+	// "/tmp/testFoo2345/001" with "out/001" instead of "out/soong".
+	outDir := filepath.Dir(outSoongDir)
+	re = regexp.MustCompile(`\Q` + outDir + `\E\b`)
+	s = re.ReplaceAllString(s, "out")
+
+	return s
+}
+
+// normalizeStringArrayRelativeToTop creates a new slice constructed by applying
+// normalizeStringRelativeToTop to each item in the slice.
+func normalizeStringArrayRelativeToTop(config Config, slice []string) []string {
+	newSlice := make([]string, len(slice))
+	for i, s := range slice {
+		newSlice[i] = normalizeStringRelativeToTop(config, s)
+	}
+	return newSlice
+}
+
+// normalizeStringMapRelativeToTop creates a new map constructed by applying
+// normalizeStringRelativeToTop to each value in the map.
+func normalizeStringMapRelativeToTop(config Config, m map[string]string) map[string]string {
+	newMap := map[string]string{}
+	for k, v := range m {
+		newMap[k] = normalizeStringRelativeToTop(config, v)
+	}
+	return newMap
+}
+
+func (b baseTestingComponent) newTestingBuildParams(bparams BuildParams) TestingBuildParams {
+	return TestingBuildParams{
+		config:      b.config,
+		BuildParams: bparams,
+		RuleParams:  b.provider.RuleParamsForTests()[bparams.Rule],
+	}
+}
+
+func (b baseTestingComponent) maybeBuildParamsFromRule(rule string) (TestingBuildParams, []string) {
 	var searchedRules []string
-	for _, p := range provider.BuildParamsForTests() {
+	for _, p := range b.provider.BuildParamsForTests() {
 		searchedRules = append(searchedRules, p.Rule.String())
 		if strings.Contains(p.Rule.String(), rule) {
-			return newTestingBuildParams(provider, p), searchedRules
+			return b.newTestingBuildParams(p), searchedRules
 		}
 	}
 	return TestingBuildParams{}, searchedRules
 }
 
-func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
-	p, searchRules := maybeBuildParamsFromRule(provider, rule)
+func (b baseTestingComponent) buildParamsFromRule(rule string) TestingBuildParams {
+	p, searchRules := b.maybeBuildParamsFromRule(rule)
 	if p.Rule == nil {
 		panic(fmt.Errorf("couldn't find rule %q.\nall rules: %v", rule, searchRules))
 	}
 	return p
 }
 
-func maybeBuildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams {
-	for _, p := range provider.BuildParamsForTests() {
+func (b baseTestingComponent) maybeBuildParamsFromDescription(desc string) TestingBuildParams {
+	for _, p := range b.provider.BuildParamsForTests() {
 		if strings.Contains(p.Description, desc) {
-			return newTestingBuildParams(provider, p)
+			return b.newTestingBuildParams(p)
 		}
 	}
 	return TestingBuildParams{}
 }
 
-func buildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams {
-	p := maybeBuildParamsFromDescription(provider, desc)
+func (b baseTestingComponent) buildParamsFromDescription(desc string) TestingBuildParams {
+	p := b.maybeBuildParamsFromDescription(desc)
 	if p.Rule == nil {
 		panic(fmt.Errorf("couldn't find description %q", desc))
 	}
 	return p
 }
 
-func maybeBuildParamsFromOutput(provider testBuildProvider, file string) (TestingBuildParams, []string) {
+func (b baseTestingComponent) maybeBuildParamsFromOutput(file string) (TestingBuildParams, []string) {
 	var searchedOutputs []string
-	for _, p := range provider.BuildParamsForTests() {
+	for _, p := range b.provider.BuildParamsForTests() {
 		outputs := append(WritablePaths(nil), p.Outputs...)
 		outputs = append(outputs, p.ImplicitOutputs...)
 		if p.Output != nil {
 			outputs = append(outputs, p.Output)
 		}
 		for _, f := range outputs {
-			if f.String() == file || f.Rel() == file {
-				return newTestingBuildParams(provider, p), nil
+			if f.String() == file || f.Rel() == file || PathRelativeToTop(f) == file {
+				return b.newTestingBuildParams(p), nil
 			}
 			searchedOutputs = append(searchedOutputs, f.Rel())
 		}
@@ -585,18 +693,18 @@
 	return TestingBuildParams{}, searchedOutputs
 }
 
-func buildParamsFromOutput(provider testBuildProvider, file string) TestingBuildParams {
-	p, searchedOutputs := maybeBuildParamsFromOutput(provider, file)
+func (b baseTestingComponent) buildParamsFromOutput(file string) TestingBuildParams {
+	p, searchedOutputs := b.maybeBuildParamsFromOutput(file)
 	if p.Rule == nil {
-		panic(fmt.Errorf("couldn't find output %q.\nall outputs: %v",
-			file, searchedOutputs))
+		panic(fmt.Errorf("couldn't find output %q.\nall outputs:\n    %s\n",
+			file, strings.Join(searchedOutputs, "\n    ")))
 	}
 	return p
 }
 
-func allOutputs(provider testBuildProvider) []string {
+func (b baseTestingComponent) allOutputs() []string {
 	var outputFullPaths []string
-	for _, p := range provider.BuildParamsForTests() {
+	for _, p := range b.provider.BuildParamsForTests() {
 		outputs := append(WritablePaths(nil), p.Outputs...)
 		outputs = append(outputs, p.ImplicitOutputs...)
 		if p.Output != nil {
@@ -607,64 +715,78 @@
 	return outputFullPaths
 }
 
+// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Returns an empty
+// BuildParams if no rule is found.
+func (b baseTestingComponent) MaybeRule(rule string) TestingBuildParams {
+	r, _ := b.maybeBuildParamsFromRule(rule)
+	return r
+}
+
+// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Panics if no rule is found.
+func (b baseTestingComponent) Rule(rule string) TestingBuildParams {
+	return b.buildParamsFromRule(rule)
+}
+
+// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string.  Returns an empty
+// BuildParams if no rule is found.
+func (b baseTestingComponent) MaybeDescription(desc string) TestingBuildParams {
+	return b.maybeBuildParamsFromDescription(desc)
+}
+
+// Description finds a call to ctx.Build with BuildParams.Description set to a the given string.  Panics if no rule is
+// found.
+func (b baseTestingComponent) Description(desc string) TestingBuildParams {
+	return b.buildParamsFromDescription(desc)
+}
+
+// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
+// value matches the provided string.  Returns an empty BuildParams if no rule is found.
+func (b baseTestingComponent) MaybeOutput(file string) TestingBuildParams {
+	p, _ := b.maybeBuildParamsFromOutput(file)
+	return p
+}
+
+// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
+// value matches the provided string.  Panics if no rule is found.
+func (b baseTestingComponent) Output(file string) TestingBuildParams {
+	return b.buildParamsFromOutput(file)
+}
+
+// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms.
+func (b baseTestingComponent) AllOutputs() []string {
+	return b.allOutputs()
+}
+
 // TestingModule is wrapper around an android.Module that provides methods to find information about individual
 // ctx.Build parameters for verification in tests.
 type TestingModule struct {
+	baseTestingComponent
 	module Module
 }
 
+func newTestingModule(config Config, module Module) TestingModule {
+	return TestingModule{
+		newBaseTestingComponent(config, module),
+		module,
+	}
+}
+
 // Module returns the Module wrapped by the TestingModule.
 func (m TestingModule) Module() Module {
 	return m.module
 }
 
-// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Returns an empty
-// BuildParams if no rule is found.
-func (m TestingModule) MaybeRule(rule string) TestingBuildParams {
-	r, _ := maybeBuildParamsFromRule(m.module, rule)
-	return r
-}
-
-// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Panics if no rule is found.
-func (m TestingModule) Rule(rule string) TestingBuildParams {
-	return buildParamsFromRule(m.module, rule)
-}
-
-// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string.  Returns an empty
-// BuildParams if no rule is found.
-func (m TestingModule) MaybeDescription(desc string) TestingBuildParams {
-	return maybeBuildParamsFromDescription(m.module, desc)
-}
-
-// Description finds a call to ctx.Build with BuildParams.Description set to a the given string.  Panics if no rule is
-// found.
-func (m TestingModule) Description(desc string) TestingBuildParams {
-	return buildParamsFromDescription(m.module, desc)
-}
-
-// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
-// value matches the provided string.  Returns an empty BuildParams if no rule is found.
-func (m TestingModule) MaybeOutput(file string) TestingBuildParams {
-	p, _ := maybeBuildParamsFromOutput(m.module, file)
-	return p
-}
-
-// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
-// value matches the provided string.  Panics if no rule is found.
-func (m TestingModule) Output(file string) TestingBuildParams {
-	return buildParamsFromOutput(m.module, file)
-}
-
-// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms.
-func (m TestingModule) AllOutputs() []string {
-	return allOutputs(m.module)
+// VariablesForTestsRelativeToTop returns a copy of the Module.VariablesForTests() with every value
+// having any temporary build dir usages replaced with paths relative to a notional top.
+func (m TestingModule) VariablesForTestsRelativeToTop() map[string]string {
+	return normalizeStringMapRelativeToTop(m.config, m.module.VariablesForTests())
 }
 
 // TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual
 // ctx.Build parameters for verification in tests.
 type TestingSingleton struct {
+	baseTestingComponent
 	singleton Singleton
-	provider  testBuildProvider
 }
 
 // Singleton returns the Singleton wrapped by the TestingSingleton.
@@ -672,48 +794,6 @@
 	return s.singleton
 }
 
-// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Returns an empty
-// BuildParams if no rule is found.
-func (s TestingSingleton) MaybeRule(rule string) TestingBuildParams {
-	r, _ := maybeBuildParamsFromRule(s.provider, rule)
-	return r
-}
-
-// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Panics if no rule is found.
-func (s TestingSingleton) Rule(rule string) TestingBuildParams {
-	return buildParamsFromRule(s.provider, rule)
-}
-
-// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string.  Returns an empty
-// BuildParams if no rule is found.
-func (s TestingSingleton) MaybeDescription(desc string) TestingBuildParams {
-	return maybeBuildParamsFromDescription(s.provider, desc)
-}
-
-// Description finds a call to ctx.Build with BuildParams.Description set to a the given string.  Panics if no rule is
-// found.
-func (s TestingSingleton) Description(desc string) TestingBuildParams {
-	return buildParamsFromDescription(s.provider, desc)
-}
-
-// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
-// value matches the provided string.  Returns an empty BuildParams if no rule is found.
-func (s TestingSingleton) MaybeOutput(file string) TestingBuildParams {
-	p, _ := maybeBuildParamsFromOutput(s.provider, file)
-	return p
-}
-
-// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
-// value matches the provided string.  Panics if no rule is found.
-func (s TestingSingleton) Output(file string) TestingBuildParams {
-	return buildParamsFromOutput(s.provider, file)
-}
-
-// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms.
-func (s TestingSingleton) AllOutputs() []string {
-	return allOutputs(s.provider)
-}
-
 func FailIfErrored(t *testing.T, errs []error) {
 	t.Helper()
 	if len(errs) > 0 {
diff --git a/android/variable_test.go b/android/variable_test.go
index d16e458..928bca6 100644
--- a/android/variable_test.go
+++ b/android/variable_test.go
@@ -182,7 +182,7 @@
 		}
 	`
 
-	emptyTestFixtureFactory.RunTest(t,
+	GroupFixturePreparers(
 		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
 			variables.Eng = proptools.BoolPtr(true)
 		}),
@@ -204,7 +204,7 @@
 			})
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 }
 
 var testProductVariableDefaultsProperties = struct {
@@ -288,7 +288,7 @@
 		}
 	`
 
-	result := emptyTestFixtureFactory.RunTest(t,
+	result := GroupFixturePreparers(
 		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
 			variables.Eng = boolPtr(true)
 		}),
@@ -299,7 +299,7 @@
 			ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory)
 		}),
 		FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	foo := result.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule)
 
diff --git a/android/visibility_test.go b/android/visibility_test.go
index fdf18ce..ffd7909 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1142,7 +1142,7 @@
 func TestVisibility(t *testing.T) {
 	for _, test := range visibilityTests {
 		t.Run(test.name, func(t *testing.T) {
-			result := emptyTestFixtureFactory.Extend(
+			result := GroupFixturePreparers(
 				// General preparers in alphabetical order as test infrastructure will enforce correct
 				// registration order.
 				PrepareForTestWithArchMutator,
diff --git a/apex/OWNERS b/apex/OWNERS
index fee739b..8e4ba5c 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1,4 +1 @@
 per-file * = jiyong@google.com
-
-per-file allowed_deps.txt = set noparent
-per-file allowed_deps.txt = dariofreni@google.com,hansson@google.com,harpin@google.com,jiyong@google.com,narayan@google.com,jham@google.com
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
deleted file mode 100644
index 154b9aa..0000000
--- a/apex/allowed_deps.txt
+++ /dev/null
@@ -1,652 +0,0 @@
-# A list of allowed dependencies for all updatable modules.
-#
-# The list tracks all direct and transitive dependencies that end up within any
-# of the updatable binaries; specifically excluding external dependencies
-# required to compile those binaries. This prevents potential regressions in
-# case a new dependency is not aware of the different functional and
-# non-functional requirements being part of an updatable module, for example
-# setting correct min_sdk_version.
-#
-# To update the list, run:
-# repo-root$ build/soong/scripts/update-apex-allowed-deps.sh
-#
-# See go/apex-allowed-deps-error for more details.
-# TODO(b/157465465): introduce automated quality signals and remove this list.
-
-adbd(minSdkVersion:(no version))
-android.hardware.cas.native@1.0(minSdkVersion:29)
-android.hardware.cas@1.0(minSdkVersion:29)
-android.hardware.common-ndk_platform(minSdkVersion:29)
-android.hardware.common-unstable-ndk_platform(minSdkVersion:29)
-android.hardware.common-V2-ndk_platform(minSdkVersion:29)
-android.hardware.graphics.allocator@2.0(minSdkVersion:29)
-android.hardware.graphics.allocator@3.0(minSdkVersion:29)
-android.hardware.graphics.allocator@4.0(minSdkVersion:29)
-android.hardware.graphics.bufferqueue@1.0(minSdkVersion:29)
-android.hardware.graphics.bufferqueue@2.0(minSdkVersion:29)
-android.hardware.graphics.common-ndk_platform(minSdkVersion:29)
-android.hardware.graphics.common-unstable-ndk_platform(minSdkVersion:29)
-android.hardware.graphics.common-V2-ndk_platform(minSdkVersion:29)
-android.hardware.graphics.common@1.0(minSdkVersion:29)
-android.hardware.graphics.common@1.1(minSdkVersion:29)
-android.hardware.graphics.common@1.2(minSdkVersion:29)
-android.hardware.graphics.mapper@2.0(minSdkVersion:29)
-android.hardware.graphics.mapper@2.1(minSdkVersion:29)
-android.hardware.graphics.mapper@3.0(minSdkVersion:29)
-android.hardware.graphics.mapper@4.0(minSdkVersion:29)
-android.hardware.media.bufferpool@2.0(minSdkVersion:29)
-android.hardware.media.c2@1.0(minSdkVersion:29)
-android.hardware.media.c2@1.1(minSdkVersion:29)
-android.hardware.media.omx@1.0(minSdkVersion:29)
-android.hardware.media@1.0(minSdkVersion:29)
-android.hardware.neuralnetworks-V1-ndk_platform(minSdkVersion:30)
-android.hardware.neuralnetworks@1.0(minSdkVersion:30)
-android.hardware.neuralnetworks@1.1(minSdkVersion:30)
-android.hardware.neuralnetworks@1.2(minSdkVersion:30)
-android.hardware.neuralnetworks@1.3(minSdkVersion:30)
-android.hardware.tetheroffload.config-V1.0-java(minSdkVersion:current)
-android.hardware.tetheroffload.control-V1.0-java(minSdkVersion:current)
-android.hidl.allocator@1.0(minSdkVersion:29)
-android.hidl.base-V1.0-java(minSdkVersion:current)
-android.hidl.memory.token@1.0(minSdkVersion:29)
-android.hidl.memory@1.0(minSdkVersion:29)
-android.hidl.safe_union@1.0(minSdkVersion:29)
-android.hidl.token@1.0(minSdkVersion:29)
-android.hidl.token@1.0-utils(minSdkVersion:29)
-android.net.ipsec.ike(minSdkVersion:30)
-android.net.ipsec.ike(minSdkVersion:current)
-android.net.ipsec.ike.xml(minSdkVersion:(no version))
-androidx-constraintlayout_constraintlayout(minSdkVersion:14)
-androidx-constraintlayout_constraintlayout-solver(minSdkVersion:24)
-androidx.activity_activity(minSdkVersion:14)
-androidx.activity_activity-ktx(minSdkVersion:14)
-androidx.annotation_annotation(minSdkVersion:24)
-androidx.annotation_annotation(minSdkVersion:current)
-androidx.appcompat_appcompat(minSdkVersion:14)
-androidx.appcompat_appcompat-resources(minSdkVersion:14)
-androidx.arch.core_core-common(minSdkVersion:24)
-androidx.arch.core_core-common(minSdkVersion:current)
-androidx.arch.core_core-runtime(minSdkVersion:14)
-androidx.asynclayoutinflater_asynclayoutinflater(minSdkVersion:14)
-androidx.autofill_autofill(minSdkVersion:14)
-androidx.cardview_cardview(minSdkVersion:14)
-androidx.collection_collection(minSdkVersion:24)
-androidx.collection_collection(minSdkVersion:current)
-androidx.collection_collection-ktx(minSdkVersion:24)
-androidx.coordinatorlayout_coordinatorlayout(minSdkVersion:14)
-androidx.core_core(minSdkVersion:14)
-androidx.core_core-ktx(minSdkVersion:14)
-androidx.cursoradapter_cursoradapter(minSdkVersion:14)
-androidx.customview_customview(minSdkVersion:14)
-androidx.documentfile_documentfile(minSdkVersion:14)
-androidx.drawerlayout_drawerlayout(minSdkVersion:14)
-androidx.dynamicanimation_dynamicanimation(minSdkVersion:14)
-androidx.fragment_fragment(minSdkVersion:14)
-androidx.fragment_fragment-ktx(minSdkVersion:14)
-androidx.interpolator_interpolator(minSdkVersion:14)
-androidx.leanback_leanback(minSdkVersion:17)
-androidx.leanback_leanback-preference(minSdkVersion:21)
-androidx.legacy_legacy-preference-v14(minSdkVersion:14)
-androidx.legacy_legacy-support-core-ui(minSdkVersion:14)
-androidx.legacy_legacy-support-core-utils(minSdkVersion:14)
-androidx.legacy_legacy-support-v13(minSdkVersion:14)
-androidx.legacy_legacy-support-v4(minSdkVersion:14)
-androidx.lifecycle_lifecycle-common(minSdkVersion:24)
-androidx.lifecycle_lifecycle-common(minSdkVersion:current)
-androidx.lifecycle_lifecycle-common-java8(minSdkVersion:24)
-androidx.lifecycle_lifecycle-extensions(minSdkVersion:14)
-androidx.lifecycle_lifecycle-livedata(minSdkVersion:14)
-androidx.lifecycle_lifecycle-livedata-core(minSdkVersion:14)
-androidx.lifecycle_lifecycle-livedata-core-ktx(minSdkVersion:14)
-androidx.lifecycle_lifecycle-process(minSdkVersion:14)
-androidx.lifecycle_lifecycle-runtime(minSdkVersion:14)
-androidx.lifecycle_lifecycle-runtime-ktx(minSdkVersion:14)
-androidx.lifecycle_lifecycle-service(minSdkVersion:14)
-androidx.lifecycle_lifecycle-viewmodel(minSdkVersion:14)
-androidx.lifecycle_lifecycle-viewmodel-ktx(minSdkVersion:14)
-androidx.lifecycle_lifecycle-viewmodel-savedstate(minSdkVersion:14)
-androidx.loader_loader(minSdkVersion:14)
-androidx.localbroadcastmanager_localbroadcastmanager(minSdkVersion:14)
-androidx.media_media(minSdkVersion:14)
-androidx.navigation_navigation-common(minSdkVersion:14)
-androidx.navigation_navigation-common-ktx(minSdkVersion:14)
-androidx.navigation_navigation-fragment(minSdkVersion:14)
-androidx.navigation_navigation-fragment-ktx(minSdkVersion:14)
-androidx.navigation_navigation-runtime(minSdkVersion:14)
-androidx.navigation_navigation-runtime-ktx(minSdkVersion:14)
-androidx.navigation_navigation-ui(minSdkVersion:14)
-androidx.navigation_navigation-ui-ktx(minSdkVersion:14)
-androidx.preference_preference(minSdkVersion:14)
-androidx.print_print(minSdkVersion:14)
-androidx.recyclerview_recyclerview(minSdkVersion:14)
-androidx.recyclerview_recyclerview-selection(minSdkVersion:14)
-androidx.savedstate_savedstate(minSdkVersion:14)
-androidx.slidingpanelayout_slidingpanelayout(minSdkVersion:14)
-androidx.swiperefreshlayout_swiperefreshlayout(minSdkVersion:14)
-androidx.transition_transition(minSdkVersion:14)
-androidx.vectordrawable_vectordrawable(minSdkVersion:14)
-androidx.vectordrawable_vectordrawable-animated(minSdkVersion:14)
-androidx.versionedparcelable_versionedparcelable(minSdkVersion:14)
-androidx.viewpager_viewpager(minSdkVersion:14)
-apache-commons-compress(minSdkVersion:current)
-art.module.public.api.stubs(minSdkVersion:(no version))
-bcm_object(minSdkVersion:29)
-bionic_libc_platform_headers(minSdkVersion:29)
-boringssl_self_test(minSdkVersion:29)
-bouncycastle_ike_digests(minSdkVersion:current)
-bpf_syscall_wrappers(minSdkVersion:30)
-brotli-java(minSdkVersion:current)
-captiveportal-lib(minSdkVersion:29)
-car-ui-lib(minSdkVersion:28)
-car-ui-lib-overlayable(minSdkVersion:28)
-CellBroadcastApp(minSdkVersion:29)
-CellBroadcastServiceModule(minSdkVersion:29)
-codecs_g711dec(minSdkVersion:29)
-com.google.android.material_material(minSdkVersion:14)
-conscrypt(minSdkVersion:29)
-conscrypt.module.platform.api.stubs(minSdkVersion:(no version))
-conscrypt.module.public.api.stubs(minSdkVersion:(no version))
-core-lambda-stubs(minSdkVersion:(no version))
-core.current.stubs(minSdkVersion:(no version))
-crtbegin_dynamic(minSdkVersion:16)
-crtbegin_dynamic(minSdkVersion:apex_inherit)
-crtbegin_dynamic1(minSdkVersion:16)
-crtbegin_dynamic1(minSdkVersion:apex_inherit)
-crtbegin_so(minSdkVersion:16)
-crtbegin_so(minSdkVersion:apex_inherit)
-crtbegin_so1(minSdkVersion:16)
-crtbegin_so1(minSdkVersion:apex_inherit)
-crtbrand(minSdkVersion:16)
-crtbrand(minSdkVersion:apex_inherit)
-crtend_android(minSdkVersion:16)
-crtend_android(minSdkVersion:apex_inherit)
-crtend_so(minSdkVersion:16)
-crtend_so(minSdkVersion:apex_inherit)
-datastallprotosnano(minSdkVersion:29)
-derive_classpath(minSdkVersion:30)
-derive_sdk(minSdkVersion:30)
-derive_sdk(minSdkVersion:current)
-derive_sdk_prefer32(minSdkVersion:30)
-derive_sdk_prefer32(minSdkVersion:current)
-dnsresolver_aidl_interface-lateststable-ndk_platform(minSdkVersion:29)
-dnsresolver_aidl_interface-unstable-ndk_platform(minSdkVersion:29)
-dnsresolver_aidl_interface-V7-ndk_platform(minSdkVersion:29)
-dnsresolver_aidl_interface-V8-ndk_platform(minSdkVersion:29)
-DocumentsUI-res-lib(minSdkVersion:29)
-exoplayer2-extractor(minSdkVersion:16)
-exoplayer2-extractor-annotation-stubs(minSdkVersion:16)
-ExtServices(minSdkVersion:current)
-ExtServices-core(minSdkVersion:current)
-flatbuffer_headers(minSdkVersion:(no version))
-fmtlib(minSdkVersion:29)
-fmtlib_ndk(minSdkVersion:29)
-framework-mediaprovider(minSdkVersion:30)
-framework-permission(minSdkVersion:30)
-framework-permission(minSdkVersion:current)
-framework-permission-s(minSdkVersion:30)
-framework-permission-s-shared(minSdkVersion:30)
-framework-sdkextensions(minSdkVersion:30)
-framework-sdkextensions(minSdkVersion:current)
-framework-statsd(minSdkVersion:30)
-framework-statsd(minSdkVersion:current)
-framework-tethering(minSdkVersion:30)
-framework-tethering(minSdkVersion:current)
-gemmlowp_headers(minSdkVersion:(no version))
-GoogleCellBroadcastApp(minSdkVersion:29)
-GoogleCellBroadcastServiceModule(minSdkVersion:29)
-GoogleExtServices(minSdkVersion:current)
-GooglePermissionController(minSdkVersion:30)
-guava(minSdkVersion:current)
-gwp_asan_headers(minSdkVersion:(no version))
-i18n.module.public.api.stubs(minSdkVersion:(no version))
-iconloader(minSdkVersion:21)
-ike-internals(minSdkVersion:current)
-InProcessTethering(minSdkVersion:30)
-InProcessTethering(minSdkVersion:current)
-ipmemorystore-aidl-interfaces-java(minSdkVersion:29)
-ipmemorystore-aidl-interfaces-unstable-java(minSdkVersion:29)
-ipmemorystore-aidl-interfaces-V10-java(minSdkVersion:29)
-ipmemorystore-aidl-interfaces-V11-java(minSdkVersion:29)
-jni_headers(minSdkVersion:29)
-jsr305(minSdkVersion:14)
-kotlinx-coroutines-android(minSdkVersion:current)
-kotlinx-coroutines-core(minSdkVersion:current)
-legacy.art.module.platform.api.stubs(minSdkVersion:(no version))
-legacy.core.platform.api.stubs(minSdkVersion:(no version))
-legacy.i18n.module.platform.api.stubs(minSdkVersion:(no version))
-libaacextractor(minSdkVersion:29)
-libadb_crypto(minSdkVersion:(no version))
-libadb_pairing_auth(minSdkVersion:(no version))
-libadb_pairing_connection(minSdkVersion:(no version))
-libadb_pairing_server(minSdkVersion:(no version))
-libadb_protos(minSdkVersion:(no version))
-libadb_sysdeps(minSdkVersion:apex_inherit)
-libadb_tls_connection(minSdkVersion:(no version))
-libadbconnection_client(minSdkVersion:(no version))
-libadbconnection_server(minSdkVersion:(no version))
-libadbd(minSdkVersion:(no version))
-libadbd_core(minSdkVersion:(no version))
-libadbd_services(minSdkVersion:(no version))
-liballoc.rust_sysroot(minSdkVersion:29)
-libamrextractor(minSdkVersion:29)
-libapp_processes_protos_lite(minSdkVersion:(no version))
-libarect(minSdkVersion:29)
-libasyncio(minSdkVersion:(no version))
-libatomic(minSdkVersion:(no version))
-libaudio_system_headers(minSdkVersion:29)
-libaudioclient_headers(minSdkVersion:29)
-libaudiofoundation_headers(minSdkVersion:29)
-libaudioutils(minSdkVersion:29)
-libaudioutils_fixedfft(minSdkVersion:29)
-libavcdec(minSdkVersion:29)
-libavcenc(minSdkVersion:29)
-libavservices_minijail(minSdkVersion:29)
-libbacktrace_headers(minSdkVersion:apex_inherit)
-libbacktrace_rs.rust_sysroot(minSdkVersion:29)
-libbacktrace_sys.rust_sysroot(minSdkVersion:29)
-libbase(minSdkVersion:29)
-libbase_headers(minSdkVersion:29)
-libbase_ndk(minSdkVersion:29)
-libbinder_headers(minSdkVersion:29)
-libbinder_headers_platform_shared(minSdkVersion:29)
-libbinderthreadstateutils(minSdkVersion:29)
-libbluetooth-types-header(minSdkVersion:29)
-libbrotli(minSdkVersion:(no version))
-libbuildversion(minSdkVersion:(no version))
-libc(minSdkVersion:(no version))
-libc++(minSdkVersion:apex_inherit)
-libc++_static(minSdkVersion:apex_inherit)
-libc++abi(minSdkVersion:apex_inherit)
-libc++demangle(minSdkVersion:apex_inherit)
-libc_headers(minSdkVersion:apex_inherit)
-libc_headers_arch(minSdkVersion:apex_inherit)
-libcap(minSdkVersion:29)
-libcfg_if(minSdkVersion:29)
-libcfg_if.rust_sysroot(minSdkVersion:29)
-libclang_rt.hwasan-aarch64-android.llndk(minSdkVersion:(no version))
-libcodec2(minSdkVersion:29)
-libcodec2_headers(minSdkVersion:29)
-libcodec2_hidl@1.0(minSdkVersion:29)
-libcodec2_hidl@1.1(minSdkVersion:29)
-libcodec2_internal(minSdkVersion:29)
-libcodec2_soft_aacdec(minSdkVersion:29)
-libcodec2_soft_aacenc(minSdkVersion:29)
-libcodec2_soft_amrnbdec(minSdkVersion:29)
-libcodec2_soft_amrnbenc(minSdkVersion:29)
-libcodec2_soft_amrwbdec(minSdkVersion:29)
-libcodec2_soft_amrwbenc(minSdkVersion:29)
-libcodec2_soft_av1dec_gav1(minSdkVersion:29)
-libcodec2_soft_avcdec(minSdkVersion:29)
-libcodec2_soft_avcenc(minSdkVersion:29)
-libcodec2_soft_common(minSdkVersion:29)
-libcodec2_soft_flacdec(minSdkVersion:29)
-libcodec2_soft_flacenc(minSdkVersion:29)
-libcodec2_soft_g711alawdec(minSdkVersion:29)
-libcodec2_soft_g711mlawdec(minSdkVersion:29)
-libcodec2_soft_gsmdec(minSdkVersion:29)
-libcodec2_soft_h263dec(minSdkVersion:29)
-libcodec2_soft_h263enc(minSdkVersion:29)
-libcodec2_soft_hevcdec(minSdkVersion:29)
-libcodec2_soft_hevcenc(minSdkVersion:29)
-libcodec2_soft_mp3dec(minSdkVersion:29)
-libcodec2_soft_mpeg2dec(minSdkVersion:29)
-libcodec2_soft_mpeg4dec(minSdkVersion:29)
-libcodec2_soft_mpeg4enc(minSdkVersion:29)
-libcodec2_soft_opusdec(minSdkVersion:29)
-libcodec2_soft_opusenc(minSdkVersion:29)
-libcodec2_soft_rawdec(minSdkVersion:29)
-libcodec2_soft_vorbisdec(minSdkVersion:29)
-libcodec2_soft_vp8dec(minSdkVersion:29)
-libcodec2_soft_vp8enc(minSdkVersion:29)
-libcodec2_soft_vp9dec(minSdkVersion:29)
-libcodec2_soft_vp9enc(minSdkVersion:29)
-libcodec2_vndk(minSdkVersion:29)
-libcompiler_builtins.rust_sysroot(minSdkVersion:29)
-libcore.rust_sysroot(minSdkVersion:29)
-libcrypto(minSdkVersion:29)
-libcrypto_static(minSdkVersion:(no version))
-libcrypto_utils(minSdkVersion:(no version))
-libcutils(minSdkVersion:29)
-libcutils_headers(minSdkVersion:29)
-libcutils_sockets(minSdkVersion:29)
-libderive_classpath(minSdkVersion:30)
-libderive_sdk(minSdkVersion:30)
-libdiagnose_usb(minSdkVersion:(no version))
-libdl(minSdkVersion:(no version))
-libdmabufheap(minSdkVersion:29)
-libeigen(minSdkVersion:(no version))
-libfifo(minSdkVersion:29)
-libFLAC(minSdkVersion:29)
-libFLAC-config(minSdkVersion:29)
-libFLAC-headers(minSdkVersion:29)
-libflacextractor(minSdkVersion:29)
-libfmq(minSdkVersion:29)
-libfmq-base(minSdkVersion:29)
-libFraunhoferAAC(minSdkVersion:29)
-libfuse(minSdkVersion:30)
-libfuse_jni(minSdkVersion:30)
-libgav1(minSdkVersion:29)
-libgcc(minSdkVersion:(no version))
-libgcc_stripped(minSdkVersion:(no version))
-libgetopts(minSdkVersion:29)
-libgralloctypes(minSdkVersion:29)
-libgrallocusage(minSdkVersion:29)
-libgsm(minSdkVersion:apex_inherit)
-libgtest_prod(minSdkVersion:apex_inherit)
-libgui_bufferqueue_static(minSdkVersion:29)
-libgui_headers(minSdkVersion:29)
-libhardware(minSdkVersion:29)
-libhardware_headers(minSdkVersion:29)
-libhashbrown.rust_sysroot(minSdkVersion:29)
-libhevcdec(minSdkVersion:29)
-libhevcenc(minSdkVersion:29)
-libhidlbase(minSdkVersion:29)
-libhidlmemory(minSdkVersion:29)
-libhwbinder-impl-internal(minSdkVersion:29)
-libhwbinder_headers(minSdkVersion:29)
-libion(minSdkVersion:29)
-libjavacrypto(minSdkVersion:29)
-libjsoncpp(minSdkVersion:29)
-liblazy_static(minSdkVersion:29)
-liblibc(minSdkVersion:29)
-liblibc.rust_sysroot(minSdkVersion:29)
-libLibGuiProperties(minSdkVersion:29)
-liblibm(minSdkVersion:29)
-liblog(minSdkVersion:(no version))
-liblog_headers(minSdkVersion:29)
-liblog_rust(minSdkVersion:29)
-liblua(minSdkVersion:(no version))
-liblz4(minSdkVersion:(no version))
-libm(minSdkVersion:(no version))
-libmath(minSdkVersion:29)
-libmdnssd(minSdkVersion:(no version))
-libmedia_codecserviceregistrant(minSdkVersion:29)
-libmedia_datasource_headers(minSdkVersion:29)
-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))
-libminijail_gen_constants_obj(minSdkVersion:29)
-libminijail_gen_syscall(minSdkVersion:(no version))
-libminijail_gen_syscall_obj(minSdkVersion:29)
-libminijail_generated(minSdkVersion:29)
-libmkvextractor(minSdkVersion:29)
-libmodules-utils-build(minSdkVersion:29)
-libmp3extractor(minSdkVersion:29)
-libmp4extractor(minSdkVersion:29)
-libmpeg2dec(minSdkVersion:29)
-libmpeg2extractor(minSdkVersion:29)
-libnativebase_headers(minSdkVersion:29)
-libnativehelper_compat_libc++(minSdkVersion:(no version))
-libnativehelper_header_only(minSdkVersion:29)
-libnativewindow_headers(minSdkVersion:29)
-libnetd_resolv(minSdkVersion:29)
-libnetdbinder_utils_headers(minSdkVersion:29)
-libnetdutils(minSdkVersion:29)
-libnetjniutils(minSdkVersion:29)
-libnetworkstackutilsjni(minSdkVersion:29)
-libneuralnetworks(minSdkVersion:(no version))
-libneuralnetworks_common(minSdkVersion:(no version))
-libneuralnetworks_headers(minSdkVersion:(no version))
-liboggextractor(minSdkVersion:29)
-libonce_cell(minSdkVersion:29)
-libopus(minSdkVersion:29)
-libpanic_unwind.rust_sysroot(minSdkVersion:29)
-libprocessgroup(minSdkVersion:29)
-libprocessgroup_headers(minSdkVersion:29)
-libprocpartition(minSdkVersion:(no version))
-libprofiler_builtins.rust_sysroot(minSdkVersion:29)
-libprotobuf-cpp-lite(minSdkVersion:29)
-libprotobuf-java-lite(minSdkVersion:current)
-libprotobuf-java-nano(minSdkVersion:9)
-libprotoutil(minSdkVersion:(no version))
-libqemu_pipe(minSdkVersion:(no version))
-libquiche_ffi(minSdkVersion:29)
-libring(minSdkVersion:29)
-libring-core(minSdkVersion:29)
-librustc_demangle.rust_sysroot(minSdkVersion:29)
-libruy_static(minSdkVersion:30)
-libsdk_proto(minSdkVersion:30)
-libsfplugin_ccodec_utils(minSdkVersion:29)
-libsonivoxwithoutjet(minSdkVersion:29)
-libspeexresampler(minSdkVersion:29)
-libspin(minSdkVersion:29)
-libssl(minSdkVersion:29)
-libstagefright_amrnb_common(minSdkVersion:29)
-libstagefright_amrnbdec(minSdkVersion:29)
-libstagefright_amrnbenc(minSdkVersion:29)
-libstagefright_amrwbdec(minSdkVersion:29)
-libstagefright_amrwbenc(minSdkVersion:29)
-libstagefright_bufferpool@2.0.1(minSdkVersion:29)
-libstagefright_bufferqueue_helper(minSdkVersion:29)
-libstagefright_enc_common(minSdkVersion:29)
-libstagefright_esds(minSdkVersion:29)
-libstagefright_flacdec(minSdkVersion:29)
-libstagefright_foundation(minSdkVersion:29)
-libstagefright_foundation_headers(minSdkVersion:29)
-libstagefright_foundation_without_imemory(minSdkVersion:29)
-libstagefright_headers(minSdkVersion:29)
-libstagefright_id3(minSdkVersion:29)
-libstagefright_m4vh263dec(minSdkVersion:29)
-libstagefright_m4vh263enc(minSdkVersion:29)
-libstagefright_metadatautils(minSdkVersion:29)
-libstagefright_mp3dec(minSdkVersion:29)
-libstagefright_mp3dec_headers(minSdkVersion:29)
-libstagefright_mpeg2extractor(minSdkVersion:29)
-libstagefright_mpeg2support_nocrypto(minSdkVersion:29)
-libstats_jni(minSdkVersion:(no version))
-libstats_jni(minSdkVersion:30)
-libstatslog_resolv(minSdkVersion:29)
-libstatslog_statsd(minSdkVersion:(no version))
-libstatslog_statsd(minSdkVersion:30)
-libstatspull(minSdkVersion:(no version))
-libstatspull(minSdkVersion:30)
-libstatspush_compat(minSdkVersion:29)
-libstatssocket(minSdkVersion:(no version))
-libstatssocket(minSdkVersion:30)
-libstatssocket_headers(minSdkVersion:29)
-libstd(minSdkVersion:29)
-libsystem_headers(minSdkVersion:apex_inherit)
-libsysutils(minSdkVersion:apex_inherit)
-libterm(minSdkVersion:29)
-libtest(minSdkVersion:29)
-libtetherutilsjni(minSdkVersion:30)
-libtetherutilsjni(minSdkVersion:current)
-libtextclassifier(minSdkVersion:(no version))
-libtextclassifier-java(minSdkVersion:current)
-libtextclassifier_hash_headers(minSdkVersion:(no version))
-libtextclassifier_hash_static(minSdkVersion:(no version))
-libtflite_kernel_utils(minSdkVersion:(no version))
-libtflite_static(minSdkVersion:(no version))
-libui(minSdkVersion:29)
-libui_headers(minSdkVersion:29)
-libunicode_width.rust_sysroot(minSdkVersion:29)
-libuntrusted(minSdkVersion:29)
-libunwind.rust_sysroot(minSdkVersion:29)
-libunwind_llvm(minSdkVersion:apex_inherit)
-libutf(minSdkVersion:(no version))
-libutils(minSdkVersion:apex_inherit)
-libutils_headers(minSdkVersion:apex_inherit)
-libvorbisidec(minSdkVersion:29)
-libvpx(minSdkVersion:29)
-libwatchdog(minSdkVersion:29)
-libwavextractor(minSdkVersion:29)
-libwebm(minSdkVersion:29)
-libyuv(minSdkVersion:29)
-libyuv_static(minSdkVersion:29)
-libzstd(minSdkVersion:(no version))
-media_ndk_headers(minSdkVersion:29)
-media_plugin_headers(minSdkVersion:29)
-MediaProvider(minSdkVersion:30)
-mediaswcodec(minSdkVersion:29)
-metrics-constants-protos(minSdkVersion:29)
-modules-annotation-minsdk(minSdkVersion:29)
-modules-utils-build(minSdkVersion:29)
-modules-utils-build_system(minSdkVersion:29)
-modules-utils-os(minSdkVersion:30)
-ndk_crtbegin_so.19(minSdkVersion:(no version))
-ndk_crtbegin_so.21(minSdkVersion:(no version))
-ndk_crtbegin_so.27(minSdkVersion:(no version))
-ndk_crtend_so.19(minSdkVersion:(no version))
-ndk_crtend_so.21(minSdkVersion:(no version))
-ndk_crtend_so.27(minSdkVersion:(no version))
-ndk_libc++_static(minSdkVersion:(no version))
-ndk_libc++_static(minSdkVersion:16)
-ndk_libc++abi(minSdkVersion:(no version))
-ndk_libc++abi(minSdkVersion:16)
-ndk_libunwind(minSdkVersion:16)
-net-utils-device-common(minSdkVersion:29)
-net-utils-framework-common(minSdkVersion:current)
-netd-client(minSdkVersion:29)
-netd_aidl_interface-java(minSdkVersion:29)
-netd_aidl_interface-lateststable-java(minSdkVersion:29)
-netd_aidl_interface-unstable-java(minSdkVersion:29)
-netd_aidl_interface-V5-java(minSdkVersion:29)
-netd_aidl_interface-V6-java(minSdkVersion:29)
-netd_event_listener_interface-java(minSdkVersion:29)
-netd_event_listener_interface-lateststable-ndk_platform(minSdkVersion:29)
-netd_event_listener_interface-ndk_platform(minSdkVersion:29)
-netd_event_listener_interface-unstable-ndk_platform(minSdkVersion:29)
-netd_event_listener_interface-V1-ndk_platform(minSdkVersion:29)
-netd_event_listener_interface-V2-ndk_platform(minSdkVersion:29)
-netlink-client(minSdkVersion:29)
-networkstack-aidl-interfaces-unstable-java(minSdkVersion:29)
-networkstack-aidl-interfaces-V10-java(minSdkVersion:29)
-networkstack-client(minSdkVersion:29)
-NetworkStackApi29Shims(minSdkVersion:29)
-NetworkStackApi30Shims(minSdkVersion:29)
-NetworkStackApiStableDependencies(minSdkVersion:29)
-NetworkStackApiStableLib(minSdkVersion:29)
-NetworkStackApiStableShims(minSdkVersion:29)
-networkstackprotos(minSdkVersion:29)
-NetworkStackShimsCommon(minSdkVersion:29)
-neuralnetworks_types(minSdkVersion:30)
-neuralnetworks_utils_hal_1_0(minSdkVersion:30)
-neuralnetworks_utils_hal_1_1(minSdkVersion:30)
-neuralnetworks_utils_hal_1_2(minSdkVersion:30)
-neuralnetworks_utils_hal_1_3(minSdkVersion:30)
-neuralnetworks_utils_hal_aidl(minSdkVersion:30)
-neuralnetworks_utils_hal_common(minSdkVersion:30)
-neuralnetworks_utils_hal_service(minSdkVersion:30)
-no_op(minSdkVersion:current)
-note_memtag_heap_async(minSdkVersion:16)
-note_memtag_heap_sync(minSdkVersion:16)
-PermissionController(minSdkVersion:30)
-permissioncontroller-statsd(minSdkVersion:current)
-philox_random(minSdkVersion:(no version))
-philox_random_headers(minSdkVersion:(no version))
-prebuilt_androidx-constraintlayout_constraintlayout-nodeps(minSdkVersion:(no version))
-prebuilt_androidx-constraintlayout_constraintlayout-solver-nodeps(minSdkVersion:current)
-prebuilt_androidx.activity_activity-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.activity_activity-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.annotation_annotation-nodeps(minSdkVersion:current)
-prebuilt_androidx.appcompat_appcompat-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.appcompat_appcompat-resources-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.arch.core_core-common-nodeps(minSdkVersion:current)
-prebuilt_androidx.arch.core_core-runtime-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.asynclayoutinflater_asynclayoutinflater-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.autofill_autofill-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.cardview_cardview-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.collection_collection-ktx-nodeps(minSdkVersion:current)
-prebuilt_androidx.collection_collection-nodeps(minSdkVersion:current)
-prebuilt_androidx.coordinatorlayout_coordinatorlayout-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.core_core-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.core_core-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.cursoradapter_cursoradapter-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.customview_customview-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.documentfile_documentfile-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.drawerlayout_drawerlayout-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.dynamicanimation_dynamicanimation-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.fragment_fragment-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.fragment_fragment-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.interpolator_interpolator-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.leanback_leanback-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.leanback_leanback-preference-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.legacy_legacy-support-core-ui-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.legacy_legacy-support-core-utils-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.legacy_legacy-support-v13-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-common-java8-nodeps(minSdkVersion:current)
-prebuilt_androidx.lifecycle_lifecycle-common-nodeps(minSdkVersion:current)
-prebuilt_androidx.lifecycle_lifecycle-extensions-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-livedata-core-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-livedata-core-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-livedata-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-process-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-runtime-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-runtime-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-service-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-viewmodel-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-viewmodel-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.lifecycle_lifecycle-viewmodel-savedstate-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.loader_loader-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.localbroadcastmanager_localbroadcastmanager-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.media_media-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-common-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-common-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-fragment-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-fragment-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-runtime-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-runtime-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-ui-ktx-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.navigation_navigation-ui-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.preference_preference-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.print_print-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.recyclerview_recyclerview-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.recyclerview_recyclerview-selection-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.savedstate_savedstate-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.slidingpanelayout_slidingpanelayout-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.swiperefreshlayout_swiperefreshlayout-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.transition_transition-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.vectordrawable_vectordrawable-animated-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.vectordrawable_vectordrawable-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.versionedparcelable_versionedparcelable-nodeps(minSdkVersion:(no version))
-prebuilt_androidx.viewpager_viewpager-nodeps(minSdkVersion:(no version))
-prebuilt_com.google.android.material_material-nodeps(minSdkVersion:(no version))
-prebuilt_error_prone_annotations(minSdkVersion:(no version))
-prebuilt_kotlin-stdlib(minSdkVersion:current)
-prebuilt_kotlinx-coroutines-android-nodeps(minSdkVersion:(no version))
-prebuilt_kotlinx-coroutines-core-nodeps(minSdkVersion:(no version))
-prebuilt_libclang_rt.builtins-aarch64-android(minSdkVersion:(no version))
-prebuilt_libclang_rt.builtins-arm-android(minSdkVersion:(no version))
-prebuilt_libclang_rt.builtins-i686-android(minSdkVersion:(no version))
-prebuilt_libclang_rt.builtins-x86_64-android(minSdkVersion:(no version))
-prebuilt_libunwind(minSdkVersion:(no version))
-prebuilt_test_framework-sdkextensions(minSdkVersion:(no version))
-server_configurable_flags(minSdkVersion:29)
-service-media-s(minSdkVersion:29)
-service-permission(minSdkVersion:30)
-service-permission(minSdkVersion:current)
-service-permission-shared(minSdkVersion:30)
-service-statsd(minSdkVersion:30)
-service-statsd(minSdkVersion:current)
-SettingsLibActionBarShadow(minSdkVersion:21)
-SettingsLibAppPreference(minSdkVersion:21)
-SettingsLibBarChartPreference(minSdkVersion:21)
-SettingsLibHelpUtils(minSdkVersion:21)
-SettingsLibLayoutPreference(minSdkVersion:21)
-SettingsLibProgressBar(minSdkVersion:21)
-SettingsLibRestrictedLockUtils(minSdkVersion:21)
-SettingsLibSearchWidget(minSdkVersion:21)
-SettingsLibSettingsTheme(minSdkVersion:21)
-SettingsLibUtils(minSdkVersion:21)
-stats_proto(minSdkVersion:29)
-statsd(minSdkVersion:(no version))
-statsd(minSdkVersion:30)
-statsd-aidl-ndk_platform(minSdkVersion:(no version))
-statsd-aidl-ndk_platform(minSdkVersion:30)
-statsprotos(minSdkVersion:29)
-tensorflow_headers(minSdkVersion:(no version))
-Tethering(minSdkVersion:30)
-Tethering(minSdkVersion:current)
-TetheringApiCurrentLib(minSdkVersion:30)
-TetheringApiCurrentLib(minSdkVersion:current)
-TetheringGoogle(minSdkVersion:30)
-TetheringGoogle(minSdkVersion:current)
-textclassifier-statsd(minSdkVersion:current)
-TextClassifierNotificationLibNoManifest(minSdkVersion:29)
-TextClassifierServiceLibNoManifest(minSdkVersion:28)
-updatable-media(minSdkVersion:29)
-xz-java(minSdkVersion:current)
diff --git a/apex/apex.go b/apex/apex.go
index 429465d..a67fe1f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -854,12 +854,7 @@
 		if required, ok := depTag.(android.AlwaysRequireApexVariantTag); ok && required.AlwaysRequireApexVariant() {
 			return true
 		}
-		if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
-			// The tag defines a dependency that never requires the child module to be part of the same
-			// apex as the parent so it does not need an apex variant created.
-			return false
-		}
-		if !parent.(android.DepIsInSameApex).DepIsInSameApex(mctx, child) {
+		if !android.IsDepInSameApex(mctx, parent, child) {
 			return false
 		}
 		if excludeVndkLibs {
@@ -1003,11 +998,7 @@
 	// If any of the dep is not available to platform, this module is also considered as being
 	// not available to platform even if it has "//apex_available:platform"
 	mctx.VisitDirectDeps(func(child android.Module) {
-		depTag := mctx.OtherModuleDependencyTag(child)
-		if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
-			return
-		}
-		if !am.DepIsInSameApex(mctx, child) {
+		if !android.IsDepInSameApex(mctx, am, child) {
 			// if the dependency crosses apex boundary, don't consider it
 			return
 		}
@@ -1207,11 +1198,13 @@
 	}).([]string)
 }
 
-// setUseVendorAllowListForTest overrides useVendorAllowList and must be called before the first
-// call to useVendorAllowList()
-func setUseVendorAllowListForTest(config android.Config, allowList []string) {
-	config.Once(useVendorAllowListKey, func() interface{} {
-		return allowList
+// setUseVendorAllowListForTest returns a FixturePreparer that overrides useVendorAllowList and
+// must be called before the first call to useVendorAllowList()
+func setUseVendorAllowListForTest(allowList []string) android.FixturePreparer {
+	return android.FixtureModifyConfig(func(config android.Config) {
+		config.Once(useVendorAllowListKey, func() interface{} {
+			return allowList
+		})
 	})
 }
 
@@ -1870,7 +1863,10 @@
 						// like to record requiredNativeLibs even when
 						// DepIsInSameAPex is false. We also shouldn't do
 						// this for host.
-						if !am.DepIsInSameApex(ctx, am) {
+						//
+						// TODO(jiyong): explain why the same module is passed in twice.
+						// Switching the first am to parent breaks lots of tests.
+						if !android.IsDepInSameApex(ctx, am, am) {
 							return false
 						}
 
@@ -2193,6 +2189,8 @@
 
 			// If `to` is not actually in the same APEX as `from` then it does not need
 			// apex_available and neither do any of its dependencies.
+			//
+			// It is ok to call DepIsInSameApex() directly from within WalkPayloadDeps().
 			if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
 				// As soon as the dependency graph crosses the APEX boundary, don't go further.
 				return false
@@ -2276,6 +2274,8 @@
 
 		// If `to` is not actually in the same APEX as `from` then it does not need
 		// apex_available and neither do any of its dependencies.
+		//
+		// It is ok to call DepIsInSameApex() directly from within WalkPayloadDeps().
 		if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
 			// As soon as the dependency graph crosses the APEX boundary, don't go
 			// further.
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index ee9fc81..0ed94af 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -58,8 +58,8 @@
 				echo "ERROR: go/apex-allowed-deps-error";
 				echo "******************************";
 				echo "Detected changes to allowed dependencies in updatable modules.";
-				echo "To fix and update build/soong/apex/allowed_deps.txt, please run:";
-				echo "$$ (croot && build/soong/scripts/update-apex-allowed-deps.sh)";
+				echo "To fix and update packages/modules/common/build/allowed_deps.txt, please run:";
+				echo "$$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)";
 				echo "Members of mainline-modularization@google.com will review the changes.";
 				echo -e "******************************\n";
 				exit 1;
@@ -81,25 +81,35 @@
 		}
 	})
 
-	allowedDeps := android.ExistentPathForSource(ctx, "build/soong/apex/allowed_deps.txt").Path()
-
+	allowedDepsSource := android.ExistentPathForSource(ctx, "packages/modules/common/build/allowed_deps.txt")
 	newAllowedDeps := android.PathForOutput(ctx, "apex", "depsinfo", "new-allowed-deps.txt")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   generateApexDepsInfoFilesRule,
-		Inputs: append(updatableFlatLists, allowedDeps),
-		Output: newAllowedDeps,
-	})
-
 	s.allowedApexDepsInfoCheckResult = android.PathForOutput(ctx, newAllowedDeps.Rel()+".check")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   diffAllowedApexDepsInfoRule,
-		Input:  newAllowedDeps,
-		Output: s.allowedApexDepsInfoCheckResult,
-		Args: map[string]string{
-			"allowed_deps":     allowedDeps.String(),
-			"new_allowed_deps": newAllowedDeps.String(),
-		},
-	})
+
+	if !allowedDepsSource.Valid() {
+		// Unbundled projects may not have packages/modules/common/ checked out; ignore those.
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Touch,
+			Output: s.allowedApexDepsInfoCheckResult,
+		})
+	} else {
+		allowedDeps := allowedDepsSource.Path()
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   generateApexDepsInfoFilesRule,
+			Inputs: append(updatableFlatLists, allowedDeps),
+			Output: newAllowedDeps,
+		})
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   diffAllowedApexDepsInfoRule,
+			Input:  newAllowedDeps,
+			Output: s.allowedApexDepsInfoCheckResult,
+			Args: map[string]string{
+				"allowed_deps":     allowedDeps.String(),
+				"new_allowed_deps": newAllowedDeps.String(),
+			},
+		})
+	}
 
 	ctx.Phony("apex-allowed-deps-check", s.allowedApexDepsInfoCheckResult)
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ac98b07..b159660 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -50,49 +50,33 @@
 	return
 }
 
-func testApexError(t *testing.T, pattern, bp string, handlers ...testCustomizer) {
+func testApexError(t *testing.T, pattern, bp string, preparers ...android.FixturePreparer) {
 	t.Helper()
-	ctx, config := testApexContext(t, bp, handlers...)
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	if len(errs) > 0 {
-		android.FailIfNoMatchingErrors(t, pattern, errs)
-		return
-	}
-	_, errs = ctx.PrepareBuildActions(config)
-	if len(errs) > 0 {
-		android.FailIfNoMatchingErrors(t, pattern, errs)
-		return
-	}
-
-	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+	apexFixtureFactory.Extend(preparers...).
+		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
+		RunTestWithBp(t, bp)
 }
 
-func testApex(t *testing.T, bp string, handlers ...testCustomizer) *android.TestContext {
+func testApex(t *testing.T, bp string, preparers ...android.FixturePreparer) *android.TestContext {
 	t.Helper()
-	ctx, config := testApexContext(t, bp, handlers...)
-	_, errs := ctx.ParseBlueprintsFiles(".")
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-	return ctx
-}
-
-type testCustomizer func(fs map[string][]byte, config android.Config)
-
-func withFiles(files map[string][]byte) testCustomizer {
-	return func(fs map[string][]byte, config android.Config) {
-		for k, v := range files {
-			fs[k] = v
-		}
+	factory := apexFixtureFactory.Extend(preparers...)
+	if bp != "" {
+		factory = factory.Extend(android.FixtureWithRootAndroidBp(bp))
 	}
+	result := factory.RunTest(t)
+	return result.TestContext
 }
 
-func withTargets(targets map[android.OsType][]android.Target) testCustomizer {
-	return func(fs map[string][]byte, config android.Config) {
+func withFiles(files android.MockFS) android.FixturePreparer {
+	return files.AddToFixture()
+}
+
+func withTargets(targets map[android.OsType][]android.Target) android.FixturePreparer {
+	return android.FixtureModifyConfig(func(config android.Config) {
 		for k, v := range targets {
 			config.Targets[k] = v
 		}
-	}
+	})
 }
 
 // withNativeBridgeTargets sets configuration with targets including:
@@ -100,34 +84,38 @@
 // - X86 (secondary)
 // - Arm64 on X86_64 (native bridge)
 // - Arm on X86 (native bridge)
-func withNativeBridgeEnabled(_ map[string][]byte, config android.Config) {
-	config.Targets[android.Android] = []android.Target{
-		{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
-			NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
-		{Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
-			NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
-		{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}},
-			NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"},
-		{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
-			NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"},
-	}
+var withNativeBridgeEnabled = android.FixtureModifyConfig(
+	func(config android.Config) {
+		config.Targets[android.Android] = []android.Target{
+			{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
+				NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+			{Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
+				NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}},
+				NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"},
+			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+				NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"},
+		}
+	},
+)
+
+func withManifestPackageNameOverrides(specs []string) android.FixturePreparer {
+	return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		variables.ManifestPackageNameOverrides = specs
+	})
 }
 
-func withManifestPackageNameOverrides(specs []string) testCustomizer {
-	return func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.ManifestPackageNameOverrides = specs
-	}
-}
+var withBinder32bit = android.FixtureModifyProductVariables(
+	func(variables android.FixtureProductVariables) {
+		variables.Binder32bit = proptools.BoolPtr(true)
+	},
+)
 
-func withBinder32bit(_ map[string][]byte, config android.Config) {
-	config.TestProductVariables.Binder32bit = proptools.BoolPtr(true)
-}
-
-func withUnbundledBuild(_ map[string][]byte, config android.Config) {
-	config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
-}
-
-var emptyFixtureFactory = android.NewFixtureFactory(&buildDir)
+var withUnbundledBuild = android.FixtureModifyProductVariables(
+	func(variables android.FixtureProductVariables) {
+		variables.Unbundled_build = proptools.BoolPtr(true)
+	},
+)
 
 var apexFixtureFactory = android.NewFixtureFactory(
 	&buildDir,
@@ -217,143 +205,6 @@
 	}),
 )
 
-func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
-	bp = bp + `
-		filegroup {
-			name: "myapex-file_contexts",
-			srcs: [
-				"system/sepolicy/apex/myapex-file_contexts",
-			],
-		}
-	`
-
-	bp = bp + cc.GatherRequiredDepsForTest(android.Android)
-
-	bp = bp + rust.GatherRequiredDepsForTest()
-
-	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,
-		"system/sepolicy/apex/com.android.vndk.current-file_contexts": nil,
-		"mylib.cpp":                                  nil,
-		"mytest.cpp":                                 nil,
-		"mytest1.cpp":                                nil,
-		"mytest2.cpp":                                nil,
-		"mytest3.cpp":                                nil,
-		"myprebuilt":                                 nil,
-		"my_include":                                 nil,
-		"foo/bar/MyClass.java":                       nil,
-		"prebuilt.jar":                               nil,
-		"prebuilt.so":                                nil,
-		"vendor/foo/devkeys/test.x509.pem":           nil,
-		"vendor/foo/devkeys/test.pk8":                nil,
-		"testkey.x509.pem":                           nil,
-		"testkey.pk8":                                nil,
-		"testkey.override.x509.pem":                  nil,
-		"testkey.override.pk8":                       nil,
-		"vendor/foo/devkeys/testkey.avbpubkey":       nil,
-		"vendor/foo/devkeys/testkey.pem":             nil,
-		"NOTICE":                                     nil,
-		"custom_notice":                              nil,
-		"custom_notice_for_static_lib":               nil,
-		"testkey2.avbpubkey":                         nil,
-		"testkey2.pem":                               nil,
-		"myapex-arm64.apex":                          nil,
-		"myapex-arm.apex":                            nil,
-		"myapex.apks":                                nil,
-		"frameworks/base/api/current.txt":            nil,
-		"framework/aidl/a.aidl":                      nil,
-		"build/make/core/proguard.flags":             nil,
-		"build/make/core/proguard_basic_keeps.flags": nil,
-		"dummy.txt":                                  nil,
-		"baz":                                        nil,
-		"bar/baz":                                    nil,
-		"testdata/baz":                               nil,
-		"AppSet.apks":                                nil,
-		"foo.rs":                                     nil,
-		"libfoo.jar":                                 nil,
-		"libbar.jar":                                 nil,
-	}
-
-	cc.GatherRequiredFilesForTest(fs)
-
-	for _, handler := range handlers {
-		// The fs now needs to be populated before creating the config, call handlers twice
-		// for now, once to get any fs changes, and later after the config was created to
-		// set product variables or targets.
-		tempConfig := android.TestArchConfig(buildDir, nil, bp, fs)
-		handler(fs, tempConfig)
-	}
-
-	config := android.TestArchConfig(buildDir, nil, bp, fs)
-	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
-	config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
-	config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
-	config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
-	config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
-	config.TestProductVariables.Platform_version_active_codenames = []string{"Q"}
-	config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
-
-	for _, handler := range handlers {
-		// The fs now needs to be populated before creating the config, call handlers twice
-		// for now, earlier to get any fs changes, and now after the config was created to
-		// set product variables or targets.
-		tempFS := map[string][]byte{}
-		handler(tempFS, config)
-	}
-
-	ctx := android.NewTestArchContext(config)
-
-	// from android package
-	android.RegisterPackageBuildComponents(ctx)
-	ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
-
-	registerApexBuildComponents(ctx)
-	registerApexKeyBuildComponents(ctx)
-
-	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
-	ctx.PreArchMutators(android.RegisterComponentsMutator)
-
-	android.RegisterPrebuiltMutators(ctx)
-
-	// Register these after the prebuilt mutators have been registered to match what
-	// happens at runtime.
-	ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
-	ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
-
-	// These must come after prebuilts and visibility rules to match runtime.
-	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
-
-	// These must come after override rules to match the runtime.
-	cc.RegisterRequiredBuildComponentsForTest(ctx)
-	rust.RegisterRequiredBuildComponentsForTest(ctx)
-	java.RegisterRequiredBuildComponentsForTest(ctx)
-
-	ctx.RegisterModuleType("cc_test", cc.TestFactory)
-	ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
-	cc.RegisterVndkLibraryTxtTypes(ctx)
-	prebuilt_etc.RegisterPrebuiltEtcBuildComponents(ctx)
-	ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
-	ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	ctx.RegisterModuleType("bpf", bpf.BpfFactory)
-
-	ctx.Register()
-
-	return ctx, config
-}
-
 func setUp() {
 	var err error
 	buildDir, err = ioutil.TempDir("", "soong_apex_test")
@@ -1139,11 +990,13 @@
 			srcs: ["mylib.cpp"],
 			shared_libs: ["libstub"],
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Z")
-		config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
-		config.TestProductVariables.Platform_version_active_codenames = []string{"Z"}
-	})
+	`,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_sdk_codename = proptools.StringPtr("Z")
+			variables.Platform_sdk_final = proptools.BoolPtr(false)
+			variables.Platform_version_active_codenames = []string{"Z"}
+		}),
+	)
 
 	// Ensure that mylib from myapex is built against the latest stub (current)
 	mylibCflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
@@ -1333,7 +1186,7 @@
 )
 
 func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
-	result := emptyFixtureFactory.Extend(prepareForTestOfRuntimeApexWithHwasan).RunTestWithBp(t, `
+	result := android.GroupFixturePreparers(prepareForTestOfRuntimeApexWithHwasan).RunTestWithBp(t, `
 		cc_library {
 			name: "libc",
 			no_libcrt: true,
@@ -1379,7 +1232,7 @@
 }
 
 func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) {
-	result := emptyFixtureFactory.Extend(
+	result := android.GroupFixturePreparers(
 		prepareForTestOfRuntimeApexWithHwasan,
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.SanitizeDevice = []string{"hwaddress"}
@@ -1491,9 +1344,10 @@
 				name: "libbar.llndk",
 				symbol_file: "",
 			}
-			`, func(fs map[string][]byte, config android.Config) {
-				setUseVendorAllowListForTest(config, []string{"myapex"})
-			}, withUnbundledBuild)
+			`,
+				setUseVendorAllowListForTest([]string{"myapex"}),
+				withUnbundledBuild,
+			)
 
 			// Ensure that LLNDK dep is not included
 			ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
@@ -1727,9 +1581,11 @@
 				versions: ["29", "R"],
 			},
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
-	})
+	`,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"R"}
+		}),
+	)
 
 	expectLink := func(from, from_variant, to, to_variant string) {
 		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
@@ -1838,6 +1694,12 @@
 	expectNoLink("libz", "shared", "libz", "shared")
 }
 
+var prepareForTestWithSantitizeHwaddress = android.FixtureModifyProductVariables(
+	func(variables android.FixtureProductVariables) {
+		variables.SanitizeDevice = []string{"hwaddress"}
+	},
+)
+
 func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -1866,9 +1728,9 @@
 				versions: ["29", "30"],
 			},
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
-	})
+	`,
+		prepareForTestWithSantitizeHwaddress,
+	)
 	expectLink := func(from, from_variant, to, to_variant string) {
 		ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
 		libFlags := ld.Args["libFlags"]
@@ -2261,10 +2123,12 @@
 }
 
 func TestApexMinSdkVersion_WorksWithSdkCodename(t *testing.T) {
-	withSAsActiveCodeNames := func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("S")
-		config.TestProductVariables.Platform_version_active_codenames = []string{"S"}
-	}
+	withSAsActiveCodeNames := android.FixtureModifyProductVariables(
+		func(variables android.FixtureProductVariables) {
+			variables.Platform_sdk_codename = proptools.StringPtr("S")
+			variables.Platform_version_active_codenames = []string{"S"}
+		},
+	)
 	testApexError(t, `libbar.*: should support min_sdk_version\(S\)`, `
 		apex {
 			name: "myapex",
@@ -2291,10 +2155,10 @@
 }
 
 func TestApexMinSdkVersion_WorksWithActiveCodenames(t *testing.T) {
-	withSAsActiveCodeNames := func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("S")
-		config.TestProductVariables.Platform_version_active_codenames = []string{"S", "T"}
-	}
+	withSAsActiveCodeNames := android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		variables.Platform_sdk_codename = proptools.StringPtr("S")
+		variables.Platform_version_active_codenames = []string{"S", "T"}
+	})
 	ctx := testApex(t, `
 		apex {
 			name: "myapex",
@@ -2484,9 +2348,9 @@
 			stl: "none",
 			apex_available: [ "myapex" ],
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorAllowListForTest(config, []string{"myapex"})
-	})
+	`,
+		setUseVendorAllowListForTest([]string{"myapex"}),
+	)
 
 	inputsList := []string{}
 	for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().BuildParamsForTests() {
@@ -2517,9 +2381,9 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorAllowListForTest(config, []string{""})
-	})
+	`,
+		setUseVendorAllowListForTest([]string{""}),
+	)
 	// no error with allow list
 	testApex(t, `
 		apex {
@@ -2533,9 +2397,9 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorAllowListForTest(config, []string{"myapex"})
-	})
+	`,
+		setUseVendorAllowListForTest([]string{"myapex"}),
+	)
 }
 
 func TestUseVendorFailsIfNotVendorAvailable(t *testing.T) {
@@ -2650,7 +2514,7 @@
 	libs := names(ldRule.Args["libFlags"])
 	// VNDK libs(libvndk/libc++) as they are
 	ensureListContains(t, libs, buildDir+"/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so")
-	ensureListContains(t, libs, buildDir+"/.intermediates/libc++/"+vendorVariant+"_shared/libc++.so")
+	ensureListContains(t, libs, buildDir+"/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"libc++/"+vendorVariant+"_shared/libc++.so")
 	// non-stable Vendor libs as APEX variants
 	ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so")
 
@@ -2687,9 +2551,10 @@
 			apex_available: ["myapex"],
 			srcs: ["foo.cpp"],
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.ProductVndkVersion = proptools.StringPtr("current")
-	})
+	`, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		variables.ProductVndkVersion = proptools.StringPtr("current")
+	}),
+	)
 
 	cflags := strings.Fields(
 		ctx.ModuleForTests("foo", "android_product.VER_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"])
@@ -2757,9 +2622,9 @@
 			vendor_available: true,
 			apex_available: ["myapex"],
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorAllowListForTest(config, []string{"myapex"})
-	})
+	`,
+		setUseVendorAllowListForTest([]string{"myapex"}),
+	)
 
 	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
@@ -5053,9 +4918,11 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.InstallExtraFlattenedApexes = proptools.BoolPtr(true)
-	})
+	`,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.InstallExtraFlattenedApexes = proptools.BoolPtr(true)
+		}),
+	)
 	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
 	ensureListContains(t, ab.requiredDeps, "myapex.flattened")
 	mk := android.AndroidMkDataForTest(t, ctx, ab)
@@ -5746,7 +5613,7 @@
 	}
 }
 
-var filesForSdkLibrary = map[string][]byte{
+var filesForSdkLibrary = android.MockFS{
 	"api/current.txt":        nil,
 	"api/removed.txt":        nil,
 	"api/system-current.txt": nil,
@@ -6368,10 +6235,12 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		delete(config.Targets, android.Android)
-		config.AndroidCommonTarget = android.Target{}
-	})
+	`,
+		android.FixtureModifyConfig(func(config android.Config) {
+			delete(config.Targets, android.Android)
+			config.AndroidCommonTarget = android.Target{}
+		}),
+	)
 
 	if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) {
 		t.Errorf("Expected variants: %v, but got: %v", expected, got)
@@ -6443,7 +6312,7 @@
 }
 
 func TestAppSetBundlePrebuilt(t *testing.T) {
-	ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+	ctx := testApex(t, "", android.FixtureModifyMockFS(func(fs android.MockFS) {
 		bp := `
 		apex_set {
 			name: "myapex",
@@ -6454,9 +6323,9 @@
 			},
 		}`
 		fs["Android.bp"] = []byte(bp)
-
-		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
-	})
+	}),
+		prepareForTestWithSantitizeHwaddress,
+	)
 
 	m := ctx.ModuleForTests("myapex", "android_common")
 	extractedApex := m.Output(buildDir + "/.intermediates/myapex/android_common/foo_v2.apex")
@@ -7021,13 +6890,17 @@
 			filename: "foo_v2.apex",
 			overrides: ["foo"],
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.Platform_sdk_version = intPtr(30)
-		config.Targets[android.Android] = []android.Target{
-			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}},
-			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}},
-		}
-	})
+	`,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_sdk_version = intPtr(30)
+		}),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.Targets[android.Android] = []android.Target{
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}},
+			}
+		}),
+	)
 
 	m := ctx.ModuleForTests("myapex", "android_common")
 
@@ -7235,9 +7108,11 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`, func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.CompressedApex = proptools.BoolPtr(true)
-	})
+	`,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.CompressedApex = proptools.BoolPtr(true)
+		}),
+	)
 
 	compressRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("compressRule")
 	ensureContains(t, compressRule.Output.String(), "myapex.capex.unsigned")
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index 2e6ed82..7e37e42 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -15,7 +15,6 @@
 package apex
 
 import (
-	"reflect"
 	"strings"
 	"testing"
 
@@ -28,7 +27,18 @@
 // modules from the ART apex.
 
 func TestBootImages(t *testing.T) {
-	ctx := testApex(t, `
+	result := apexFixtureFactory.Extend(
+		// Configure some libraries in the art and framework boot images.
+		dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
+		dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+		filesForSdkLibrary.AddToFixture(),
+		// Some additional files needed for the art apex.
+		android.FixtureMergeMockFs(android.MockFS{
+			"com.android.art.avbpubkey":                          nil,
+			"com.android.art.pem":                                nil,
+			"system/sepolicy/apex/com.android.art-file_contexts": nil,
+		}),
+	).RunTestWithBp(t, `
 		java_sdk_library {
 			name: "foo",
 			srcs: ["b.java"],
@@ -83,20 +93,10 @@
 			image_name: "boot",
 		}
 `,
-		// Configure some libraries in the art and framework boot images.
-		withArtBootImageJars("com.android.art:baz", "com.android.art:quuz"),
-		withFrameworkBootImageJars("platform:foo", "platform:bar"),
-		withFiles(filesForSdkLibrary),
-		// Some additional files needed for the art apex.
-		withFiles(map[string][]byte{
-			"com.android.art.avbpubkey":                          nil,
-			"com.android.art.pem":                                nil,
-			"system/sepolicy/apex/com.android.art-file_contexts": nil,
-		}),
 	)
 
 	// Make sure that the framework-boot-image is using the correct configuration.
-	checkBootImage(t, ctx, "framework-boot-image", "platform:foo,platform:bar", `
+	checkBootImage(t, result, "framework-boot-image", "platform:foo,platform:bar", `
 test_device/dex_bootjars/android/system/framework/arm/boot-foo.art
 test_device/dex_bootjars/android/system/framework/arm/boot-foo.oat
 test_device/dex_bootjars/android/system/framework/arm/boot-foo.vdex
@@ -112,7 +112,7 @@
 `)
 
 	// Make sure that the art-boot-image is using the correct configuration.
-	checkBootImage(t, ctx, "art-boot-image", "com.android.art:baz,com.android.art:quuz", `
+	checkBootImage(t, result, "art-boot-image", "com.android.art:baz,com.android.art:quuz", `
 test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
 test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat
 test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex
@@ -128,16 +128,14 @@
 `)
 }
 
-func checkBootImage(t *testing.T, ctx *android.TestContext, moduleName string, expectedConfiguredModules string, expectedBootImageFiles string) {
+func checkBootImage(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootImageFiles string) {
 	t.Helper()
 
-	bootImage := ctx.ModuleForTests(moduleName, "android_common").Module().(*java.BootImageModule)
+	bootImage := result.ModuleForTests(moduleName, "android_common").Module().(*java.BootImageModule)
 
-	bootImageInfo := ctx.ModuleProvider(bootImage, java.BootImageInfoProvider).(java.BootImageInfo)
+	bootImageInfo := result.ModuleProvider(bootImage, java.BootImageInfoProvider).(java.BootImageInfo)
 	modules := bootImageInfo.Modules()
-	if actual := modules.String(); actual != expectedConfiguredModules {
-		t.Errorf("invalid modules for %s: expected %q, actual %q", moduleName, expectedConfiguredModules, actual)
-	}
+	android.AssertStringEquals(t, "invalid modules for "+moduleName, expectedConfiguredModules, modules.String())
 
 	// Get a list of all the paths in the boot image sorted by arch type.
 	allPaths := []string{}
@@ -149,39 +147,15 @@
 			}
 		}
 	}
-	if expected, actual := strings.TrimSpace(expectedBootImageFiles), strings.TrimSpace(strings.Join(allPaths, "\n")); !reflect.DeepEqual(expected, actual) {
-		t.Errorf("invalid paths for %s: expected \n%s, actual \n%s", moduleName, expected, actual)
-	}
-}
 
-func modifyDexpreoptConfig(configModifier func(dexpreoptConfig *dexpreopt.GlobalConfig)) func(fs map[string][]byte, config android.Config) {
-	return func(fs map[string][]byte, config android.Config) {
-		// Initialize the dexpreopt GlobalConfig to an empty structure. This has no effect if it has
-		// already been set.
-		pathCtx := android.PathContextForTesting(config)
-		dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
-		dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
-
-		// Retrieve the existing configuration and modify it.
-		dexpreoptConfig = dexpreopt.GetGlobalConfig(pathCtx)
-		configModifier(dexpreoptConfig)
-	}
-}
-
-func withArtBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
-	return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
-		dexpreoptConfig.ArtApexJars = android.CreateTestConfiguredJarList(bootJars)
-	})
-}
-
-func withFrameworkBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
-	return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
-		dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars)
-	})
+	android.AssertTrimmedStringEquals(t, "invalid paths for "+moduleName, expectedBootImageFiles, strings.Join(allPaths, "\n"))
 }
 
 func TestBootImageInApex(t *testing.T) {
-	ctx := testApex(t, `
+	result := apexFixtureFactory.Extend(
+		// Configure some libraries in the framework boot image.
+		dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -216,12 +190,9 @@
 				"myapex",
 			],
 		}
-`,
-		// Configure some libraries in the framework boot image.
-		withFrameworkBootImageJars("platform:foo", "platform:bar"),
-	)
+	`)
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
 		"javalib/arm/boot-bar.art",
 		"javalib/arm/boot-bar.oat",
 		"javalib/arm/boot-bar.vdex",
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 34b9408..015283d 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -48,9 +48,11 @@
 			stl: "none",
 			apex_available: [ "com.android.vndk.current" ],
 		}
-	`+vndkLibrariesTxtFiles("current"), func(fs map[string][]byte, config android.Config) {
-		config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("")
-	})
+	`+vndkLibrariesTxtFiles("current"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.DeviceVndkVersion = proptools.StringPtr("")
+		}),
+	)
 	// VNDK-Lite contains only core variants of VNDK-Sp libraries
 	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
 		"lib/libvndksp.so",
@@ -113,20 +115,24 @@
 	})
 
 	t.Run("VNDK APEX gathers only vendor variants even if product variants are available", func(t *testing.T) {
-		ctx := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
-			// Now product variant is available
-			config.TestProductVariables.ProductVndkVersion = proptools.StringPtr("current")
-		})
+		ctx := testApex(t, bp,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				// Now product variant is available
+				variables.ProductVndkVersion = proptools.StringPtr("current")
+			}),
+		)
 
 		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")
 	})
 
 	t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
-		ctx := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
-			config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
-			config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
-		})
+		ctx := testApex(t, bp,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.GcovCoverage = proptools.BoolPtr(true)
+				variables.Native_coverage = proptools.BoolPtr(true)
+			}),
+		)
 
 		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")
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index 0bf15db..51fbc15 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -26,8 +26,7 @@
 	os.Exit(m.Run())
 }
 
-var bpfFactory = android.NewFixtureFactory(
-	nil,
+var prepareForBpfTest = android.GroupFixturePreparers(
 	cc.PrepareForTestWithCcDefaultModules,
 	android.FixtureMergeMockFs(
 		map[string][]byte{
@@ -53,7 +52,7 @@
 		}
 	`
 
-	bpfFactory.RunTestWithBp(t, bp)
+	prepareForBpfTest.RunTestWithBp(t, bp)
 
 	// We only verify the above BP configuration is processed successfully since the data property
 	// value is not available for testing from this package.
diff --git a/cc/config/global.go b/cc/config/global.go
index cb7d17d..7e80900 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -144,8 +144,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r412851"
-	ClangDefaultShortVersion = "12.0.3"
+	ClangDefaultVersion      = "clang-r416183"
+	ClangDefaultShortVersion = "12.0.4"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index f800c48..9c3db3b 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -26,8 +26,7 @@
 	os.Exit(m.Run())
 }
 
-var prebuiltEtcFixtureFactory = android.NewFixtureFactory(
-	nil,
+var prepareForPrebuiltEtcTest = android.GroupFixturePreparers(
 	android.PrepareForTestWithArchMutator,
 	PrepareForTestWithPrebuiltEtc,
 	android.FixtureMergeMockFs(android.MockFS{
@@ -38,7 +37,7 @@
 )
 
 func TestPrebuiltEtcVariants(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
 			name: "foo.conf",
 			src: "foo.conf",
@@ -72,7 +71,7 @@
 }
 
 func TestPrebuiltEtcOutputPath(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
 			name: "foo.conf",
 			src: "foo.conf",
@@ -85,7 +84,7 @@
 }
 
 func TestPrebuiltEtcGlob(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
 			name: "my_foo",
 			src: "foo.*",
@@ -105,7 +104,7 @@
 }
 
 func TestPrebuiltEtcAndroidMk(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
 			name: "foo",
 			src: "foo.conf",
@@ -139,7 +138,7 @@
 }
 
 func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
 			name: "foo.conf",
 			src: "foo.conf",
@@ -153,7 +152,7 @@
 }
 
 func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) {
-	prebuiltEtcFixtureFactory.
+	prepareForPrebuiltEtcTest.
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("relative_install_path is set. Cannot set sub_dir")).
 		RunTestWithBp(t, `
 			prebuilt_etc {
@@ -166,7 +165,7 @@
 }
 
 func TestPrebuiltEtcHost(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc_host {
 			name: "foo.conf",
 			src: "foo.conf",
@@ -181,7 +180,7 @@
 }
 
 func TestPrebuiltUserShareInstallDirPath(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_usr_share {
 			name: "foo.conf",
 			src: "foo.conf",
@@ -195,7 +194,7 @@
 }
 
 func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_usr_share_host {
 			name: "foo.conf",
 			src: "foo.conf",
@@ -210,7 +209,7 @@
 }
 
 func TestPrebuiltFontInstallDirPath(t *testing.T) {
-	result := prebuiltEtcFixtureFactory.RunTestWithBp(t, `
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_font {
 			name: "foo.conf",
 			src: "foo.conf",
@@ -249,7 +248,7 @@
 	}}
 	for _, tt := range tests {
 		t.Run(tt.description, func(t *testing.T) {
-			result := prebuiltEtcFixtureFactory.RunTestWithBp(t, tt.config)
+			result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config)
 			p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
 			android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath)
 		})
@@ -283,7 +282,7 @@
 	}}
 	for _, tt := range tests {
 		t.Run(tt.description, func(t *testing.T) {
-			result := prebuiltEtcFixtureFactory.RunTestWithBp(t, tt.config)
+			result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config)
 			p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
 			android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath)
 		})
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 8974eba..b2bd6bd 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -91,7 +91,7 @@
 
 var dependencyTag = struct {
 	blueprint.BaseDependencyTag
-	android.InstallAlwaysNeededDependencyTag
+	android.PackagingItemAlwaysDepTag
 }{}
 
 func (f *filesystem) DepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 199a7df..bb17e8e 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -28,8 +28,7 @@
 	os.Exit(m.Run())
 }
 
-var genruleFixtureFactory = android.NewFixtureFactory(
-	nil,
+var prepareForGenRuleTest = android.GroupFixturePreparers(
 	android.PrepareForTestWithArchMutator,
 	android.PrepareForTestWithDefaults,
 
@@ -447,7 +446,8 @@
 				expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
 			}
 
-			result := genruleFixtureFactory.Extend(
+			result := android.GroupFixturePreparers(
+				prepareForGenRuleTest,
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
 				}),
@@ -523,7 +523,7 @@
 		},
 	}
 
-	result := genruleFixtureFactory.RunTestWithBp(t, testGenruleBp()+bp)
+	result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
 
 	for _, test := range testcases {
 		t.Run(test.name, func(t *testing.T) {
@@ -605,7 +605,7 @@
 				expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
 			}
 
-			result := genruleFixtureFactory.
+			result := prepareForGenRuleTest.
 				ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
 				RunTestWithBp(t, testGenruleBp()+bp)
 
@@ -642,7 +642,7 @@
 				}
 			`
 
-	result := genruleFixtureFactory.RunTestWithBp(t, testGenruleBp()+bp)
+	result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
 
 	gen := result.Module("gen", "").(*Module)
 
@@ -662,11 +662,12 @@
 		}
 	`
 
-	result := genruleFixtureFactory.Extend(android.FixtureModifyConfig(func(config android.Config) {
-		config.BazelContext = android.MockBazelContext{
-			AllFiles: map[string][]string{
-				"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
-	})).RunTestWithBp(t, testGenruleBp()+bp)
+	result := android.GroupFixturePreparers(
+		prepareForGenRuleTest, android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				AllFiles: map[string][]string{
+					"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
+		})).RunTestWithBp(t, testGenruleBp()+bp)
 
 	gen := result.Module("foo", "").(*Module)
 
diff --git a/java/android_resources.go b/java/android_resources.go
index 4d420cf..6864ebb 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -22,8 +22,11 @@
 )
 
 func init() {
-	android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
+	registerOverlayBuildComponents(android.InitRegistrationContext)
+}
 
+func registerOverlayBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
 }
 
 var androidResourceIgnoreFilenames = []string{
diff --git a/java/java_test.go b/java/java_test.go
index 99a96e1..6bebf37 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -48,20 +48,34 @@
 	os.RemoveAll(buildDir)
 }
 
-var emptyFixtureFactory = android.NewFixtureFactory(&buildDir)
+// Legacy factory to use to create fixtures for tests in this package.
+//
+// deprecated: See prepareForJavaTest
+var javaFixtureFactory = android.NewFixtureFactory(
+	&buildDir,
+	prepareForJavaTest,
+)
 
-// Factory to use to create fixtures for tests in this package.
-var javaFixtureFactory = emptyFixtureFactory.Extend(
+// Legacy preparer used for running tests within the java package.
+//
+// This includes everything that was needed to run any test in the java package prior to the
+// introduction of the test fixtures. Tests that are being converted to use fixtures directly
+// rather than through the testJava...() methods should avoid using this and instead use the
+// various preparers directly, using android.GroupFixturePreparers(...) to group them when
+// necessary.
+//
+// deprecated
+var prepareForJavaTest = android.GroupFixturePreparers(
 	genrule.PrepareForTestWithGenRuleBuildComponents,
 	// Get the CC build components but not default modules.
 	cc.PrepareForTestWithCcBuildComponents,
 	// Include all the default java modules.
 	PrepareForTestWithJavaDefaultModules,
+	PrepareForTestWithOverlayBuildComponents,
 	python.PrepareForTestWithPythonBuildComponents,
 	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("java_plugin", PluginFactory)
 
-		ctx.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
 		ctx.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
 	}),
 	dexpreopt.PrepareForTestWithDexpreopt,
diff --git a/java/platform_compat_config_test.go b/java/platform_compat_config_test.go
index 0c5d001..1ff6ac3 100644
--- a/java/platform_compat_config_test.go
+++ b/java/platform_compat_config_test.go
@@ -21,7 +21,7 @@
 )
 
 func TestPlatformCompatConfig(t *testing.T) {
-	result := emptyFixtureFactory.RunTest(t,
+	result := android.GroupFixturePreparers(
 		PrepareForTestWithPlatformCompatConfig,
 		android.FixtureWithRootAndroidBp(`
 			platform_compat_config {
@@ -34,7 +34,7 @@
 				name: "myconfig3",
 			}
 		`),
-	)
+	).RunTest(t)
 
 	checkMergedCompatConfigInputs(t, result, "myconfig",
 		"out/soong/.intermediates/myconfig1/myconfig1_meta.xml",
diff --git a/java/testing.go b/java/testing.go
index 6fc3b03..2343294 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -39,18 +39,23 @@
 // module types as possible. The exceptions are those module types that require mutators and/or
 // singletons in order to function in which case they should be kept together in a separate
 // preparer.
-var PrepareForTestWithJavaBuildComponents = android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest)
+var PrepareForTestWithJavaBuildComponents = android.GroupFixturePreparers(
+	// Make sure that mutators and module types, e.g. prebuilt mutators available.
+	android.PrepareForTestWithAndroidBuildComponents,
+	// Make java build components available to the test.
+	android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
+)
 
 // Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
 var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
-	// Make sure that mutators and module types, e.g. prebuilt mutators available.
-	android.PrepareForTestWithAndroidBuildComponents,
 	// Make sure that all the module types used in the defaults are registered.
 	PrepareForTestWithJavaBuildComponents,
 	// The java default module definitions.
 	android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", GatherRequiredDepsForTest()),
 )
 
+var PrepareForTestWithOverlayBuildComponents = android.FixtureRegisterWithContext(registerOverlayBuildComponents)
+
 // Prepare a fixture to use all java module types, mutators and singletons fully.
 //
 // This should only be used by tests that want to run with as much of the build enabled as possible.
diff --git a/python/python_test.go b/python/python_test.go
index 6263c8a..f57f504 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -335,13 +335,12 @@
 		}
 
 		t.Run(d.desc, func(t *testing.T) {
-			result := emptyFixtureFactory.
-				ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(errorPatterns)).
-				RunTest(t,
-					android.PrepareForTestWithDefaults,
-					PrepareForTestWithPythonBuildComponents,
-					d.mockFiles.AddToFixture(),
-				)
+			result := android.GroupFixturePreparers(
+				android.PrepareForTestWithDefaults,
+				PrepareForTestWithPythonBuildComponents,
+				d.mockFiles.AddToFixture(),
+			).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(errorPatterns)).
+				RunTest(t)
 
 			if len(result.Errs) > 0 {
 				return
@@ -376,8 +375,6 @@
 	android.AssertPathsRelativeToTopEquals(t, "depsSrcsZips", expectedDepsSrcsZips, base.depsSrcsZips)
 }
 
-var emptyFixtureFactory = android.NewFixtureFactory(nil)
-
 func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
diff --git a/scripts/update-apex-allowed-deps.sh b/scripts/update-apex-allowed-deps.sh
deleted file mode 100755
index 872d746..0000000
--- a/scripts/update-apex-allowed-deps.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash -e
-#
-# The script to run locally to re-generate global allowed list of dependencies
-# for updatable modules.
-
-if [ ! -e "build/envsetup.sh" ]; then
-  echo "ERROR: $0 must be run from the top of the tree"
-  exit 1
-fi
-
-source build/envsetup.sh > /dev/null || exit 1
-
-readonly OUT_DIR=$(get_build_var OUT_DIR)
-
-readonly ALLOWED_DEPS_FILE="build/soong/apex/allowed_deps.txt"
-readonly NEW_ALLOWED_DEPS_FILE="${OUT_DIR}/soong/apex/depsinfo/new-allowed-deps.txt"
-
-# If the script is run after droidcore failure, ${NEW_ALLOWED_DEPS_FILE}
-# should already be built. If running the script manually, make sure it exists.
-m "${NEW_ALLOWED_DEPS_FILE}" -j
-
-cat > "${ALLOWED_DEPS_FILE}" << EndOfFileComment
-# A list of allowed dependencies for all updatable modules.
-#
-# The list tracks all direct and transitive dependencies that end up within any
-# of the updatable binaries; specifically excluding external dependencies
-# required to compile those binaries. This prevents potential regressions in
-# case a new dependency is not aware of the different functional and
-# non-functional requirements being part of an updatable module, for example
-# setting correct min_sdk_version.
-#
-# To update the list, run:
-# repo-root$ build/soong/scripts/update-apex-allowed-deps.sh
-#
-# See go/apex-allowed-deps-error for more details.
-# TODO(b/157465465): introduce automated quality signals and remove this list.
-EndOfFileComment
-
-cat "${NEW_ALLOWED_DEPS_FILE}" >> "${ALLOWED_DEPS_FILE}"
diff --git a/sdk/boot_image_sdk_test.go b/sdk/boot_image_sdk_test.go
index 9805a6a..bc09bbc 100644
--- a/sdk/boot_image_sdk_test.go
+++ b/sdk/boot_image_sdk_test.go
@@ -14,20 +14,27 @@
 
 package sdk
 
-import "testing"
+import (
+	"testing"
+
+	"android/soong/android"
+)
 
 func TestSnapshotWithBootImage(t *testing.T) {
-	result := testSdkWithJava(t, `
-		sdk {
-			name: "mysdk",
-			boot_images: ["mybootimage"],
-		}
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				boot_images: ["mybootimage"],
+			}
 
-		boot_image {
-			name: "mybootimage",
-			image_name: "art",
-		}
-	`)
+			boot_image {
+				name: "mybootimage",
+				image_name: "art",
+			}
+		`),
+	).RunTest(t)
 
 	CheckSnapshot(t, result, "mysdk", "",
 		checkUnversionedAndroidBpContents(`
diff --git a/sdk/bp_test.go b/sdk/bp_test.go
index 2bd8a43..c620ac2 100644
--- a/sdk/bp_test.go
+++ b/sdk/bp_test.go
@@ -84,9 +84,9 @@
 		set.AddProperty(name, val)
 		android.AssertDeepEquals(t, "wrong value", val, set.getValue(name))
 	}
-	android.AssertPanic(t, "adding x again should panic",
+	android.AssertPanicMessageContains(t, "adding x again should panic", `Property "x" already exists in property set`,
 		func() { set.AddProperty("x", "taxi") })
-	android.AssertPanic(t, "adding arr again should panic",
+	android.AssertPanicMessageContains(t, "adding arr again should panic", `Property "arr" already exists in property set`,
 		func() { set.AddProperty("arr", []string{"d"}) })
 }
 
@@ -124,14 +124,14 @@
 
 	t.Run("add conflicting subset", func(t *testing.T) {
 		set := propertySetFixture().(*bpPropertySet)
-		android.AssertPanic(t, "adding x again should panic",
+		android.AssertPanicMessageContains(t, "adding x again should panic", `Property "x" already exists in property set`,
 			func() { set.AddProperty("x", propertySetFixture()) })
 	})
 
 	t.Run("add non-pointer struct", func(t *testing.T) {
 		set := propertySetFixture().(*bpPropertySet)
 		str := propertyStructFixture().(*propertyStruct)
-		android.AssertPanic(t, "adding a non-pointer struct should panic",
+		android.AssertPanicMessageContains(t, "adding a non-pointer struct should panic", "Value is a struct, not a pointer to one:",
 			func() { set.AddProperty("new", *str) })
 	})
 }
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index a2539c9..9626a04 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -808,7 +808,8 @@
 }
 
 func TestSnapshotWithSingleHostOsType(t *testing.T) {
-	result := sdkFixtureFactory.Extend(
+	result := android.GroupFixturePreparers(
+		prepareForSdkTest,
 		ccTestFs.AddToFixture(),
 		cc.PrepareForTestOnLinuxBionic,
 		android.FixtureModifyConfig(func(config android.Config) {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index f4e9380..2be3c9c 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -21,6 +21,11 @@
 	"android/soong/java"
 )
 
+var prepareForSdkTestWithJava = android.GroupFixturePreparers(
+	java.PrepareForTestWithJavaBuildComponents,
+	PrepareForTestWithSdkBuildComponents,
+)
+
 func testSdkWithJava(t *testing.T, bp string) *android.TestResult {
 	t.Helper()
 
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 6ca8512..e561529 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -445,20 +445,26 @@
 	}
 }
 
+// An interface that encapsulates all the functionality needed to manage the sdk dependencies.
+//
+// It is a mixture of apex and sdk module functionality.
+type sdkAndApexModule interface {
+	android.Module
+	android.DepIsInSameApex
+	android.RequiredSdks
+}
+
 // Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
 // descendants
 func sdkDepsMutator(mctx android.TopDownMutatorContext) {
-	if parent, ok := mctx.Module().(interface {
-		android.DepIsInSameApex
-		android.RequiredSdks
-	}); ok {
+	if parent, ok := mctx.Module().(sdkAndApexModule); ok {
 		// Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
 		// by reading its own properties like `uses_sdks`.
 		requiredSdks := parent.RequiredSdks()
 		if len(requiredSdks) > 0 {
 			mctx.VisitDirectDeps(func(m android.Module) {
 				// Only propagate required sdks from the apex onto its contents.
-				if dep, ok := m.(android.SdkAware); ok && parent.DepIsInSameApex(mctx, dep) {
+				if dep, ok := m.(android.SdkAware); ok && android.IsDepInSameApex(mctx, parent, dep) {
 					dep.BuildWithSdks(requiredSdks)
 				}
 			})
@@ -497,10 +503,7 @@
 
 // Step 6: ensure that the dependencies outside of the APEX are all from the required SDKs
 func sdkRequirementsMutator(mctx android.TopDownMutatorContext) {
-	if m, ok := mctx.Module().(interface {
-		android.DepIsInSameApex
-		android.RequiredSdks
-	}); ok {
+	if m, ok := mctx.Module().(sdkAndApexModule); ok {
 		requiredSdks := m.RequiredSdks()
 		if len(requiredSdks) == 0 {
 			return
@@ -519,9 +522,18 @@
 				return
 			}
 
-			// If the dep is outside of the APEX, but is not in any of the
-			// required SDKs, we know that the dep is a violation.
+			// If the dep is outside of the APEX, but is not in any of the required SDKs, we know that the
+			// dep is a violation.
 			if sa, ok := dep.(android.SdkAware); ok {
+				// It is not an error if a dependency that is excluded from the apex due to the tag is not
+				// in one of the required SDKs. That is because all of the existing tags that implement it
+				// do not depend on modules which can or should belong to an sdk_snapshot.
+				if _, ok := tag.(android.ExcludeFromApexContentsTag); ok {
+					// The tag defines a dependency that never requires the child module to be part of the
+					// same apex.
+					return
+				}
+
 				if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) {
 					mctx.ModuleErrorf("depends on %q (in SDK %q) that isn't part of the required SDKs: %v",
 						sa.Name(), sa.ContainingSdk(), requiredSdks)
diff --git a/sdk/testing.go b/sdk/testing.go
index 6df402c..d21f425 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -27,14 +27,9 @@
 	"android/soong/java"
 )
 
-var sdkFixtureFactory = android.NewFixtureFactory(
-	nil,
+// Prepare for running an sdk test with an apex.
+var prepareForSdkTestWithApex = android.GroupFixturePreparers(
 	apex.PrepareForTestWithApexBuildComponents,
-	cc.PrepareForTestWithCcDefaultModules,
-	genrule.PrepareForTestWithGenRuleBuildComponents,
-	java.PrepareForTestWithJavaBuildComponents,
-	PrepareForTestWithSdkBuildComponents,
-
 	android.FixtureAddTextFile("sdk/tests/Android.bp", `
 		apex_key {
 			name: "myapex.key",
@@ -59,6 +54,24 @@
 		"myapex.x509.pem":                              nil,
 		"myapex.pk8":                                   nil,
 	}),
+)
+
+// Legacy preparer used for running tests within the sdk package.
+//
+// This includes everything that was needed to run any test in the sdk package prior to the
+// introduction of the test fixtures. Tests that are being converted to use fixtures directly
+// rather than through the testSdkError() and testSdkWithFs() methods should avoid using this and
+// instead should use the various preparers directly using android.GroupFixturePreparers(...) to
+// group them when necessary.
+//
+// deprecated
+var prepareForSdkTest = android.GroupFixturePreparers(
+	cc.PrepareForTestWithCcDefaultModules,
+	genrule.PrepareForTestWithGenRuleBuildComponents,
+	java.PrepareForTestWithJavaBuildComponents,
+	PrepareForTestWithSdkBuildComponents,
+
+	prepareForSdkTestWithApex,
 
 	cc.PrepareForTestOnWindows,
 	android.FixtureModifyConfig(func(config android.Config) {
@@ -77,12 +90,12 @@
 
 func testSdkWithFs(t *testing.T, bp string, fs android.MockFS) *android.TestResult {
 	t.Helper()
-	return sdkFixtureFactory.RunTest(t, fs.AddToFixture(), android.FixtureWithRootAndroidBp(bp))
+	return prepareForSdkTest.RunTest(t, fs.AddToFixture(), android.FixtureWithRootAndroidBp(bp))
 }
 
 func testSdkError(t *testing.T, pattern, bp string) {
 	t.Helper()
-	sdkFixtureFactory.
+	prepareForSdkTest.
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
 		RunTestWithBp(t, bp)
 }
@@ -201,13 +214,33 @@
 
 	// Populate a mock filesystem with the files that would have been copied by
 	// the rules.
-	fs := make(map[string][]byte)
+	fs := android.MockFS{}
+	snapshotSubDir := "snapshot"
 	for _, dest := range snapshotBuildInfo.snapshotContents {
-		fs[dest] = nil
+		fs[filepath.Join(snapshotSubDir, dest)] = nil
 	}
+	fs[filepath.Join(snapshotSubDir, "Android.bp")] = []byte(snapshotBuildInfo.androidBpContents)
 
-	// Process the generated bp file to make sure it is valid.
-	testSdkWithFs(t, snapshotBuildInfo.androidBpContents, fs)
+	preparer := result.Preparer()
+
+	// Process the generated bp file to make sure it is valid. Use the same preparer as was used to
+	// produce this result.
+	t.Run("snapshot without source", func(t *testing.T) {
+		android.GroupFixturePreparers(
+			preparer,
+			// TODO(b/183184375): Set Config.TestAllowNonExistentPaths = false to verify that all the
+			//  files the snapshot needs are actually copied into the snapshot.
+
+			// Add the files (including bp) created for this snapshot to the test fixture.
+			fs.AddToFixture(),
+
+			// Remove the source Android.bp file to make sure it works without.
+			// TODO(b/183184375): Add a test with the source.
+			android.FixtureModifyMockFS(func(fs android.MockFS) {
+				delete(fs, "Android.bp")
+			}),
+		).RunTest(t)
+	})
 }
 
 type snapshotBuildInfoChecker func(info *snapshotBuildInfo)
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 5887b56..9e7e594 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -13,8 +13,7 @@
 	os.Exit(m.Run())
 }
 
-var shFixtureFactory = android.NewFixtureFactory(
-	nil,
+var prepareForShTest = android.GroupFixturePreparers(
 	cc.PrepareForTestWithCcBuildComponents,
 	PrepareForTestWithShBuildComponents,
 	android.FixtureMergeMockFs(android.MockFS{
@@ -24,19 +23,19 @@
 	}),
 )
 
-// testShBinary runs tests using the shFixtureFactory
+// testShBinary runs tests using the prepareForShTest
 //
-// Do not add any new usages of this, instead use the shFixtureFactory directly as it makes it much
+// Do not add any new usages of this, instead use the prepareForShTest directly as it makes it much
 // easier to customize the test behavior.
 //
 // If it is necessary to customize the behavior of an existing test that uses this then please first
-// convert the test to using shFixtureFactory first and then in a following change add the
+// convert the test to using prepareForShTest first and then in a following change add the
 // appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify
 // that it did not change the test behavior unexpectedly.
 //
 // deprecated
 func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config) {
-	result := shFixtureFactory.RunTestWithBp(t, bp)
+	result := prepareForShTest.RunTestWithBp(t, bp)
 
 	return result.TestContext, result.Config
 }
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index cb1e362..e9d9051 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -30,8 +30,6 @@
 	os.Exit(m.Run())
 }
 
-var emptyFixtureFactory = android.NewFixtureFactory(nil)
-
 func test(t *testing.T, bp string) *android.TestResult {
 	t.Helper()
 
@@ -124,7 +122,7 @@
 		"com/android2/OdmProperties.sysprop":         nil,
 	}
 
-	result := emptyFixtureFactory.RunTest(t,
+	result := android.GroupFixturePreparers(
 		cc.PrepareForTestWithCcDefaultModules,
 		java.PrepareForTestWithJavaDefaultModules,
 		PrepareForTestWithSyspropBuildComponents,
@@ -135,7 +133,7 @@
 		}),
 		mockFS.AddToFixture(),
 		android.FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 
 	return result
 }
diff --git a/xml/xml_test.go b/xml/xml_test.go
index 83ae51c..a59a293 100644
--- a/xml/xml_test.go
+++ b/xml/xml_test.go
@@ -26,8 +26,6 @@
 	os.Exit(m.Run())
 }
 
-var emptyFixtureFactory = android.NewFixtureFactory(nil)
-
 func testXml(t *testing.T, bp string) *android.TestResult {
 	fs := android.MockFS{
 		"foo.xml": nil,
@@ -37,13 +35,13 @@
 		"baz.xml": nil,
 	}
 
-	return emptyFixtureFactory.RunTest(t,
+	return android.GroupFixturePreparers(
 		android.PrepareForTestWithArchMutator,
 		etc.PrepareForTestWithPrebuiltEtc,
 		PreparerForTestWithXmlBuildComponents,
 		fs.AddToFixture(),
 		android.FixtureWithRootAndroidBp(bp),
-	)
+	).RunTest(t)
 }
 
 // Minimal test