Merge "Make rollback_index configurable" into main
diff --git a/android/Android.bp b/android/Android.bp
index 4b75148..00dc50a 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -171,7 +171,3 @@
     // Used by plugins
     visibility: ["//visibility:public"],
 }
-
-otatools_package_filegroup {
-    name: "otatools_package_filegroup",
-}
diff --git a/android/arch_list.go b/android/arch_list.go
index 389f194..8659549 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -27,6 +27,8 @@
 		"armv8-2a-dotprod",
 		"armv9-a",
 		"armv9-2a",
+		"armv9-3a",
+		"armv9-4a",
 	},
 	X86: {
 		"alderlake",
@@ -151,6 +153,12 @@
 		"armv9-2a": {
 			"dotprod",
 		},
+		"armv9-3a": {
+			"dotprod",
+		},
+		"armv9-4a": {
+			"dotprod",
+		},
 	},
 	X86: {
 		"alderlake": {
diff --git a/android/config.go b/android/config.go
index d47f0d4..52d7f3b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -22,6 +22,7 @@
 	"fmt"
 	"os"
 	"path/filepath"
+	"reflect"
 	"runtime"
 	"strconv"
 	"strings"
@@ -108,6 +109,10 @@
 
 const testKeyDir = "build/make/target/product/security"
 
+func (c Config) genericConfig() Config {
+	return Config{c.config.genericConfig}
+}
+
 // SoongOutDir returns the build output directory for the configuration.
 func (c Config) SoongOutDir() string {
 	return c.soongOutDir
@@ -372,7 +377,7 @@
 	// regenerate build.ninja.
 	ninjaFileDepsSet sync.Map
 
-	OncePer
+	*OncePer
 
 	// If buildFromSourceStub is true then the Java API stubs are
 	// built from the source Java files, not the signature text files.
@@ -382,6 +387,17 @@
 	// modules that aren't mixed-built for at least one variant will cause a build
 	// failure
 	ensureAllowlistIntegrity bool
+
+	// If isGeneric is true, this config is the generic config.
+	isGeneric bool
+
+	// InstallPath requires the device name.
+	// This is only for the installPath.
+	deviceNameToInstall *string
+
+	// Copy of this config struct but some product-specific variables are
+	// replaced with the generic configuration values.
+	genericConfig *config
 }
 
 type partialCompileFlags struct {
@@ -639,11 +655,9 @@
 	}
 }
 
-// NewConfig creates a new Config object. The srcDir argument specifies the path
-// to the root source directory. It also loads the config file, if found.
-func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
+func initConfig(cmdArgs CmdArgs, availableEnv map[string]string) (*config, error) {
 	// Make a config with default options.
-	config := &config{
+	newConfig := &config{
 		ProductVariablesFileName: cmdArgs.SoongVariables,
 
 		env: availableEnv,
@@ -657,70 +671,72 @@
 		moduleListFile: cmdArgs.ModuleListFile,
 		fs:             pathtools.NewOsFs(absSrcDir),
 
+		OncePer: &OncePer{},
+
 		buildFromSourceStub: cmdArgs.BuildFromSourceStub,
 	}
 	variant, ok := os.LookupEnv("TARGET_BUILD_VARIANT")
 	isEngBuild := !ok || variant == "eng"
 
-	config.deviceConfig = &deviceConfig{
-		config: config,
+	newConfig.deviceConfig = &deviceConfig{
+		config: newConfig,
 	}
 
 	// Soundness check of the build and source directories. This won't catch strange
 	// configurations with symlinks, but at least checks the obvious case.
 	absBuildDir, err := filepath.Abs(cmdArgs.SoongOutDir)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	absSrcDir, err := filepath.Abs(".")
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	if strings.HasPrefix(absSrcDir, absBuildDir) {
-		return Config{}, fmt.Errorf("Build dir must not contain source directory")
+		return &config{}, fmt.Errorf("Build dir must not contain source directory")
 	}
 
 	// Load any configurable options from the configuration file
-	err = loadConfig(config)
+	err = loadConfig(newConfig)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	KatiEnabledMarkerFile := filepath.Join(cmdArgs.SoongOutDir, ".soong.kati_enabled")
 	if _, err := os.Stat(absolutePath(KatiEnabledMarkerFile)); err == nil {
-		config.katiEnabled = true
+		newConfig.katiEnabled = true
 	}
 
-	determineBuildOS(config)
+	determineBuildOS(newConfig)
 
 	// Sets up the map of target OSes to the finer grained compilation targets
 	// that are configured from the product variables.
-	targets, err := decodeTargetProductVariables(config)
+	targets, err := decodeTargetProductVariables(newConfig)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
-	config.partialCompileFlags, err = config.parsePartialCompileFlags(isEngBuild)
+	newConfig.partialCompileFlags, err = newConfig.parsePartialCompileFlags(isEngBuild)
 	if err != nil {
-		return Config{}, err
+		return &config{}, err
 	}
 
 	// Make the CommonOS OsType available for all products.
 	targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
 
 	var archConfig []archConfig
-	if config.NdkAbis() {
+	if newConfig.NdkAbis() {
 		archConfig = getNdkAbisConfig()
-	} else if config.AmlAbis() {
+	} else if newConfig.AmlAbis() {
 		archConfig = getAmlAbisConfig()
 	}
 
 	if archConfig != nil {
 		androidTargets, err := decodeAndroidArchSettings(archConfig)
 		if err != nil {
-			return Config{}, err
+			return &config{}, err
 		}
 		targets[Android] = androidTargets
 	}
@@ -728,37 +744,113 @@
 	multilib := make(map[string]bool)
 	for _, target := range targets[Android] {
 		if seen := multilib[target.Arch.ArchType.Multilib]; seen {
-			config.multilibConflicts[target.Arch.ArchType] = true
+			newConfig.multilibConflicts[target.Arch.ArchType] = true
 		}
 		multilib[target.Arch.ArchType.Multilib] = true
 	}
 
 	// Map of OS to compilation targets.
-	config.Targets = targets
+	newConfig.Targets = targets
 
 	// Compilation targets for host tools.
-	config.BuildOSTarget = config.Targets[config.BuildOS][0]
-	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
+	newConfig.BuildOSTarget = newConfig.Targets[newConfig.BuildOS][0]
+	newConfig.BuildOSCommonTarget = getCommonTargets(newConfig.Targets[newConfig.BuildOS])[0]
 
 	// Compilation targets for Android.
-	if len(config.Targets[Android]) > 0 {
-		config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
-		config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
+	if len(newConfig.Targets[Android]) > 0 {
+		newConfig.AndroidCommonTarget = getCommonTargets(newConfig.Targets[Android])[0]
+		newConfig.AndroidFirstDeviceTarget = FirstTarget(newConfig.Targets[Android], "lib64", "lib32")[0]
 	}
 
 	setBuildMode := func(arg string, mode SoongBuildMode) {
 		if arg != "" {
-			if config.BuildMode != AnalysisNoBazel {
+			if newConfig.BuildMode != AnalysisNoBazel {
 				fmt.Fprintf(os.Stderr, "buildMode is already set, illegal argument: %s", arg)
 				os.Exit(1)
 			}
-			config.BuildMode = mode
+			newConfig.BuildMode = mode
 		}
 	}
 	setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
 	setBuildMode(cmdArgs.DocFile, GenerateDocFile)
 
-	config.productVariables.Build_from_text_stub = boolPtr(config.BuildFromTextStub())
+	newConfig.productVariables.Build_from_text_stub = boolPtr(newConfig.BuildFromTextStub())
+
+	newConfig.deviceNameToInstall = newConfig.productVariables.DeviceName
+
+	return newConfig, err
+}
+
+// Replace variables in config.productVariables that have tags with "generic" key.
+// A generic tag may have a string or an int value for the generic configuration.
+// If the value is "unset", generic configuration will unset the variable.
+func overrideGenericConfig(config *config) {
+	config.genericConfig.isGeneric = true
+	type_pv := reflect.TypeOf(config.genericConfig.productVariables)
+	value_pv := reflect.ValueOf(&config.genericConfig.productVariables)
+	for i := range type_pv.NumField() {
+		type_pv_field := type_pv.Field(i)
+		generic_value := type_pv_field.Tag.Get("generic")
+		// If a product variable has an annotation of "generic" tag, use the
+		// value of the tag to set the generic variable.
+		if generic_value != "" {
+			value_pv_field := value_pv.Elem().Field(i)
+
+			if generic_value == "unset" {
+				// unset the product variable
+				value_pv_field.SetZero()
+				continue
+			}
+
+			kind_of_type_pv := type_pv_field.Type.Kind()
+			is_pointer := false
+			if kind_of_type_pv == reflect.Pointer {
+				is_pointer = true
+				kind_of_type_pv = type_pv_field.Type.Elem().Kind()
+			}
+
+			switch kind_of_type_pv {
+			case reflect.String:
+				if is_pointer {
+					value_pv_field.Set(reflect.ValueOf(stringPtr(generic_value)))
+				} else {
+					value_pv_field.Set(reflect.ValueOf(generic_value))
+				}
+			case reflect.Int:
+				generic_int, err := strconv.Atoi(generic_value)
+				if err != nil {
+					panic(fmt.Errorf("Only an int value can be assigned to int variable: %s", err))
+				}
+				if is_pointer {
+					value_pv_field.Set(reflect.ValueOf(intPtr(generic_int)))
+				} else {
+					value_pv_field.Set(reflect.ValueOf(generic_int))
+				}
+			default:
+				panic(fmt.Errorf("Unknown type to replace for generic variable: %s", &kind_of_type_pv))
+			}
+		}
+	}
+
+	// OncePer must be a singleton.
+	config.genericConfig.OncePer = config.OncePer
+	// keep the device name to get the install path.
+	config.genericConfig.deviceNameToInstall = config.deviceNameToInstall
+}
+
+// NewConfig creates a new Config object. It also loads the config file, if
+// found. The Config object includes a duplicated Config object in it for the
+// generic configuration that does not provide any product specific information.
+func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
+	config, err := initConfig(cmdArgs, availableEnv)
+	if err != nil {
+		return Config{}, err
+	}
+
+	// Initialize generic configuration.
+	config.genericConfig, err = initConfig(cmdArgs, availableEnv)
+	// Update product specific variables with the generic configuration.
+	overrideGenericConfig(config)
 
 	return Config{config}, err
 }
@@ -946,7 +1038,7 @@
 // require them to run and get the current build fingerprint. This ensures they
 // don't rebuild on every incremental build when the build number changes.
 func (c *config) BuildFingerprintFile(ctx PathContext) Path {
-	return PathForArbitraryOutput(ctx, "target", "product", c.DeviceName(), String(c.productVariables.BuildFingerprintFile))
+	return PathForArbitraryOutput(ctx, "target", "product", *c.deviceNameToInstall, String(c.productVariables.BuildFingerprintFile))
 }
 
 // BuildNumberFile returns the path to a text file containing metadata
@@ -974,7 +1066,7 @@
 // require them to run and get the current build thumbprint. This ensures they
 // don't rebuild on every incremental build when the build thumbprint changes.
 func (c *config) BuildThumbprintFile(ctx PathContext) Path {
-	return PathForArbitraryOutput(ctx, "target", "product", c.DeviceName(), String(c.productVariables.BuildThumbprintFile))
+	return PathForArbitraryOutput(ctx, "target", "product", *c.deviceNameToInstall, String(c.productVariables.BuildThumbprintFile))
 }
 
 // DeviceName returns the name of the current device target.
@@ -1207,6 +1299,10 @@
 	return otaPaths
 }
 
+func (c *config) ExtraOtaRecoveryKeys() []string {
+	return c.productVariables.ExtraOtaRecoveryKeys
+}
+
 func (c *config) BuildKeys() string {
 	defaultCert := String(c.productVariables.DefaultAppCertificate)
 	if defaultCert == "" || defaultCert == filepath.Join(testKeyDir, "testkey") {
diff --git a/android/config_test.go b/android/config_test.go
index d1b26c1..81b7c3e 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -281,3 +281,72 @@
 		})
 	}
 }
+
+type configTestProperties struct {
+	Use_generic_config *bool
+}
+
+type configTestModule struct {
+	ModuleBase
+	properties configTestProperties
+}
+
+func (d *configTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	deviceName := ctx.Config().DeviceName()
+	if ctx.ModuleName() == "foo" {
+		if ctx.Module().UseGenericConfig() {
+			ctx.PropertyErrorf("use_generic_config", "must not be set for this test")
+		}
+	} else if ctx.ModuleName() == "bar" {
+		if !ctx.Module().UseGenericConfig() {
+			ctx.ModuleErrorf("\"use_generic_config: true\" must be set for this test")
+		}
+	}
+
+	if ctx.Module().UseGenericConfig() {
+		if deviceName != "generic" {
+			ctx.ModuleErrorf("Device name for this module must be \"generic\" but %q\n", deviceName)
+		}
+	} else {
+		if deviceName == "generic" {
+			ctx.ModuleErrorf("Device name for this module must not be \"generic\"\n")
+		}
+	}
+}
+
+func configTestModuleFactory() Module {
+	module := &configTestModule{}
+	module.AddProperties(&module.properties)
+	InitAndroidModule(module)
+	return module
+}
+
+var prepareForConfigTest = GroupFixturePreparers(
+	FixtureRegisterWithContext(func(ctx RegistrationContext) {
+		ctx.RegisterModuleType("test", configTestModuleFactory)
+	}),
+)
+
+func TestGenericConfig(t *testing.T) {
+	bp := `
+		test {
+			name: "foo",
+		}
+
+		test {
+			name: "bar",
+			use_generic_config: true,
+		}
+	`
+
+	result := GroupFixturePreparers(
+		prepareForConfigTest,
+		FixtureWithRootAndroidBp(bp),
+	).RunTest(t)
+
+	foo := result.Module("foo", "").(*configTestModule)
+	bar := result.Module("bar", "").(*configTestModule)
+
+	AssertBoolEquals(t, "Do not use generic config", false, foo.UseGenericConfig())
+	AssertBoolEquals(t, "Use generic config", true, bar.UseGenericConfig())
+}
diff --git a/android/early_module_context.go b/android/early_module_context.go
index 8d28285..300edf1 100644
--- a/android/early_module_context.go
+++ b/android/early_module_context.go
@@ -146,6 +146,13 @@
 }
 
 func (e *earlyModuleContext) Config() Config {
+	// Only the system image may use the generic config.
+	// If a module builds multiple image variations, provide the generic config only for the core
+	// variant which is installed in the system partition. Other image variant may still read the
+	// original configurations.
+	if e.Module().base().UseGenericConfig() && e.Module().base().commonProperties.ImageVariation == "" {
+		return e.EarlyModuleContext.Config().(Config).genericConfig()
+	}
 	return e.EarlyModuleContext.Config().(Config)
 }
 
diff --git a/android/filegroup.go b/android/filegroup.go
index 9bcfd0a..4fad52a 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -33,7 +33,6 @@
 func RegisterFilegroupBuildComponents(ctx RegistrationContext) {
 	ctx.RegisterModuleType("filegroup", FileGroupFactory)
 	ctx.RegisterModuleType("filegroup_defaults", FileGroupDefaultsFactory)
-	ctx.RegisterModuleType("otatools_package_filegroup", OtatoolsFileGroupFactory)
 }
 
 type fileGroupProperties struct {
@@ -164,54 +163,3 @@
 		}
 	}
 }
