Merge changes from topic "recovery_soong_export" into main

* changes:
  Support auto-generating prebuilt_* modules for recovery partition
  Support auto gen module type matching in neverallow
  Introduce prebuilt_vendor module type
  Auto generate recovery partition
diff --git a/android/config.go b/android/config.go
index cb604a6..b811c55 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1519,6 +1519,13 @@
 	return "64"
 }
 
+func (c *deviceConfig) RecoveryPath() string {
+	if c.config.productVariables.RecoveryPath != nil {
+		return *c.config.productVariables.RecoveryPath
+	}
+	return "recovery"
+}
+
 func (c *deviceConfig) VendorPath() string {
 	if c.config.productVariables.VendorPath != nil {
 		return *c.config.productVariables.VendorPath
@@ -1614,6 +1621,10 @@
 	return proptools.Bool(c.config.productVariables.BuildingUserdataImage)
 }
 
+func (c *deviceConfig) BuildingRecoveryImage() bool {
+	return proptools.Bool(c.config.productVariables.BuildingRecoveryImage)
+}
+
 func (c *deviceConfig) BtConfigIncludeDir() string {
 	return String(c.config.productVariables.BtConfigIncludeDir)
 }
diff --git a/android/module.go b/android/module.go
index 67dab4f..588fd66 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1387,6 +1387,8 @@
 		partition = "ramdisk"
 	} else if m.InstallInVendorRamdisk() {
 		partition = "vendor_ramdisk"
+	} else if m.InstallInRecovery() {
+		partition = "recovery"
 	}
 	return partition
 }
diff --git a/android/neverallow.go b/android/neverallow.go
index 7f7ffa7..18e9a17 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -245,6 +245,7 @@
 			Without("name", "librecovery_ui_ext").
 			With("install_in_root", "true").
 			NotModuleType("prebuilt_root").
+			NotModuleType("prebuilt_vendor").
 			Because("install_in_root is only for init_first_stage or librecovery_ui_ext."),
 	}
 }
@@ -341,6 +342,7 @@
 			"prebuilt_tvservice",
 			"prebuilt_optee",
 			"prebuilt_tvconfig",
+			"prebuilt_vendor",
 		).
 		DefinedInBpFile().
 		Because("module type not allowed to be defined in bp file")
@@ -705,6 +707,9 @@
 }
 
 func (r *rule) appliesToModuleType(moduleType string) bool {
+	// Remove prefix for auto-generated modules
+	moduleType = strings.TrimSuffix(moduleType, "__loadHookModule")
+	moduleType = strings.TrimSuffix(moduleType, "__bottomUpMutatorModule")
 	return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
 }
 
diff --git a/android/variable.go b/android/variable.go
index 46f54db..e06fb8a 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -351,6 +351,8 @@
 	OemPath               *string `json:",omitempty"`
 	UserdataPath          *string `json:",omitempty"`
 	BuildingUserdataImage *bool   `json:",omitempty"`
+	RecoveryPath          *string `json:",omitempty"`
+	BuildingRecoveryImage *bool   `json:",omitempty"`
 
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index b0b5da9..190d129 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -81,6 +81,7 @@
 	ctx.RegisterModuleType("prebuilt_tvservice", PrebuiltTvServiceFactory)
 	ctx.RegisterModuleType("prebuilt_optee", PrebuiltOpteeFactory)
 	ctx.RegisterModuleType("prebuilt_tvconfig", PrebuiltTvConfigFactory)
+	ctx.RegisterModuleType("prebuilt_vendor", PrebuiltVendorFactory)
 
 	ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
 
@@ -573,6 +574,7 @@
 	p.installDirBase = dirBase
 	p.AddProperties(&p.properties)
 	p.AddProperties(&p.subdirProperties)
+	p.AddProperties(&p.rootProperties)
 }
 
 func InitPrebuiltRootModule(p *PrebuiltEtc) {
@@ -972,3 +974,13 @@
 	android.InitDefaultableModule(module)
 	return module
 }
+
+// prebuilt_vendor installs files in <partition>/vendor directory.
+func PrebuiltVendorFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "vendor")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index eb34180..b5f7e48 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -790,6 +790,7 @@
 	"system_dlkm",
 	"ramdisk",
 	"vendor_ramdisk",
