Merge "Really fix queryview."
diff --git a/android/fixture.go b/android/fixture.go
index 2c8997b..2085e43 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -564,7 +564,11 @@
 }
 
 func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixtureFactory {
-	all := append(f.preparers, dedupAndFlattenPreparers(f.preparers, preparers)...)
+	// 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
diff --git a/android/mutator.go b/android/mutator.go
index b023001..9552aa1 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -33,22 +33,8 @@
 //   run FinalDeps mutators (CreateVariations disallowed in this phase)
 //   continue on to GenerateAndroidBuildActions
 
-func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
-	for _, t := range mutators {
-		var handle blueprint.MutatorHandle
-		if t.bottomUpMutator != nil {
-			handle = ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator)
-		} else if t.topDownMutator != nil {
-			handle = ctx.RegisterTopDownMutator(t.name, t.topDownMutator)
-		}
-		if t.parallel {
-			handle.Parallel()
-		}
-	}
-}
-
 // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
-func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, preArchMutators, depsMutators, bp2buildMutators []RegisterMutatorFunc) {
+func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators, depsMutators, bp2buildMutators []RegisterMutatorFunc) {
 	mctx := &registerMutatorsContext{
 		bazelConversionMode: true,
 	}
@@ -80,10 +66,17 @@
 		f(mctx)
 	}
 
-	registerMutatorsToContext(ctx, mctx.mutators)
+	mctx.mutators.registerAll(ctx)
 }
 
-func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) {
+// collateGloballyRegisteredMutators constructs the list of mutators that have been registered
+// with the InitRegistrationContext and will be used at runtime.
+func collateGloballyRegisteredMutators() sortableComponents {
+	return collateRegisteredMutators(preArch, preDeps, postDeps, finalDeps)
+}
+
+// collateRegisteredMutators constructs a single list of mutators from the separate lists.
+func collateRegisteredMutators(preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) sortableComponents {
 	mctx := &registerMutatorsContext{}
 
 	register := func(funcs []RegisterMutatorFunc) {
@@ -103,11 +96,11 @@
 	mctx.finalPhase = true
 	register(finalDeps)
 
-	registerMutatorsToContext(ctx, mctx.mutators)
+	return mctx.mutators
 }
 
 type registerMutatorsContext struct {
-	mutators            []*mutator
+	mutators            sortableComponents
 	finalPhase          bool
 	bazelConversionMode bool
 }
@@ -473,6 +466,23 @@
 	return mutator
 }
 
+func (mutator *mutator) componentName() string {
+	return mutator.name
+}
+
+func (mutator *mutator) register(ctx *Context) {
+	blueprintCtx := ctx.Context
+	var handle blueprint.MutatorHandle
+	if mutator.bottomUpMutator != nil {
+		handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator)
+	} else if mutator.topDownMutator != nil {
+		handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator)
+	}
+	if mutator.parallel {
+		handle.Parallel()
+	}
+}
+
 type MutatorHandle interface {
 	Parallel() MutatorHandle
 }
diff --git a/android/register.go b/android/register.go
index 47df972..c9e66e9 100644
--- a/android/register.go
+++ b/android/register.go
@@ -21,21 +21,78 @@
 	"github.com/google/blueprint"
 )
 
+// A sortable component is one whose registration order affects the order in which it is executed
+// and so affects the behavior of the build system. As a result it is important for the order in
+// which they are registered during tests to match the order used at runtime and so the test
+// infrastructure will sort them to match.
+//
+// The sortable components are mutators, singletons and pre-singletons. Module types are not
+// sortable because their order of registration does not affect the runtime behavior.
+type sortableComponent interface {
+	// componentName returns the name of the component.
+	//
+	// Uniquely identifies the components within the set of components used at runtimr and during
+	// tests.
+	componentName() string
+
+	// register registers this component in the supplied context.
+	register(ctx *Context)
+}
+
+type sortableComponents []sortableComponent
+
+// registerAll registers all components in this slice with the supplied context.
+func (r sortableComponents) registerAll(ctx *Context) {
+	for _, c := range r {
+		c.register(ctx)
+	}
+}
+
 type moduleType struct {
 	name    string
 	factory ModuleFactory
 }
 
+func (t moduleType) register(ctx *Context) {
+	ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
+}
+
 var moduleTypes []moduleType
 var moduleTypesForDocs = map[string]reflect.Value{}
 
 type singleton struct {
+	// True if this should be registered as a pre-singleton, false otherwise.
+	pre bool
+
 	name    string
 	factory SingletonFactory
 }
 
-var singletons []singleton
-var preSingletons []singleton
+func newSingleton(name string, factory SingletonFactory) singleton {
+	return singleton{false, name, factory}
+}
+
+func newPreSingleton(name string, factory SingletonFactory) singleton {
+	return singleton{true, name, factory}
+}
+
+func (s singleton) componentName() string {
+	return s.name
+}
+
+func (s singleton) register(ctx *Context) {
+	adaptor := SingletonFactoryAdaptor(ctx, s.factory)
+	if s.pre {
+		ctx.RegisterPreSingletonType(s.name, adaptor)
+	} else {
+		ctx.RegisterSingletonType(s.name, adaptor)
+	}
+}
+
+var _ sortableComponent = singleton{}
+
+var singletons sortableComponents
+var preSingletons sortableComponents
 
 type mutator struct {
 	name            string
@@ -44,6 +101,8 @@
 	parallel        bool
 }
 
+var _ sortableComponent = &mutator{}
+
 type ModuleFactory func() Module
 
 // ModuleFactoryAdaptor wraps a ModuleFactory into a blueprint.ModuleFactory by converting a Module
