Snap for 12755599 from 6cba6573f7ff997a14fc05fda064c2855fb3669c to 25Q1-release

Change-Id: I61f5be5bed24a0d343bebea5f473c957dddbc7c6
diff --git a/android/variable.go b/android/variable.go
index 3829f48..e012103 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -582,6 +582,11 @@
 	BoardAvbRollbackIndexLocation string `json:",omitempty"`
 }
 
+type BoardSuperPartitionGroupProps struct {
+	GroupSize     string   `json:",omitempty"`
+	PartitionList []string `json:",omitempty"`
+}
+
 type ChainedAvbPartitionProps struct {
 	Partitions            []string `json:",omitempty"`
 	Key                   string   `json:",omitempty"`
@@ -635,6 +640,18 @@
 	InternalBootconfig              []string `json:",omitempty"`
 	InternalBootconfigFile          string   `json:",omitempty"`
 
+	// Super image stuff
+	ProductUseDynamicPartitions       bool                                     `json:",omitempty"`
+	ProductRetrofitDynamicPartitions  bool                                     `json:",omitempty"`
+	ProductBuildSuperPartition        bool                                     `json:",omitempty"`
+	BoardSuperPartitionSize           string                                   `json:",omitempty"`
+	BoardSuperPartitionMetadataDevice string                                   `json:",omitempty"`
+	BoardSuperPartitionBlockDevices   []string                                 `json:",omitempty"`
+	BoardSuperPartitionGroups         map[string]BoardSuperPartitionGroupProps `json:",omitempty"`
+	ProductVirtualAbOta               bool                                     `json:",omitempty"`
+	ProductVirtualAbOtaRetrofit       bool                                     `json:",omitempty"`
+	AbOtaUpdater                      bool                                     `json:",omitempty"`
+
 	// Avb (android verified boot) stuff
 	BoardAvbEnable          bool                                `json:",omitempty"`
 	BoardAvbAlgorithm       string                              `json:",omitempty"`
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index bbb3ea7..127faa7 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -25,6 +25,7 @@
         "fsverity_metadata.go",
         "logical_partition.go",
         "raw_binary.go",
+        "super_image.go",
         "system_image.go",
         "vbmeta.go",
         "testing.go",
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index fbc8089..d49ac1f 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -53,6 +53,12 @@
 	})
 }
 
+// Remember to add referenced files to implicits!
+var textFileProcessorRule = pctx.AndroidStaticRule("text_file_processing", blueprint.RuleParams{
+	Command:     "build/soong/scripts/text_file_processor.py $in $out",
+	CommandDeps: []string{"build/soong/scripts/text_file_processor.py"},
+})
+
 type filesystem struct {
 	android.ModuleBase
 	android.PackagingBase
@@ -107,6 +113,9 @@
 	// avbtool. Default used by avbtool is sha1.
 	Avb_hash_algorithm *string
 
+	// Whether or not to use forward-error-correction codes when signing with AVB. Defaults to true.
+	Use_fec *bool
+
 	// The index used to prevent rollback of the image. Only used if use_avb is true.
 	Rollback_index *int64
 
@@ -563,11 +572,21 @@
 		FlagWithArg("--out_system=", rootDir.String()+"/system")
 
 	propFile, toolDeps := f.buildPropFile(ctx)
+
+	// Most of the time, if build_image were to call a host tool, it accepts the path to the
+	// host tool in a field in the prop file. However, it doesn't have that option for fec, which
+	// it expects to just be on the PATH. Add fec to the PATH.
+	fec := ctx.Config().HostToolPath(ctx, "fec")
+	pathToolDirs := []string{filepath.Dir(fec.String())}
+
 	output := android.PathForModuleOut(ctx, f.installFileName())
-	builder.Command().BuiltTool("build_image").
+	builder.Command().
+		Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")).
+		BuiltTool("build_image").
 		Text(rootDir.String()). // input directory
 		Input(propFile).
 		Implicits(toolDeps).
+		Implicit(fec).
 		Output(output).
 		Text(rootDir.String()) // directory where to find fs_config_files|dirs
 
@@ -634,10 +653,15 @@
 		addPath("avb_avbtool", ctx.Config().HostToolPath(ctx, "avbtool"))
 		algorithm := proptools.StringDefault(f.properties.Avb_algorithm, "SHA256_RSA4096")
 		addStr("avb_algorithm", algorithm)
-		key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
-		addPath("avb_key_path", key)
+		if f.properties.Avb_private_key != nil {
+			key := android.PathForModuleSrc(ctx, *f.properties.Avb_private_key)
+			addPath("avb_key_path", key)
+		}
 		addStr("partition_name", f.partitionName())
-		avb_add_hashtree_footer_args := "--do_not_generate_fec"
+		avb_add_hashtree_footer_args := ""
+		if !proptools.BoolDefault(f.properties.Use_fec, true) {
+			avb_add_hashtree_footer_args += " --do_not_generate_fec"
+		}
 		if hashAlgorithm := proptools.String(f.properties.Avb_hash_algorithm); hashAlgorithm != "" {
 			avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
 		}
@@ -648,9 +672,9 @@
 			}
 			avb_add_hashtree_footer_args += " --rollback_index " + strconv.Itoa(rollbackIndex)
 		}
