Specify dtb_prebuilt property in the autogen vendor_boot.img

prebuilt_etc_modules_gen currently elides entries that are not installed
within partition directories but are installed in the product root.
However, dtb.img is copied from source via PRODUCT_COPY_FILES and
installed in the product root and then used for vendor_boot.img
generation.

This change creates the filegroup module from the PRODUCT_COPY_FILES for
the source dtb.img to utilize it in the vendor_boot.img generation, but
not actually install the file. We may consider installing this file if
this is essential in runtime.

Test: inspect the ninja command of the vendor_boot.img
Bug: 379945468
Change-Id: I760b8eb9c15b74b124828ea041ca106f8355efd4
diff --git a/android/variable.go b/android/variable.go
index e666530..6eb8a22 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -627,6 +627,7 @@
 	BoardUsesGenericKernelImage     bool   `json:",omitempty"`
 	BootSecurityPatch               string `json:",omitempty"`
 	InitBootSecurityPatch           string `json:",omitempty"`
+	BoardIncludeDtbInBootimg        bool   `json:",omitempty"`
 
 	// Avb (android verified boot) stuff
 	BoardAvbEnable          bool                                `json:",omitempty"`
diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go
index 6647a9a..4ccc90a 100644
--- a/fsgen/boot_imgs.go
+++ b/fsgen/boot_imgs.go
@@ -6,11 +6,12 @@
 	"fmt"
 	"path/filepath"
 	"strconv"
+	"strings"
 
 	"github.com/google/blueprint/proptools"
 )
 
-func createBootImage(ctx android.LoadHookContext) bool {
+func createBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool {
 	partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
 
 	if partitionVariables.TargetKernelPath == "" {
@@ -55,6 +56,11 @@
 
 	bootImageName := generatedModuleNameForPartition(ctx.Config(), "boot")
 
+	var dtbPrebuilt *string
+	if dtbImg.include && dtbImg.imgType == "boot" {
+		dtbPrebuilt = proptools.StringPtr(":" + dtbImg.name)
+	}
+
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
@@ -67,6 +73,7 @@
 			Avb_rollback_index: avbInfo.avbRollbackIndex,
 			Avb_algorithm:      avbInfo.avbAlgorithm,
 			Security_patch:     securityPatch,
+			Dtb_prebuilt:       dtbPrebuilt,
 		},
 		&struct {
 			Name *string
@@ -77,13 +84,18 @@
 	return true
 }
 
-func createVendorBootImage(ctx android.LoadHookContext) bool {
+func createVendorBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool {
 	partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
 
 	bootImageName := generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
 
 	avbInfo := getAvbInfo(ctx.Config(), "vendor_boot")
 
+	var dtbPrebuilt *string
+	if dtbImg.include && dtbImg.imgType == "vendor_boot" {
+		dtbPrebuilt = proptools.StringPtr(":" + dtbImg.name)
+	}
+
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
@@ -95,6 +107,7 @@
 			Avb_private_key:    avbInfo.avbkeyFilegroup,
 			Avb_rollback_index: avbInfo.avbRollbackIndex,
 			Avb_algorithm:      avbInfo.avbAlgorithm,
+			Dtb_prebuilt:       dtbPrebuilt,
 		},
 		&struct {
 			Name *string
@@ -217,3 +230,47 @@
 	}
 	return int(v), true
 }
+
+type dtbImg struct {
+	// whether to include the dtb image in boot image
+	include bool
+
+	// name of the generated dtb image filegroup name
+	name string
+
+	// type of the boot image that the dtb image argument should be specified
+	imgType string
+}
+
+func createDtbImgFilegroup(ctx android.LoadHookContext) dtbImg {
+	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+	if !partitionVars.BoardIncludeDtbInBootimg {
+		return dtbImg{include: false}
+	}
+	for _, copyFilePair := range partitionVars.ProductCopyFiles {
+		srcDestList := strings.Split(copyFilePair, ":")
+		if len(srcDestList) < 2 {
+			ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair)
+		}
+		if srcDestList[1] == "dtb.img" {
+			moduleName := generatedModuleName(ctx.Config(), "dtb_img_filegroup")
+			ctx.CreateModuleInDirectory(
+				android.FileGroupFactory,
+				filepath.Dir(srcDestList[0]),
+				&struct {
+					Name *string
+					Srcs []string
+				}{
+					Name: proptools.StringPtr(moduleName),
+					Srcs: []string{filepath.Base(srcDestList[1])},
+				},
+			)
+			imgType := "vendor_boot"
+			if !buildingVendorBootImage(partitionVars) {
+				imgType = "boot"
+			}
+			return dtbImg{include: true, name: moduleName, imgType: imgType}
+		}
+	}
+	return dtbImg{include: false}
+}
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index d4301f9..08812ec 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -124,15 +124,17 @@
 	}
 
 	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+	dtbImg := createDtbImgFilegroup(ctx)
+
 	if buildingBootImage(partitionVars) {
-		if createBootImage(ctx) {
+		if createBootImage(ctx, dtbImg) {
 			f.properties.Boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "boot")
 		} else {
 			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "boot")
 		}
 	}
 	if buildingVendorBootImage(partitionVars) {
-		if createVendorBootImage(ctx) {
+		if createVendorBootImage(ctx, dtbImg) {
 			f.properties.Vendor_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
 		} else {
 			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "vendor_boot")