@@ -84,11 +143,11 @@
 }
 
 func RegisterSingletonType(name string, factory SingletonFactory) {
-	singletons = append(singletons, singleton{name, factory})
+	singletons = append(singletons, newSingleton(name, factory))
 }
 
 func RegisterPreSingletonType(name string, factory SingletonFactory) {
-	preSingletons = append(preSingletons, singleton{name, factory})
+	preSingletons = append(preSingletons, newPreSingleton(name, factory))
 }
 
 type Context struct {
@@ -107,46 +166,51 @@
 // files to semantically equivalent BUILD files.
 func (ctx *Context) RegisterForBazelConversion() {
 	for _, t := range moduleTypes {
-		ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
+		t.register(ctx)
 	}
 
 	// Required for SingletonModule types, even though we are not using them.
 	for _, t := range singletons {
-		ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
+		t.register(ctx)
 	}
 
-	RegisterMutatorsForBazelConversion(ctx.Context, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutators)
 }
 
 // Register the pipeline of singletons, module types, and mutators for
 // generating build.ninja and other files for Kati, from Android.bp files.
 func (ctx *Context) Register() {
-	for _, t := range preSingletons {
-		ctx.RegisterPreSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
-	}
+	preSingletons.registerAll(ctx)
 
 	for _, t := range moduleTypes {
-		ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
+		t.register(ctx)
 	}
 
-	for _, t := range singletons {
-		ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
-	}
+	mutators := collateGloballyRegisteredMutators()
+	mutators.registerAll(ctx)
 
-	registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps)
+	singletons := collateGloballyRegisteredSingletons()
+	singletons.registerAll(ctx)
+}
 
-	ctx.RegisterSingletonType("bazeldeps", SingletonFactoryAdaptor(ctx, BazelSingleton))
+func collateGloballyRegisteredSingletons() sortableComponents {
+	allSingletons := append(sortableComponents(nil), singletons...)
+	allSingletons = append(allSingletons,
+		singleton{false, "bazeldeps", BazelSingleton},
 
-	// Register phony just before makevars so it can write out its phony rules as Make rules
-	ctx.RegisterSingletonType("phony", SingletonFactoryAdaptor(ctx, phonySingletonFactory))
+		// Register phony just before makevars so it can write out its phony rules as Make rules
+		singleton{false, "phony", phonySingletonFactory},
 
-	// Register makevars after other singletons so they can export values through makevars
-	ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(ctx, makeVarsSingletonFunc))
+		// Register makevars after other singletons so they can export values through makevars
+		singleton{false, "makevars", makeVarsSingletonFunc},
 
-	// Register env and ninjadeps last so that they can track all used environment variables and
-	// Ninja file dependencies stored in the config.
-	ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(ctx, EnvSingleton))
-	ctx.RegisterSingletonType("ninjadeps", SingletonFactoryAdaptor(ctx, ninjaDepsSingletonFactory))
+		// Register env and ninjadeps last so that they can track all used environment variables and
+		// Ninja file dependencies stored in the config.
+		singleton{false, "env", EnvSingleton},
+		singleton{false, "ninjadeps", ninjaDepsSingletonFactory},
+	)
+
+	return allSingletons
 }
 
 func ModuleTypeFactories() map[string]ModuleFactory {
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index c62e76d..34b180d 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -295,18 +295,25 @@
 	recurse = func(prefix string, aps []string) ([]string, reflect.Type) {
 		var fields []reflect.StructField
 
+		// Iterate while the list is non-empty so it can be modified in the loop.
 		for len(affectableProperties) > 0 {
 			p := affectableProperties[0]
 			if !strings.HasPrefix(affectableProperties[0], prefix) {
+				// The properties are sorted and recurse is always called with a prefix that matches
+				// the first property in the list, so if we've reached one that doesn't match the
+				// prefix we are done with this prefix.
 				break
 			}
-			affectableProperties = affectableProperties[1:]
 
 			nestedProperty := strings.TrimPrefix(p, prefix)
 			if i := strings.IndexRune(nestedProperty, '.'); i >= 0 {
 				var nestedType reflect.Type
 				nestedPrefix := nestedProperty[:i+1]
 
+				// Recurse to handle the properties with the found prefix.  This will return
+				// an updated affectableProperties with the handled entries removed from the front
+				// of the list, and the type that contains the handled entries.  The type may be
+				// nil if none of the entries matched factoryProps.
 				affectableProperties, nestedType = recurse(prefix+nestedPrefix, affectableProperties)
 
 				if nestedType != nil {
@@ -325,6 +332,8 @@
 						Type: typ,
 					})
 				}
+				// The first element in the list has been handled, remove it from the list.
+				affectableProperties = affectableProperties[1:]
 			}
 		}
 
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index b824c78..48cdfe7 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -235,6 +235,44 @@
 			}{},
 			want: "",
 		},
+		{
+			name:                 "nested",
+			affectableProperties: []string{"multilib.lib32.cflags"},
+			factoryProps: struct {
+				Multilib struct {
+					Lib32 struct {
+						Cflags string
+					}
+				}
+			}{},
+			want: "*struct { Multilib struct { Lib32 struct { Cflags string } } }",
+		},
+		{
+			name: "complex",
+			affectableProperties: []string{
+				"cflags",
+				"multilib.lib32.cflags",
+				"multilib.lib32.ldflags",
+				"multilib.lib64.cflags",
+				"multilib.lib64.ldflags",
+				"zflags",
+			},
+			factoryProps: struct {
+				Cflags   string
+				Multilib struct {
+					Lib32 struct {
+						Cflags  string
+						Ldflags string
+					}
+					Lib64 struct {
+						Cflags  string
+						Ldflags string
+					}
+				}
+				Zflags string
+			}{},
+			want: "*struct { Cflags string; Multilib struct { Lib32 struct { Cflags string; Ldflags string }; Lib64 struct { Cflags string; Ldflags string } }; Zflags string }",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/android/testing.go b/android/testing.go
index d8c123b..2c24372 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -20,6 +20,7 @@
 	"regexp"
 	"sort"
 	"strings"
+	"sync"
 	"testing"
 
 	"github.com/google/blueprint"
@@ -96,6 +97,13 @@
 	preArch, preDeps, postDeps, finalDeps           []RegisterMutatorFunc
 	bp2buildPreArch, bp2buildDeps, bp2buildMutators []RegisterMutatorFunc
 	NameResolver                                    *NameResolver
+
+	// The list of pre-singletons and singletons registered for the test.
+	preSingletons, singletons sortableComponents
+
+	// The order in which the pre-singletons, mutators and singletons will be run in this test
+	// context; for debugging.
+	preSingletonOrder, mutatorOrder, singletonOrder []string
 }
 
 func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