-		securityPatchKey := "com.android.build." + f.partitionName() + ".security_patch"
-		securityPatchValue := ctx.Config().PlatformSecurityPatch()
-		avb_add_hashtree_footer_args += " --prop " + securityPatchKey + ":" + securityPatchValue
+		avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.os_version:%s", f.partitionName(), ctx.Config().PlatformVersionLastStable())
+		avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", f.partitionName(), ctx.Config().BuildFingerprintFile(ctx))
+		avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.security_patch:%s", f.partitionName(), ctx.Config().PlatformSecurityPatch())
 		addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args)
 		addStr("avb_salt", f.salt())
 	}
@@ -694,8 +718,15 @@
 	}
 	f.checkFsTypePropertyError(ctx, fst, fsTypeStr(fst))
 
+	propFilePreProcessing := android.PathForModuleOut(ctx, "prop_pre_processing")
+	android.WriteFileRuleVerbatim(ctx, propFilePreProcessing, propFileString.String())
 	propFile := android.PathForModuleOut(ctx, "prop")
-	android.WriteFileRuleVerbatim(ctx, propFile, propFileString.String())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:     textFileProcessorRule,
+		Input:    propFilePreProcessing,
+		Output:   propFile,
+		Implicit: ctx.Config().BuildFingerprintFile(ctx),
+	})
 	return propFile, deps
 }
 
