Merge "Add sortableComponent abstraction"
diff --git a/android/mutator.go b/android/mutator.go
index b023001..8bfb24e 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,10 @@
 		f(mctx)
 	}
 
-	registerMutatorsToContext(ctx, mctx.mutators)
+	mctx.mutators.registerAll(ctx)
 }
 
-func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) {
+func registerMutators(ctx *Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) {
 	mctx := &registerMutatorsContext{}
 
 	register := func(funcs []RegisterMutatorFunc) {
@@ -103,11 +89,11 @@
 	mctx.finalPhase = true
 	register(finalDeps)
 
-	registerMutatorsToContext(ctx, mctx.mutators)
+	mctx.mutators.registerAll(ctx)
 }
 
 type registerMutatorsContext struct {
-	mutators            []*mutator
+	mutators            sortableComponents
 	finalPhase          bool
 	bazelConversionMode bool
 }
@@ -473,6 +459,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..5efa280 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,33 +166,29 @@
 // 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))
-	}
+	singletons.registerAll(ctx)
 
-	registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps)
+	registerMutators(ctx, preArch, preDeps, postDeps, finalDeps)
 
 	ctx.RegisterSingletonType("bazeldeps", SingletonFactoryAdaptor(ctx, BazelSingleton))
 
diff --git a/android/testing.go b/android/testing.go
index d8c123b..556db78 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -141,14 +141,14 @@
 }
 
 func (ctx *TestContext) Register() {
-	registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
+	registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
 
 	ctx.RegisterSingletonType("env", EnvSingleton)
 }
 
 // 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) {