-
-type OtatoolsFileGroup struct {
-	ModuleBase
-}
-
-func OtatoolsFileGroupFactory() Module {
-	module := &OtatoolsFileGroup{}
-	InitAndroidModule(module)
-	AddLoadHook(module, func(ctx LoadHookContext) {
-		module.createOTAToolsPackagefilegroup(ctx)
-	})
-	return module
-}
-
-func (fg *OtatoolsFileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
-
-// Create the filegroup to collect cert files for otatools.zip.
-func (fg *OtatoolsFileGroup) createOTAToolsPackagefilegroup(ctx LoadHookContext) {
-	ctx.CreateModuleInDirectory(
-		FileGroupFactory,
-		".",
-		&struct {
-			Name       *string
-			Srcs       []string
-			Visibility []string
-		}{
-			Name: proptools.StringPtr("soong_generated_otatools_package_filegroup"),
-			Srcs: []string{
-				"build/make/target/product/security/**/*.x509.pem",
-				"build/make/target/product/security/**/*.pk8",
-				"device/**/*.pk8",
-				"device/**/verifiedboot*",
-				"device/**/*.pem",
-				"device/**/oem*.prop",
-				"device/**/*.avbpubkey",
-				"external/avb/test/data/**/testkey_*.pem",
-				"external/avb/test/data/**/atx_metadata.bin",
-				"packages/modules/**/*.x509.pem",
-				"packages/modules/**/*.pk8",
-				"packages/modules/**/*.key.pem",
-				"vendor/**/*.pk8",
-				"vendor/**/verifiedboot*",
-				"vendor/**/*.pem",
-				"vendor/**/oem*.prop",
-				"vendor/**/*.avbpubkey",
-			},
-			Visibility: []string{"//build/make/tools/otatools_package"},
-		},
-	)
-}
diff --git a/android/module.go b/android/module.go
index 45a20a0..ecd0f23 100644
--- a/android/module.go
+++ b/android/module.go
@@ -129,6 +129,9 @@
 	// WARNING: This should not be used outside build/soong/fsgen
 	// Overrides returns the list of modules which should not be installed if this module is installed.
 	Overrides() []string
+
+	// If this is true, the module must not read product-specific configurations.
+	UseGenericConfig() bool
 }
 
 // Qualified id for a module