@@ -981,7 +1012,7 @@
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		for _, ps := range android.OtherModuleProviderOrDefault(
 			ctx, child, android.InstallFilesProvider).PackagingSpecs {
-			if _, ok := deps[ps.RelPathInPackage()]; ok {
+			if _, ok := deps[ps.RelPathInPackage()]; ok && ps.Partition() == f.PartitionType() {
 				modulesInPackageByModule[child] = true
 				modulesInPackageByName[child.Name()] = true
 				return true
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 72a5211..86496eb 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -593,7 +593,7 @@
 	`)
 
 	partition := result.ModuleForTests("erofs_partition", "android_common")
-	buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop"))
+	buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop_pre_processing"))
 	android.AssertStringDoesContain(t, "erofs fs type", buildImageConfig, "fs_type=erofs")
 	android.AssertStringDoesContain(t, "erofs fs type compress algorithm", buildImageConfig, "erofs_default_compressor=lz4hc,9")
 	android.AssertStringDoesContain(t, "erofs fs type compress hint", buildImageConfig, "erofs_default_compress_hints=compress_hints.txt")
@@ -609,7 +609,7 @@
 	`)
 
 	partition := result.ModuleForTests("f2fs_partition", "android_common")
-	buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop"))
+	buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop_pre_processing"))
 	android.AssertStringDoesContain(t, "f2fs fs type", buildImageConfig, "fs_type=f2fs")
 	android.AssertStringDoesContain(t, "f2fs fs type sparse", buildImageConfig, "f2fs_sparse_flag=-S")
 }
diff --git a/filesystem/super_image.go b/filesystem/super_image.go
new file mode 100644
index 0000000..1583c0b
--- /dev/null
+++ b/filesystem/super_image.go
@@ -0,0 +1,234 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+	"fmt"
+	"path/filepath"
+	"strconv"
+	"strings"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	android.RegisterModuleType("super_image", SuperImageFactory)
+}
+
+type superImage struct {
+	android.ModuleBase
+
+	properties     SuperImageProperties
+	partitionProps SuperImagePartitionNameProperties
+
+	installDir android.InstallPath
+}
+
+type SuperImageProperties struct {
+	// the size of the super partition
+	Size *int64
+	// the block device where metadata for dynamic partitions is stored
+	Metadata_device *string
+	// the super partition block device list
+	Block_devices *string
+	// whether A/B updater is used
+	Ab_update *bool
+	// whether dynamic partitions is enabled on devices that were launched without this support
+	Retrofit *bool
+	// whether virtual A/B seamless update is enabled
+	Virtual_ab *bool
+	// whether retrofitting virtual A/B seamless update is enabled
+	Virtual_ab_retrofit *bool
+	// whether the output is a sparse image
+	Sparse *bool
+	// information about how partitions within the super partition are grouped together
+	Partition_groups []PartitionGroupsInfo
+	// whether dynamic partitions is used
+	Use_dynamic_partitions *bool
+}
+
+type PartitionGroupsInfo struct {
+	Name          string
+	GroupSize     string
+	PartitionList []string
+}
+
+type SuperImagePartitionNameProperties struct {
+	// Name of the System partition filesystem module
+	System_partition *string
+	// Name of the System_ext partition filesystem module
+	System_ext_partition *string
+	// Name of the System_dlkm partition filesystem module
+	System_dlkm_partition *string
+	// Name of the System_other partition filesystem module
+	System_other_partition *string
+	// Name of the Product partition filesystem module
+	Product_partition *string
+	// Name of the Vendor partition filesystem module
+	Vendor_partition *string
+	// Name of the Vendor_dlkm partition filesystem module
+	Vendor_dlkm_partition *string
+	// Name of the Odm partition filesystem module
+	Odm_partition *string
+	// Name of the Odm_dlkm partition filesystem module
+	Odm_dlkm_partition *string
+}
+
+func SuperImageFactory() android.Module {
+	module := &superImage{}
+	module.AddProperties(&module.properties, &module.partitionProps)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+type superImageDepTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var superImageDepTag superImageDepTagType
+
+func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) {
+	addDependencyIfDefined := func(dep *string) {
+		if dep != nil {
+			ctx.AddDependency(ctx.Module(), superImageDepTag, proptools.String(dep))
+		}
+	}
+
+	addDependencyIfDefined(s.partitionProps.System_partition)
+	addDependencyIfDefined(s.partitionProps.System_ext_partition)
+	addDependencyIfDefined(s.partitionProps.System_dlkm_partition)
+	addDependencyIfDefined(s.partitionProps.System_other_partition)
+	addDependencyIfDefined(s.partitionProps.Product_partition)
+	addDependencyIfDefined(s.partitionProps.Vendor_partition)
+	addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition)
+	addDependencyIfDefined(s.partitionProps.Odm_partition)
+	addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition)
+}
+
+func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	miscInfo, deps := s.buildMiscInfo(ctx)
+	builder := android.NewRuleBuilder(pctx, ctx)
+	output := android.PathForModuleOut(ctx, s.installFileName())
+	lpMake := ctx.Config().HostToolPath(ctx, "lpmake")
+	lpMakeDir := filepath.Dir(lpMake.String())
+	deps = append(deps, lpMake)
+	builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir).
+		BuiltTool("build_super_image").
+		Text("-v").
+		Input(miscInfo).
+		Implicits(deps).
+		Output(output)
+	builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName()))
+	ctx.SetOutputFiles([]android.Path{output}, "")
+}
+
+func (s *superImage) installFileName() string {
+	return s.BaseModuleName() + ".img"
+}
+
+func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths) {
+	var miscInfoString strings.Builder
+	addStr := func(name string, value string) {
+		miscInfoString.WriteString(name)
+		miscInfoString.WriteRune('=')
+		miscInfoString.WriteString(value)
+		miscInfoString.WriteRune('\n')
+	}
+
+	addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
+	addStr("dynamic_partition_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Retrofit)))
+	addStr("lpmake", "lpmake")
+	addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
+	addStr("super_block_devices", proptools.String(s.properties.Block_devices))
+	addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
+	var groups, partitionList []string
+	for _, groupInfo := range s.properties.Partition_groups {
+		groups = append(groups, groupInfo.Name)
+		partitionList = append(partitionList, groupInfo.PartitionList...)
+		addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
+		addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
+	}
+	addStr("super_partition_groups", strings.Join(groups, " "))
+	addStr("dynamic_partition_list", strings.Join(partitionList, " "))
+
+	addStr("virtual_ab", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab)))
+	addStr("virtual_ab_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab_retrofit)))
+	addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
+	addStr("build_non_sparse_super_partition", strconv.FormatBool(!proptools.Bool(s.properties.Sparse)))
+
+	partitionToImagePath := make(map[string]string)
+	nameToPartition := make(map[string]string)
+	var systemOtherPartitionNameNeeded string
+	addEntryToPartitionToName := func(p string, s *string) {
+		if proptools.String(s) != "" {
+			nameToPartition[*s] = p
+		}
+	}
+
+	// Build partitionToImagePath, because system partition may need system_other
+	// partition image path
+	for _, p := range partitionList {
+		if _, ok := nameToPartition[p]; ok {
+			continue
+		}
+		switch p {
+		case "system":
+			addEntryToPartitionToName(p, s.partitionProps.System_partition)
+			systemOtherPartitionNameNeeded = proptools.String(s.partitionProps.System_other_partition)
+		case "system_dlkm":
+			addEntryToPartitionToName(p, s.partitionProps.System_dlkm_partition)
+		case "system_ext":
+			addEntryToPartitionToName(p, s.partitionProps.System_ext_partition)
+		case "product":
+			addEntryToPartitionToName(p, s.partitionProps.Product_partition)
+		case "vendor":
+			addEntryToPartitionToName(p, s.partitionProps.Vendor_partition)
+		case "vendor_dlkm":
+			addEntryToPartitionToName(p, s.partitionProps.Vendor_dlkm_partition)
+		case "odm":
+			addEntryToPartitionToName(p, s.partitionProps.Odm_partition)
+		case "odm_dlkm":
+			addEntryToPartitionToName(p, s.partitionProps.Odm_dlkm_partition)
+		default:
+			ctx.ModuleErrorf("current partition %s not a super image supported partition", p)
+		}
+	}
+
+	var deps android.Paths
+	ctx.VisitDirectDeps(func(m android.Module) {
+		if p, ok := nameToPartition[m.Name()]; ok {
+			if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
+				partitionToImagePath[p] = output.DefaultOutputFiles[0].String()
+				deps = append(deps, output.DefaultOutputFiles[0])
+			}
+		} else if systemOtherPartitionNameNeeded != "" && m.Name() == systemOtherPartitionNameNeeded {
+			if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
+				partitionToImagePath["system_other"] = output.DefaultOutputFiles[0].String()
+				// TODO: add system_other to deps after it can be generated
+				// deps = append(deps, output.DefaultOutputFiles[0])
+			}
+		}
+	})
+
+	for _, p := range android.SortedKeys(partitionToImagePath) {
+		addStr(p+"_image", partitionToImagePath[p])
+	}
+
+	miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
+	android.WriteFileRule(ctx, miscInfo, miscInfoString.String())
+	return miscInfo, deps
+}
diff --git a/fsgen/Android.bp b/fsgen/Android.bp
index e8065f3..365d954 100644
--- a/fsgen/Android.bp
+++ b/fsgen/Android.bp
@@ -17,6 +17,7 @@
         "filesystem_creator.go",
         "fsgen_mutators.go",
         "prebuilt_etc_modules_gen.go",