@@ -140,15 +148,244 @@
 	ctx.bp2buildDeps = append(ctx.bp2buildDeps, f)
 }
 
-func (ctx *TestContext) Register() {
-	registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
+// registeredComponentOrder defines the order in which a sortableComponent type is registered at
+// runtime and provides support for reordering the components registered for a test in the same
+// way.
+type registeredComponentOrder struct {
+	// The name of the component type, used for error messages.
+	componentType string
 
+	// The names of the registered components in the order in which they were registered.
+	namesInOrder []string
+
+	// Maps from the component name to its position in the runtime ordering.
+	namesToIndex map[string]int
+
+	// A function that defines the order between two named components that can be used to sort a slice
+	// of component names into the same order as they appear in namesInOrder.
+	less func(string, string) bool
+}
+
+// registeredComponentOrderFromExistingOrder takes an existing slice of sortableComponents and
+// creates a registeredComponentOrder that contains a less function that can be used to sort a
+// subset of that list of names so it is in the same order as the original sortableComponents.
+func registeredComponentOrderFromExistingOrder(componentType string, existingOrder sortableComponents) registeredComponentOrder {
+	// Only the names from the existing order are needed for this so create a list of component names
+	// in the correct order.
+	namesInOrder := componentsToNames(existingOrder)
+
+	// Populate the map from name to position in the list.
+	nameToIndex := make(map[string]int)
+	for i, n := range namesInOrder {
+		nameToIndex[n] = i
+	}
+
+	// A function to use to map from a name to an index in the original order.
+	indexOf := func(name string) int {
+		index, ok := nameToIndex[name]
+		if !ok {
+			// Should never happen as tests that use components that are not known at runtime do not sort
+			// so should never use this function.
+			panic(fmt.Errorf("internal error: unknown %s %q should be one of %s", componentType, name, strings.Join(namesInOrder, ", ")))
+		}
+		return index
+	}
+
+	// The less function.
+	less := func(n1, n2 string) bool {
+		i1 := indexOf(n1)
+		i2 := indexOf(n2)
+		return i1 < i2
+	}
+
+	return registeredComponentOrder{
+		componentType: componentType,
+		namesInOrder:  namesInOrder,
+		namesToIndex:  nameToIndex,
+		less:          less,
+	}
+}
+
+// componentsToNames maps from the slice of components to a slice of their names.
+func componentsToNames(components sortableComponents) []string {
+	names := make([]string, len(components))
+	for i, c := range components {
+		names[i] = c.componentName()
+	}
+	return names
+}
+
+// enforceOrdering enforces the supplied components are in the same order as is defined in this
+// object.
+//
+// If the supplied components contains any components that are not registered at runtime, i.e. test
+// specific components, then it is impossible to sort them into an order that both matches the
+// runtime and also preserves the implicit ordering defined in the test. In that case it will not
+// sort the components, instead it will just check that the components are in the correct order.
+//
+// Otherwise, this will sort the supplied components in place.
+func (o *registeredComponentOrder) enforceOrdering(components sortableComponents) {
+	// Check to see if the list of components contains any components that are
+	// not registered at runtime.
+	var unknownComponents []string
+	testOrder := componentsToNames(components)
+	for _, name := range testOrder {
+		if _, ok := o.namesToIndex[name]; !ok {
+			unknownComponents = append(unknownComponents, name)
+			break
+		}
+	}
+
+	// If the slice contains some unknown components then it is not possible to
+	// sort them into an order that matches the runtime while also preserving the
+	// order expected from the test, so in that case don't sort just check that
+	// the order of the known mutators does match.
+	if len(unknownComponents) > 0 {
+		// Check order.
+		o.checkTestOrder(testOrder, unknownComponents)
+	} else {
+		// Sort the components.
+		sort.Slice(components, func(i, j int) bool {
+			n1 := components[i].componentName()
+			n2 := components[j].componentName()
+			return o.less(n1, n2)
+		})
+	}
+}
+
+// checkTestOrder checks that the supplied testOrder matches the one defined by this object,
+// panicking if it does not.
+func (o *registeredComponentOrder) checkTestOrder(testOrder []string, unknownComponents []string) {
+	lastMatchingTest := -1
+	matchCount := 0
+	// Take a copy of the runtime order as it is modified during the comparison.
+	runtimeOrder := append([]string(nil), o.namesInOrder...)
+	componentType := o.componentType
+	for i, j := 0, 0; i < len(testOrder) && j < len(runtimeOrder); {
+		test := testOrder[i]
+		runtime := runtimeOrder[j]
+
+		if test == runtime {
+			testOrder[i] = test + fmt.Sprintf(" <-- matched with runtime %s %d", componentType, j)
+			runtimeOrder[j] = runtime + fmt.Sprintf(" <-- matched with test %s %d", componentType, i)
+			lastMatchingTest = i
+			i += 1
+			j += 1
+			matchCount += 1
+		} else if _, ok := o.namesToIndex[test]; !ok {
+			// The test component is not registered globally so assume it is the correct place, treat it
+			// as having matched and skip it.
+			i += 1
+			matchCount += 1
+		} else {
+			// Assume that the test list is in the same order as the runtime list but the runtime list
+			// contains some components that are not present in the tests. So, skip the runtime component
+			// to try and find the next one that matches the current test component.
+			j += 1
+		}
+	}
+
+	// If every item in the test order was either test specific or matched one in the runtime then
+	// it is in the correct order. Otherwise, it was not so fail.
+	if matchCount != len(testOrder) {
+		// The test component names were not all matched with a runtime component name so there must
+		// either be a component present in the test that is not present in the runtime or they must be
+		// in the wrong order.
+		testOrder[lastMatchingTest+1] = testOrder[lastMatchingTest+1] + " <--- unmatched"
+		panic(fmt.Errorf("the tests uses test specific components %q and so cannot be automatically sorted."+
+			" Unfortunately it uses %s components in the wrong order.\n"+
+			"test order:\n    %s\n"+
+			"runtime order\n    %s\n",
+			SortedUniqueStrings(unknownComponents),
+			componentType,
+			strings.Join(testOrder, "\n    "),
+			strings.Join(runtimeOrder, "\n    ")))
+	}
+}
+
+// registrationSorter encapsulates the information needed to ensure that the test mutators are
+// registered, and thereby executed, in the same order as they are at runtime.
+//
+// It MUST be populated lazily AFTER all package initialization has been done otherwise it will
+// only define the order for a subset of all the registered build components that are available for
+// the packages being tested.
+//
+// e.g if this is initialized during say the cc package initialization then any tests run in the
+// java package will not sort build components registered by the java package's init() functions.
+type registrationSorter struct {
+	// Used to ensure that this is only created once.
+	once sync.Once
+
+	// The order of pre-singletons
+	preSingletonOrder registeredComponentOrder
+
+	// The order of mutators
+	mutatorOrder registeredComponentOrder
+
+	// The order of singletons
+	singletonOrder registeredComponentOrder
+}
+
+// populate initializes this structure from globally registered build components.
+//
+// Only the first call has any effect.
+func (s *registrationSorter) populate() {
+	s.once.Do(func() {
+		// Create an ordering from the globally registered pre-singletons.
+		s.preSingletonOrder = registeredComponentOrderFromExistingOrder("pre-singleton", preSingletons)
+
+		// Created an ordering from the globally registered mutators.
+		globallyRegisteredMutators := collateGloballyRegisteredMutators()
+		s.mutatorOrder = registeredComponentOrderFromExistingOrder("mutator", globallyRegisteredMutators)
+
+		// Create an ordering from the globally registered singletons.
+		globallyRegisteredSingletons := collateGloballyRegisteredSingletons()
+		s.singletonOrder = registeredComponentOrderFromExistingOrder("singleton", globallyRegisteredSingletons)
+	})
+}
+
+// Provides support for enforcing the same order in which build components are registered globally
+// to the order in which they are registered during tests.
+//
+// MUST only be accessed via the globallyRegisteredComponentsOrder func.
+var globalRegistrationSorter registrationSorter
+
+// globallyRegisteredComponentsOrder returns the globalRegistrationSorter after ensuring it is
+// correctly populated.
+func globallyRegisteredComponentsOrder() *registrationSorter {
+	globalRegistrationSorter.populate()
+	return &globalRegistrationSorter
+}
+
+func (ctx *TestContext) Register() {
+	globalOrder := globallyRegisteredComponentsOrder()
+
+	// Ensure that the pre-singletons used in the test are in the same order as they are used at
+	// runtime.
+	globalOrder.preSingletonOrder.enforceOrdering(ctx.preSingletons)
+	ctx.preSingletons.registerAll(ctx.Context)
+
+	mutators := collateRegisteredMutators(ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
+	// Ensure that the mutators used in the test are in the same order as they are used at runtime.
+	globalOrder.mutatorOrder.enforceOrdering(mutators)
+	mutators.registerAll(ctx.Context)
+
+	// Register the env singleton with this context before sorting.
 	ctx.RegisterSingletonType("env", EnvSingleton)
+
+	// Ensure that the singletons used in the test are in the same order as they are used at runtime.
+	globalOrder.singletonOrder.enforceOrdering(ctx.singletons)
+	ctx.singletons.registerAll(ctx.Context)
+
+	// Save the sorted components order away to make them easy to access while debugging.
+	ctx.preSingletonOrder = componentsToNames(preSingletons)
+	ctx.mutatorOrder = componentsToNames(mutators)
+	ctx.singletonOrder = componentsToNames(singletons)
 }
 
 // RegisterForBazelConversion prepares a test context for bp2build conversion.
 func (ctx *TestContext) RegisterForBazelConversion() {
-	RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildPreArch, ctx.bp2buildDeps, ctx.bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch, ctx.bp2buildDeps, ctx.bp2buildMutators)
 }
 
 func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
@@ -174,11 +411,11 @@
 }
 
 func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) {
-	ctx.Context.RegisterSingletonType(name, SingletonFactoryAdaptor(ctx.Context, factory))
+	ctx.singletons = append(ctx.singletons, newSingleton(name, factory))
 }
 
 func (ctx *TestContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	ctx.Context.RegisterPreSingletonType(name, SingletonFactoryAdaptor(ctx.Context, factory))
+	ctx.preSingletons = append(ctx.preSingletons, newPreSingleton(name, factory))
 }
 
 func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule {
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 047a0f3..faa6569 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -163,6 +163,7 @@
 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)