@@ -508,6 +511,10 @@
 	// List of module names that are prevented from being installed when this module gets
 	// installed.
 	Overrides []string
+
+	// Set to true if this module must be generic and does not require product-specific information.
+	// To be included in the system image, this property must be set to true.
+	Use_generic_config *bool
 }
 
 // Properties common to all modules inheriting from ModuleBase. Unlike commonProperties, these
@@ -2589,6 +2596,10 @@
 	return m.commonProperties.Overrides
 }
 
+func (m *ModuleBase) UseGenericConfig() bool {
+	return proptools.Bool(m.commonProperties.Use_generic_config)
+}
+
 type ConfigContext interface {
 	Config() Config
 }
diff --git a/android/module_proxy.go b/android/module_proxy.go
index 77abc11..561c477 100644
--- a/android/module_proxy.go
+++ b/android/module_proxy.go
@@ -231,3 +231,7 @@
 func (m ModuleProxy) VintfFragments(ctx ConfigurableEvaluatorContext) []string {
 	panic("method is not implemented on ModuleProxy")
 }
+
+func (m ModuleProxy) UseGenericConfig() bool {
+	panic("method is not implemented on ModuleProxy")
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index 5c90501..e693f2d 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -388,6 +388,7 @@
 			"prebuilt_radio",
 			"prebuilt_gpu",
 			"prebuilt_vendor_overlay",
+			"prebuilt_tee",
 		).
 		DefinedInBpFile().
 		Because("module type not allowed to be defined in bp file")
diff --git a/android/paths.go b/android/paths.go
index 977473f..6612d37 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -2054,7 +2054,7 @@
 	var partitionPaths []string
 
 	if os.Class == Device {
-		partitionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
+		partitionPaths = []string{"target", "product", *ctx.Config().deviceNameToInstall, partition}
 	} else {
 		osName := os.String()
 		if os == Linux {
diff --git a/android/test_config.go b/android/test_config.go
index 3609e6b..5d79df0 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -23,8 +23,7 @@
 	"github.com/google/blueprint/proptools"
 )
 
-// TestConfig returns a Config object for testing.
-func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+func initTestConfig(buildDir string, env map[string]string) *config {
 	envCopy := make(map[string]string)
 	for k, v := range env {
 		envCopy[k] = v
@@ -58,6 +57,7 @@
 		soongOutDir:  filepath.Join(buildDir, "soong"),
 		captureBuild: true,
 		env:          envCopy,
+		OncePer:      &OncePer{},
 
 		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
 		// passed to PathForSource or PathForModuleSrc.
@@ -69,10 +69,21 @@
 		config: config,
 	}
 	config.TestProductVariables = &config.productVariables
+	config.deviceNameToInstall = config.TestProductVariables.DeviceName
+
+	determineBuildOS(config)
+
+	return config
+}
+
+// TestConfig returns a Config object for testing.
+func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+	config := initTestConfig(buildDir, env)
 
 	config.mockFileSystem(bp, fs)
 
-	determineBuildOS(config)
+	config.genericConfig = initTestConfig(buildDir, env)
+	overrideGenericConfig(config)
 
 	return Config{config}
 }
diff --git a/android/variable.go b/android/variable.go
index 3d5a6ae..8c9a0b1 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -225,8 +225,8 @@
 	Platform_version_last_stable           *string  `json:",omitempty"`
 	Platform_version_known_codenames       *string  `json:",omitempty"`
 