+        "super_img.go",
         "util.go",
         "vbmeta_partitions.go",
     ],
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 745aeaa..8d355dd 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -18,6 +18,7 @@
 	"crypto/sha256"
 	"fmt"
 	"path/filepath"
+	"slices"
 	"strconv"
 	"strings"
 
@@ -51,6 +52,7 @@
 	Boot_image        string `blueprint:"mutated" android:"path_device_first"`
 	Vendor_boot_image string `blueprint:"mutated" android:"path_device_first"`
 	Init_boot_image   string `blueprint:"mutated" android:"path_device_first"`
+	Super_image       string `blueprint:"mutated" android:"path_device_first"`
 }
 
 type filesystemCreator struct {
@@ -157,6 +159,11 @@
 		f.properties.Vbmeta_partition_names = append(f.properties.Vbmeta_partition_names, x.partitionName)
 	}
 
+	if buildingSuperImage(partitionVars) {
+		createSuperImage(ctx, finalSoongGeneratedPartitions, partitionVars)
+		f.properties.Super_image = ":" + generatedModuleName(ctx.Config(), "super")
+	}
+
 	ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions = finalSoongGeneratedPartitions
 	f.createDeviceModule(ctx, finalSoongGeneratedPartitions, f.properties.Vbmeta_module_names)
 }
