Merge "Autogenerate a system_dlkm android_filesystem" into main
diff --git a/android/variable.go b/android/variable.go
index a4ee886..df9db7c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -605,6 +605,9 @@
 	ProductLinkerConfigSrcs []string `json:",omitempty"`
 
 	ProductCopyFiles map[string]string `json:",omitempty"`
+
+	BuildingSystemDlkmImage bool     `json:",omitempty"`
+	SystemKernelModules     []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/fsgen/Android.bp b/fsgen/Android.bp
index baf9291..e3cbdb3 100644
--- a/fsgen/Android.bp
+++ b/fsgen/Android.bp
@@ -10,6 +10,7 @@
         "soong",
         "soong-android",
         "soong-filesystem",
+        "soong-kernel",
     ],
     srcs: [
         "filesystem_creator.go",
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 06e154a..7ef7d99 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -25,6 +25,7 @@
 
 	"android/soong/android"
 	"android/soong/filesystem"
+	"android/soong/kernel"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/parser"
@@ -115,6 +116,9 @@
 		if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
 			generatedPartitions = append(generatedPartitions, "odm")
 		}
+		if partitionVars.BuildingSystemDlkmImage {
+			generatedPartitions = append(generatedPartitions, "system_dlkm")
+		}
 
 		return &FsGenState{
 			depCandidates: candidates,
@@ -160,6 +164,7 @@
 					"com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
 					"com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
 				},
+				"system_dlkm": {},
 			},
 			soongGeneratedPartitions:  generatedPartitions,
 			fsDepsMutex:               sync.Mutex{},
@@ -500,9 +505,19 @@
 		fsProps.Linkerconfig.Linker_config_srcs = f.createLinkerConfigSourceFilegroups(ctx, partitionType)
 	}
 
+	if partitionType == "system_dlkm" {
+		kernelModules := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules
+		f.createPrebuiltKernelModules(ctx, partitionType, kernelModules)
+	}
+
 	var module android.Module
 	if partitionType == "system" {
 		module = ctx.CreateModule(filesystem.SystemImageFactory, baseProps, fsProps)
+	} else if partitionType == "system_dlkm" {
+		// Do not set partition_type. build/soong/android/paths#modulePartition currently does not support dlkm
+		// partitions. Since `android_filesystem` uses a partition based filter, setting the partition here
+		// would result in missing in entries.
+		module = ctx.CreateModule(filesystem.FilesystemFactory, baseProps, fsProps)
 	} else {
 		// Explicitly set the partition.
 		fsProps.Partition_type = proptools.StringPtr(partitionType)
@@ -531,6 +546,41 @@
 	return true
 }
 
+// createPrebuiltKernelModules creates `prebuilt_kernel_modules`. These modules will be added to deps of the
+// autogenerated *_dlkm filsystem modules.
+// The input `kernelModules` is a space separated list of .ko files in the workspace. This will be partitioned per directory
+// and a `prebuilt_kernel_modules` will be created per partition.
+// These autogenerated modules will be subsequently added to the deps of the top level *_dlkm android_filesystem
+func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookContext, partitionType string, kernelModules []string) {
+	// Partition the files per directory
+	dirToFiles := map[string][]string{}
+	for _, kernelModule := range kernelModules {
+		dir := filepath.Dir(kernelModule)
+		base := filepath.Base(kernelModule)
+		dirToFiles[dir] = append(dirToFiles[dir], base)
+	}
+	// Create a prebuilt_kernel_modules module per partition
+	fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+	for index, dir := range android.SortedKeys(dirToFiles) {
+		name := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-kernel-modules-%s", partitionType, strconv.Itoa(index)))
+		props := &struct {
+			Name *string
+			Srcs []string
+		}{
+			Name: proptools.StringPtr(name),
+			Srcs: dirToFiles[dir],
+		}
+		kernelModule := ctx.CreateModuleInDirectory(
+			kernel.PrebuiltKernelModulesFactory,
+			dir,
+			props,
+		)
+		kernelModule.HideFromMake()
+		// Add to deps
+		(*fsGenState.fsDeps[partitionType])[name] = defaultDepCandidateProps(ctx.Config())
+	}
+}
+
 // createLinkerConfigSourceFilegroups creates filegroup modules to generate linker.config.pb for the following partitions
 // 1. vendor: Using PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS (space separated file list)
 // 1. product: Using PRODUCT_PRODUCT_LINKER_CONFIG_FRAGMENTS (space separated file list)
diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go
index e200ee2..4c0a911 100644
--- a/kernel/prebuilt_kernel_modules.go
+++ b/kernel/prebuilt_kernel_modules.go
@@ -32,7 +32,7 @@
 }
 
 func registerKernelBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("prebuilt_kernel_modules", prebuiltKernelModulesFactory)
+	ctx.RegisterModuleType("prebuilt_kernel_modules", PrebuiltKernelModulesFactory)
 }
 
 type prebuiltKernelModules struct {
@@ -58,7 +58,7 @@
 // prebuilt_kernel_modules installs a set of prebuilt kernel module files to the correct directory.
 // In addition, this module builds modules.load, modules.dep, modules.softdep and modules.alias
 // using depmod and installs them as well.
-func prebuiltKernelModulesFactory() android.Module {
+func PrebuiltKernelModulesFactory() android.Module {
 	module := &prebuiltKernelModules{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)