@@ -306,6 +307,7 @@
 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))
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e3b7f95..991f5c9 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -67,14 +67,14 @@
 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
 }
 
-func testApex(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
+func testApex(t *testing.T, bp string, handlers ...testCustomizer) *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, config
+	return ctx
 }
 
 type testCustomizer func(fs map[string][]byte, config android.Config)
@@ -360,7 +360,7 @@
 
 // Minimal test
 func TestBasicApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_defaults {
 			name: "myapex-defaults",
 			manifest: ":myapex.manifest",
@@ -666,7 +666,7 @@
 }
 
 func TestDefaults(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_defaults {
 			name: "myapex-defaults",
 			key: "myapex.key",
@@ -741,7 +741,7 @@
 }
 
 func TestApexManifest(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -763,7 +763,7 @@
 }
 
 func TestBasicZipApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -814,7 +814,7 @@
 }
 
 func TestApexWithStubs(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -909,7 +909,7 @@
 
 func TestApexWithStubsWithMinSdkVersion(t *testing.T) {
 	t.Parallel()
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1016,7 +1016,7 @@
 	//                                  |
 	//   <platform>                     |
 	//      libplatform ----------------'
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1081,7 +1081,7 @@
 }
 
 func TestApexWithExplicitStubsDependency(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex2",
 			key: "myapex2.key",
@@ -1177,7 +1177,7 @@
 			    |
 			    `------> libbar
 	*/
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1239,7 +1239,7 @@
 }
 
 func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
-	ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+	ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
 		bp := `
 		apex {
 			name: "com.android.runtime",
@@ -1303,7 +1303,7 @@
 }
 
 func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) {
-	ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+	ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
 		bp := `
 		apex {
 			name: "com.android.runtime",
@@ -1389,7 +1389,7 @@
 	}
 	for _, tc := range testcases {
 		t.Run(tc.name, func(t *testing.T) {
-			ctx, _ := testApex(t, `
+			ctx := testApex(t, `
 			apex {
 				name: "myapex",
 				key: "myapex.key",
@@ -1456,7 +1456,7 @@
 }
 
 func TestApexWithSystemLibsStubs(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1552,7 +1552,7 @@
 	// 1) myapex -> libx -> liba -> libz    : this should be #30 link
 	// 2) otherapex -> liby -> liba -> libz : this should be #30 link
 	// 3) (platform) -> liba -> libz        : this should be non-stub link
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1634,7 +1634,7 @@
 }
 
 func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1683,7 +1683,7 @@
 }
 
 func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1729,7 +1729,7 @@
 }
 
 func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1777,7 +1777,7 @@
 }
 
 func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1816,7 +1816,7 @@
 }
 
 func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2143,7 +2143,7 @@
 }
 
 func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2230,7 +2230,7 @@
 		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("S")
 		config.TestProductVariables.Platform_version_active_codenames = []string{"S", "T"}
 	}
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2264,7 +2264,7 @@
 }
 
 func TestFilesInSubDir(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2327,7 +2327,7 @@
 }
 
 func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2386,7 +2386,7 @@
 }
 
 func TestUseVendor(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2499,7 +2499,7 @@
 }
 
 func TestVendorApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2546,7 +2546,7 @@
 }
 
 func TestVendorApex_use_vndk_as_stable(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2610,7 +2610,7 @@
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			ctx, _ := testApex(t, `
+			ctx := testApex(t, `
 				apex {
 					name: "myapex",
 					key: "myapex.key",
@@ -2638,7 +2638,7 @@
 }
 
 func TestAndroidMk_UseVendorRequired(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2673,7 +2673,7 @@
 }
 
 func TestAndroidMk_VendorApexRequired(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2705,7 +2705,7 @@
 }
 
 func TestAndroidMkWritesCommonProperties(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2735,7 +2735,7 @@
 }
 
 func TestStaticLinking(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2780,7 +2780,7 @@
 }
 
 func TestKeys(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex_keytest",
 			key: "myapex.key",
@@ -2838,7 +2838,7 @@
 
 func TestCertificate(t *testing.T) {
 	t.Run("if unspecified, it defaults to DefaultAppCertificate", func(t *testing.T) {
-		ctx, _ := testApex(t, `
+		ctx := testApex(t, `
 			apex {
 				name: "myapex",
 				key: "myapex.key",
@@ -2856,7 +2856,7 @@
 		}
 	})
 	t.Run("override when unspecified", func(t *testing.T) {
-		ctx, _ := testApex(t, `
+		ctx := testApex(t, `
 			apex {
 				name: "myapex_keytest",
 				key: "myapex.key",
@@ -2879,7 +2879,7 @@
 		}
 	})
 	t.Run("if specified as :module, it respects the prop", func(t *testing.T) {
-		ctx, _ := testApex(t, `
+		ctx := testApex(t, `
 			apex {
 				name: "myapex",
 				key: "myapex.key",
@@ -2902,7 +2902,7 @@
 		}
 	})
 	t.Run("override when specifiec as <:module>", func(t *testing.T) {
-		ctx, _ := testApex(t, `
+		ctx := testApex(t, `
 			apex {
 				name: "myapex_keytest",
 				key: "myapex.key",
@@ -2926,7 +2926,7 @@
 		}
 	})
 	t.Run("if specified as name, finds it from DefaultDevKeyDir", func(t *testing.T) {
-		ctx, _ := testApex(t, `
+		ctx := testApex(t, `
 			apex {
 				name: "myapex",
 				key: "myapex.key",
@@ -2945,7 +2945,7 @@
 		}
 	})
 	t.Run("override when specified as <name>", func(t *testing.T) {
-		ctx, _ := testApex(t, `
+		ctx := testApex(t, `
 			apex {
 				name: "myapex_keytest",
 				key: "myapex.key",
@@ -2971,7 +2971,7 @@
 }
 
 func TestMacro(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -3099,7 +3099,7 @@
 }
 
 func TestHeaderLibsDependency(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -3243,7 +3243,7 @@
 }
 
 func TestVndkApexCurrent(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.current",
 			key: "com.android.vndk.current.key",
@@ -3300,7 +3300,7 @@
 }
 
 func TestVndkApexWithPrebuilt(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.current",
 			key: "com.android.vndk.current.key",
@@ -3384,7 +3384,7 @@
 }
 
 func TestVndkApexVersion(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.v27",
 			key: "myapex.key",
@@ -3453,7 +3453,7 @@
 }
 
 func TestVndkApexNameRule(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.current",
 			key: "myapex.key",
@@ -3486,7 +3486,7 @@
 }
 
 func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.current",
 			key: "com.android.vndk.current.key",
@@ -3558,7 +3558,7 @@
 }
 
 func TestVndkApexWithBinder32(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.v27",
 			key: "myapex.key",
@@ -3627,7 +3627,7 @@
 }
 
 func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.current",
 			key: "com.android.vndk.current.key",
@@ -3663,7 +3663,7 @@
 }
 
 func TestDependenciesInApexManifest(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex_nodep",
 			key: "myapex.key",
@@ -3771,7 +3771,7 @@
 }
 
 func TestApexName(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -3816,7 +3816,7 @@
 }
 
 func TestNonTestApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -3869,7 +3869,7 @@
 }
 
 func TestTestApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_test {
 			name: "myapex",
 			key: "myapex.key",
@@ -3918,7 +3918,7 @@
 }
 
 func TestApexWithTarget(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -4009,7 +4009,7 @@
 }
 
 func TestApexWithArch(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -4068,7 +4068,7 @@
 }
 
 func TestApexWithShBinary(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -4109,7 +4109,7 @@
 	}
 	for _, tc := range testcases {
 		t.Run(tc.propName+":"+tc.parition, func(t *testing.T) {
-			ctx, _ := testApex(t, `
+			ctx := testApex(t, `
 				apex {
 					name: "myapex",
 					key: "myapex.key",
@@ -4142,7 +4142,7 @@
 }
 
 func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -4196,7 +4196,7 @@
 		}
 	`)
 
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -4219,7 +4219,7 @@
 }
 
 func TestFileContexts_SetViaFileGroup(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -4247,7 +4247,7 @@
 }
 
 func TestApexKeyFromOtherModule(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_key {
 			name: "myapex.key",
 			public_key: ":my.avbpubkey",
@@ -4280,7 +4280,7 @@
 }
 
 func TestPrebuilt(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -4303,7 +4303,7 @@
 }
 
 func TestPrebuiltFilenameOverride(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		prebuilt_apex {
 			name: "myapex",
 			src: "myapex-arm.apex",
@@ -4320,7 +4320,7 @@
 }
 
 func TestPrebuiltOverrides(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		prebuilt_apex {
 			name: "myapex.prebuilt",
 			src: "myapex-arm.apex",
@@ -4831,7 +4831,7 @@
 }
 
 func TestApexWithTests(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_test {
 			name: "myapex",
 			key: "myapex.key",
@@ -4943,7 +4943,7 @@
 }
 
 func TestInstallExtraFlattenedApexes(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5013,7 +5013,7 @@
 }
 
 func TestApexWithJavaImport(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5042,7 +5042,7 @@
 }
 
 func TestApexWithApps(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5121,7 +5121,7 @@
 }
 
 func TestApexWithAppImports(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5170,7 +5170,7 @@
 }
 
 func TestApexWithAppImportsPrefer(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5213,7 +5213,7 @@
 }
 
 func TestApexWithTestHelperApp(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5424,7 +5424,7 @@
 }
 
 func TestApexAvailable_CheckForPlatform(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -5487,7 +5487,7 @@
 }
 
 func TestApexAvailable_CreatedForApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -5522,7 +5522,7 @@
 }
 
 func TestOverrideApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5606,7 +5606,7 @@
 }
 
 func TestLegacyAndroid10Support(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5666,7 +5666,7 @@
 }
 
 func TestJavaSDKLibrary(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5704,7 +5704,7 @@
 }
 
 func TestJavaSDKLibrary_WithinApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5757,7 +5757,7 @@
 }
 
 func TestJavaSDKLibrary_CrossBoundary(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5808,7 +5808,7 @@
 }
 
 func TestJavaSDKLibrary_ImportPreferred(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		prebuilt_apis {
 			name: "sdk",
 			api_dirs: ["100"],
@@ -5925,7 +5925,7 @@
 }
 
 func TestCompatConfig(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -5986,7 +5986,7 @@
 }
 
 func TestCarryRequiredModuleNames(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -6130,7 +6130,7 @@
 
 	// For unbundled build, symlink shouldn't exist regardless of whether an APEX
 	// is updatable or not
-	ctx, _ := testApex(t, bp, withUnbundledBuild)
+	ctx := testApex(t, bp, withUnbundledBuild)
 	files := getFiles(t, ctx, "myapex", "android_common_myapex_image")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
@@ -6142,7 +6142,7 @@
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")
 
 	// For bundled build, symlink to the system for the non-updatable APEXes only
-	ctx, _ = testApex(t, bp)
+	ctx = testApex(t, bp)
 	files = getFiles(t, ctx, "myapex", "android_common_myapex_image")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
@@ -6155,7 +6155,7 @@
 }
 
 func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -6207,7 +6207,7 @@
 }
 
 func TestApexWithJniLibs(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -6249,7 +6249,7 @@
 }
 
 func TestApexMutatorsDontRunIfDisabled(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -6271,7 +6271,7 @@
 }
 
 func TestAppBundle(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -6302,7 +6302,7 @@
 }
 
 func TestAppSetBundle(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -6335,7 +6335,7 @@
 }
 
 func TestAppSetBundlePrebuilt(t *testing.T) {
-	ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+	ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
 		bp := `
 		apex_set {
 			name: "myapex",
@@ -6820,7 +6820,7 @@
 }
 
 func TestTestFor(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -6906,7 +6906,7 @@
 }
 
 func TestApexSet(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_set {
 			name: "myapex",
 			set: "myapex.apks",
@@ -6982,7 +6982,7 @@
 }
 
 func TestApexKeysTxt(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -7023,7 +7023,7 @@
 }
 
 func TestAllowedFiles(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -7079,7 +7079,7 @@
 }
 
 func TestNonPreferredPrebuiltDependency(t *testing.T) {
-	_, _ = testApex(t, `
+	testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -7115,7 +7115,7 @@
 }
 
 func TestCompressedApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -7150,7 +7150,7 @@
 }
 
 func TestPreferredPrebuiltSharedLibDep(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -7202,7 +7202,7 @@
 }
 
 func TestExcludeDependency(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -7346,7 +7346,7 @@
 		t.Run(test.name, func(t *testing.T) {
 			for _, otherApexEnabled := range test.otherApexEnabled {
 				t.Run("otherapex_enabled_"+otherApexEnabled, func(t *testing.T) {
-					ctx, _ := testApex(t, fmt.Sprintf(bpBase, otherApexEnabled)+test.stublibBp)
+					ctx := testApex(t, fmt.Sprintf(bpBase, otherApexEnabled)+test.stublibBp)
 
 					type modAndMkEntries struct {
 						mod       *cc.Module
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index ff779e1..2e6ed82 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -28,7 +28,7 @@
 // modules from the ART apex.
 
 func TestBootImages(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		java_sdk_library {
 			name: "foo",
 			srcs: ["b.java"],
@@ -181,7 +181,7 @@
 }
 
 func TestBootImageInApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 5e9a11f..34b9408 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -9,7 +9,7 @@
 )
 
 func TestVndkApexForVndkLite(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx := testApex(t, `
 		apex_vndk {
 			name: "com.android.vndk.current",
 			key: "com.android.vndk.current.key",
@@ -100,7 +100,7 @@
 	}
 
 	t.Run("VNDK lib doesn't have an apex variant", func(t *testing.T) {
-		ctx, _ := testApex(t, bp)
+		ctx := testApex(t, bp)
 
 		// libfoo doesn't have apex variants
 		for _, variant := range ctx.ModuleVariantsForTests("libfoo") {
@@ -113,7 +113,7 @@
 	})
 
 	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) {
+		ctx := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
 			// Now product variant is available
 			config.TestProductVariables.ProductVndkVersion = proptools.StringPtr("current")
 		})
@@ -123,7 +123,7 @@
 	})
 
 	t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
-		ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
+		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)
 		})
diff --git a/build_kzip.bash b/build_kzip.bash
index 9564723..a4659d4 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -16,6 +16,7 @@
 : ${BUILD_NUMBER:=$(uuidgen)}
 : ${KYTHE_JAVA_SOURCE_BATCH_SIZE:=500}
 : ${KYTHE_KZIP_ENCODING:=proto}
+: ${XREF_CORPUS:?should be set}
 export KYTHE_JAVA_SOURCE_BATCH_SIZE KYTHE_KZIP_ENCODING
 
 # The extraction might fail for some source files, so run with -k and then check that
@@ -29,11 +30,15 @@
 declare -r abspath_out=$(realpath "${out}")
 declare -r go_extractor=$(realpath prebuilts/build-tools/linux-x86/bin/go_extractor)
 declare -r go_root=$(realpath prebuilts/go/linux-x86)
-declare -r vnames_path=$(realpath build/soong/vnames.go.json)
 declare -r source_root=$PWD
+
+# TODO(asmundak): Until b/182183061 is fixed, default corpus has to be specified 
+# in the rules file. Generate this file on the fly with corpus value set from the
+# environment variable.
 for dir in blueprint soong; do
   (cd "build/$dir";
-   KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" --rules="${vnames_path}" \
+   KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" \
+   --rules=<(printf '[{"pattern": "(.*)","vname": {"path": "@1@", "corpus":"%s"}}]' "${XREF_CORPUS}") \
    --canonicalize_package_corpus --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
   )
 done
diff --git a/java/app.go b/java/app.go
index 2d918e9..0660aa6 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1280,6 +1280,14 @@
 	outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
 	statusFile := dexpreopt.UsesLibrariesStatusFile(ctx)
 
+	// Disable verify_uses_libraries check if dexpreopt is globally disabled. Without dexpreopt the
+	// check is not necessary, and although it is good to have, it is difficult to maintain on
+	// non-linux build platforms where dexpreopt is generally disabled (the check may fail due to
+	// various unrelated reasons, such as a failure to get manifest from an APK).
+	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
+		return manifest
+	}
+
 	rule := android.NewRuleBuilder(pctx, ctx)
 	cmd := rule.Command().BuiltTool("manifest_check").
 		Flag("--enforce-uses-libraries").
@@ -1310,6 +1318,14 @@
 	outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
 	statusFile := dexpreopt.UsesLibrariesStatusFile(ctx)
 
+	// Disable verify_uses_libraries check if dexpreopt is globally disabled. Without dexpreopt the
+	// check is not necessary, and although it is good to have, it is difficult to maintain on
+	// non-linux build platforms where dexpreopt is generally disabled (the check may fail due to
+	// various unrelated reasons, such as a failure to get manifest from an APK).
+	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
+		return apk
+	}
+
 	rule := android.NewRuleBuilder(pctx, ctx)
 	aapt := ctx.Config().HostToolPath(ctx, "aapt")
 	rule.Command().
diff --git a/java/robolectric.go b/java/robolectric.go
index 98bb710..00f233e 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -31,13 +31,15 @@
 }
 
 var robolectricDefaultLibs = []string{
-	"Robolectric_all-target",
 	"mockito-robolectric-prebuilt",
 	"truth-prebuilt",
 	// TODO(ccross): this is not needed at link time
 	"junitxml",
 }
 
+const robolectricCurrentLib = "Robolectric_all-target"
+const robolectricPrebuiltLibPattern = "platform-robolectric-%s-prebuilt"
+
 var (
 	roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"}
 	roboRuntimesTag     = dependencyTag{name: "roboRuntimes"}
@@ -57,6 +59,10 @@
 		// Number of shards to use when running the tests.
 		Shards *int64
 	}
+
+	// The version number of a robolectric prebuilt to use from prebuilts/misc/common/robolectric
+	// instead of the one built from source in external/robolectric-shadows.
+	Robolectric_prebuilt_version *string
 }
 
 type robolectricTest struct {
@@ -94,6 +100,12 @@
 		ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module")
 	}
 
+	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
+		ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
+	} else {
+		ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
+	}
+
 	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
 
 	ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
@@ -298,7 +310,11 @@
 	if t := r.robolectricProperties.Test_options.Timeout; t != nil {
 		fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
 	}
-	fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
+	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
+		fmt.Fprintf(w, "-include prebuilts/misc/common/robolectric/%s/run_robotests.mk\n", v)
+	} else {
+		fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
+	}
 }
 
 // An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 4ad68ea..892a16c 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -165,6 +165,12 @@
 		// Forwarded to cc_library.min_sdk_version
 		Min_sdk_version *string
 	}
+
+	Java struct {
+		// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+		// Forwarded to java_library.min_sdk_version
+		Min_sdk_version *string
+	}
 }
 
 var (
@@ -403,6 +409,8 @@
 	Libs              []string
 	Stem              *string
 	SyspropPublicStub string
+	Apex_available    []string
+	Min_sdk_version   *string
 }
 
 func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
@@ -508,6 +516,8 @@
 		Sdk_version:       proptools.StringPtr("core_current"),
 		Libs:              []string{javaSyspropStub},
 		SyspropPublicStub: publicStub,
+		Apex_available:    m.ApexProperties.Apex_available,
+		Min_sdk_version:   m.properties.Java.Min_sdk_version,
 	})
 
 	if publicStub != "" {
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 9d914e3..fde41d6 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -81,6 +81,51 @@
 }
 
 func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
+	bp += `
+		cc_library {
+			name: "libbase",
+			host_supported: true,
+		}
+
+		cc_library_headers {
+			name: "libbase_headers",
+			vendor_available: true,
+			recovery_available: true,
+		}
+
+		cc_library {
+			name: "liblog",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			recovery_available: true,
+			host_supported: true,
+			llndk_stubs: "liblog.llndk",
+		}
+
+		llndk_library {
+			name: "liblog.llndk",
+			symbol_file: "",
+		}
+
+		java_library {
+			name: "sysprop-library-stub-platform",
+			sdk_version: "core_current",
+		}
+
+		java_library {
+			name: "sysprop-library-stub-vendor",
+			soc_specific: true,
+			sdk_version: "core_current",
+		}
+
+		java_library {
+			name: "sysprop-library-stub-product",
+			product_specific: true,
+			sdk_version: "core_current",
+		}
+	`
+
 	bp += cc.GatherRequiredDepsForTest(android.Android)
 
 	mockFS := map[string][]byte{
@@ -250,54 +295,11 @@
 			static_libs: ["sysprop-platform", "sysprop-vendor"],
 		}
 
-		cc_library {
-			name: "libbase",
-			host_supported: true,
-		}
-
-		cc_library_headers {
-			name: "libbase_headers",
-			vendor_available: true,
-			recovery_available: true,
-		}
-
-		cc_library {
-			name: "liblog",
-			no_libcrt: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-			host_supported: true,
-			llndk_stubs: "liblog.llndk",
-		}
-
 		cc_binary_host {
 			name: "hostbin",
 			static_libs: ["sysprop-platform"],
 		}
-
-		llndk_library {
-			name: "liblog.llndk",
-			symbol_file: "",
-		}
-
-		java_library {
-			name: "sysprop-library-stub-platform",
-			sdk_version: "core_current",
-		}
-
-		java_library {
-			name: "sysprop-library-stub-vendor",
-			soc_specific: true,
-			sdk_version: "core_current",
-		}
-
-		java_library {
-			name: "sysprop-library-stub-product",
-			product_specific: true,
-			sdk_version: "core_current",
-		}
-		`)
+	`)
 
 	// Check for generated cc_library
 	for _, variant := range []string{
@@ -391,3 +393,62 @@
 		t.Errorf("system api client should use public stub %q, got %q", w, g)
 	}
 }
+
+func TestApexAvailabilityIsForwarded(t *testing.T) {
+	ctx := test(t, `
+		sysprop_library {
+			name: "sysprop-platform",
+			apex_available: ["//apex_available:platform"],
+			srcs: ["android/sysprop/PlatformProperties.sysprop"],
+			api_packages: ["android.sysprop"],
+			property_owner: "Platform",
+		}
+	`)
+
+	expected := []string{"//apex_available:platform"}
+
+	ccModule := ctx.ModuleForTests("libsysprop-platform", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+	propFromCc := ccModule.ApexProperties.Apex_available
+	if !reflect.DeepEqual(propFromCc, expected) {
+		t.Errorf("apex_available not forwarded to cc module. expected %#v, got %#v",
+			expected, propFromCc)
+	}
+
+	javaModule := ctx.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
+	propFromJava := javaModule.ApexProperties.Apex_available
+	if !reflect.DeepEqual(propFromJava, expected) {
+		t.Errorf("apex_available not forwarded to java module. expected %#v, got %#v",
+			expected, propFromJava)
+	}
+}
+
+func TestMinSdkVersionIsForwarded(t *testing.T) {
+	ctx := test(t, `
+		sysprop_library {
+			name: "sysprop-platform",
+			srcs: ["android/sysprop/PlatformProperties.sysprop"],
+			api_packages: ["android.sysprop"],
+			property_owner: "Platform",
+			cpp: {
+				min_sdk_version: "29",
+			},
+			java: {
+				min_sdk_version: "30",
+			},
+		}
+	`)
+
+	ccModule := ctx.ModuleForTests("libsysprop-platform", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+	propFromCc := proptools.String(ccModule.Properties.Min_sdk_version)
+	if propFromCc != "29" {
+		t.Errorf("min_sdk_version not forwarded to cc module. expected %#v, got %#v",
+			"29", propFromCc)
+	}
+
+	javaModule := ctx.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
+	propFromJava := javaModule.MinSdkVersion()
+	if propFromJava != "30" {
+		t.Errorf("min_sdk_version not forwarded to java module. expected %#v, got %#v",
+			"30", propFromJava)
+	}
+}
diff --git a/vnames.go.json b/vnames.go.json
deleted file mode 100644
index f8c6b7f..0000000
--- a/vnames.go.json
+++ /dev/null
@@ -1,8 +0,0 @@
-[
-    {
-        "pattern": "(.*)",
-        "vname": {
-            "path": "@1@"
-        }
-    }
-]