@@ -766,6 +773,7 @@
 	fsProps.Avb_algorithm = avbInfo.avbAlgorithm
 	// BOARD_AVB_SYSTEM_ROLLBACK_INDEX
 	fsProps.Rollback_index = avbInfo.avbRollbackIndex
+	fsProps.Avb_hash_algorithm = avbInfo.avbHashAlgorithm
 
 	fsProps.Partition_name = proptools.StringPtr(partitionType)
 
@@ -799,6 +807,7 @@
 	avbAlgorithm     *string
 	avbRollbackIndex *int64
 	avbMode          *string
+	avbHashAlgorithm *string
 }
 
 func getAvbInfo(config android.Config, partitionType string) avbInfo {
@@ -808,10 +817,23 @@
 	boardAvbEnable := partitionVars.BoardAvbEnable
 	if boardAvbEnable {
 		result.avbEnable = proptools.BoolPtr(true)
+		// There are "global" and "specific" copies of a lot of these variables. Sometimes they
+		// choose the specific and then fall back to the global one if it's not set, other times
+		// the global one actually only applies to the vbmeta partition.
+		if partitionType == "vbmeta" {
+			if partitionVars.BoardAvbKeyPath != "" {
+				result.avbKeyPath = proptools.StringPtr(partitionVars.BoardAvbKeyPath)
+			}
+			if partitionVars.BoardAvbRollbackIndex != "" {
+				parsed, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64)
+				if err != nil {
+					panic(fmt.Sprintf("Rollback index must be an int, got %s", partitionVars.BoardAvbRollbackIndex))
+				}
+				result.avbRollbackIndex = &parsed
+			}
+		}
 		if specificPartitionVars.BoardAvbKeyPath != "" {
 			result.avbKeyPath = proptools.StringPtr(specificPartitionVars.BoardAvbKeyPath)
-		} else if partitionVars.BoardAvbKeyPath != "" {
-			result.avbKeyPath = proptools.StringPtr(partitionVars.BoardAvbKeyPath)
 		}
 		if specificPartitionVars.BoardAvbAlgorithm != "" {
 			result.avbAlgorithm = proptools.StringPtr(specificPartitionVars.BoardAvbAlgorithm)
@@ -824,13 +846,24 @@
 				panic(fmt.Sprintf("Rollback index must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndex))
 			}
 			result.avbRollbackIndex = &parsed
-		} else if partitionVars.BoardAvbRollbackIndex != "" {
-			parsed, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64)
+		}
+		if specificPartitionVars.BoardAvbRollbackIndex != "" {
+			parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndex, 10, 64)
 			if err != nil {
-				panic(fmt.Sprintf("Rollback index must be an int, got %s", partitionVars.BoardAvbRollbackIndex))
+				panic(fmt.Sprintf("Rollback index must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndex))
 			}
 			result.avbRollbackIndex = &parsed
 		}
+
+		// Make allows you to pass arbitrary arguments to avbtool via this variable, but in practice
+		// it's only used for --hash_algorithm. The soong module has a dedicated property for the
+		// hashtree algorithm, and doesn't allow custom arguments, so just extract the hashtree
+		// algorithm out of the arbitrary arguments.
+		addHashtreeFooterArgs := strings.Split(specificPartitionVars.BoardAvbAddHashtreeFooterArgs, " ")
+		if i := slices.Index(addHashtreeFooterArgs, "--hash_algorithm"); i >= 0 {
+			result.avbHashAlgorithm = &addHashtreeFooterArgs[i+1]
+		}
+
 		result.avbMode = proptools.StringPtr("make_legacy")
 	}
 	if result.avbKeyPath != nil {
@@ -971,6 +1004,14 @@
 		diffTestFiles = append(diffTestFiles, diffTestFile)
 		ctx.Phony("soong_generated_init_boot_filesystem_test", diffTestFile)
 	}
+	if f.properties.Super_image != "" {
+		diffTestFile := android.PathForModuleOut(ctx, "super_diff_test.txt")
+		soongSuperImg := android.PathForModuleSrc(ctx, f.properties.Super_image)
+		makeSuperImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/super.img", ctx.Config().DeviceName()))
+		createDiffTest(ctx, diffTestFile, soongSuperImg, makeSuperImage)
+		diffTestFiles = append(diffTestFiles, diffTestFile)
+		ctx.Phony("soong_generated_super_filesystem_test", diffTestFile)
+	}
 	ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...)
 }
 