+	"recovery",
 }
 
 func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.Path) {
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index e40bce5..ec52f61 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -108,6 +108,9 @@
 	if buildingVendorBootImage(partitionVars) {
 		generatedPartitions = append(generatedPartitions, "vendor_ramdisk")
 	}
+	if ctx.DeviceConfig().BuildingRecoveryImage() && ctx.DeviceConfig().RecoveryPath() == "recovery" {
+		generatedPartitions = append(generatedPartitions, "recovery")
+	}
 	return generatedPartitions
 }
 
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 0cc643e..b99e2da 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -150,6 +150,7 @@
 				},
 				"ramdisk":        {},
 				"vendor_ramdisk": {},
+				"recovery":       {},
 			},
 			fsDepsMutex:                     sync.Mutex{},
 			moduleToInstallationProps:       map[string]installationProperties{},
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
index efbc462..902d183 100644
--- a/fsgen/prebuilt_etc_modules_gen.go
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -36,6 +36,7 @@
 	system_ext map[string][]srcBaseFileInstallBaseFileTuple
 	product    map[string][]srcBaseFileInstallBaseFileTuple
 	vendor     map[string][]srcBaseFileInstallBaseFileTuple
+	recovery   map[string][]srcBaseFileInstallBaseFileTuple
 }
 
 func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition {
@@ -44,6 +45,7 @@
 		system_ext: map[string][]srcBaseFileInstallBaseFileTuple{},
 		product:    map[string][]srcBaseFileInstallBaseFileTuple{},
 		vendor:     map[string][]srcBaseFileInstallBaseFileTuple{},
+		recovery:   map[string][]srcBaseFileInstallBaseFileTuple{},
 	}
 }
 
@@ -73,6 +75,8 @@
 				srcMap = srcGroup.product
 			case "vendor":
 				srcMap = srcGroup.vendor
+			case "recovery":
+				srcMap = srcGroup.recovery
 			}
 			if srcMap != nil {
 				srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{
@@ -128,6 +132,7 @@
 	// System is intentionally added at the last to consider the scenarios where
 	// non-system partitions are installed as part of the system partition
 	partitionToInstallPathList := []partitionToInstallPath{
+		{name: "recovery", installPath: "recovery/root"},
 		{name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
 		{name: "product", installPath: ctx.DeviceConfig().ProductPath()},
 		{name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
@@ -155,6 +160,7 @@
 	Soc_specific        *bool
 	Product_specific    *bool
 	System_ext_specific *bool
+	Recovery            *bool
 
 	Srcs []string
 	Dsts []string
@@ -174,6 +180,12 @@
 	Relative_install_path *string
 }
 
+// Split install_in_root to a separate struct as it is part of rootProperties instead of
+// properties
+type prebuiltInstallInRootProperties struct {
+	Install_in_root *bool
+}
+
 var (
 	etcInstallPathToFactoryList = map[string]android.ModuleFactory{
 		"":                etc.PrebuiltRootFactory,
@@ -207,6 +219,7 @@
 		"usr/keychars":    etc.PrebuiltUserKeyCharsFactory,
 		"usr/srec":        etc.PrebuiltUserSrecFactory,
 		"usr/idc":         etc.PrebuiltUserIdcFactory,
+		"vendor":          etc.PrebuiltVendorFactory,
 		"vendor_dlkm":     etc.PrebuiltVendorDlkmFactory,
 		"wallpaper":       etc.PrebuiltWallpaperFactory,
 		"wlc_upt":         etc.PrebuiltWlcUptFactory,
@@ -254,6 +267,8 @@
 		moduleProps.Product_specific = proptools.BoolPtr(true)
 	case "vendor":
 		moduleProps.Soc_specific = proptools.BoolPtr(true)
+	case "recovery":
+		moduleProps.Recovery = proptools.BoolPtr(true)
 	}
 
 	moduleProps.No_full_install = proptools.BoolPtr(true)
@@ -301,6 +316,16 @@
 			installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
 		}
 
+		// Recovery partition-installed modules are installed to `recovery/root/system` by
+		// default (See modulePartition() in android/paths.go). If the destination file
+		// directory is not `recovery/root/system/...`, it should set install_in_root to true
+		// to prevent being installed in `recovery/root/system`.
+		if partition == "recovery" && !strings.HasPrefix(destDir, "system") {
+			propsList = append(propsList, &prebuiltInstallInRootProperties{
+				Install_in_root: proptools.BoolPtr(true),
+			})
+		}
+
 		// Set appropriate srcs, dsts, and releative_install_path based on
 		// the source and install file names
 		if allCopyFileNamesUnchanged {
@@ -346,6 +371,7 @@
 		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
 		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
 		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
+		ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "recovery", srcDir, groupedSource.recovery)...)
 	}
 
 	return ret