-	DeviceName                            *string  `json:",omitempty"`
-	DeviceProduct                         *string  `json:",omitempty"`
+	DeviceName                            *string  `json:",omitempty" generic:"generic"`
+	DeviceProduct                         *string  `json:",omitempty" generic:"generic"`
 	DeviceArch                            *string  `json:",omitempty"`
 	DeviceArchVariant                     *string  `json:",omitempty"`
 	DeviceCpuVariant                      *string  `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index c6566e1..a726098 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -569,19 +569,6 @@
 	shBinary
 )
 
-var (
-	classes = map[string]apexFileClass{
-		"app":              app,
-		"appSet":           appSet,
-		"etc":              etc,
-		"javaSharedLib":    javaSharedLib,
-		"nativeExecutable": nativeExecutable,
-		"nativeSharedLib":  nativeSharedLib,
-		"nativeTest":       nativeTest,
-		"shBinary":         shBinary,
-	}
-)
-
 // apexFile represents a file in an APEX bundle. This is created during the first half of
 // GenerateAndroidBuildActions by traversing the dependencies of the APEX. Then in the second half
 // of the function, this is used to create commands that copies the files into a staging directory,
@@ -1970,7 +1957,11 @@
 		case testTag:
 			if ccInfo, ok := android.OtherModuleProvider(ctx, child, cc.CcInfoProvider); ok {
 				af := apexFileForExecutable(ctx, child, commonInfo, ccInfo)
-				af.class = nativeTest
+				// We make this a nativeExecutable instead of a nativeTest because we don't want
+				// the androidmk modules generated in AndroidMkForFiles to be treated as real
+				// tests that are then packaged into suites. Our AndroidMkForFiles does not
+				// implement enough functionality to support real tests.
+				af.class = nativeExecutable
 				vctx.filesInfo = append(vctx.filesInfo, af)
 				return true // track transitive dependencies
 			} else {
diff --git a/cc/compdb.go b/cc/compdb.go
index 4132e09..3818e9c 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -193,7 +193,7 @@
 			}
 			builds[src.String()] = compDbEntry{
 				Directory: android.AbsSrcDirForExistingUseCases(),
-				Arguments: getArguments(src, ctx, ccModule, ccPath, cxxPath),
+				Arguments: args,
 				File:      src.String(),
 			}
 		}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 45b1580..25edb79 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -53,6 +53,16 @@
 			"-mbranch-protection=standard",
 			"-fno-stack-protector",
 		},
+		"armv9-3a": []string{
+			"-march=armv9.3-a",
+			"-mbranch-protection=standard",
+			"-fno-stack-protector",
+		},
+		"armv9-4a": []string{
+			"-march=armv9.4-a",
+			"-mbranch-protection=standard",
+			"-fno-stack-protector",
+		},
 	}
 
 	arm64Ldflags = []string{
diff --git a/ci_tests/ci_test_package_zip.go b/ci_tests/ci_test_package_zip.go
index 95249aa..d7aaa66 100644
--- a/ci_tests/ci_test_package_zip.go
+++ b/ci_tests/ci_test_package_zip.go
@@ -284,6 +284,10 @@
 		android.AndroidMkEntries{
 			Class:      "ETC",
 			OutputFile: android.OptionalPathForPath(p.output),
+			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+				func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+					entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+				}},
 		},
 	}
 }
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state.go b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
index bf4f866..0f88159 100644
--- a/cmd/find_input_delta/find_input_delta_lib/internal_state.go
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
@@ -95,9 +95,14 @@
 	}
 	ret := []*fid_proto.PartialCompileInput{}
 	for _, v := range rc.File {
+		// Only include timestamp when there is no CRC.
+		timeNsec := proto.Int64(v.ModTime().UnixNano())
+		if v.CRC32 != 0 {
+			timeNsec = nil
+		}
 		pci := &fid_proto.PartialCompileInput{
 			Name:      proto.String(v.Name),
-			MtimeNsec: proto.Int64(v.ModTime().UnixNano()),
+			MtimeNsec: timeNsec,
 			Hash:      proto.String(fmt.Sprintf("%08x", v.CRC32)),
 		}
 		ret = append(ret, pci)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index e57384f..af09dbc 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -139,6 +139,11 @@
 
 // Returns all jars that system_server loads.
 func (g *GlobalConfig) AllSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
+	// dexpreopt does not initialize the soong config.
+	// Initialize the OncePer here.
+	if ctx.Config().OncePer == nil {
+		ctx.Config().OncePer = &android.OncePer{}
+	}
 	return ctx.Config().Once(allSystemServerJarsKey, func() interface{} {
 		res := g.AllPlatformSystemServerJars(ctx).AppendList(g.AllApexSystemServerJars(ctx))
 		return &res
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 3b0c032..7820047 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -78,6 +78,7 @@
 	ctx.RegisterModuleType("prebuilt_rfs", PrebuiltRfsFactory)
 	ctx.RegisterModuleType("prebuilt_framework", PrebuiltFrameworkFactory)
 	ctx.RegisterModuleType("prebuilt_res", PrebuiltResFactory)
+	ctx.RegisterModuleType("prebuilt_tee", PrebuiltTeeFactory)
 	ctx.RegisterModuleType("prebuilt_wlc_upt", PrebuiltWlcUptFactory)
 	ctx.RegisterModuleType("prebuilt_odm", PrebuiltOdmFactory)
 	ctx.RegisterModuleType("prebuilt_vendor_dlkm", PrebuiltVendorDlkmFactory)
@@ -910,6 +911,16 @@
 	return module
 }
 
+// prebuilt_tee installs files in <partition>/tee directory.
+func PrebuiltTeeFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "tee")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_media installs media files in <partition>/media directory.
 func PrebuiltMediaFactory() android.Module {
 	module := &PrebuiltEtc{}
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 3f6348d..443e80e 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -748,26 +748,91 @@
 
 }
 
+var (
+	// https://cs.android.com/android/_/android/platform/build/+/30f05352c3e6f4333c77d4af66c253572d3ea6c9:core/Makefile;l=2111-2120;drc=519f75666431ee2926e0ec8991c682b28a4c9521;bpv=1;bpt=0
+	defaultTargetRecoveryFstypeMountOptions = "ext4=max_batch_time=0,commit=1,data=ordered,barrier=1,errors=panic,nodelalloc"
+)
+
 // A partial implementation of make's $PRODUCT_OUT/misc_info.txt
 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5894?q=misc_info.txt%20f:build%2Fmake%2Fcore%2FMakefile&ss=android%2Fplatform%2Fsuperproject%2Fmain
 // This file is subsequently used by add_img_to_target_files to create additioanl metadata files like apex_info.pb
 // TODO (b/399788119): Complete the migration of misc_info.txt
 func (a *androidDevice) addMiscInfo(ctx android.ModuleContext) android.Path {
+	buildType := func() string {
+		if ctx.Config().Debuggable() {
+			return "userdebug"
+		} else if ctx.Config().Eng() {
+			return "eng"
+		} else {
+			return "user"
+		}
+	}
+	defaultAppCertificate := func() string {
+		pem, _ := ctx.Config().DefaultAppCertificate(ctx)
+		return strings.TrimSuffix(pem.String(), ".x509.pem")
+	}
+
 	builder := android.NewRuleBuilder(pctx, ctx)
 	miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
 	builder.Command().
 		Textf("rm -f %s", miscInfo).
 		Textf("&& echo recovery_api_version=%s >> %s", ctx.Config().VendorConfig("recovery").String("recovery_api_version"), miscInfo).
 		Textf("&& echo fstab_version=%s >> %s", ctx.Config().VendorConfig("recovery").String("recovery_fstab_version"), miscInfo).
+		Textf("&& echo build_type=%s >> %s", buildType(), miscInfo).
+		Textf("&& echo default_system_dev_certificate=%s >> %s", defaultAppCertificate(), miscInfo).
+		Textf("&& echo root_dir=%s >> %s", android.PathForModuleInPartitionInstall(ctx, "root"), miscInfo).
 		ImplicitOutput(miscInfo)
+	if len(ctx.Config().ExtraOtaRecoveryKeys()) > 0 {
+		builder.Command().Textf(`echo "extra_recovery_keys=%s" >> %s`, strings.Join(ctx.Config().ExtraOtaRecoveryKeys(), ""), miscInfo)
+	} else {
+		if a.partitionProps.Boot_partition_name != nil {
+			builder.Command().
+				Textf("echo mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo).
+				// TODO: Use boot's header version for recovery for now since cuttlefish does not set `BOARD_RECOVERY_MKBOOTIMG_ARGS`
+				Textf(" && echo recovery_mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo)
+		}
+		if a.partitionProps.Init_boot_partition_name != nil {
+			builder.Command().
+				Textf("echo mkbootimg_init_args='--header_version' %s >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Init_boot_partition_name), miscInfo)
+		}
+		builder.Command().
+			Textf("echo mkbootimg_version_args='--os_version %s --os_patch_level %s' >> %s", ctx.Config().PlatformVersionLastStable(), ctx.Config().PlatformSecurityPatch(), miscInfo).
+			Textf(" && echo multistage_support=1 >> %s", miscInfo).
+			Textf(" && echo blockimgdiff_versions=3,4 >> %s", miscInfo)
+	}
+	fsInfos := a.getFsInfos(ctx)
+	if _, ok := fsInfos["vendor"]; ok {
+		builder.Command().Textf("echo board_uses_vendorimage=true >> %s", miscInfo)
+	}
+	if fsInfos["system"].ErofsCompressHints != nil {
+		builder.Command().Textf("echo erofs_default_compress_hints=%s >> %s", fsInfos["system"].ErofsCompressHints, miscInfo)
+	}
+	if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil {
+		builder.Command().Textf("echo tool_extensions=%s >> %s", filepath.Dir(releaseTools.String()), miscInfo)
+	}
+	// ramdisk uses `compressed_cpio` fs_type
+	// https://cs.android.com/android/_/android/platform/build/+/30f05352c3e6f4333c77d4af66c253572d3ea6c9:core/Makefile;l=5923-5925;drc=519f75666431ee2926e0ec8991c682b28a4c9521;bpv=1;bpt=0
+	if _, ok := fsInfos["ramdisk"]; ok {
+		builder.Command().Textf("echo lz4_ramdisks=true >> %s", miscInfo)
+	}
+	// recovery_mount_options
+	// TODO: Add support for TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS which can be used to override the default
+	builder.Command().Textf("echo recovery_mount_options=%s >> %s", defaultTargetRecoveryFstypeMountOptions, miscInfo)
+
+	// vintf information
+	if proptools.Bool(ctx.Config().ProductVariables().Enforce_vintf_manifest) {
+		builder.Command().Textf("echo vintf_enforce=true >> %s", miscInfo)
+	}
+	if len(ctx.Config().DeviceManifestFiles()) > 0 {
+		builder.Command().Textf("echo vintf_include_empty_vendor_sku=true >> %s", miscInfo)
+	}
 
 	if a.partitionProps.Recovery_partition_name == nil {
 		builder.Command().Textf("echo no_recovery=true >> %s", miscInfo)
 	}
-	fsInfos := a.getFsInfos(ctx)
 	for _, partition := range android.SortedKeys(fsInfos) {
-		if fsInfos[partition].UseAvb {
-			builder.Command().Textf("echo 'avb_%s_hashtree_enable=true' >> %s", partition, miscInfo)
+		if fsInfos[partition].PropFileForMiscInfo != nil {
+			builder.Command().Text("cat").Input(fsInfos[partition].PropFileForMiscInfo).Textf(" >> %s", miscInfo)
 		}
 	}
 	if len(a.partitionProps.Vbmeta_partitions) > 0 {
@@ -785,6 +850,10 @@
 		if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
 			// cat dynamic_partition_info.txt
 			builder.Command().Text("cat").Input(info.DynamicPartitionsInfo).Textf(" >> %s", miscInfo)
+			if info.AbUpdate {
+				builder.Command().Textf("echo ab_update=true >> %s", miscInfo)
+			}
+
 		} else {
 			ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
 		}
@@ -805,11 +874,20 @@
 		builder.Command().Text("cat").Input(bootImgInfo.PropFileForMiscInfo).Textf(" >> %s", miscInfo)
 	}
 
+	// Sort and dedup
+	builder.Command().Textf("sort -u %s -o %s", miscInfo, miscInfo)
+
 	builder.Build("misc_info", "Building misc_info")
 
 	return miscInfo
 }
 
+func (a *androidDevice) getBootimgHeaderVersion(ctx android.ModuleContext, bootImgName *string) string {
+	bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(bootImgName), filesystemDepTag)
+	bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider)
+	return bootImgInfo.HeaderVersion
+}
+
 // addImgToTargetFiles invokes `add_img_to_target_files` and creates the following files in META/
 // - apex_info.pb
 // - care_map.pb
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 7959365..5ab0c68 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -244,6 +244,7 @@
 		Bootconfig:          b.getBootconfigPath(ctx),
 		Output:              output,
 		PropFileForMiscInfo: b.buildPropFileForMiscInfo(ctx),
+		HeaderVersion:       proptools.String(b.properties.Header_version),
 	})
 
 	extractedPublicKey := android.PathForModuleOut(ctx, b.partitionName()+".avbpubkey")
@@ -292,6 +293,7 @@
 	Bootconfig          android.Path
 	Output              android.Path
 	PropFileForMiscInfo android.Path
+	HeaderVersion       string
 }
 
 func (b *bootimg) getKernelPath(ctx android.ModuleContext) android.Path {
@@ -510,6 +512,25 @@
 	return propFile, deps
 }
 
+func (b *bootimg) getAvbHashFooterArgs(ctx android.ModuleContext) string {
+	ret := ""
+	if !b.bootImageType.isVendorBoot() {
+		ret += "--prop " + fmt.Sprintf("com.android.build.%s.os_version:%s", b.bootImageType.String(), ctx.Config().PlatformVersionLastStable())
+	}
+
+	fingerprintFile := ctx.Config().BuildFingerprintFile(ctx)
+	ret += " --prop " + fmt.Sprintf("com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", b.bootImageType.String(), fingerprintFile.String())
+
+	if b.properties.Security_patch != nil {
+		ret += " --prop " + fmt.Sprintf("com.android.build.%s.security_patch:%s", b.bootImageType.String(), *b.properties.Security_patch)
+	}
+
+	if b.properties.Avb_rollback_index != nil {
+		ret += " --rollback_index " + strconv.FormatInt(*b.properties.Avb_rollback_index, 10)
+	}
+	return strings.TrimSpace(ret)
+}
+
 func (b *bootimg) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
 	var sb strings.Builder
 	addStr := func(name string, value string) {
@@ -517,15 +538,28 @@
 	}
 
 	bootImgType := proptools.String(b.properties.Boot_image_type)
-	addStr("avb_"+bootImgType+"_add_hash_footer_args", "TODO(b/398036609)")
+	addStr("avb_"+bootImgType+"_add_hash_footer_args", b.getAvbHashFooterArgs(ctx))
 	if b.properties.Avb_private_key != nil {
 		addStr("avb_"+bootImgType+"_algorithm", proptools.StringDefault(b.properties.Avb_algorithm, "SHA256_RSA4096"))
 		addStr("avb_"+bootImgType+"_key_path", android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key)).String())
 		addStr("avb_"+bootImgType+"_rollback_index_location", strconv.Itoa(proptools.Int(b.properties.Avb_rollback_index_location)))
 	}
+	if b.properties.Partition_size != nil {
+		addStr(bootImgType+"_size", strconv.FormatInt(*b.properties.Partition_size, 10))
+	}
+	if bootImgType != "boot" {
+		addStr(bootImgType, "true")
+	}
 
-	propFile := android.PathForModuleOut(ctx, "prop_for_misc_info")
-	android.WriteFileRuleVerbatim(ctx, propFile, sb.String())
+	propFilePreProcessing := android.PathForModuleOut(ctx, "prop_for_misc_info_pre_processing")
+	android.WriteFileRuleVerbatim(ctx, propFilePreProcessing, sb.String())
+	propFile := android.PathForModuleOut(ctx, "prop_file_for_misc_info")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   textFileProcessorRule,
+		Input:  propFilePreProcessing,
+		Output: propFile,
+	})
+
 	return propFile
 }
 
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index b854880..e86ebf4 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -452,9 +452,17 @@
 
 	Owners []InstalledModuleInfo
 
-	UseAvb bool
-
 	HasFsverity bool
+
+	PropFileForMiscInfo android.Path
+
+	// Additional avb and partition size information.
+	// `system_other` will use this information of `system` dep for misc_info.txt processing.
+	PartitionSize    *int64
+	UseAvb           bool
+	AvbAlgorithm     string
+	AvbHashAlgorithm string
+	AvbKey           android.Path
 }
 
 // FullInstallPathInfo contains information about the "full install" paths of all the files
@@ -638,9 +646,11 @@
 	var buildImagePropFile android.Path
 	var buildImagePropFileDeps android.Paths
 	var extraRootDirs android.Paths
+	var propFileForMiscInfo android.Path
 	switch f.fsType(ctx) {
 	case ext4Type, erofsType, f2fsType:
 		buildImagePropFile, buildImagePropFileDeps = f.buildPropFile(ctx)
+		propFileForMiscInfo = f.buildPropFileForMiscInfo(ctx)
 		output := android.PathForModuleOut(ctx, f.installFileName())
 		f.buildImageUsingBuildImage(ctx, builder, buildImageParams{rootDir, buildImagePropFile, buildImagePropFileDeps, output})
 		f.output = output
@@ -703,12 +713,21 @@
 			[]InstalledFilesStruct{buildInstalledFiles(ctx, partitionNameForInstalledFiles, rootDir, f.output)},
 			includeFilesInstalledFiles(ctx),
 		),
-		ErofsCompressHints: erofsCompressHints,
-		SelinuxFc:          f.selinuxFc,
-		FilesystemConfig:   f.generateFilesystemConfig(ctx, rootDir, rebasedDir),
-		Owners:             f.gatherOwners(specs),
-		UseAvb:             proptools.Bool(f.properties.Use_avb),
-		HasFsverity:        f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) != nil,
+		ErofsCompressHints:  erofsCompressHints,
+		SelinuxFc:           f.selinuxFc,
+		FilesystemConfig:    f.generateFilesystemConfig(ctx, rootDir, rebasedDir),
+		Owners:              f.gatherOwners(specs),
+		HasFsverity:         f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) != nil,
+		PropFileForMiscInfo: propFileForMiscInfo,
+		PartitionSize:       f.properties.Partition_size,
+	}
+	if proptools.Bool(f.properties.Use_avb) {
+		fsInfo.UseAvb = true
+		fsInfo.AvbAlgorithm = proptools.StringDefault(f.properties.Avb_algorithm, "SHA256_RSA4096")
+		fsInfo.AvbHashAlgorithm = proptools.StringDefault(f.properties.Avb_hash_algorithm, "sha256")
+		if f.properties.Avb_private_key != nil {
+			fsInfo.AvbKey = android.PathForModuleSrc(ctx, *f.properties.Avb_private_key)
+		}
 	}
 
 	android.SetProvider(ctx, FilesystemProvider, fsInfo)
@@ -1144,6 +1163,83 @@
 	return propFile, deps
 }
 
+func (f *filesystem) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
+	var lines []string
+	addStr := func(name string, value string) {
+		lines = append(lines, fmt.Sprintf("%s=%s", name, value))
+	}
+
+	addStr("use_dynamic_partition_size", "true")
+	addStr("ext_mkuserimg", "mkuserimg_mke2fs")
+
+	addStr("building_"+f.partitionName()+"_image", "true")
+	addStr(f.partitionName()+"_fs_type", f.fsType(ctx).String())
+
+	if proptools.Bool(f.properties.Use_avb) {
+		addStr("avb_"+f.partitionName()+"_hashtree_enable", "true")
+		if f.properties.Avb_private_key != nil {
+			key := android.PathForModuleSrc(ctx, *f.properties.Avb_private_key)
+			addStr("avb_"+f.partitionName()+"_key_path", key.String())
+		}
+		addStr("avb_"+f.partitionName()+"_add_hashtree_footer_args", strings.TrimSpace(f.getAvbAddHashtreeFooterArgs(ctx)))
+	}
+
+	if f.selinuxFc != nil {
+		addStr(f.partitionName()+"_selinux_fc", f.selinuxFc.String())
+	}
+
+	// Disable sparse only when partition size is not defined. disable_sparse has the same
+	// effect as <partition name>_disable_sparse.
+	if f.properties.Partition_size == nil {
+		addStr(f.partitionName()+"_disable_sparse", "true")
+	} else if f.partitionName() == "userdata" {
+		// Add userdata's partition size to misc_info.txt.
+		// userdata has been special-cased to make the make packaging misc_info.txt implementation
+		addStr("userdata_size", strconv.FormatInt(*f.properties.Partition_size, 10))
+	}
+
+	fst := f.fsType(ctx)
+	switch fst {
+	case erofsType:
+		// Add erofs properties
+		addStr("erofs_default_compressor", proptools.StringDefault(f.properties.Erofs.Compressor, "lz4hc,9"))
+		if proptools.BoolDefault(f.properties.Erofs.Sparse, true) {
+			// https://source.corp.google.com/h/googleplex-android/platform/build/+/88b1c67239ca545b11580237242774b411f2fed9:core/Makefile;l=2292;bpv=1;bpt=0;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b
+			addStr("erofs_sparse_flag", "-s")
+		}
+	case f2fsType:
+		if proptools.BoolDefault(f.properties.F2fs.Sparse, true) {
+			// https://source.corp.google.com/h/googleplex-android/platform/build/+/88b1c67239ca545b11580237242774b411f2fed9:core/Makefile;l=2294;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0
+			addStr("f2fs_sparse_flag", "-S")
+		}
+	}
+
+	if proptools.BoolDefault(f.properties.Support_casefolding, false) {
+		addStr("needs_casefold", "1")
+	}
+
+	if proptools.BoolDefault(f.properties.Support_project_quota, false) {
+		addStr("needs_projid", "1")
+	}
+
+	if proptools.BoolDefault(f.properties.Enable_compression, false) {
+		addStr("needs_compress", "1")
+	}
+
+	sort.Strings(lines)
+
+	propFilePreProcessing := android.PathForModuleOut(ctx, "prop_misc_info_pre_processing")
+	android.WriteFileRule(ctx, propFilePreProcessing, strings.Join(lines, "\n"))
+	propFile := android.PathForModuleOut(ctx, "prop_file_for_misc_info")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   textFileProcessorRule,
+		Input:  propFilePreProcessing,
+		Output: propFile,
+	})
+
+	return propFile
+}
+
 func (f *filesystem) getAvbAddHashtreeFooterArgs(ctx android.ModuleContext) string {
 	avb_add_hashtree_footer_args := ""
 	if !proptools.BoolDefault(f.properties.Use_fec, true) {
diff --git a/filesystem/super_image.go b/filesystem/super_image.go
index cd7df02..cf7e125 100644
--- a/filesystem/super_image.go
+++ b/filesystem/super_image.go
@@ -122,6 +122,8 @@
 	DynamicPartitionsInfo android.Path
 
 	SuperEmptyImage android.Path
+
+	AbUpdate bool
 }
 
 var SuperImageProvider = blueprint.NewProvider[SuperImageInfo]()
@@ -201,6 +203,7 @@
 		SubImageInfo:          subImageInfos,
 		DynamicPartitionsInfo: s.generateDynamicPartitionsInfo(ctx),
 		SuperEmptyImage:       superEmptyImage,
+		AbUpdate:              proptools.Bool(s.properties.Ab_update),
 	})
 	ctx.SetOutputFiles([]android.Path{output}, "")
 	ctx.CheckbuildFile(output)
diff --git a/filesystem/system_other.go b/filesystem/system_other.go
index cbfd78b..348c010 100644
--- a/filesystem/system_other.go
+++ b/filesystem/system_other.go
@@ -16,8 +16,11 @@
 
 import (
 	"android/soong/android"
+	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
+	"time"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -172,10 +175,11 @@
 	builder.Build("build_system_other_hermetic", "build system other")
 
 	fsInfo := FilesystemInfo{
-		Output:           output,
-		OutputHermetic:   outputHermetic,
-		RootDir:          stagingDir,
-		FilesystemConfig: m.generateFilesystemConfig(ctx, stagingDir, stagingDirTimestamp),
+		Output:              output,
+		OutputHermetic:      outputHermetic,
+		RootDir:             stagingDir,
+		FilesystemConfig:    m.generateFilesystemConfig(ctx, stagingDir, stagingDirTimestamp),
+		PropFileForMiscInfo: m.buildPropFileForMiscInfo(ctx),
 	}
 
 	android.SetProvider(ctx, FilesystemProvider, fsInfo)
@@ -204,3 +208,52 @@
 		Textf(" && echo use_fixed_timestamp=true >> %s", propFilePinnedTimestamp)
 	return propFilePinnedTimestamp
 }
+
+func (f *systemOtherImage) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
+	var lines []string
+	addStr := func(name string, value string) {
+		lines = append(lines, fmt.Sprintf("%s=%s", name, value))
+	}
+
+	addStr("building_system_other_image", "true")
+
+	systemImage := ctx.GetDirectDepProxyWithTag(*f.properties.System_image, systemImageDependencyTag)
+	systemInfo, ok := android.OtherModuleProvider(ctx, systemImage, FilesystemProvider)
+	if !ok {
+		ctx.PropertyErrorf("system_image", "Expected system_image module to provide FilesystemProvider")
+		return nil
+	}
+	if systemInfo.PartitionSize == nil {
+		addStr("system_other_disable_sparse", "true")
+	}
+	if systemInfo.UseAvb {
+		addStr("avb_system_other_hashtree_enable", "true")
+		addStr("avb_system_other_algorithm", systemInfo.AvbAlgorithm)
+		footerArgs := fmt.Sprintf("--hash_algorithm %s", systemInfo.AvbHashAlgorithm)
+		if rollbackIndex, err := f.avbRollbackIndex(ctx); err == nil {
+			footerArgs += fmt.Sprintf(" --rollback_index %d", rollbackIndex)
+		} else {
+			ctx.ModuleErrorf("Could not determine rollback_index %s\n", err)
+		}
+		addStr("avb_system_other_add_hashtree_footer_args", footerArgs)
+		if systemInfo.AvbKey != nil {
+			addStr("avb_system_other_key_path", systemInfo.AvbKey.String())
+		}
+	}
+
+	sort.Strings(lines)
+
+	propFile := android.PathForModuleOut(ctx, "prop_file")
+	android.WriteFileRule(ctx, propFile, strings.Join(lines, "\n"))
+	return propFile
+}
+
+// Use the default: PlatformSecurityPatch
+// TODO: Get this value from vbmeta_system
+func (f *systemOtherImage) avbRollbackIndex(ctx android.ModuleContext) (int64, error) {
+	t, err := time.Parse(time.DateOnly, ctx.Config().PlatformSecurityPatch())
+	if err != nil {
+		return -1, err
+	}
+	return t.Unix(), err
+}
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
index 81236a0..651d2d1 100644
--- a/fsgen/filesystem_creator_test.go
+++ b/fsgen/filesystem_creator_test.go
@@ -312,14 +312,14 @@
 		}),
 	).RunTest(t)
 
-	checkModuleProp := func(m android.Module, matcher func(actual interface{}) bool) bool {
+	getModuleProp := func(m android.Module, matcher func(actual interface{}) string) string {
 		for _, prop := range m.GetProperties() {
 
-			if matcher(prop) {
-				return true
+			if str := matcher(prop); str != "" {
+				return str
 			}
 		}
-		return false
+		return ""
 	}
 
 	// check generated prebuilt_* module type install path and install partition
@@ -350,6 +350,37 @@
 		etcModule.SubDir(),
 	)
 
+	// check that generated prebuilt_* module sets correct srcs
+	eval := generatedModule.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"Vendor_0079_Product_0011.kl",
+		getModuleProp(generatedModule, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 2 {
+					return srcs[0]
+				}
+			}
+			return ""
+		}),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"Vendor_0079_Product_18d4.kl",
+		getModuleProp(generatedModule, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 2 {
+					return srcs[1]
+				}
+			}
+			return ""
+		}),
+	)
+
 	// check that prebuilt_* module is not generated for non existing source file
 	android.AssertStringEquals(
 		t,
@@ -363,60 +394,130 @@
 	generatedModule1 := result.ModuleForTests(t, "product-device_sample_etc-etc-1", "android_arm64_armv8-a").Module()
 
 	// check that generated prebuilt_* module sets correct srcs and dsts property
-	eval := generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
-	android.AssertBoolEquals(
+	eval = generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
 		t,
 		"module expected to set correct srcs property",
-		true,
-		checkModuleProp(generatedModule0, func(actual interface{}) bool {
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
 			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
 				srcs := p.Srcs.GetOrDefault(eval, nil)
-				return len(srcs) == 1 &&
-					srcs[0] == "apns-full-conf.xml"
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
 			}
-			return false
+			return ""
 		}),
 	)
-	android.AssertBoolEquals(
+	android.AssertStringEquals(
 		t,
 		"module expected to set correct dsts property",
-		true,
-		checkModuleProp(generatedModule0, func(actual interface{}) bool {
+		"apns-conf.xml",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
 			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
 				dsts := p.Dsts.GetOrDefault(eval, nil)
-				return len(dsts) == 1 &&
-					dsts[0] == "apns-conf.xml"
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
 			}
-			return false
+			return ""
 		}),
 	)
 
 	// check that generated prebuilt_* module sets correct srcs and dsts property
 	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
-	android.AssertBoolEquals(
+	android.AssertStringEquals(
 		t,
 		"module expected to set correct srcs property",
-		true,
-		checkModuleProp(generatedModule1, func(actual interface{}) bool {
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
 			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
 				srcs := p.Srcs.GetOrDefault(eval, nil)
-				return len(srcs) == 1 &&
-					srcs[0] == "apns-full-conf.xml"
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
 			}
-			return false
+			return ""
 		}),
 	)
-	android.AssertBoolEquals(
+	android.AssertStringEquals(
 		t,
 		"module expected to set correct dsts property",
-		true,
-		checkModuleProp(generatedModule1, func(actual interface{}) bool {
+		"apns-conf-2.xml",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
 			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
 				dsts := p.Dsts.GetOrDefault(eval, nil)
-				return len(dsts) == 1 &&
-					dsts[0] == "apns-conf-2.xml"
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
 			}
-			return false
+			return ""
+		}),
+	)
+
+	generatedModule0 = result.ModuleForTests(t, "system-device_sample_etc-foo-0", "android_common").Module()
+	generatedModule1 = result.ModuleForTests(t, "system-device_sample_etc-foo-1", "android_common").Module()
+
+	// check that generated prebuilt_* module sets correct srcs and dsts property
+	eval = generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
+			}
+			return ""
+		}),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct dsts property",
+		"foo/file.txt",
+		getModuleProp(generatedModule0, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				if len(dsts) == 1 {
+					return dsts[0]
+				}
+			}
+			return ""
+		}),
+	)
+
+	// check generated prebuilt_* module specifies correct install path and relative install path
+	etcModule, _ = generatedModule1.(*etc.PrebuiltEtc)
+	android.AssertStringEquals(
+		t,
+		"module expected to have . install path",
+		".",
+		etcModule.BaseDir(),
+	)
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct relative_install_path properties",
+		"foo",
+		etcModule.SubDir(),
+	)
+
+	// check that generated prebuilt_* module sets correct srcs
+	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringEquals(
+		t,
+		"module expected to set correct srcs property",
+		"apns-full-conf.xml",
+		getModuleProp(generatedModule1, func(actual interface{}) string {
+			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
+				srcs := p.Srcs.GetOrDefault(eval, nil)
+				if len(srcs) == 1 {
+					return srcs[0]
+				}
+			}
+			return ""
 		}),
 	)
 }
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
index df36197..e9dabe4 100644
--- a/fsgen/prebuilt_etc_modules_gen.go
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -215,6 +215,7 @@
 		"system":              etc.PrebuiltSystemFactory,
 		"res":                 etc.PrebuiltResFactory,
 		"rfs":                 etc.PrebuiltRfsFactory,
+		"tee":                 etc.PrebuiltTeeFactory,
 		"tts":                 etc.PrebuiltVoicepackFactory,
 		"tvconfig":            etc.PrebuiltTvConfigFactory,
 		"tvservice":           etc.PrebuiltTvServiceFactory,
@@ -340,28 +341,35 @@
 
 		// Set appropriate srcs, dsts, and releative_install_path based on
 		// the source and install file names
-		if allCopyFileNamesUnchanged {
-			modulePropsPtr.Srcs = srcBaseFiles
+		modulePropsPtr.Srcs = srcBaseFiles
 
-			// Specify relative_install_path if it is not installed in the root directory of the
-			// partition
+		// prebuilt_root should only be used in very limited cases in prebuilt_etc moddule gen, where:
+		// - all source file names are identical to the installed file names, and
+		// - all source files are installed in root, not the subdirectories of root
+		// prebuilt_root currently does not have a good way to specify the names of the multiple
+		// installed files, and prebuilt_root does not allow installing files at a subdirectory
+		// of the root.
+		// Use prebuilt_any instead of prebuilt_root if either of the conditions are not met as
+		// a fallback behavior.
+		if etcInstallPathKey == "" {
+			if !(allCopyFileNamesUnchanged && android.InList(relDestDirFromInstallDirBase, []string{"", "."})) {
+				moduleFactory = etc.PrebuiltAnyFactory
+			}
+		}
+
+		if allCopyFileNamesUnchanged {
+			// Specify relative_install_path if it is not installed in the base directory of the module.
+			// In case of prebuilt_{root,any} this is equivalent to the root of the partition.
 			if !android.InList(relDestDirFromInstallDirBase, []string{"", "."}) {
 				propsList = append(propsList, &prebuiltSubdirProperties{
 					Relative_install_path: proptools.StringPtr(relDestDirFromInstallDirBase),
 				})
 			}
 		} else {
-			// If dsts property has to be set and the selected module type is prebuilt_root,
-			// use prebuilt_any instead.
-			if etcInstallPathKey == "" {
-				moduleFactory = etc.PrebuiltAnyFactory
-			}
-			modulePropsPtr.Srcs = srcBaseFiles
 			dsts := proptools.NewConfigurable[[]string](nil, nil)
 			for _, installBaseFile := range installBaseFiles {
 				dsts.AppendSimpleValue([]string{filepath.Join(relDestDirFromInstallDirBase, installBaseFile)})
 			}
-
 			propsList = append(propsList, &etc.PrebuiltDstsProperties{
 				Dsts: dsts,
 			})
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 49df480..b82f2a9 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -14,7 +14,6 @@
         "soong-shared",
     ],
     srcs: [
-        "allowlists.go",
         "genrule.go",
         "locations.go",
     ],
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
deleted file mode 100644
index 45a7f72..0000000
--- a/genrule/allowlists.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// 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 genrule
-
-var (
-	SandboxingDenyModuleList = []string{
-		// go/keep-sorted start
-		// go/keep-sorted end
-	}
-)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 710ec95..a7c09e7 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -969,30 +969,9 @@
 	return module
 }
 
-var sandboxingAllowlistKey = android.NewOnceKey("genruleSandboxingAllowlistKey")
-
-type sandboxingAllowlistSets struct {
-	sandboxingDenyModuleSet map[string]bool
-}
-
-func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSets {
-	return ctx.Config().Once(sandboxingAllowlistKey, func() interface{} {
-		sandboxingDenyModuleSet := map[string]bool{}
-
-		android.AddToStringSet(sandboxingDenyModuleSet, SandboxingDenyModuleList)
-		return &sandboxingAllowlistSets{
-			sandboxingDenyModuleSet: sandboxingDenyModuleSet,
-		}
-	}).(*sandboxingAllowlistSets)
-}
-
 func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
 	if !ctx.DeviceConfig().GenruleSandboxing() {
 		return r.SandboxTools()
 	}
-	sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
-	if sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
-		return r.SandboxTools()
-	}
 	return r.SandboxInputs()
 }
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 94a4457..efcd56a 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -45,6 +45,14 @@
 			"-Z branch-protection=bti,pac-ret",
 			"-Z stack-protector=none",
 		},
+		"armv9-3a": []string{
+			"-Z branch-protection=bti,pac-ret",
+			"-Z stack-protector=none",
+		},
+		"armv9-4a": []string{
+			"-Z branch-protection=bti,pac-ret",
+			"-Z stack-protector=none",
+		},
 	}
 )
 
diff --git a/rust/image.go b/rust/image.go
index 51b8289..aa10a6d 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -137,7 +137,7 @@
 	// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
 	// module. As well as SoC specific modules, vendor variants must be installed to /vendor
 	// unless they have "odm_available: true".
-	return mod.InVendor() && !mod.VendorVariantToOdm()
+	return mod.HasVendorVariant() && mod.InVendor() && !mod.VendorVariantToOdm()
 }
 
 func (mod *Module) InstallInOdm() bool {
diff --git a/tradefed_modules/Android.bp b/tradefed_modules/Android.bp
index a765a05..37bae39 100644
--- a/tradefed_modules/Android.bp
+++ b/tradefed_modules/Android.bp
@@ -14,11 +14,9 @@
     ],
     srcs: [
         "test_module_config.go",
-        "test_suite.go",
     ],
     testSrcs: [
         "test_module_config_test.go",
-        "test_suite_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/tradefed_modules/test_suite.go b/tradefed_modules/test_suite.go
deleted file mode 100644
index 8b7babf..0000000
--- a/tradefed_modules/test_suite.go
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2024 Google Inc. All rights reserved.
-//
-// 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 tradefed_modules
-
-import (
-	"encoding/json"
-	"path"
-	"path/filepath"
-
-	"android/soong/android"
-	"android/soong/tradefed"
-	"github.com/google/blueprint"
-)
-
-const testSuiteModuleType = "test_suite"
-
-type testSuiteTag struct {
-	blueprint.BaseDependencyTag
-}
-
-type testSuiteManifest struct {
-	Name  string   `json:"name"`
-	Files []string `json:"files"`
-}
-
-func init() {
-	RegisterTestSuiteBuildComponents(android.InitRegistrationContext)
-}
-
-func RegisterTestSuiteBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType(testSuiteModuleType, TestSuiteFactory)
-}
-
-var PrepareForTestWithTestSuiteBuildComponents = android.GroupFixturePreparers(
-	android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-)
-
-type testSuiteProperties struct {
-	Description string
-	Tests       []string `android:"path,arch_variant"`
-}
-
-type testSuiteModule struct {
-	android.ModuleBase
-	android.DefaultableModuleBase
-	testSuiteProperties
-}
-
-func (t *testSuiteModule) DepsMutator(ctx android.BottomUpMutatorContext) {
-	for _, test := range t.Tests {
-		if ctx.OtherModuleDependencyVariantExists(ctx.Config().BuildOSCommonTarget.Variations(), test) {
-			// Host tests.
-			ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), testSuiteTag{}, test)
-		} else {
-			// Target tests.
-			ctx.AddDependency(ctx.Module(), testSuiteTag{}, test)
-		}
-	}
-}
-
-func (t *testSuiteModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	suiteName := ctx.ModuleName()
-	modulesByName := make(map[string]android.Module)
-	ctx.WalkDeps(func(child, parent android.Module) bool {
-		// Recurse into test_suite dependencies.
-		if ctx.OtherModuleType(child) == testSuiteModuleType {
-			ctx.Phony(suiteName, android.PathForPhony(ctx, child.Name()))
-			return true
-		}
-
-		// Only write out top level test suite dependencies here.
-		if _, ok := ctx.OtherModuleDependencyTag(child).(testSuiteTag); !ok {
-			return false
-		}
-
-		if !child.InstallInTestcases() {
-			ctx.ModuleErrorf("test_suite only supports modules installed in testcases. %q is not installed in testcases.", child.Name())
-			return false
-		}
-
-		modulesByName[child.Name()] = child
-		return false
-	})
-
-	var files []string
-	for name, module := range modulesByName {
-		// Get the test provider data from the child.
-		tp, ok := android.OtherModuleProvider(ctx, module, tradefed.BaseTestProviderKey)
-		if !ok {
-			// TODO: Consider printing out a list of all module types.
-			ctx.ModuleErrorf("%q is not a test module.", name)
-			continue
-		}
-
-		files = append(files, packageModuleFiles(ctx, suiteName, module, tp)...)
-		ctx.Phony(suiteName, android.PathForPhony(ctx, name))
-	}
-
-	manifestPath := android.PathForSuiteInstall(ctx, suiteName, suiteName+".json")
-	b, err := json.Marshal(testSuiteManifest{Name: suiteName, Files: android.SortedUniqueStrings(files)})
-	if err != nil {
-		ctx.ModuleErrorf("Failed to marshal manifest: %v", err)
-		return
-	}
-	android.WriteFileRule(ctx, manifestPath, string(b))
-
-	ctx.Phony(suiteName, manifestPath)
-}
-
-func TestSuiteFactory() android.Module {
-	module := &testSuiteModule{}
-	module.AddProperties(&module.testSuiteProperties)
-
-	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
-	android.InitDefaultableModule(module)
-
-	return module
-}
-
-func packageModuleFiles(ctx android.ModuleContext, suiteName string, module android.Module, tp tradefed.BaseTestProviderData) []string {
-
-	hostOrTarget := "target"
-	if tp.IsHost {
-		hostOrTarget = "host"
-	}
-
-	// suiteRoot at out/soong/packaging/<suiteName>.
-	suiteRoot := android.PathForSuiteInstall(ctx, suiteName)
-
-	var installed android.InstallPaths
-	// Install links to installed files from the module.
-	if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok {
-		for _, f := range installFilesInfo.InstallFiles {
-			// rel is anything under .../<partition>, normally under .../testcases.
-			rel := android.Rel(ctx, f.PartitionDir(), f.String())
-
-			// Install the file under <suiteRoot>/<host|target>/<partition>.
-			installDir := suiteRoot.Join(ctx, hostOrTarget, f.Partition(), path.Dir(rel))
-			linkTo, err := filepath.Rel(installDir.String(), f.String())
-			if err != nil {
-				ctx.ModuleErrorf("Failed to get relative path from %s to %s: %v", installDir.String(), f.String(), err)
-				continue
-			}
-			installed = append(installed, ctx.InstallAbsoluteSymlink(installDir, path.Base(rel), linkTo))
-		}
-	}
-
-	// Install config file.
-	if tp.TestConfig != nil {
-		moduleRoot := suiteRoot.Join(ctx, hostOrTarget, "testcases", module.Name())
-		installed = append(installed, ctx.InstallFile(moduleRoot, module.Name()+".config", tp.TestConfig))
-	}
-
-	// Add to phony and manifest, manifestpaths are relative to suiteRoot.
-	var manifestEntries []string
-	for _, f := range installed {
-		manifestEntries = append(manifestEntries, android.Rel(ctx, suiteRoot.String(), f.String()))
-		ctx.Phony(suiteName, f)
-	}
-	return manifestEntries
-}
diff --git a/tradefed_modules/test_suite_test.go b/tradefed_modules/test_suite_test.go
deleted file mode 100644
index 3e1472c..0000000
--- a/tradefed_modules/test_suite_test.go
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2024 Google Inc. All rights reserved.
-//
-// 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 tradefed_modules
-
-import (
-	"android/soong/android"
-	"android/soong/java"
-	"encoding/json"
-	"slices"
-	"testing"
-)
-
-func TestTestSuites(t *testing.T) {
-	t.Parallel()
-	ctx := android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-	).RunTestWithBp(t, `
-		android_test {
-			name: "TestModule1",
-			sdk_version: "current",
-		}
-
-		android_test {
-			name: "TestModule2",
-			sdk_version: "current",
-		}
-
-		test_suite {
-			name: "my-suite",
-			description: "a test suite",
-			tests: [
-				"TestModule1",
-				"TestModule2",
-			]
-		}
-	`)
-	manifestPath := ctx.ModuleForTests(t, "my-suite", "android_common").Output("out/soong/test_suites/my-suite/my-suite.json")
-	var actual testSuiteManifest
-	if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil {
-		t.Errorf("failed to unmarshal manifest: %v", err)
-	}
-	slices.Sort(actual.Files)
-
-	expected := testSuiteManifest{
-		Name: "my-suite",
-		Files: []string{
-			"target/testcases/TestModule1/TestModule1.config",
-			"target/testcases/TestModule1/arm64/TestModule1.apk",
-			"target/testcases/TestModule2/TestModule2.config",
-			"target/testcases/TestModule2/arm64/TestModule2.apk",
-		},
-	}
-
-	android.AssertDeepEquals(t, "manifests differ", expected, actual)
-}
-
-func TestTestSuitesWithNested(t *testing.T) {
-	t.Parallel()
-	ctx := android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-	).RunTestWithBp(t, `
-		android_test {
-			name: "TestModule1",
-			sdk_version: "current",
-		}
-
-		android_test {
-			name: "TestModule2",
-			sdk_version: "current",
-		}
-
-		android_test {
-			name: "TestModule3",
-			sdk_version: "current",
-		}
-
-		test_suite {
-			name: "my-child-suite",
-			description: "a child test suite",
-			tests: [
-				"TestModule1",
-				"TestModule2",
-			]
-		}
-
-		test_suite {
-			name: "my-all-tests-suite",
-			description: "a parent test suite",
-			tests: [
-				"TestModule1",
-				"TestModule3",
-				"my-child-suite",
-			]
-		}
-	`)
-	manifestPath := ctx.ModuleForTests(t, "my-all-tests-suite", "android_common").Output("out/soong/test_suites/my-all-tests-suite/my-all-tests-suite.json")
-	var actual testSuiteManifest
-	if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil {
-		t.Errorf("failed to unmarshal manifest: %v", err)
-	}
-	slices.Sort(actual.Files)
-
-	expected := testSuiteManifest{
-		Name: "my-all-tests-suite",
-		Files: []string{
-			"target/testcases/TestModule1/TestModule1.config",
-			"target/testcases/TestModule1/arm64/TestModule1.apk",
-			"target/testcases/TestModule2/TestModule2.config",
-			"target/testcases/TestModule2/arm64/TestModule2.apk",
-			"target/testcases/TestModule3/TestModule3.config",
-			"target/testcases/TestModule3/arm64/TestModule3.apk",
-		},
-	}
-
-	android.AssertDeepEquals(t, "manifests differ", expected, actual)
-}
-
-func TestTestSuitesNotInstalledInTestcases(t *testing.T) {
-	t.Parallel()
-	android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
-	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{
-		`"SomeHostTest" is not installed in testcases`,
-	})).RunTestWithBp(t, `
-			java_test_host {
-				name: "SomeHostTest",
-				srcs: ["a.java"],
-			}
-			test_suite {
-				name: "my-suite",
-				description: "a test suite",
-				tests: [
-					"SomeHostTest",
-				]
-			}
-	`)
-}