diff --git a/fsgen/super_img.go b/fsgen/super_img.go
new file mode 100644
index 0000000..4569896
--- /dev/null
+++ b/fsgen/super_img.go
@@ -0,0 +1,91 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fsgen
+
+import (
+	"strconv"
+
+	"android/soong/android"
+	"android/soong/filesystem"
+	"github.com/google/blueprint/proptools"
+)
+
+func buildingSuperImage(partitionVars android.PartitionVariables) bool {
+	return partitionVars.ProductBuildSuperPartition
+}
+
+func createSuperImage(ctx android.LoadHookContext, partitions []string, partitionVars android.PartitionVariables) {
+	baseProps := &struct {
+		Name *string
+	}{
+		Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "super")),
+	}
+
+	superImageProps := &filesystem.SuperImageProperties{
+		Metadata_device:        proptools.StringPtr(partitionVars.BoardSuperPartitionMetadataDevice),
+		Block_devices:          proptools.StringPtr(partitionVars.BoardSuperPartitionBlockDevices[0]),
+		Ab_update:              proptools.BoolPtr(partitionVars.AbOtaUpdater),
+		Retrofit:               proptools.BoolPtr(partitionVars.ProductRetrofitDynamicPartitions),
+		Virtual_ab:             proptools.BoolPtr(partitionVars.ProductVirtualAbOta),
+		Virtual_ab_retrofit:    proptools.BoolPtr(partitionVars.ProductVirtualAbOtaRetrofit),
+		Use_dynamic_partitions: proptools.BoolPtr(partitionVars.ProductUseDynamicPartitions),
+	}
+	size, _ := strconv.ParseInt(partitionVars.BoardSuperPartitionSize, 10, 64)
+	superImageProps.Size = proptools.Int64Ptr(size)
+	sparse := !partitionVars.TargetUserimagesSparseExtDisabled && !partitionVars.TargetUserimagesSparseF2fsDisabled
+	superImageProps.Sparse = proptools.BoolPtr(sparse)
+
+	var partitionGroupsInfo []filesystem.PartitionGroupsInfo
+	for _, groupName := range android.SortedKeys(partitionVars.BoardSuperPartitionGroups) {
+		info := filesystem.PartitionGroupsInfo{
+			Name:          groupName,
+			GroupSize:     partitionVars.BoardSuperPartitionGroups[groupName].GroupSize,
+			PartitionList: partitionVars.BoardSuperPartitionGroups[groupName].PartitionList,
+		}
+		partitionGroupsInfo = append(partitionGroupsInfo, info)
+	}
+	superImageProps.Partition_groups = partitionGroupsInfo
+
+	partitionNameProps := &filesystem.SuperImagePartitionNameProperties{}
+	if android.InList("system", partitions) {
+		partitionNameProps.System_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system"))
+	}
+	if android.InList("system_ext", partitions) {
+		partitionNameProps.System_ext_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system_ext"))
+	}
+	if android.InList("system_dlkm", partitions) {
+		partitionNameProps.System_dlkm_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system_dlkm"))
+	}
+	if android.InList("system_other", partitions) {
+		partitionNameProps.System_other_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system_other"))
+	}
+	if android.InList("product", partitions) {
+		partitionNameProps.Product_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "product"))
+	}
+	if android.InList("vendor", partitions) {
+		partitionNameProps.Vendor_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor"))
+	}
+	if android.InList("vendor_dlkm", partitions) {
+		partitionNameProps.Vendor_dlkm_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_dlkm"))
+	}
+	if android.InList("odm", partitions) {
+		partitionNameProps.Odm_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "odm"))
+	}
+	if android.InList("odm_dlkm", partitions) {
+		partitionNameProps.Odm_dlkm_partition = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "odm_dlkm"))
+	}
+
+	ctx.CreateModule(filesystem.SuperImageFactory, baseProps, superImageProps, partitionNameProps)
+}
diff --git a/java/app.go b/java/app.go
index 8739d1c..bedb45c 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1794,9 +1794,9 @@
 
 	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
 	android.InitOverrideModule(m)
