Avb sign boot images

The bootimg module had a very different implementation of avb signing
than what was in make. Add an alternate implemenation that is used
when avb_private_key is not set.

Bug: 377562951
Test: m nothing --no-skip-soong-tests
Change-Id: I253bcc8135f3d294eb6e09f39429c84c7c0fc037
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 2249506..90409b3 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -89,6 +89,10 @@
 
 	// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
 	Avb_algorithm *string
+
+	// The security patch passed to as the com.android.build.<type>.security_patch avb property.
+	// Replacement for the make variables BOOT_SECURITY_PATCH / INIT_BOOT_SECURITY_PATCH.
+	Security_patch *string
 }
 
 type bootImageType int
@@ -114,6 +118,19 @@
 	return unsupported
 }
 
+func (b bootImageType) String() string {
+	switch b {
+	case boot:
+		return "boot"
+	case vendorBoot:
+		return "vendor_boot"
+	case initBoot:
+		return "init_boot"
+	default:
+		panic("unknown boot image type")
+	}
+}
+
 func (b bootImageType) isBoot() bool {
 	return b == boot
 }
@@ -158,11 +175,39 @@
 
 func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	b.bootImageType = toBootImageType(ctx, proptools.StringDefault(b.properties.Boot_image_type, "boot"))
-	unsignedOutput := b.buildBootImage(ctx)
+	if b.bootImageType == unsupported {
+		return
+	}
+
+	kernelProp := proptools.String(b.properties.Kernel_prebuilt)
+	if b.bootImageType.isVendorBoot() && kernelProp != "" {
+		ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
+		return
+	}
+	if b.bootImageType.isBoot() && kernelProp == "" {
+		ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
+		return
+	}
+	var kernel android.Path
+	if kernelProp != "" {
+		kernel = android.PathForModuleSrc(ctx, kernelProp)
+	}
+
+	unsignedOutput := b.buildBootImage(ctx, kernel)
 
 	output := unsignedOutput
 	if proptools.Bool(b.properties.Use_avb) {
-		output = b.signImage(ctx, unsignedOutput)
+		// This bootimg module supports 2 modes of avb signing, it picks between them based on
+		// if the private key is specified or not. If there is a key, it does a signing process
+		// similar to how the regular partitions (system, product, vendor, etc) are signed.
+		// If the key is not provided, it will just add an avb footer to the image. The avb
+		// footer only signing is how the make-built init_boot, boot, and vendor_boot images are
+		// built.
+		if proptools.String(b.properties.Avb_private_key) != "" {
+			output = b.signImage(ctx, unsignedOutput)
+		} else {
+			output = b.addAvbFooter(ctx, unsignedOutput, kernel)
+		}
 	}
 
 	b.installDir = android.PathForModuleInstall(ctx, "etc")
@@ -172,24 +217,14 @@
 	b.output = output
 }
 
-func (b *bootimg) buildBootImage(ctx android.ModuleContext) android.Path {
+func (b *bootimg) buildBootImage(ctx android.ModuleContext, kernel android.Path) android.Path {
 	output := android.PathForModuleOut(ctx, "unsigned", b.installFileName())
 
 	builder := android.NewRuleBuilder(pctx, ctx)
 	cmd := builder.Command().BuiltTool("mkbootimg")
 
-	kernel := proptools.String(b.properties.Kernel_prebuilt)
-	if b.bootImageType.isVendorBoot() && kernel != "" {
-		ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
-		return output
-	}
-
-	if b.bootImageType.isBoot() && kernel == "" {
-		ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
-		return output
-	}
-	if kernel != "" {
-		cmd.FlagWithInput("--kernel ", android.PathForModuleSrc(ctx, kernel))
+	if kernel != nil {
+		cmd.FlagWithInput("--kernel ", kernel)
 	}
 
 	// These arguments are passed for boot.img and init_boot.img generation
@@ -272,6 +307,45 @@
 	return output
 }
 
+func (b *bootimg) addAvbFooter(ctx android.ModuleContext, unsignedImage android.Path, kernel android.Path) android.Path {
+	output := android.PathForModuleOut(ctx, b.installFileName())
+	builder := android.NewRuleBuilder(pctx, ctx)
+	builder.Command().Text("cp").Input(unsignedImage).Output(output)
+	cmd := builder.Command().BuiltTool("avbtool").
+		Text("add_hash_footer").
+		FlagWithInput("--image ", output)
+
+	if b.properties.Partition_size != nil {
+		cmd.FlagWithArg("--partition_size ", strconv.FormatInt(*b.properties.Partition_size, 10))
+	} else {
+		cmd.Flag("--dynamic_partition_size")
+	}
+
+	if kernel != nil {
+		cmd.Textf(`--salt $(sha256sum "%s" | cut -d " " -f 1)`, kernel.String())
+		cmd.Implicit(kernel)
+	}
+
+	cmd.FlagWithArg("--partition_name ", b.bootImageType.String())
+
+	if !b.bootImageType.isVendorBoot() {
+		cmd.FlagWithArg("--prop ", proptools.NinjaAndShellEscape(fmt.Sprintf(
+			"com.android.build.%s.os_version:%s", b.bootImageType.String(), ctx.Config().PlatformVersionLastStable())))
+	}
+
+	fingerprintFile := ctx.Config().BuildFingerprintFile(ctx)
+	cmd.FlagWithArg("--prop ", fmt.Sprintf("com.android.build.%s.fingerprint:%s", b.bootImageType.String(), fingerprintFile.String()))
+	cmd.OrderOnly(fingerprintFile)
+
+	if b.properties.Security_patch != nil {
+		cmd.FlagWithArg("--prop ", proptools.NinjaAndShellEscape(fmt.Sprintf(
+			"com.android.build.%s.security_patch:%s", b.bootImageType.String(), *b.properties.Security_patch)))
+	}
+
+	builder.Build("add_avb_footer", fmt.Sprintf("Adding avb footer to %s", b.BaseModuleName()))
+	return output
+}
+
 func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.Path) android.Path {
 	propFile, toolDeps := b.buildPropFile(ctx)