Rewrite code to copy images to PRODUCT_OUT

Move the logic to android_device. The reasons for this are:
 - As we start to check in android_device and filesystem modules,
   only one set should do the copying. It's easy enough to mark the
   android_device as the one, but harder for the filesystem modules
   given that they may be reused between different devices and now
   that top-down mutators are no longer supported.
 - It's easier to manage this code in one place, especially since it's
   temporary and should be removed eventually.

Having this higher confidence that there's only 1 copy rule set in
the build makes it less of a problem to use actual ninja rules for
the images.

Bug: 376727180
Test: m --soong-only && ls out/target/product/vsoc_x86_64/
Change-Id: If20ea2c55053cc962de9f9770db002edbc194835
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 080e6b7..e340602 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -62,6 +62,12 @@
 	Bootloader *string `android:"path"`
 	// Path to android-info.txt file containing board specific info.
 	Android_info *string `android:"path"`
+	// If this is the "main" android_device target for the build, i.e. the one that gets built
+	// when running a plain `m` command. Currently, this is the autogenerated android_device module
+	// in soong-only builds, but in the future when we check in android_device modules, the main
+	// one will be determined based on the lunch product. TODO: Figure out how to make this
+	// blueprint:"mutated" and still set it from filesystem_creator
+	Main_device *bool
 }
 
 type androidDevice struct {
@@ -70,9 +76,6 @@
 	partitionProps PartitionNameProperties
 
 	deviceProps DeviceProperties
-
-	// copyToProductOutTimestamp for copying necessary files to PRODUCT_OUT
-	copyToProductOutTimestamp android.WritablePath
 }
 
 func AndroidDeviceFactory() android.Module {
@@ -82,7 +85,7 @@
 	return module
 }
 
-var numAutogeneratedAndroidDevicesOnceKey android.OnceKey = android.NewOnceKey("num_auto_generated_anroid_devices")
+var numMainAndroidDevicesOnceKey android.OnceKey = android.NewOnceKey("num_auto_generated_anroid_devices")
 
 type partitionDepTagType struct {
 	blueprint.BaseDependencyTag
@@ -123,25 +126,19 @@
 	}
 }
 
-func (a *androidDevice) copyToProductOut(ctx android.ModuleContext, builder *android.RuleBuilder, src android.Path, dest string) {
-	destPath := android.PathForModuleInPartitionInstall(ctx, "").Join(ctx, dest)
-	builder.Command().Text("rsync").Flag("-a").Flag("--checksum").Input(src).Text(destPath.String())
-}
-
-func (a *androidDevice) copyFilesToProductOut(ctx android.ModuleContext) {
-	a.copyToProductOutTimestamp = android.PathForModuleOut(ctx, "timestamp")
-	builder := android.NewRuleBuilder(pctx, ctx)
-	builder.Command().Text("touch").Output(a.copyToProductOutTimestamp)
-
-	// List all individual files to be copied to PRODUCT_OUT here
-	if a.deviceProps.Bootloader != nil {
-		a.copyToProductOut(ctx, builder, android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Bootloader)), "bootloader")
+func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if proptools.Bool(a.deviceProps.Main_device) {
+		numMainAndroidDevices := ctx.Config().Once(numMainAndroidDevicesOnceKey, func() interface{} {
+			return &atomic.Int32{}
+		}).(*atomic.Int32)
+		total := numMainAndroidDevices.Add(1)
+		if total > 1 {
+			// There should only be 1 main android_device module. That one will be
+			// made the default thing to build in soong-only builds.
+			ctx.ModuleErrorf("There cannot be more than 1 main android_device module")
+		}
 	}
 
-	builder.Build("copy_to_product_out", "Copy files to PRODUCT_OUT")
-}
-
-func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.buildTargetFilesZip(ctx)
 	var deps []android.Path
 	if proptools.String(a.partitionProps.Super_partition_name) != "" {
@@ -193,36 +190,26 @@
 		deps = append(deps, imageOutput.DefaultOutputFiles[0])
 	})
 
-	a.copyFilesToProductOut(ctx)
-
 	allImagesStamp := android.PathForModuleOut(ctx, "all_images_stamp")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:       android.Touch,
-		Output:     allImagesStamp,
-		Implicits:  deps,
-		Validation: a.copyToProductOutTimestamp,
-	})
-	ctx.SetOutputFiles(android.Paths{allImagesStamp}, "")
-	ctx.CheckbuildFile(allImagesStamp)
-
-	if ctx.OtherModuleIsAutoGenerated(ctx.Module()) {
-		numAutogeneratedAndroidDevices := ctx.Config().Once(numAutogeneratedAndroidDevicesOnceKey, func() interface{} {
-			return &atomic.Int32{}
-		}).(*atomic.Int32)
-		total := numAutogeneratedAndroidDevices.Add(1)
-		if total > 1 {
-			// There should only be 1 autogenerated android_device module. That one will be
-			// made the default thing to build in soong-only builds.
-			ctx.ModuleErrorf("There cannot be more than 1 autogenerated android_device module")
-		}
-	}
-
-	if !ctx.Config().KatiEnabled() && ctx.OtherModuleIsAutoGenerated(ctx.Module()) {
+	var validations android.Paths
+	if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) {
 		// In soong-only builds, build this module by default.
 		// This is the analogue to this make code:
 		// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/main.mk;l=1396;drc=6595459cdd8164a6008335f6372c9f97b9094060
 		ctx.Phony("droidcore-unbundled", allImagesStamp)
+
+		validations = append(validations, a.copyFilesToProductOutForSoongOnly(ctx))
 	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Touch,
+		Output:      allImagesStamp,
+		Implicits:   deps,
+		Validations: validations,
+	})
+
+	// Checkbuilding it causes soong to make a phony, so you can say `m <module name>`
+	ctx.CheckbuildFile(allImagesStamp)
 }
 
 // Helper structs for target_files.zip creation
@@ -335,7 +322,7 @@
 
 	if a.deviceProps.Android_info != nil {
 		builder.Command().Textf("mkdir -p %s/OTA", targetFilesDir)
-		builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Android_info))).Textf(" %s/OTA/android-info.txt", targetFilesDir)
+		builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, *a.deviceProps.Android_info)).Textf(" %s/OTA/android-info.txt", targetFilesDir)
 	}
 
 	a.copyImagesToTargetZip(ctx, builder, targetFilesDir)