-	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
+	android.AddLoadHookWithPriority(m, func(ctx android.LoadHookContext) {
 		createInternalRuntimeOverlays(ctx, m.ModuleBase)
-	})
+	}, 1) // Run after soong config load hoook
 
 	return m
 }
diff --git a/java/app_test.go b/java/app_test.go
index 61b718d..11556b0 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -4798,3 +4798,76 @@
 		android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.Rule != nil)
 	}
 }
+
+func TestNoAutogeneratedStaticRroForDisabledOverrideApps(t *testing.T) {
+	t.Parallel()
+	bp := `
+soong_config_module_type {
+	name: "my_custom_override_android_app",
+	module_type: "override_android_app",
+	config_namespace: "my_namespace",
+	value_variables: ["my_app_enabled"],
+	properties: ["enabled"],
+}
+soong_config_bool_variable {
+	name: "my_app_enabled",
+}
+android_app {
+	name: "foo",
+	srcs: ["foo.java"],
+	platform_apis: true,
+}
+my_custom_override_android_app {
+	name: "override_foo",
+	base: "foo",
+	soong_config_variables: {
+		my_app_enabled: {
+			enabled: true,
+			conditions_default: {
+				enabled: false
+			},
+		},
+	}
+}
+`
+	testCases := []struct {
+		desc               string
+		preparer           android.FixturePreparer
+		overlayApkExpected bool
+	}{
+		{
+			desc:               "my_app_enabled is empty",
+			overlayApkExpected: false,
+		},
+		{
+			desc:               "my_app_enabled is true",
+			overlayApkExpected: true,
+			preparer: android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"my_namespace": {
+						"my_app_enabled": "true",
+					},
+				}
+			}),
+		},
+	}
+	for _, tc := range testCases {
+		result := android.GroupFixturePreparers(
+			PrepareForTestWithJavaDefaultModules,
+			android.PrepareForTestWithSoongConfigModuleBuildComponents,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.EnforceRROTargets = []string{"*"}
+			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.DeviceResourceOverlays = []string{"device/company/test_product"}
+			}),
+			android.MockFS{
+				"res/foo.xml": nil,
+				"device/company/test_product/res/foo.xml": nil,
+			}.AddToFixture(),
+			android.OptionalFixturePreparer(tc.preparer),
+		).RunTestWithBp(t, bp)
+		overrideVendorOverlayApk := result.ModuleForTests("override_foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").Module().(*AutogenRuntimeResourceOverlay)
+		android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.exportPackage != nil)
+	}
+}
diff --git a/root.bp b/root.bp
index 7e0c1ed..8e621c4 100644
--- a/root.bp
+++ b/root.bp
@@ -2,3 +2,10 @@
 // subdirs= and optional_subdirs= are obsolete and this file no longer
 // needs a list of the top level directories that may contain Android.bp
 // files.
+
+// TODO(b/253827323) Remove this. A module in internal builds needs to disable a new check,
+// IdentifierName, when errorprone is updated. In order to avoid having the update errorprone
+// in internal first, and then aosp, create this variable that we can fill out in internal in the
+// same topic as the errorprone update, then move the flag out of the variable after the update,
+// then remove the variable.
+disable_identifiername_for_errorprone_update = []
diff --git a/scripts/build-apex-bundle.py b/scripts/build-apex-bundle.py
index dcdd9ef..277e112 100644
--- a/scripts/build-apex-bundle.py
+++ b/scripts/build-apex-bundle.py
@@ -16,8 +16,6 @@
 #
 """A tool to create an APEX bundle out of Soong-built base.zip"""
 
