Introduce Soong API CreateModuleInDirectory(...)

The method allows generating module in a specified directory. Note
that the method is only supported in LoadHookContext, and does not
support BottomUpMutatorContext.

Test: m nothing
Bug: 375053752
Change-Id: I40ac7678b280a89cdca932632811fef3a1494353
diff --git a/android/hooks.go b/android/hooks.go
index bd2fa5e..9f4e5b6 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -37,6 +37,7 @@
 	AppendProperties(...interface{})
 	PrependProperties(...interface{})
 	CreateModule(ModuleFactory, ...interface{}) Module
+	CreateModuleInDirectory(ModuleFactory, string, ...interface{}) Module
 
 	registerScopedModuleType(name string, factory blueprint.ModuleFactory)
 	moduleFactories() map[string]blueprint.ModuleFactory
@@ -93,13 +94,37 @@
 	return l.bp.CreateModule(factory, name, props...)
 }
 
+func (l *loadHookContext) createModuleInDirectory(factory blueprint.ModuleFactory, name, moduleDir string, props ...interface{}) blueprint.Module {
+	return l.bp.CreateModuleInDirectory(factory, name, moduleDir, props...)
+}
+
+type specifyDirectory struct {
+	specified bool
+	directory string
+}
+
+func doesNotSpecifyDirectory() specifyDirectory {
+	return specifyDirectory{
+		specified: false,
+		directory: "",
+	}
+}
+
+func specifiesDirectory(directory string) specifyDirectory {
+	return specifyDirectory{
+		specified: true,
+		directory: directory,
+	}
+}
+
 type createModuleContext interface {
 	Module() Module
 	HasMutatorFinished(mutatorName string) bool
 	createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module
+	createModuleInDirectory(blueprint.ModuleFactory, string, string, ...interface{}) blueprint.Module
 }
 
-func createModule(ctx createModuleContext, factory ModuleFactory, ext string, props ...interface{}) Module {
+func createModule(ctx createModuleContext, factory ModuleFactory, ext string, specifyDirectory specifyDirectory, props ...interface{}) Module {
 	if ctx.HasMutatorFinished("defaults") {
 		// Creating modules late is oftentimes problematic, because they don't have earlier
 		// mutators run on them. Prevent making modules after the defaults mutator has run.
@@ -119,7 +144,12 @@
 	}
 	typeName = typeName + "_" + ext
 
-	module := ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
+	var module Module
+	if specifyDirectory.specified {
+		module = ctx.createModuleInDirectory(ModuleFactoryAdaptor(factory), typeName, specifyDirectory.directory, append(inherited, props...)...).(Module)
+	} else {
+		module = ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
+	}
 
 	if ctx.Module().base().variableProperties != nil && module.base().variableProperties != nil {
 		src := ctx.Module().base().variableProperties
@@ -139,7 +169,11 @@
 }
 
 func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
-	return createModule(l, factory, "_loadHookModule", props...)
+	return createModule(l, factory, "_loadHookModule", doesNotSpecifyDirectory(), props...)
+}
+
+func (l *loadHookContext) CreateModuleInDirectory(factory ModuleFactory, directory string, props ...interface{}) Module {
+	return createModule(l, factory, "_loadHookModule", specifiesDirectory(directory), props...)
 }
 
 func (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) {