-from __future__ import print_function
-
 import argparse
 import sys
 import tempfile
diff --git a/scripts/check_boot_jars/check_boot_jars.py b/scripts/check_boot_jars/check_boot_jars.py
index b711f9d..174b96e 100755
--- a/scripts/check_boot_jars/check_boot_jars.py
+++ b/scripts/check_boot_jars/check_boot_jars.py
@@ -4,7 +4,6 @@
 Usage: check_boot_jars.py <dexdump_path> <package_allow_list_file> <jar1> \
 <jar2> ...
 """
-from __future__ import print_function
 import logging
 import re
 import subprocess
diff --git a/scripts/construct_context.py b/scripts/construct_context.py
index fc3a89e..882c2db 100755
--- a/scripts/construct_context.py
+++ b/scripts/construct_context.py
@@ -16,8 +16,6 @@
 #
 """A tool for constructing class loader context."""
 
-from __future__ import print_function
-
 import argparse
 import json
 import sys
diff --git a/scripts/manifest.py b/scripts/manifest.py
index 32603e8..87f4f0c 100755
--- a/scripts/manifest.py
+++ b/scripts/manifest.py
@@ -16,7 +16,6 @@
 #
 """A tool for inserting values from the build system into a manifest or a test config."""
 
-from __future__ import print_function
 from xml.dom import minidom
 
 
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 1e32d1d..175451e 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -16,8 +16,6 @@
 #
 """A tool for checking that a manifest agrees with the build system."""
 
-from __future__ import print_function
-
 import argparse
 import json
 import re
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 9847ad5..ad3b313 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -16,8 +16,6 @@
 #
 """A tool for inserting values from the build system into a manifest."""
 
-from __future__ import print_function
-
 import argparse
 import sys
 from xml.dom import minidom
diff --git a/scripts/modify_permissions_allowlist.py b/scripts/modify_permissions_allowlist.py
index 38ec7ec..4a0ca8f 100755
--- a/scripts/modify_permissions_allowlist.py
+++ b/scripts/modify_permissions_allowlist.py
@@ -16,8 +16,6 @@
 #
 """A tool for modifying privileged permission allowlists."""
 
-from __future__ import print_function
-
 import argparse
 import sys
 from xml.dom import minidom
diff --git a/scripts/modify_permissions_allowlist_test.py b/scripts/modify_permissions_allowlist_test.py
index ee8b12c..577388f 100755
--- a/scripts/modify_permissions_allowlist_test.py
+++ b/scripts/modify_permissions_allowlist_test.py
@@ -16,8 +16,6 @@
 #
 """Unit tests for modify_permissions_allowlist.py."""
 
-from __future__ import print_function
-
 import unittest
 
 from xml.dom import minidom
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 2876bcb..91a83f2 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -16,8 +16,6 @@
 #
 """A tool for modifying values in a test config."""
 
-from __future__ import print_function
-
 import argparse
 import json
 import sys
diff --git a/scripts/text_file_processor.py b/scripts/text_file_processor.py
new file mode 100755
index 0000000..10186ce
--- /dev/null
+++ b/scripts/text_file_processor.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import re
+
+def main():
+    parser = argparse.ArgumentParser(description='This script looks for '
+        '`{CONTENTS_OF:path/to/file}` markers in the input file and replaces them with the actual '
+        'contents of that file, with leading/trailing whitespace stripped. The idea is that this '
+        'script could be extended to support more types of markers in the future.')
+    parser.add_argument('input')
+    parser.add_argument('output')
+    args = parser.parse_args()
+
+    with open(args.input, 'r') as f:
+        contents = f.read()
+
+    i = 0
+    replacedContents = ''
+    for m in re.finditer(r'{CONTENTS_OF:([a-zA-Z0-9 _/.-]+)}', contents):
+        replacedContents += contents[i:m.start()]
+        with open(m.group(1), 'r') as f:
+            replacedContents += f.read().strip()
+        i = m.end()
+    replacedContents += contents[i:]
+
+    with open(args.output, 'w') as f:
+        f.write(replacedContents)
+
+
+if __name__ == '__main__':
+    main()