Merge "Revert "Revert "Enable from-text stub generation in non-sdk java..."" into main
diff --git a/Android.bp b/Android.bp
index 0d1ff02..8d1280c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -104,7 +104,6 @@
 // Instantiate the dex_bootjars singleton module.
 dex_bootjars {
     name: "dex_bootjars",
-    no_full_install: true,
 }
 
 // Pseudo-test that's run on checkbuilds to ensure that get_clang_version can
@@ -121,20 +120,6 @@
     name: "dexpreopt_systemserver_check",
 }
 
-// buildinfo.prop contains common properties for system/build.prop, like ro.build.version.*
-// TODO(b/322090587): merge this to gen_build_prop.py script.
-buildinfo_prop {
-    name: "buildinfo.prop",
-
-    // not installable because this will be included to system/build.prop
-    installable: false,
-
-    product_config: ":product_config",
-
-    // Currently, only microdroid can refer to buildinfo.prop
-    visibility: ["//packages/modules/Virtualization/build/microdroid"],
-}
-
 // container for apex_contributions selected using build flags
 all_apex_contributions {
     name: "all_apex_contributions",
@@ -144,3 +129,23 @@
     name: "product_config",
     visibility: ["//device/google/cuttlefish/system_image"],
 }
+
+build_prop {
+    name: "system-build.prop",
+    stem: "build.prop",
+    product_config: ":product_config",
+    // Currently, only microdroid and cf system image can refer to system-build.prop
+    visibility: [
+        "//device/google/cuttlefish/system_image",
+        "//packages/modules/Virtualization/build/microdroid",
+    ],
+}
+
+build_prop {
+    name: "system_ext-build.prop",
+    stem: "build.prop",
+    system_ext_specific: true,
+    product_config: ":product_config",
+    relative_install_path: "etc", // system_ext/etc/build.prop
+    visibility: ["//visibility:private"],
+}
diff --git a/android/Android.bp b/android/Android.bp
index 774d24a..841a6af 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -39,7 +39,6 @@
         "arch_module_context.go",
         "base_module_context.go",
         "build_prop.go",
-        "buildinfo_prop.go",
         "compliance_metadata.go",
         "config.go",
         "container.go",
@@ -93,6 +92,7 @@
         "register.go",
         "rule_builder.go",
         "sandbox.go",
+        "sbom.go",
         "sdk.go",
         "sdk_version.go",
         "shared_properties.go",
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
index 8b72f8e..4cd8dda 100644
--- a/android/apex_contributions.go
+++ b/android/apex_contributions.go
@@ -119,7 +119,10 @@
 func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) {
 	addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) {
 		for _, content := range m.Contents() {
-			if !ctx.OtherModuleExists(content) && !ctx.Config().AllowMissingDependencies() {
+			// Verify that the module listed in contents exists in the tree
+			// Remove the prebuilt_ prefix to account for partner worksapces where the source module does not
+			// exist, and PrebuiltRenameMutator renames `prebuilt_foo` to `foo`
+			if !ctx.OtherModuleExists(content) && !ctx.OtherModuleExists(RemoveOptionalPrebuiltPrefix(content)) && !ctx.Config().AllowMissingDependencies() {
 				ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name())
 			}
 			pi := &PrebuiltSelectionInfo{
diff --git a/android/build_prop.go b/android/build_prop.go
index 45c17c3..d48d94d 100644
--- a/android/build_prop.go
+++ b/android/build_prop.go
@@ -31,16 +31,15 @@
 	// properties in prop_files.
 	Block_list []string
 
-	// Path to the input prop files. The contents of the files are directly
-	// emitted to the output
-	Prop_files []string `android:"path"`
-
 	// Files to be appended at the end of build.prop. These files are appended after
 	// post_process_props without any further checking.
 	Footer_files []string `android:"path"`
 
 	// Path to a JSON file containing product configs.
 	Product_config *string `android:"path"`
+
+	// Optional subdirectory under which this file is installed into
+	Relative_install_path *string
 }
 
 type buildPropModule struct {
@@ -56,16 +55,42 @@
 	return proptools.StringDefault(p.properties.Stem, "build.prop")
 }
 
+func (p *buildPropModule) propFiles(ctx ModuleContext) Paths {
+	partition := p.PartitionTag(ctx.DeviceConfig())
+	if partition == "system" {
+		return ctx.Config().SystemPropFiles(ctx)
+	} else if partition == "system_ext" {
+		return ctx.Config().SystemExtPropFiles(ctx)
+	}
+	return nil
+}
+
+func shouldAddBuildThumbprint(config Config) bool {
+	knownOemProperties := []string{
+		"ro.product.brand",
+		"ro.product.name",
+		"ro.product.device",
+	}
+
+	for _, knownProp := range knownOemProperties {
+		if InList(knownProp, config.OemProperties()) {
+			return true
+		}
+	}
+	return false
+}
+
 func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 	p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath
 	if !ctx.Config().KatiEnabled() {
 		WriteFileRule(ctx, p.outputFilePath, "# no build.prop if kati is disabled")
+		ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
 		return
 	}
 
 	partition := p.PartitionTag(ctx.DeviceConfig())
-	if partition != "system" {
-		ctx.PropertyErrorf("partition", "unsupported partition %q: only \"system\" is supported", partition)
+	if partition != "system" && partition != "system_ext" {
+		ctx.PropertyErrorf("partition", "unsupported partition %q: only \"system\" and \"system_ext\" are supported", partition)
 		return
 	}
 
@@ -93,6 +118,7 @@
 	cmd.FlagWithInput("--platform-preview-sdk-fingerprint-file=", ApiFingerprintPath(ctx))
 	cmd.FlagWithInput("--product-config=", PathForModuleSrc(ctx, proptools.String(p.properties.Product_config)))
 	cmd.FlagWithArg("--partition=", partition)
+	cmd.FlagForEachInput("--prop-files=", ctx.Config().SystemPropFiles(ctx))
 	cmd.FlagWithOutput("--out=", p.outputFilePath)
 
 	postProcessCmd := rule.Command().BuiltTool("post_process_props")
@@ -100,7 +126,12 @@
 		postProcessCmd.Flag("--allow-dup")
 	}
 	postProcessCmd.FlagWithArg("--sdk-version ", config.PlatformSdkVersion().String())
-	postProcessCmd.FlagWithInput("--kernel-version-file-for-uffd-gc ", PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt"))
+	if ctx.Config().EnableUffdGc() == "default" {
+		postProcessCmd.FlagWithInput("--kernel-version-file-for-uffd-gc ", PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt"))
+	} else {
+		// still need to pass an empty string to kernel-version-file-for-uffd-gc
+		postProcessCmd.FlagWithArg("--kernel-version-file-for-uffd-gc ", `""`)
+	}
 	postProcessCmd.Text(p.outputFilePath.String())
 	postProcessCmd.Flags(p.properties.Block_list)
 
@@ -108,12 +139,25 @@
 
 	rule.Build(ctx.ModuleName(), "generating build.prop")
 
-	p.installPath = PathForModuleInstall(ctx)
+	p.installPath = PathForModuleInstall(ctx, proptools.String(p.properties.Relative_install_path))
 	ctx.InstallFile(p.installPath, p.stem(), p.outputFilePath)
 
 	ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
 }
 
+func (p *buildPropModule) AndroidMkEntries() []AndroidMkEntries {
+	return []AndroidMkEntries{{
+		Class:      "ETC",
+		OutputFile: OptionalPathForPath(p.outputFilePath),
+		ExtraEntries: []AndroidMkExtraEntriesFunc{
+			func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_PATH", p.installPath.String())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+			},
+		},
+	}}
+}
+
 // build_prop module generates {partition}/build.prop file. At first common build properties are
 // printed based on Soong config variables. And then prop_files are printed as-is. Finally,
 // post_process_props tool is run to check if the result build.prop is valid or not.
diff --git a/android/buildinfo_prop.go b/android/buildinfo_prop.go
deleted file mode 100644
index bba4c0d..0000000
--- a/android/buildinfo_prop.go
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2022 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 android
-
-import (
-	"github.com/google/blueprint/proptools"
-)
-
-func init() {
-	ctx := InitRegistrationContext
-	ctx.RegisterModuleType("buildinfo_prop", buildinfoPropFactory)
-}
-
-type buildinfoPropProperties struct {
-	// Whether this module is directly installable to one of the partitions. Default: true.
-	Installable *bool
-
-	Product_config *string `android:"path"`
-}
-
-type buildinfoPropModule struct {
-	ModuleBase
-
-	properties buildinfoPropProperties
-
-	outputFilePath OutputPath
-	installPath    InstallPath
-}
-
-func (p *buildinfoPropModule) installable() bool {
-	return proptools.BoolDefault(p.properties.Installable, true)
-}
-
-func shouldAddBuildThumbprint(config Config) bool {
-	knownOemProperties := []string{
-		"ro.product.brand",
-		"ro.product.name",
-		"ro.product.device",
-	}
-
-	for _, knownProp := range knownOemProperties {
-		if InList(knownProp, config.OemProperties()) {
-			return true
-		}
-	}
-	return false
-}
-
-func (p *buildinfoPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
-	if ctx.ModuleName() != "buildinfo.prop" || ctx.ModuleDir() != "build/soong" {
-		ctx.ModuleErrorf("There can only be one buildinfo_prop module in build/soong")
-		return
-	}
-	p.outputFilePath = PathForModuleOut(ctx, p.Name()).OutputPath
-	ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
-
-	if !ctx.Config().KatiEnabled() {
-		WriteFileRule(ctx, p.outputFilePath, "# no buildinfo.prop if kati is disabled")
-		return
-	}
-
-	rule := NewRuleBuilder(pctx, ctx)
-
-	config := ctx.Config()
-
-	cmd := rule.Command().BuiltTool("buildinfo")
-
-	cmd.FlagWithInput("--build-hostname-file=", config.BuildHostnameFile(ctx))
-	// Note: depending on BuildNumberFile will cause the build.prop file to be rebuilt
-	// every build, but that's intentional.
-	cmd.FlagWithInput("--build-number-file=", config.BuildNumberFile(ctx))
-	// Export build thumbprint only if the product has specified at least one oem fingerprint property
-	// b/17888863
-	if shouldAddBuildThumbprint(config) {
-		// In the previous make implementation, a dependency was not added on the thumbprint file
-		cmd.FlagWithArg("--build-thumbprint-file=", config.BuildThumbprintFile(ctx).String())
-	}
-	cmd.FlagWithArg("--build-username=", config.Getenv("BUILD_USERNAME"))
-	// Technically we should also have a dependency on BUILD_DATETIME_FILE,
-	// but it can be either an absolute or relative path, which is hard to turn into
-	// a Path object. So just rely on the BuildNumberFile always changing to cause
-	// us to rebuild.
-	cmd.FlagWithArg("--date-file=", ctx.Config().Getenv("BUILD_DATETIME_FILE"))
-	cmd.FlagWithInput("--platform-preview-sdk-fingerprint-file=", ApiFingerprintPath(ctx))
-	cmd.FlagWithInput("--product-config=", PathForModuleSrc(ctx, proptools.String(p.properties.Product_config)))
-	cmd.FlagWithOutput("--out=", p.outputFilePath)
-
-	rule.Build(ctx.ModuleName(), "generating buildinfo props")
-
-	if !p.installable() {
-		p.SkipInstall()
-	}
-
-	p.installPath = PathForModuleInstall(ctx)
-	ctx.InstallFile(p.installPath, p.Name(), p.outputFilePath)
-}
-
-func (p *buildinfoPropModule) AndroidMkEntries() []AndroidMkEntries {
-	return []AndroidMkEntries{{
-		Class:      "ETC",
-		OutputFile: OptionalPathForPath(p.outputFilePath),
-		ExtraEntries: []AndroidMkExtraEntriesFunc{
-			func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
-				entries.SetString("LOCAL_MODULE_PATH", p.installPath.String())
-				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
-				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
-			},
-		},
-	}}
-}
-
-// buildinfo_prop module generates a build.prop file, which contains a set of common
-// system/build.prop properties, such as ro.build.version.*.  Not all properties are implemented;
-// currently this module is only for microdroid.
-func buildinfoPropFactory() Module {
-	module := &buildinfoPropModule{}
-	module.AddProperties(&module.properties)
-	InitAndroidModule(module)
-	return module
-}
diff --git a/android/config.go b/android/config.go
index 7c6f7ce..a2dfce9 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1195,6 +1195,10 @@
 	return Bool(c.productVariables.UseGoma)
 }
 
+func (c *config) UseABFS() bool {
+	return Bool(c.productVariables.UseABFS)
+}
+
 func (c *config) UseRBE() bool {
 	return Bool(c.productVariables.UseRBE)
 }
@@ -1989,41 +1993,41 @@
 }
 
 var (
-	mainlineApexContributionBuildFlags = []string{
-		"RELEASE_APEX_CONTRIBUTIONS_ADBD",
-		"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES",
-		"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH",
-		"RELEASE_APEX_CONTRIBUTIONS_ART",
-		"RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH",
-		"RELEASE_APEX_CONTRIBUTIONS_CAPTIVEPORTALLOGIN",
-		"RELEASE_APEX_CONTRIBUTIONS_CELLBROADCAST",
-		"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE",
-		"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY",
-		"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT",
-		"RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY",
-		"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK",
-		"RELEASE_APEX_CONTRIBUTIONS_DOCUMENTSUIGOOGLE",
-		"RELEASE_APEX_CONTRIBUTIONS_EXTSERVICES",
-		"RELEASE_APEX_CONTRIBUTIONS_HEALTHFITNESS",
-		"RELEASE_APEX_CONTRIBUTIONS_IPSEC",
-		"RELEASE_APEX_CONTRIBUTIONS_MEDIA",
-		"RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER",
-		"RELEASE_APEX_CONTRIBUTIONS_MODULE_METADATA",
-		"RELEASE_APEX_CONTRIBUTIONS_NETWORKSTACKGOOGLE",
-		"RELEASE_APEX_CONTRIBUTIONS_NEURALNETWORKS",
-		"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION",
-		"RELEASE_APEX_CONTRIBUTIONS_PERMISSION",
-		"RELEASE_APEX_CONTRIBUTIONS_PRIMARY_LIBS",
-		"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING",
-		"RELEASE_APEX_CONTRIBUTIONS_RESOLV",
-		"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING",
-		"RELEASE_APEX_CONTRIBUTIONS_SDKEXTENSIONS",
-		"RELEASE_APEX_CONTRIBUTIONS_SWCODEC",
-		"RELEASE_APEX_CONTRIBUTIONS_STATSD",
-		"RELEASE_APEX_CONTRIBUTIONS_TELEMETRY_TVP",
-		"RELEASE_APEX_CONTRIBUTIONS_TZDATA",
-		"RELEASE_APEX_CONTRIBUTIONS_UWB",
-		"RELEASE_APEX_CONTRIBUTIONS_WIFI",
+	mainlineApexContributionBuildFlagsToApexNames = map[string]string{
+		"RELEASE_APEX_CONTRIBUTIONS_ADBD":                    "com.android.adbd",
+		"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES":              "com.android.adservices",
+		"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH":               "com.android.appsearch",
+		"RELEASE_APEX_CONTRIBUTIONS_ART":                     "com.android.art",
+		"RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH":               "com.android.btservices",
+		"RELEASE_APEX_CONTRIBUTIONS_CAPTIVEPORTALLOGIN":      "",
+		"RELEASE_APEX_CONTRIBUTIONS_CELLBROADCAST":           "com.android.cellbroadcast",
+		"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE":    "com.android.configinfrastructure",
+		"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY":            "com.android.tethering",
+		"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT":               "com.android.conscrypt",
+		"RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY":           "",
+		"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK":              "com.android.devicelock",
+		"RELEASE_APEX_CONTRIBUTIONS_DOCUMENTSUIGOOGLE":       "",
+		"RELEASE_APEX_CONTRIBUTIONS_EXTSERVICES":             "com.android.extservices",
+		"RELEASE_APEX_CONTRIBUTIONS_HEALTHFITNESS":           "com.android.healthfitness",
+		"RELEASE_APEX_CONTRIBUTIONS_IPSEC":                   "com.android.ipsec",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIA":                   "com.android.media",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER":           "com.android.mediaprovider",
+		"RELEASE_APEX_CONTRIBUTIONS_MODULE_METADATA":         "",
+		"RELEASE_APEX_CONTRIBUTIONS_NETWORKSTACKGOOGLE":      "",
+		"RELEASE_APEX_CONTRIBUTIONS_NEURALNETWORKS":          "com.android.neuralnetworks",
+		"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION": "com.android.ondevicepersonalization",
+		"RELEASE_APEX_CONTRIBUTIONS_PERMISSION":              "com.android.permission",
+		"RELEASE_APEX_CONTRIBUTIONS_PRIMARY_LIBS":            "",
+		"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING":   "com.android.rkpd",
+		"RELEASE_APEX_CONTRIBUTIONS_RESOLV":                  "com.android.resolv",
+		"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING":              "com.android.scheduling",
+		"RELEASE_APEX_CONTRIBUTIONS_SDKEXTENSIONS":           "com.android.sdkext",
+		"RELEASE_APEX_CONTRIBUTIONS_SWCODEC":                 "com.android.media.swcodec",
+		"RELEASE_APEX_CONTRIBUTIONS_STATSD":                  "com.android.os.statsd",
+		"RELEASE_APEX_CONTRIBUTIONS_TELEMETRY_TVP":           "",
+		"RELEASE_APEX_CONTRIBUTIONS_TZDATA":                  "com.android.tzdata",
+		"RELEASE_APEX_CONTRIBUTIONS_UWB":                     "com.android.uwb",
+		"RELEASE_APEX_CONTRIBUTIONS_WIFI":                    "com.android.wifi",
 	}
 )
 
@@ -2031,7 +2035,7 @@
 // Each mainline module will have one entry in the list
 func (c *config) AllApexContributions() []string {
 	ret := []string{}
-	for _, f := range mainlineApexContributionBuildFlags {
+	for _, f := range SortedKeys(mainlineApexContributionBuildFlagsToApexNames) {
 		if val, exists := c.GetBuildFlag(f); exists && val != "" {
 			ret = append(ret, val)
 		}
@@ -2039,6 +2043,10 @@
 	return ret
 }
 
+func (c *config) AllMainlineApexNames() []string {
+	return SortedStringValues(mainlineApexContributionBuildFlagsToApexNames)
+}
+
 func (c *config) BuildIgnoreApexContributionContents() *bool {
 	return c.productVariables.BuildIgnoreApexContributionContents
 }
@@ -2066,3 +2074,15 @@
 
 	return Bool(c.productVariables.Eng)
 }
+
+func (c *config) SystemPropFiles(ctx PathContext) Paths {
+	return PathsForSource(ctx, c.productVariables.SystemPropFiles)
+}
+
+func (c *config) SystemExtPropFiles(ctx PathContext) Paths {
+	return PathsForSource(ctx, c.productVariables.SystemExtPropFiles)
+}
+
+func (c *config) EnableUffdGc() string {
+	return String(c.productVariables.EnableUffdGc)
+}
diff --git a/android/configurable_properties.go b/android/configurable_properties.go
index dad42fa..2c794a1 100644
--- a/android/configurable_properties.go
+++ b/android/configurable_properties.go
@@ -26,3 +26,9 @@
 		resultCases,
 	)
 }
+
+func NewSimpleConfigurable[T proptools.ConfigurableElements](value T) proptools.Configurable[T] {
+	return proptools.NewConfigurable(nil, []proptools.ConfigurableCase[T]{
+		proptools.NewConfigurableCase(nil, &value),
+	})
+}
diff --git a/android/defaults.go b/android/defaults.go
index ff79002..c0a2fc6 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -28,7 +28,7 @@
 var DefaultsDepTag defaultsDependencyTag
 
 type defaultsProperties struct {
-	Defaults []string
+	Defaults proptools.Configurable[[]string]
 }
 
 type DefaultableModuleBase struct {
@@ -278,13 +278,14 @@
 
 func defaultsDepsMutator(ctx BottomUpMutatorContext) {
 	if defaultable, ok := ctx.Module().(Defaultable); ok {
-		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
+		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults.GetOrDefault(ctx, nil)...)
 	}
 }
 
 func defaultsMutator(ctx TopDownMutatorContext) {
 	if defaultable, ok := ctx.Module().(Defaultable); ok {
-		if len(defaultable.defaults().Defaults) > 0 {
+		defaults := defaultable.defaults().Defaults.GetOrDefault(ctx, nil)
+		if len(defaults) > 0 {
 			var defaultsList []Defaults
 			seen := make(map[Defaults]bool)
 
@@ -294,7 +295,7 @@
 						if !seen[defaults] {
 							seen[defaults] = true
 							defaultsList = append(defaultsList, defaults)
-							return len(defaults.defaults().Defaults) > 0
+							return len(defaults.defaults().Defaults.GetOrDefault(ctx, nil)) > 0
 						}
 					} else {
 						ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
diff --git a/android/image.go b/android/image.go
index 0f03107..6e5a551 100644
--- a/android/image.go
+++ b/android/image.go
@@ -14,7 +14,7 @@
 
 package android
 
-// ImageInterface is implemented by modules that need to be split by the imageMutator.
+// ImageInterface is implemented by modules that need to be split by the imageTransitionMutator.
 type ImageInterface interface {
 	// ImageMutatorBegin is called before any other method in the ImageInterface.
 	ImageMutatorBegin(ctx BaseModuleContext)
@@ -81,18 +81,16 @@
 	DebugRamdiskVariation string = "debug_ramdisk"
 )
 
-// imageMutator creates variants for modules that implement the ImageInterface that
+// imageTransitionMutator creates variants for modules that implement the ImageInterface that
 // allow them to build differently for each partition (recovery, core, vendor, etc.).
-func imageMutator(ctx BottomUpMutatorContext) {
-	if ctx.Os() != Android {
-		return
-	}
+type imageTransitionMutator struct{}
 
-	if m, ok := ctx.Module().(ImageInterface); ok {
+func (imageTransitionMutator) Split(ctx BaseModuleContext) []string {
+	var variations []string
+
+	if m, ok := ctx.Module().(ImageInterface); ctx.Os() == Android && ok {
 		m.ImageMutatorBegin(ctx)
 
-		var variations []string
-
 		if m.CoreVariantNeeded(ctx) {
 			variations = append(variations, CoreVariation)
 		}
@@ -117,15 +115,29 @@
 
 		extraVariations := m.ExtraImageVariations(ctx)
 		variations = append(variations, extraVariations...)
+	}
 
-		if len(variations) == 0 {
-			return
-		}
+	if len(variations) == 0 {
+		variations = append(variations, "")
+	}
 
-		mod := ctx.CreateVariations(variations...)
-		for i, v := range variations {
-			mod[i].base().setImageVariation(v)
-			mod[i].(ImageInterface).SetImageVariation(ctx, v)
-		}
+	return variations
+}
+
+func (imageTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+	return sourceVariation
+}
+
+func (imageTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+	if _, ok := ctx.Module().(ImageInterface); ctx.Os() != Android || !ok {
+		return CoreVariation
+	}
+	return incomingVariation
+}
+
+func (imageTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+	ctx.Module().base().setImageVariation(variation)
+	if m, ok := ctx.Module().(ImageInterface); ok {
+		m.SetImageVariation(ctx, variation)
 	}
 }
diff --git a/android/module.go b/android/module.go
index 37e26f9..f9fab96 100644
--- a/android/module.go
+++ b/android/module.go
@@ -389,7 +389,7 @@
 	Init_rc []string `android:"arch_variant,path"`
 
 	// VINTF manifest fragments to be installed if this module is installed
-	Vintf_fragments []string `android:"path"`
+	Vintf_fragments proptools.Configurable[[]string] `android:"path"`
 
 	// names of other modules to install if this module is installed
 	Required proptools.Configurable[[]string] `android:"arch_variant"`
@@ -1853,7 +1853,7 @@
 				}
 			}
 
-			m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
+			m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil))
 			vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
 			for _, src := range m.vintfFragmentsPaths {
 				installedVintfFragment := vintfDir.Join(ctx, src.Base())
@@ -1914,7 +1914,7 @@
 				return
 			}
 			cacheKey = &blueprint.BuildActionCacheKey{
-				Id:        ctx.bp.ModuleId(),
+				Id:        ctx.bp.ModuleCacheKey(),
 				InputHash: hash,
 			}
 		}
diff --git a/android/module_test.go b/android/module_test.go
index 922ea21..829c079 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -722,7 +722,6 @@
 				propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"},
 				propInfo{Name: "B", Type: "bool", Value: "true"},
 				propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}},
-				propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}},
 				propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
 				propInfo{Name: "Name", Type: "string", Value: "foo"},
 				propInfo{Name: "Nested.E", Type: "string", Value: "nested e"},
@@ -746,7 +745,6 @@
 			foo := result.ModuleForTests("foo", "").Module().base()
 
 			AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues())
-
 		})
 	}
 }
diff --git a/android/mutator.go b/android/mutator.go
index b81dd12..38fb857 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -149,7 +149,7 @@
 
 func registerArchMutator(ctx RegisterMutatorsContext) {
 	ctx.BottomUpBlueprint("os", osMutator).Parallel()
-	ctx.BottomUp("image", imageMutator).Parallel()
+	ctx.Transition("image", &imageTransitionMutator{})
 	ctx.BottomUpBlueprint("arch", archMutator).Parallel()
 }
 
diff --git a/android/paths.go b/android/paths.go
index dda48dd..dad70f7 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -245,13 +245,13 @@
 	// A standard build has the following structure:
 	//   ../top/
 	//          out/ - make install files go here.
-	//          out/soong - this is the soongOutDir passed to NewTestConfig()
+	//          out/soong - this is the outDir passed to NewTestConfig()
 	//          ... - the source files
 	//
 	// This function converts a path so that it appears relative to the ../top/ directory, i.e.
-	// * Make install paths, which have the pattern "soongOutDir/../<path>" are converted into the top
+	// * Make install paths, which have the pattern "outDir/../<path>" are converted into the top
 	//   relative path "out/<path>"
-	// * Soong install paths and other writable paths, which have the pattern "soongOutDir/<path>" are
+	// * Soong install paths and other writable paths, which have the pattern "outDir/soong/<path>" are
 	//   converted into the top relative path "out/soong/<path>".
 	// * Source paths are already relative to the top.
 	// * Phony paths are not relative to anything.
@@ -261,8 +261,9 @@
 }
 
 const (
-	OutDir      = "out"
-	OutSoongDir = OutDir + "/soong"
+	testOutDir         = "out"
+	testOutSoongSubDir = "/soong"
+	TestOutSoongDir    = testOutDir + testOutSoongSubDir
 )
 
 // WritablePath is a type of path that can be used as an output for build rules.
@@ -1118,11 +1119,6 @@
 	return p
 }
 
-func (p basePath) RelativeToTop() Path {
-	ensureTestOnly()
-	return p
-}
-
 // SourcePath is a Path representing a file path rooted from SrcDir
 type SourcePath struct {
 	basePath
@@ -1135,6 +1131,11 @@
 	return p
 }
 
+func (p SourcePath) RelativeToTop() Path {
+	ensureTestOnly()
+	return p
+}
+
 // safePathForSource is for paths that we expect are safe -- only for use by go
 // code that is embedding ninja variables in paths
 func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
@@ -1218,11 +1219,13 @@
 // PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
 // the path is relative to the root of the output folder, not the out/soong folder.
 func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
-	p, err := validatePath(pathComponents...)
+	path, err := validatePath(pathComponents...)
 	if err != nil {
 		reportPathError(ctx, err)
 	}
-	return basePath{path: filepath.Join(ctx.Config().OutDir(), p)}
+	fullPath := filepath.Join(ctx.Config().OutDir(), path)
+	path = fullPath[len(fullPath)-len(path):]
+	return OutputPath{basePath{path, ""}, ctx.Config().OutDir(), fullPath}
 }
 
 // MaybeExistentPathForSource joins the provided path components and validates that the result
@@ -1325,8 +1328,8 @@
 type OutputPath struct {
 	basePath
 
-	// The soong build directory, i.e. Config.SoongOutDir()
-	soongOutDir string
+	// The base out directory for this path, either Config.SoongOutDir() or Config.OutDir()
+	outDir string
 
 	fullPath string
 }
@@ -1334,7 +1337,7 @@
 func (p OutputPath) GobEncode() ([]byte, error) {
 	w := new(bytes.Buffer)
 	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.soongOutDir), encoder.Encode(p.fullPath))
+	err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.outDir), encoder.Encode(p.fullPath))
 	if err != nil {
 		return nil, err
 	}
@@ -1345,7 +1348,7 @@
 func (p *OutputPath) GobDecode(data []byte) error {
 	r := bytes.NewBuffer(data)
 	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.soongOutDir), decoder.Decode(&p.fullPath))
+	err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.outDir), decoder.Decode(&p.fullPath))
 	if err != nil {
 		return err
 	}
@@ -1365,7 +1368,7 @@
 }
 
 func (p OutputPath) getSoongOutDir() string {
-	return p.soongOutDir
+	return p.outDir
 }
 
 func (p OutputPath) RelativeToTop() Path {
@@ -1373,8 +1376,13 @@
 }
 
 func (p OutputPath) outputPathRelativeToTop() OutputPath {
-	p.fullPath = StringPathRelativeToTop(p.soongOutDir, p.fullPath)
-	p.soongOutDir = OutSoongDir
+	p.fullPath = StringPathRelativeToTop(p.outDir, p.fullPath)
+	if strings.HasSuffix(p.outDir, testOutSoongSubDir) {
+		p.outDir = TestOutSoongDir
+	} else {
+		// Handle the PathForArbitraryOutput case
+		p.outDir = testOutDir
+	}
 	return p
 }
 
@@ -1420,7 +1428,7 @@
 	return OutputPath{basePath{path, ""}, ctx.Config().soongOutDir, fullPath}
 }
 
-// PathsForOutput returns Paths rooted from soongOutDir
+// PathsForOutput returns Paths rooted from outDir
 func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
 	ret := make(WritablePaths, len(paths))
 	for i, path := range paths {
@@ -1751,9 +1759,9 @@
 func (p InstallPath) RelativeToTop() Path {
 	ensureTestOnly()
 	if p.makePath {
-		p.soongOutDir = OutDir
+		p.soongOutDir = testOutDir
 	} else {
-		p.soongOutDir = OutSoongDir
+		p.soongOutDir = TestOutSoongDir
 	}
 	p.fullPath = filepath.Join(p.soongOutDir, p.path)
 	return p
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 51b86a5..9c8c130 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -61,7 +61,7 @@
 type UserSuppliedPrebuiltProperties struct {
 	// When prefer is set to true the prebuilt will be used instead of any source module with
 	// a matching name.
-	Prefer *bool `android:"arch_variant"`
+	Prefer proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
 
 	// When specified this names a Soong config variable that controls the prefer property.
 	//
@@ -148,11 +148,7 @@
 }
 
 func (p *Prebuilt) ForcePrefer() {
-	p.properties.Prefer = proptools.BoolPtr(true)
-}
-
-func (p *Prebuilt) Prefer() bool {
-	return proptools.Bool(p.properties.Prefer)
+	p.properties.Prefer = NewSimpleConfigurable(true)
 }
 
 // SingleSourcePathFromSupplier invokes the supplied supplier for the current module in the
@@ -423,15 +419,7 @@
 // The metadata will be used for source vs prebuilts selection
 func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
-	// If this module is a prebuilt, is enabled and has not been renamed to source then add a
-	// dependency onto the source if it is present.
-	if p := GetEmbeddedPrebuilt(m); p != nil && m.Enabled(ctx) && !p.properties.PrebuiltRenamedToSource {
-		bmn, _ := m.(baseModuleName)
-		name := bmn.BaseModuleName()
-		if ctx.OtherModuleReverseDependencyVariantExists(name) {
-			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
-			p.properties.SourceExists = true
-		}
+	if p := GetEmbeddedPrebuilt(m); p != nil {
 		// Add a dependency from the prebuilt to the `all_apex_contributions`
 		// metadata module
 		// TODO: When all branches contain this singleton module, make this strict
@@ -439,7 +427,16 @@
 		if ctx.OtherModuleExists("all_apex_contributions") {
 			ctx.AddDependency(m, AcDepTag, "all_apex_contributions")
 		}
-
+		if m.Enabled(ctx) && !p.properties.PrebuiltRenamedToSource {
+			// If this module is a prebuilt, is enabled and has not been renamed to source then add a
+			// dependency onto the source if it is present.
+			bmn, _ := m.(baseModuleName)
+			name := bmn.BaseModuleName()
+			if ctx.OtherModuleReverseDependencyVariantExists(name) {
+				ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
+				p.properties.SourceExists = true
+			}
+		}
 	}
 }
 
@@ -668,12 +665,37 @@
 	return p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0
 }
 
+type apexVariationName interface {
+	ApexVariationName() string
+}
+
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
 func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool {
+	isMainlinePrebuilt := func(prebuilt Module) bool {
+		apex, ok := prebuilt.(apexVariationName)
+		if !ok {
+			return false
+		}
+		// Prebuilts of aosp apexes in prebuilts/runtime
+		// Used in minimal art branches
+		if prebuilt.base().BaseModuleName() == apex.ApexVariationName() {
+			return false
+		}
+		return InList(apex.ApexVariationName(), ctx.Config().AllMainlineApexNames())
+	}
+
 	// Use `all_apex_contributions` for source vs prebuilt selection.
 	psi := PrebuiltSelectionInfoMap{}
-	ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(am Module) {
+	var psiDepTag blueprint.DependencyTag
+	if p := GetEmbeddedPrebuilt(ctx.Module()); p != nil {
+		// This is a prebuilt module, visit all_apex_contributions to get the info
+		psiDepTag = AcDepTag
+	} else {
+		// This is a source module, visit any of its prebuilts to get the info
+		psiDepTag = PrebuiltDepTag
+	}
+	ctx.VisitDirectDepsWithTag(psiDepTag, func(am Module) {
 		psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
 	})
 
@@ -686,6 +708,11 @@
 		return true
 	}
 
+	// If this is a mainline prebuilt, but has not been flagged, hide it.
+	if isMainlinePrebuilt(prebuilt) {
+		return false
+	}
+
 	// If the baseModuleName could not be found in the metadata module,
 	// fall back to the existing source vs prebuilt selection.
 	// TODO: Drop the fallback mechanisms
@@ -707,7 +734,7 @@
 	}
 
 	// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
-	return Bool(p.properties.Prefer)
+	return p.properties.Prefer.GetOrDefault(ctx, false)
 }
 
 func (p *Prebuilt) SourceExists() bool {
diff --git a/android/sbom.go b/android/sbom.go
new file mode 100644
index 0000000..2a5499e
--- /dev/null
+++ b/android/sbom.go
@@ -0,0 +1,111 @@
+// 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 android
+
+import (
+	"io"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint"
+)
+
+var (
+	// Command line tool to generate SBOM in Soong
+	genSbom = pctx.HostBinToolVariable("genSbom", "gen_sbom")
+
+	// Command to generate SBOM in Soong.
+	genSbomRule = pctx.AndroidStaticRule("genSbomRule", blueprint.RuleParams{
+		Command:     "rm -rf $out && ${genSbom} --output_file ${out} --metadata ${in} --product_out ${productOut} --soong_out ${soongOut} --build_version \"$$(cat ${buildFingerprintFile})\" --product_mfr \"${productManufacturer}\" --json",
+		CommandDeps: []string{"${genSbom}"},
+	}, "productOut", "soongOut", "buildFingerprintFile", "productManufacturer")
+)
+
+func init() {
+	RegisterSbomSingleton(InitRegistrationContext)
+}
+
+func RegisterSbomSingleton(ctx RegistrationContext) {
+	ctx.RegisterParallelSingletonType("sbom_singleton", sbomSingletonFactory)
+}
+
+// sbomSingleton is used to generate build actions of generating SBOM of products.
+type sbomSingleton struct {
+	sbomFile OutputPath
+}
+
+func sbomSingletonFactory() Singleton {
+	return &sbomSingleton{}
+}
+
+// Generates SBOM of products
+func (this *sbomSingleton) GenerateBuildActions(ctx SingletonContext) {
+	if !ctx.Config().HasDeviceProduct() {
+		return
+	}
+	// Get all METADATA files and add them as implicit input
+	metadataFileListFile := PathForArbitraryOutput(ctx, ".module_paths", "METADATA.list")
+	f, err := ctx.Config().fs.Open(metadataFileListFile.String())
+	if err != nil {
+		panic(err)
+	}
+	b, err := io.ReadAll(f)
+	if err != nil {
+		panic(err)
+	}
+	allMetadataFiles := strings.Split(string(b), "\n")
+	implicits := []Path{metadataFileListFile}
+	for _, path := range allMetadataFiles {
+		implicits = append(implicits, PathForSource(ctx, path))
+	}
+	prodVars := ctx.Config().productVariables
+	buildFingerprintFile := PathForArbitraryOutput(ctx, "target", "product", String(prodVars.DeviceName), "build_fingerprint.txt")
+	implicits = append(implicits, buildFingerprintFile)
+
+	// Add installed_files.stamp as implicit input, which depends on all installed files of the product.
+	installedFilesStamp := PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "installed_files.stamp")
+	implicits = append(implicits, installedFilesStamp)
+
+	metadataDb := PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "compliance-metadata.db")
+	this.sbomFile = PathForOutput(ctx, "sbom", ctx.Config().DeviceProduct(), "sbom.spdx.json")
+	ctx.Build(pctx, BuildParams{
+		Rule:      genSbomRule,
+		Input:     metadataDb,
+		Implicits: implicits,
+		Output:    this.sbomFile,
+		Args: map[string]string{
+			"productOut":           filepath.Join(ctx.Config().OutDir(), "target", "product", String(prodVars.DeviceName)),
+			"soongOut":             ctx.Config().soongOutDir,
+			"buildFingerprintFile": buildFingerprintFile.String(),
+			"productManufacturer":  ctx.Config().ProductVariables().ProductManufacturer,
+		},
+	})
+
+	if !ctx.Config().UnbundledBuildApps() {
+		// When building SBOM of products, phony rule "sbom" is for generating product SBOM in Soong.
+		ctx.Build(pctx, BuildParams{
+			Rule:   blueprint.Phony,
+			Inputs: []Path{this.sbomFile},
+			Output: PathForPhony(ctx, "sbom"),
+		})
+	}
+}
+
+func (this *sbomSingleton) MakeVars(ctx MakeVarsContext) {
+	// When building SBOM of products
+	if !ctx.Config().UnbundledBuildApps() {
+		ctx.DistForGoalWithFilename("droid", this.sbomFile, "sbom/sbom.spdx.json")
+	}
+}
diff --git a/android/testing.go b/android/testing.go
index e39a1a7..dae787b 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -822,15 +822,15 @@
 // containing at most one instance of the temporary build directory at the start of the path while
 // this assumes that there can be any number at any position.
 func normalizeStringRelativeToTop(config Config, s string) string {
-	// The soongOutDir usually looks something like: /tmp/testFoo2345/001
+	// The outDir usually looks something like: /tmp/testFoo2345/001
 	//
-	// Replace any usage of the soongOutDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with
+	// Replace any usage of the outDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with
 	// "out/soong".
 	outSoongDir := filepath.Clean(config.soongOutDir)
 	re := regexp.MustCompile(`\Q` + outSoongDir + `\E\b`)
 	s = re.ReplaceAllString(s, "out/soong")
 
-	// Replace any usage of the soongOutDir/.. with out, e.g. replace "/tmp/testFoo2345" with
+	// Replace any usage of the outDir/.. with out, e.g. replace "/tmp/testFoo2345" with
 	// "out". This must come after the previous replacement otherwise this would replace
 	// "/tmp/testFoo2345/001" with "out/001" instead of "out/soong".
 	outDir := filepath.Dir(outSoongDir)
@@ -1234,8 +1234,14 @@
 	}
 
 	if isRel {
-		// The path is in the soong out dir so indicate that in the relative path.
-		return filepath.Join("out/soong", rel)
+		if strings.HasSuffix(soongOutDir, testOutSoongSubDir) {
+			// The path is in the soong out dir so indicate that in the relative path.
+			return filepath.Join(TestOutSoongDir, rel)
+		} else {
+			// Handle the PathForArbitraryOutput case
+			return filepath.Join(testOutDir, rel)
+
+		}
 	}
 
 	// Check to see if the path is relative to the top level out dir.
diff --git a/android/variable.go b/android/variable.go
index eb0e210..c9b29f1 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -294,6 +294,7 @@
 	HostStaticBinaries           *bool    `json:",omitempty"`
 	Binder32bit                  *bool    `json:",omitempty"`
 	UseGoma                      *bool    `json:",omitempty"`
+	UseABFS                      *bool    `json:",omitempty"`
 	UseRBE                       *bool    `json:",omitempty"`
 	UseRBEJAVAC                  *bool    `json:",omitempty"`
 	UseRBER8                     *bool    `json:",omitempty"`
@@ -506,6 +507,11 @@
 	OemProperties []string `json:",omitempty"`
 
 	ArtTargetIncludeDebugBuild *bool `json:",omitempty"`
+
+	SystemPropFiles    []string `json:",omitempty"`
+	SystemExtPropFiles []string `json:",omitempty"`
+
+	EnableUffdGc *string `json:",omitempty"`
 }
 
 type PartitionQualifiedVariablesType struct {
diff --git a/apex/apex.go b/apex/apex.go
index c1a9d74..fc0500a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -86,7 +86,7 @@
 
 	// AndroidManifest.xml file used for the zip container of this APEX bundle. If unspecified,
 	// a default one is automatically generated.
-	AndroidManifest *string `android:"path"`
+	AndroidManifest proptools.Configurable[string] `android:"path,replace_instead_of_append"`
 
 	// Determines the file contexts file for setting the security contexts to files in this APEX
 	// bundle. For platform APEXes, this should points to a file under /system/sepolicy Default:
@@ -104,7 +104,7 @@
 	// path_or_glob is a path or glob pattern for a file or set of files,
 	// uid/gid are numerial values of user ID and group ID, mode is octal value
 	// for the file mode, and cap is hexadecimal value for the capability.
-	Canned_fs_config *string `android:"path"`
+	Canned_fs_config proptools.Configurable[string] `android:"path,replace_instead_of_append"`
 
 	ApexNativeDependencies
 
@@ -117,7 +117,8 @@
 	Bootclasspath_fragments []string
 
 	// List of systemserverclasspath fragments that are embedded inside this APEX bundle.
-	Systemserverclasspath_fragments []string
+	Systemserverclasspath_fragments        proptools.Configurable[[]string]
+	ResolvedSystemserverclasspathFragments []string `blueprint:"mutated"`
 
 	// List of java libraries that are embedded inside this APEX bundle.
 	Java_libs []string
@@ -221,7 +222,8 @@
 	Rust_dyn_libs []string
 
 	// List of native executables that are embedded inside this APEX.
-	Binaries []string
+	Binaries         proptools.Configurable[[]string]
+	ResolvedBinaries []string `blueprint:"mutated"`
 
 	// List of native tests that are embedded inside this APEX.
 	Tests []string
@@ -230,7 +232,8 @@
 	Filesystems []string
 
 	// List of prebuilt_etcs that are embedded inside this APEX bundle.
-	Prebuilts []string
+	Prebuilts         proptools.Configurable[[]string]
+	ResolvedPrebuilts []string `blueprint:"mutated"`
 
 	// List of native libraries to exclude from this APEX.
 	Exclude_native_shared_libs []string
@@ -255,14 +258,14 @@
 }
 
 // Merge combines another ApexNativeDependencies into this one
-func (a *ApexNativeDependencies) Merge(b ApexNativeDependencies) {
+func (a *ApexNativeDependencies) Merge(ctx android.BaseMutatorContext, b ApexNativeDependencies) {
 	a.Native_shared_libs = append(a.Native_shared_libs, b.Native_shared_libs...)
 	a.Jni_libs = append(a.Jni_libs, b.Jni_libs...)
 	a.Rust_dyn_libs = append(a.Rust_dyn_libs, b.Rust_dyn_libs...)
-	a.Binaries = append(a.Binaries, b.Binaries...)
+	a.ResolvedBinaries = append(a.ResolvedBinaries, b.Binaries.GetOrDefault(ctx, nil)...)
 	a.Tests = append(a.Tests, b.Tests...)
 	a.Filesystems = append(a.Filesystems, b.Filesystems...)
-	a.Prebuilts = append(a.Prebuilts, b.Prebuilts...)
+	a.ResolvedPrebuilts = append(a.ResolvedPrebuilts, b.Prebuilts.GetOrDefault(ctx, nil)...)
 
 	a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...)
 	a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...)
@@ -338,10 +341,10 @@
 // base apex.
 type overridableProperties struct {
 	// List of APKs that are embedded inside this APEX.
-	Apps []string
+	Apps proptools.Configurable[[]string]
 
 	// List of prebuilt files that are embedded inside this APEX bundle.
-	Prebuilts []string
+	Prebuilts proptools.Configurable[[]string]
 
 	// List of BPF programs inside this APEX bundle.
 	Bpfs []string
@@ -715,7 +718,7 @@
 	// this module. This is required since arch variant of an APEX bundle is 'common' but it is
 	// 'arm' or 'arm64' for native shared libs.
 	ctx.AddFarVariationDependencies(binVariations, executableTag,
-		android.RemoveListFromList(nativeModules.Binaries, nativeModules.Exclude_binaries)...)
+		android.RemoveListFromList(nativeModules.ResolvedBinaries, nativeModules.Exclude_binaries)...)
 	ctx.AddFarVariationDependencies(binVariations, testTag,
 		android.RemoveListFromList(nativeModules.Tests, nativeModules.Exclude_tests)...)
 	ctx.AddFarVariationDependencies(libVariations, jniLibTag,
@@ -727,7 +730,7 @@
 	ctx.AddFarVariationDependencies(target.Variations(), fsTag,
 		android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...)
 	ctx.AddFarVariationDependencies(target.Variations(), prebuiltTag,
-		android.RemoveListFromList(nativeModules.Prebuilts, nativeModules.Exclude_prebuilts)...)
+		android.RemoveListFromList(nativeModules.ResolvedPrebuilts, nativeModules.Exclude_prebuilts)...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -782,20 +785,19 @@
 
 		// Add native modules targeting both ABIs. When multilib.* is omitted for
 		// native_shared_libs/jni_libs/tests, it implies multilib.both
-		deps.Merge(a.properties.Multilib.Both)
-		deps.Merge(ApexNativeDependencies{
+		deps.Merge(ctx, a.properties.Multilib.Both)
+		deps.Merge(ctx, ApexNativeDependencies{
 			Native_shared_libs: a.properties.Native_shared_libs,
 			Tests:              a.properties.Tests,
 			Jni_libs:           a.properties.Jni_libs,
-			Binaries:           nil,
 		})
 
 		// Add native modules targeting the first ABI When multilib.* is omitted for
 		// binaries, it implies multilib.first
 		isPrimaryAbi := i == 0
 		if isPrimaryAbi {
-			deps.Merge(a.properties.Multilib.First)
-			deps.Merge(ApexNativeDependencies{
+			deps.Merge(ctx, a.properties.Multilib.First)
+			deps.Merge(ctx, ApexNativeDependencies{
 				Native_shared_libs: nil,
 				Tests:              nil,
 				Jni_libs:           nil,
@@ -806,27 +808,27 @@
 		// Add native modules targeting either 32-bit or 64-bit ABI
 		switch target.Arch.ArchType.Multilib {
 		case "lib32":
-			deps.Merge(a.properties.Multilib.Lib32)
-			deps.Merge(a.properties.Multilib.Prefer32)
+			deps.Merge(ctx, a.properties.Multilib.Lib32)
+			deps.Merge(ctx, a.properties.Multilib.Prefer32)
 		case "lib64":
-			deps.Merge(a.properties.Multilib.Lib64)
+			deps.Merge(ctx, a.properties.Multilib.Lib64)
 			if !has32BitTarget {
-				deps.Merge(a.properties.Multilib.Prefer32)
+				deps.Merge(ctx, a.properties.Multilib.Prefer32)
 			}
 		}
 
 		// Add native modules targeting a specific arch variant
 		switch target.Arch.ArchType {
 		case android.Arm:
-			deps.Merge(a.archProperties.Arch.Arm.ApexNativeDependencies)
+			deps.Merge(ctx, a.archProperties.Arch.Arm.ApexNativeDependencies)
 		case android.Arm64:
-			deps.Merge(a.archProperties.Arch.Arm64.ApexNativeDependencies)
+			deps.Merge(ctx, a.archProperties.Arch.Arm64.ApexNativeDependencies)
 		case android.Riscv64:
-			deps.Merge(a.archProperties.Arch.Riscv64.ApexNativeDependencies)
+			deps.Merge(ctx, a.archProperties.Arch.Riscv64.ApexNativeDependencies)
 		case android.X86:
-			deps.Merge(a.archProperties.Arch.X86.ApexNativeDependencies)
+			deps.Merge(ctx, a.archProperties.Arch.X86.ApexNativeDependencies)
 		case android.X86_64:
-			deps.Merge(a.archProperties.Arch.X86_64.ApexNativeDependencies)
+			deps.Merge(ctx, a.archProperties.Arch.X86_64.ApexNativeDependencies)
 		default:
 			panic(fmt.Errorf("unsupported arch %v\n", ctx.Arch().ArchType))
 		}
@@ -840,11 +842,13 @@
 		}
 	}
 
+	a.properties.ResolvedSystemserverclasspathFragments = a.properties.Systemserverclasspath_fragments.GetOrDefault(ctx, nil)
+
 	// Common-arch dependencies come next
 	commonVariation := ctx.Config().AndroidCommonTarget.Variations()
 	ctx.AddFarVariationDependencies(commonVariation, rroTag, a.properties.Rros...)
 	ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
-	ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments...)
+	ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.ResolvedSystemserverclasspathFragments...)
 	ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
 	ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
 	ctx.AddFarVariationDependencies(commonVariation, compatConfigTag, a.properties.Compat_configs...)
@@ -857,9 +861,9 @@
 	}
 
 	commonVariation := ctx.Config().AndroidCommonTarget.Variations()
-	ctx.AddFarVariationDependencies(commonVariation, androidAppTag, a.overridableProperties.Apps...)
+	ctx.AddFarVariationDependencies(commonVariation, androidAppTag, a.overridableProperties.Apps.GetOrDefault(ctx, nil)...)
 	ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.overridableProperties.Bpfs...)
-	if prebuilts := a.overridableProperties.Prebuilts; len(prebuilts) > 0 {
+	if prebuilts := a.overridableProperties.Prebuilts.GetOrDefault(ctx, nil); len(prebuilts) > 0 {
 		// For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device)
 		// regardless of the TARGET_PREFER_* setting. See b/144532908
 		arches := ctx.DeviceConfig().Arches()
@@ -1492,7 +1496,6 @@
 					Native_shared_libs: []string{"libclang_rt.hwasan"},
 					Tests:              nil,
 					Jni_libs:           nil,
-					Binaries:           nil,
 				}, target, imageVariation)
 				break
 			}
@@ -2806,7 +2809,7 @@
 func (a *apexBundle) IDEInfo(dpInfo *android.IdeInfo) {
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.Java_libs...)
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.Bootclasspath_fragments...)
-	dpInfo.Deps = append(dpInfo.Deps, a.properties.Systemserverclasspath_fragments...)
+	dpInfo.Deps = append(dpInfo.Deps, a.properties.ResolvedSystemserverclasspathFragments...)
 }
 
 var (
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b18ad40..852f5fb 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5244,7 +5244,7 @@
 		myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module()
 
 		overrideNames := []string{
-			"myapex",
+			"",
 			"myjavalib.myapex",
 			"libfoo.myapex",
 			"libbar.myapex",
@@ -8993,6 +8993,30 @@
 	ensureContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.capex\n")
 }
 
+func TestApexSet_ShouldRespectCompressedApexFlag(t *testing.T) {
+	for _, compressionEnabled := range []bool{true, false} {
+		t.Run(fmt.Sprintf("compressionEnabled=%v", compressionEnabled), func(t *testing.T) {
+			ctx := testApex(t, `
+				apex_set {
+					name: "com.company.android.myapex",
+					apex_name: "com.android.myapex",
+					set: "company-myapex.apks",
+				}
+			`, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.CompressedApex = proptools.BoolPtr(compressionEnabled)
+			}),
+			)
+
+			build := ctx.ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex").Output("com.company.android.myapex.apex")
+			if compressionEnabled {
+				ensureEquals(t, build.Rule.String(), "android/soong/android.Cp")
+			} else {
+				ensureEquals(t, build.Rule.String(), "android/apex.decompressApex")
+			}
+		})
+	}
+}
+
 func TestPreferredPrebuiltSharedLibDep(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -11291,13 +11315,6 @@
 // Test that product packaging installs the selected mainline module (either source or a specific prebuilt)
 // RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
 func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) {
-	// check that the LOCAL_MODULE in the generated mk file matches the name used in PRODUCT_PACKAGES
-	// Since the name used in PRODUCT_PACKAGES does not contain prebuilt_ prefix, LOCAL_MODULE should not contain any prefix either
-	checkLocalModuleName := func(t *testing.T, ctx *android.TestContext, soongApexModuleName string, expectedLocalModuleName string) {
-		// Variations are created based on apex_name
-		entries := android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests(soongApexModuleName, "android_common_com.android.foo").Module())
-		android.AssertStringEquals(t, "LOCAL_MODULE of the prebuilt apex must match the name listed in PRODUCT_PACKAGES", expectedLocalModuleName, entries[0].EntryMap["LOCAL_MODULE"][0])
-	}
 	// for a mainline module family, check that only the flagged soong module is visible to make
 	checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) {
 		variation := func(moduleName string) string {
@@ -11352,7 +11369,7 @@
 		prebuilt_apex {
 			name: "com.google.android.foo.v2",
 			apex_name: "com.android.foo",
-			source_apex_name: "com.google.android.foo", // source_apex_name becomes LOCAL_MODULE in the generated mk file
+			source_apex_name: "com.google.android.foo",
 			src: "com.android.foo-arm.apex",
 			prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present
 		}
@@ -11438,11 +11455,6 @@
 		}
 		ctx := testApex(t, bp, preparer)
 
-		// Check that the LOCAL_MODULE of the two prebuilts is com.android.foo
-		// This ensures that product packaging can pick them for installation if it has been flagged by apex_contributions
-		checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo", "com.google.android.foo")
-		checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo.v2", "com.google.android.foo")
-
 		// Check that
 		// 1. The contents of the selected apex_contributions are visible to make
 		// 2. The rest of the apexes in the mainline module family (source or other prebuilt) is hidden from make
@@ -11450,6 +11462,118 @@
 	}
 }
 
+// Test that product packaging installs the selected mainline module in workspaces withtout source mainline module
+func TestInstallationRulesForMultipleApexPrebuiltsWithoutSource(t *testing.T) {
+	// for a mainline module family, check that only the flagged soong module is visible to make
+	checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleNames []string, hiddenModuleNames []string) {
+		variation := func(moduleName string) string {
+			ret := "android_common_com.android.adservices"
+			if moduleName == "com.google.android.foo" {
+				ret = "android_common_com.google.android.foo_com.google.android.foo"
+			}
+			return ret
+		}
+
+		for _, visibleModuleName := range visibleModuleNames {
+			visibleModule := ctx.ModuleForTests(visibleModuleName, variation(visibleModuleName)).Module()
+			android.AssertBoolEquals(t, "Apex "+visibleModuleName+" selected using apex_contributions should be visible to make", false, visibleModule.IsHideFromMake())
+		}
+
+		for _, hiddenModuleName := range hiddenModuleNames {
+			hiddenModule := ctx.ModuleForTests(hiddenModuleName, variation(hiddenModuleName)).Module()
+			android.AssertBoolEquals(t, "Apex "+hiddenModuleName+" not selected using apex_contributions should be hidden from make", true, hiddenModule.IsHideFromMake())
+
+		}
+	}
+
+	bp := `
+		apex_key {
+			name: "com.android.adservices.key",
+			public_key: "com.android.adservices.avbpubkey",
+			private_key: "com.android.adservices.pem",
+		}
+
+		// AOSP source apex
+		apex {
+			name: "com.android.adservices",
+			key: "com.android.adservices.key",
+			updatable: false,
+		}
+
+		// Prebuilt Google APEX.
+
+		prebuilt_apex {
+			name: "com.google.android.adservices",
+			apex_name: "com.android.adservices",
+			src: "com.android.foo-arm.apex",
+		}
+
+		// Another Prebuilt Google APEX
+		prebuilt_apex {
+			name: "com.google.android.adservices.v2",
+			apex_name: "com.android.adservices",
+			src: "com.android.foo-arm.apex",
+		}
+
+		// APEX contribution modules
+
+
+		apex_contributions {
+			name: "adservices.prebuilt.contributions",
+			api_domain: "com.android.adservices",
+			contents: ["prebuilt_com.google.android.adservices"],
+		}
+
+		apex_contributions {
+			name: "adservices.prebuilt.v2.contributions",
+			api_domain: "com.android.adservices",
+			contents: ["prebuilt_com.google.android.adservices.v2"],
+		}
+	`
+
+	testCases := []struct {
+		desc                       string
+		selectedApexContributions  string
+		expectedVisibleModuleNames []string
+		expectedHiddenModuleNames  []string
+	}{
+		{
+			desc:                       "No apex contributions selected, source aosp apex should be visible, and mainline prebuilts should be hidden",
+			selectedApexContributions:  "",
+			expectedVisibleModuleNames: []string{"com.android.adservices"},
+			expectedHiddenModuleNames:  []string{"com.google.android.adservices", "com.google.android.adservices.v2"},
+		},
+		{
+			desc:                       "Prebuilt apex prebuilt_com.android.foo is selected",
+			selectedApexContributions:  "adservices.prebuilt.contributions",
+			expectedVisibleModuleNames: []string{"com.android.adservices", "com.google.android.adservices"},
+			expectedHiddenModuleNames:  []string{"com.google.android.adservices.v2"},
+		},
+		{
+			desc:                       "Prebuilt apex prebuilt_com.android.foo.v2 is selected",
+			selectedApexContributions:  "adservices.prebuilt.v2.contributions",
+			expectedVisibleModuleNames: []string{"com.android.adservices", "com.google.android.adservices.v2"},
+			expectedHiddenModuleNames:  []string{"com.google.android.adservices"},
+		},
+	}
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			android.FixtureMergeMockFs(map[string][]byte{
+				"system/sepolicy/apex/com.android.adservices-file_contexts": nil,
+			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions,
+				}
+			}),
+		)
+		ctx := testApex(t, bp, preparer)
+
+		checkHideFromMake(t, ctx, tc.expectedVisibleModuleNames, tc.expectedHiddenModuleNames)
+	}
+}
+
 func TestAconfifDeclarationsValidation(t *testing.T) {
 	aconfigDeclarationLibraryString := func(moduleNames []string) (ret string) {
 		for _, moduleName := range moduleNames {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 919cb01..533f937 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -561,6 +561,7 @@
 		result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,"))
 
 		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
+			`all_apex_contributions`,
 			`dex2oatd`,
 			`prebuilt_art-bootclasspath-fragment`,
 			`prebuilt_com.android.art.apex.selector`,
@@ -568,6 +569,7 @@
 		})
 
 		java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{
+			`all_apex_contributions`,
 			`dex2oatd`,
 			`prebuilt_bar`,
 			`prebuilt_com.android.art.deapexer`,
diff --git a/apex/builder.go b/apex/builder.go
index 763ce4d..bfe1692 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -704,8 +704,9 @@
 		optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
 	}
 
-	if a.properties.AndroidManifest != nil {
-		androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+	androidManifest := a.properties.AndroidManifest.GetOrDefault(ctx, "")
+	if androidManifest != "" {
+		androidManifestFile := android.PathForModuleSrc(ctx, androidManifest)
 
 		if a.testApex {
 			androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
@@ -1195,8 +1196,9 @@
 	}
 	// Custom fs_config is "appended" to the last so that entries from the file are preferred
 	// over default ones set above.
-	if a.properties.Canned_fs_config != nil {
-		cmd.Text("cat").Input(android.PathForModuleSrc(ctx, *a.properties.Canned_fs_config))
+	customFsConfig := a.properties.Canned_fs_config.GetOrDefault(ctx, "")
+	if customFsConfig != "" {
+		cmd.Text("cat").Input(android.PathForModuleSrc(ctx, customFsConfig))
 	}
 	cmd.Text(")").FlagWithOutput("> ", cannedFsConfig)
 	builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName()))
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 65c23d3..5e46bab 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -42,6 +42,11 @@
 			CommandDeps: []string{"${extract_apks}"},
 		},
 		"abis", "allow-prereleased", "sdk-version", "skip-sdk-check")
+	decompressApex = pctx.StaticRule("decompressApex", blueprint.RuleParams{
+		Command:     `${deapexer} decompress --copy-if-uncompressed --input ${in} --output ${out}`,
+		CommandDeps: []string{"${deapexer}"},
+		Description: "decompress",
+	})
 )
 
 type prebuilt interface {
@@ -246,7 +251,6 @@
 			OutputFile:    android.OptionalPathForPath(p.outputApex),
 			Include:       "$(BUILD_PREBUILT)",
 			Host_required: p.hostRequired,
-			OverrideName:  p.BaseModuleName(),
 			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 				func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 					entries.SetString("LOCAL_MODULE_PATH", p.installDir.String())
@@ -1073,8 +1077,14 @@
 
 	inputApex := android.OptionalPathForModuleSrc(ctx, a.prebuiltCommonProperties.Selected_apex).Path()
 	a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
+
+	// Build the output APEX. If compression is not enabled, make sure the output is not compressed even if the input is compressed
+	buildRule := android.Cp
+	if !ctx.Config().ApexCompressionEnabled() {
+		buildRule = decompressApex
+	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:   android.Cp,
+		Rule:   buildRule,
 		Input:  inputApex,
 		Output: a.outputApex,
 	})
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index f6c53b2..452a43e 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -274,6 +274,7 @@
 	ctx := result.TestContext
 
 	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
+		`all_apex_contributions`,
 		`dex2oatd`,
 		`prebuilt_myapex.apex.selector`,
 		`prebuilt_myapex.deapexer`,
@@ -281,6 +282,7 @@
 	})
 
 	java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
+		`all_apex_contributions`,
 		`prebuilt_bar`,
 		`prebuilt_foo`,
 		`prebuilt_myapex.deapexer`,
@@ -432,6 +434,7 @@
 	ctx := result.TestContext
 
 	java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
+		`all_apex_contributions`,
 		`prebuilt_bar`,
 		`prebuilt_foo`,
 		`prebuilt_myapex.deapexer`,
diff --git a/bin/installmod b/bin/installmod
index 1d0d836..1ad5b84 100755
--- a/bin/installmod
+++ b/bin/installmod
@@ -28,7 +28,6 @@
     return 1
 fi
 
-local _path
 _path=$(outmod ${@:$#:1})
 if [ $? -ne 0 ]; then
     return 1
@@ -39,7 +38,7 @@
     echo "Module '$1' does not produce a file ending with .apk (try 'refreshmod' if there have been build changes?)" >&2
     return 1
 fi
-local serial_device=""
+serial_device=""
 if [[ "$1" == "-s" ]]; then
     if [[ $# -le 2 ]]; then
         echo "-s requires an argument" >&2
@@ -48,7 +47,7 @@
     serial_device="-s $2"
     shift 2
 fi
-local length=$(( $# - 1 ))
+length=$(( $# - 1 ))
 echo adb $serial_device install ${@:1:$length} $_path
 adb $serial_device install ${@:1:$length} $_path
 
diff --git a/bin/soongdbg b/bin/soongdbg
index a73bdf9..98d31eb 100755
--- a/bin/soongdbg
+++ b/bin/soongdbg
@@ -216,7 +216,7 @@
                         help="jq query for each module metadata")
     parser.add_argument("--deptags", action="store_true",
                         help="show dependency tags (makes the graph much more complex)")
-    parser.add_argument("--tag", action="append",
+    parser.add_argument("--tag", action="append", default=[],
                         help="Limit output to these dependency tags.")
 
     group = parser.add_argument_group("output formats",
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 09262e5..6445394 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -148,6 +148,10 @@
 		"-no-canonical-prefixes",
 
 		"-O2",
+		"-Wall",
+		"-Werror",
+		"-Wextra",
+
 		"-isystem bionic/libc/include",
 		"-isystem bionic/libc/kernel/uapi",
 		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
@@ -165,7 +169,7 @@
 
 	cflags = append(cflags, bpf.properties.Cflags...)
 
-	if proptools.Bool(bpf.properties.Btf) {
+	if proptools.BoolDefault(bpf.properties.Btf, true) {
 		cflags = append(cflags, "-g")
 		if runtime.GOOS != "darwin" {
 			cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
@@ -190,7 +194,7 @@
 			},
 		})
 
-		if proptools.Bool(bpf.properties.Btf) {
+		if proptools.BoolDefault(bpf.properties.Btf, true) {
 			objStripped := android.ObjPathWithExt(ctx, "", src, "o")
 			ctx.Build(pctx, android.BuildParams{
 				Rule:   stripRule,
diff --git a/cc/Android.bp b/cc/Android.bp
index 3bbcaa9..e68e4a3 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -73,7 +73,6 @@
         "ndk_abi.go",
         "ndk_headers.go",
         "ndk_library.go",
-        "ndk_prebuilt.go",
         "ndk_sysroot.go",
 
         "llndk_library.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 4134653..cecaae2 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -451,10 +451,6 @@
 	})
 }
 
-func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
-	entries.Class = "SHARED_LIBRARIES"
-}
-
 func (p *prebuiltLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 		if p.properties.Check_elf_files != nil {
diff --git a/cc/builder.go b/cc/builder.go
index 367bda3..a05a16d 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -156,11 +156,17 @@
 		"args")
 
 	// Rule to invoke `strip` (to discard symbols and data from object files) on darwin architecture.
-	darwinStrip = pctx.AndroidStaticRule("darwinStrip",
-		blueprint.RuleParams{
-			Command:     "${config.MacStripPath} -u -r -o $out $in",
-			CommandDeps: []string{"${config.MacStripPath}"},
-		})
+	darwinStrip = func() blueprint.Rule {
+		if runtime.GOOS == "darwin" {
+			return pctx.AndroidStaticRule("darwinStrip",
+				blueprint.RuleParams{
+					Command:     "${config.MacStripPath} -u -r -o $out $in",
+					CommandDeps: []string{"${config.MacStripPath}"},
+				})
+		} else {
+			return nil
+		}
+	}()
 
 	// b/132822437: objcopy uses a file descriptor per .o file when called on .a files, which runs the system out of
 	// file descriptors on darwin.  Limit concurrent calls to 5 on darwin.
@@ -174,11 +180,17 @@
 		}
 	}()
 
-	darwinLipo = pctx.AndroidStaticRule("darwinLipo",
-		blueprint.RuleParams{
-			Command:     "${config.MacLipoPath} -create -output $out $in",
-			CommandDeps: []string{"${config.MacLipoPath}"},
-		})
+	darwinLipo = func() blueprint.Rule {
+		if runtime.GOOS == "darwin" {
+			return pctx.AndroidStaticRule("darwinLipo",
+				blueprint.RuleParams{
+					Command:     "${config.MacLipoPath} -create -output $out $in",
+					CommandDeps: []string{"${config.MacLipoPath}"},
+				})
+		} else {
+			return nil
+		}
+	}()
 
 	_ = pctx.SourcePathVariable("archiveRepackPath", "build/soong/scripts/archive_repack.sh")
 
diff --git a/cc/cc.go b/cc/cc.go
index 3c17be6..3c276d2 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1028,13 +1028,6 @@
 	return ""
 }
 
-func (c *Module) NdkPrebuiltStl() bool {
-	if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok {
-		return true
-	}
-	return false
-}
-
 func (c *Module) StubDecorator() bool {
 	if _, ok := c.linker.(*stubDecorator); ok {
 		return true
@@ -1088,16 +1081,6 @@
 	return false
 }
 
-func (c *Module) IsNdkPrebuiltStl() bool {
-	if c.linker == nil {
-		return false
-	}
-	if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok {
-		return true
-	}
-	return false
-}
-
 func (c *Module) RlibStd() bool {
 	panic(fmt.Errorf("RlibStd called on non-Rust module: %q", c.BaseModuleName()))
 }
@@ -2754,10 +2737,6 @@
 		return
 	}
 	if c, ok := to.(*Module); ok {
-		if c.NdkPrebuiltStl() {
-			// These are allowed, but they don't set sdk_version
-			return
-		}
 		if c.StubDecorator() {
 			// These aren't real libraries, but are the stub shared libraries that are included in
 			// the NDK.
@@ -3927,7 +3906,6 @@
 	headerLibrary
 	testBin // testBinary already declared
 	ndkLibrary
-	ndkPrebuiltStl
 )
 
 func (c *Module) typ() moduleType {
@@ -3966,8 +3944,6 @@
 		return sharedLibrary
 	} else if c.isNDKStubLibrary() {
 		return ndkLibrary
-	} else if c.IsNdkPrebuiltStl() {
-		return ndkPrebuiltStl
 	}
 	return unknownType
 }
diff --git a/cc/cc_test.go b/cc/cc_test.go
index ccdaae5..b1c0945 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2760,7 +2760,7 @@
 		"external/foo/libarm",
 		"external/foo/lib32",
 		"external/foo/libandroid_arm",
-		"defaults/cc/common/ndk_libc++_shared",
+		"defaults/cc/common/ndk_libc++_shared_include_dirs",
 	}
 
 	conly := []string{"-fPIC", "${config.CommonGlobalConlyflags}"}
diff --git a/cc/compiler.go b/cc/compiler.go
index 03f9899..ed10533 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -53,7 +53,7 @@
 	Cflags proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// list of module-specific flags that will be used for C++ compiles
-	Cppflags []string `android:"arch_variant"`
+	Cppflags proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// list of module-specific flags that will be used for C compiles
 	Conlyflags []string `android:"arch_variant"`
@@ -367,8 +367,9 @@
 	compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...)
 
 	cflags := compiler.Properties.Cflags.GetOrDefault(ctx, nil)
+	cppflags := compiler.Properties.Cppflags.GetOrDefault(ctx, nil)
 	CheckBadCompilerFlags(ctx, "cflags", cflags)
-	CheckBadCompilerFlags(ctx, "cppflags", compiler.Properties.Cppflags)
+	CheckBadCompilerFlags(ctx, "cppflags", cppflags)
 	CheckBadCompilerFlags(ctx, "conlyflags", compiler.Properties.Conlyflags)
 	CheckBadCompilerFlags(ctx, "asflags", compiler.Properties.Asflags)
 	CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
@@ -381,7 +382,7 @@
 	esc := proptools.NinjaAndShellEscapeList
 
 	flags.Local.CFlags = append(flags.Local.CFlags, esc(cflags)...)
-	flags.Local.CppFlags = append(flags.Local.CppFlags, esc(compiler.Properties.Cppflags)...)
+	flags.Local.CppFlags = append(flags.Local.CppFlags, esc(cppflags)...)
 	flags.Local.ConlyFlags = append(flags.Local.ConlyFlags, esc(compiler.Properties.Conlyflags)...)
 	flags.Local.AsFlags = append(flags.Local.AsFlags, esc(compiler.Properties.Asflags)...)
 	flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...)
@@ -808,7 +809,7 @@
 
 	// list of c++ specific clang flags required to correctly interpret the headers.
 	// This is provided primarily to make sure cppflags defined in cc_defaults are pulled in.
-	Cppflags []string `android:"arch_variant"`
+	Cppflags proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// C standard version to use. Can be a specific version (such as "gnu11"),
 	// "experimental" (which will use draft versions like C1x when available),
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 4856669..2ea607a 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"os/exec"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"sync"
 
@@ -73,31 +74,33 @@
 )
 
 func init() {
-	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
-		return getMacTools(ctx).sdkRoot
-	})
-	pctx.StaticVariable("macMinVersion", "10.14")
-	pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
-		return getMacTools(ctx).arPath
-	})
+	if runtime.GOOS == "darwin" {
+		pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
+			return getMacTools(ctx).sdkRoot
+		})
+		pctx.StaticVariable("macMinVersion", "10.14")
+		pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
+			return getMacTools(ctx).arPath
+		})
 
-	pctx.VariableFunc("MacLipoPath", func(ctx android.PackageVarContext) string {
-		return getMacTools(ctx).lipoPath
-	})
+		pctx.VariableFunc("MacLipoPath", func(ctx android.PackageVarContext) string {
+			return getMacTools(ctx).lipoPath
+		})
 
-	pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
-		return getMacTools(ctx).stripPath
-	})
+		pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
+			return getMacTools(ctx).stripPath
+		})
 
-	pctx.VariableFunc("MacToolPath", func(ctx android.PackageVarContext) string {
-		return getMacTools(ctx).toolPath
-	})
+		pctx.VariableFunc("MacToolPath", func(ctx android.PackageVarContext) string {
+			return getMacTools(ctx).toolPath
+		})
 
-	pctx.StaticVariable("DarwinCflags", strings.Join(darwinCflags, " "))
-	pctx.StaticVariable("DarwinLdflags", strings.Join(darwinLdflags, " "))
-	pctx.StaticVariable("DarwinLldflags", strings.Join(darwinLdflags, " "))
+		pctx.StaticVariable("DarwinCflags", strings.Join(darwinCflags, " "))
+		pctx.StaticVariable("DarwinLdflags", strings.Join(darwinLdflags, " "))
+		pctx.StaticVariable("DarwinLldflags", strings.Join(darwinLdflags, " "))
 
-	pctx.StaticVariable("DarwinYasmFlags", "-f macho -m amd64")
+		pctx.StaticVariable("DarwinYasmFlags", "-f macho -m amd64")
+	}
 }
 
 func MacStripPath(ctx android.PathContext) string {
diff --git a/cc/config/global.go b/cc/config/global.go
index bf2502f..66196c2 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -136,11 +136,6 @@
 		// displaying logs in web browsers.
 		"-fmessage-length=0",
 
-		// Disable C++17 "relaxed template template argument matching" as a workaround for
-		// our out-dated libcxx.
-		// http://b/341084395
-		"-fno-relaxed-template-template-args",
-
 		// Using simple template names reduces the size of debug builds.
 		"-gsimple-template-names",
 
diff --git a/cc/library.go b/cc/library.go
index ff21cc3..092b177 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -64,7 +64,7 @@
 	Stubs struct {
 		// Relative path to the symbol map. The symbol map provides the list of
 		// symbols that are exported for stubs variant of this library.
-		Symbol_file *string `android:"path"`
+		Symbol_file *string `android:"path,arch_variant"`
 
 		// List versions to generate stubs libs for. The version name "current" is always
 		// implicitly added.
@@ -75,7 +75,7 @@
 		// implementation is made available by some other means, e.g. in a Microdroid
 		// virtual machine.
 		Implementation_installable *bool
-	}
+	} `android:"arch_variant"`
 
 	// set the name of the output
 	Stem *string `android:"arch_variant"`
@@ -118,7 +118,7 @@
 
 	// If this is an LLNDK library, properties to describe the LLNDK stubs.  Will be copied from
 	// the module pointed to by llndk_stubs if it is set.
-	Llndk llndkLibraryProperties
+	Llndk llndkLibraryProperties `android:"arch_variant"`
 
 	// If this is a vendor public library, properties to describe the vendor public library stubs.
 	Vendor_public_library vendorPublicLibraryProperties
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 85c3edf..5ece78a 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -30,7 +30,7 @@
 type llndkLibraryProperties struct {
 	// Relative path to the symbol map.
 	// An example file can be seen here: TODO(danalbert): Make an example.
-	Symbol_file *string
+	Symbol_file *string `android:"path,arch_variant"`
 
 	// Whether to export any headers as -isystem instead of -I. Mainly for use by
 	// bionic/libc.
diff --git a/cc/makevars.go b/cc/makevars.go
index cd13965..c9352a4 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -140,7 +140,6 @@
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 
 	ctx.Strict("HWADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(hwasanCflags, " "))
-	ctx.Strict("HWADDRESS_SANITIZER_GLOBAL_OPTIONS", strings.Join(hwasanGlobalOptions, ","))
 
 	ctx.Strict("CFI_EXTRA_CFLAGS", strings.Join(cfiCflags, " "))
 	ctx.Strict("CFI_EXTRA_ASFLAGS", strings.Join(cfiAsflags, " "))
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
deleted file mode 100644
index f503982..0000000
--- a/cc/ndk_prebuilt.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2016 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 cc
-
-import (
-	"strings"
-
-	"android/soong/android"
-)
-
-func init() {
-	android.RegisterModuleType("ndk_prebuilt_static_stl", NdkPrebuiltStaticStlFactory)
-	android.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
-}
-
-// NDK prebuilt libraries.
-//
-// These differ from regular prebuilts in that they aren't stripped and usually aren't installed
-// either (with the exception of the shared STLs, which are installed to the app's directory rather
-// than to the system image).
-
-type ndkPrebuiltStlLinker struct {
-	*libraryDecorator
-}
-
-func (ndk *ndkPrebuiltStlLinker) linkerProps() []interface{} {
-	return append(ndk.libraryDecorator.linkerProps(), &ndk.Properties, &ndk.flagExporter.Properties)
-}
-
-func (*ndkPrebuiltStlLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
-	// NDK libraries can't have any dependencies
-	return deps
-}
-
-func (*ndkPrebuiltStlLinker) availableFor(what string) bool {
-	// ndk prebuilt objects are available to everywhere
-	return true
-}
-
-// ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template
-// library (stl) library for linking operation. The soong's module name format
-// is ndk_<NAME>.so where the library is located under
-// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.so.
-func NdkPrebuiltSharedStlFactory() android.Module {
-	module, library := NewLibrary(android.DeviceSupported)
-	library.BuildOnlyShared()
-	module.compiler = nil
-	module.linker = &ndkPrebuiltStlLinker{
-		libraryDecorator: library,
-	}
-	module.installer = nil
-	module.Properties.Sdk_version = StringPtr("minimum")
-	module.Properties.AlwaysSdk = true
-	module.stl.Properties.Stl = StringPtr("none")
-	return module.Init()
-}
-
-// ndk_prebuilt_static_stl exports a precompiled ndk static standard template
-// library (stl) library for linking operation. The soong's module name format
-// is ndk_<NAME>.a where the library is located under
-// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.a.
-func NdkPrebuiltStaticStlFactory() android.Module {
-	module, library := NewLibrary(android.DeviceSupported)
-	library.BuildOnlyStatic()
-	module.compiler = nil
-	module.linker = &ndkPrebuiltStlLinker{
-		libraryDecorator: library,
-	}
-	module.installer = nil
-	module.Properties.Sdk_version = StringPtr("minimum")
-	module.Properties.HideFromMake = true
-	module.Properties.AlwaysSdk = true
-	module.Properties.Sdk_version = StringPtr("current")
-	module.stl.Properties.Stl = StringPtr("none")
-	return module.Init()
-}
-
-const (
-	libDir = "current/sources/cxx-stl/llvm-libc++/libs"
-)
-
-func getNdkStlLibDir(ctx android.ModuleContext) android.SourcePath {
-	return android.PathForSource(ctx, ctx.ModuleDir(), libDir).Join(ctx, ctx.Arch().Abi[0])
-}
-
-func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags,
-	deps PathDeps, objs Objects) android.Path {
-	// A null build step, but it sets up the output path.
-	if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") {
-		ctx.ModuleErrorf("NDK prebuilt libraries must have an ndk_lib prefixed name")
-	}
-
-	ndk.libraryDecorator.flagExporter.exportIncludesAsSystem(ctx)
-
-	libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
-	libExt := flags.Toolchain.ShlibSuffix()
-	if ndk.static() {
-		libExt = staticLibraryExtension
-	}
-
-	libDir := getNdkStlLibDir(ctx)
-	lib := libDir.Join(ctx, libName+libExt)
-
-	ndk.libraryDecorator.flagExporter.setProvider(ctx)
-
-	if ndk.static() {
-		depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(lib).Build()
-		android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
-			StaticLibrary: lib,
-
-			TransitiveStaticLibrariesForOrdering: depSet,
-		})
-	} else {
-		android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
-			SharedLibrary: lib,
-			Target:        ctx.Target(),
-		})
-	}
-
-	return lib
-}
diff --git a/cc/proto.go b/cc/proto.go
index 4d72f26..93142b9 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -19,6 +19,8 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+
+	"strings"
 )
 
 const (
@@ -35,13 +37,21 @@
 		srcSuffix = ".c"
 	}
 
+	srcInfix := "pb"
+	for _, value := range flags.proto.Flags {
+		if strings.HasPrefix(value, "--plugin=") && strings.HasSuffix(value, "protoc-gen-grpc-cpp-plugin") {
+			srcInfix = "grpc.pb"
+			break
+		}
+	}
+
 	if flags.proto.CanonicalPathFromRoot {
-		ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb"+srcSuffix)
-		headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
+		ccFile = android.GenPathWithExt(ctx, "proto", protoFile, srcInfix+srcSuffix)
+		headerFile = android.GenPathWithExt(ctx, "proto", protoFile, srcInfix+".h")
 	} else {
 		rel := protoFile.Rel()
-		ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb"+srcSuffix))
-		headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb.h"))
+		ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, srcInfix+srcSuffix))
+		headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, srcInfix+".h"))
 	}
 
 	protoDeps := flags.proto.Deps
diff --git a/cc/proto_test.go b/cc/proto_test.go
index abcb273..a905ea8 100644
--- a/cc/proto_test.go
+++ b/cc/proto_test.go
@@ -68,4 +68,36 @@
 		}
 	})
 
+	t.Run("grpc-cpp-plugin", func(t *testing.T) {
+		ctx := testCc(t, `
+                cc_binary_host {
+                        name: "protoc-gen-grpc-cpp-plugin",
+                        stl: "none",
+                }
+
+                cc_library_shared {
+                        name: "libgrpc",
+                        srcs: ["a.proto"],
+                        proto: {
+                                plugin: "grpc-cpp-plugin",
+                        },
+                }`)
+
+		buildOS := ctx.Config().BuildOS.String()
+
+		proto := ctx.ModuleForTests("libgrpc", "android_arm_armv7-a-neon_shared").Output("proto/a.grpc.pb.cc")
+		grpcCppPlugin := ctx.ModuleForTests("protoc-gen-grpc-cpp-plugin", buildOS+"_x86_64")
+
+		cmd := proto.RuleParams.Command
+		if w := "--grpc-cpp-plugin_out="; !strings.Contains(cmd, w) {
+			t.Errorf("expected %q in %q", w, cmd)
+		}
+
+		grpcCppPluginPath := grpcCppPlugin.Module().(android.HostToolProvider).HostToolPath().RelativeToTop().String()
+
+		if w := "--plugin=protoc-gen-grpc-cpp-plugin=" + grpcCppPluginPath; !strings.Contains(cmd, w) {
+			t.Errorf("expected %q in %q", w, cmd)
+		}
+	})
+
 }
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 64a313b..7b0652c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -79,8 +79,6 @@
 
 	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
 		"-fno-sanitize-recover=integer,undefined"}
-	hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512",
-		"export_memory_stats=0", "max_malloc_fill_size=131072", "malloc_fill_byte=0"}
 	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
 	memtagStackLlvmFlags   = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
 
diff --git a/cc/stl.go b/cc/stl.go
index de2066f..8c4ef0b 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -177,7 +177,7 @@
 		} else {
 			deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi")
 		}
-		deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind")
+		deps.StaticLibs = append(deps.StaticLibs, "libunwind")
 	default:
 		panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
 	}
diff --git a/cc/testing.go b/cc/testing.go
index 02f9924..ed567af 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -38,8 +38,6 @@
 	ctx.RegisterModuleType("cc_cmake_snapshot", CmakeSnapshotFactory)
 	ctx.RegisterModuleType("cc_object", ObjectFactory)
 	ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
-	ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
-	ctx.RegisterModuleType("ndk_prebuilt_static_stl", NdkPrebuiltStaticStlFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
 	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 }
@@ -312,6 +310,25 @@
 			],
 		}
 		cc_library {
+			name: "ndk_libc++_shared",
+			export_include_dirs: ["ndk_libc++_shared_include_dirs"],
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			vendor_available: true,
+			vendor_ramdisk_available: true,
+			product_available: true,
+			recovery_available: true,
+			host_supported: false,
+			sdk_version: "minimum",
+			double_loadable: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
+		}
+		cc_library {
 			name: "libc++demangle",
 			no_libcrt: true,
 			nocrt: true,
@@ -397,13 +414,6 @@
 			name: "libprotobuf-cpp-lite",
 		}
 
-		cc_library {
-			name: "ndk_libunwind",
-			sdk_version: "minimum",
-			stl: "none",
-			system_shared_libs: [],
-		}
-
 		ndk_library {
 			name: "libc",
 			first_version: "minimum",
@@ -422,11 +432,6 @@
 			symbol_file: "libdl.map.txt",
 		}
 
-		ndk_prebuilt_shared_stl {
-			name: "ndk_libc++_shared",
-			export_include_dirs: ["ndk_libc++_shared"],
-		}
-
 		cc_library_static {
 			name: "libgoogle-benchmark",
 			sdk_version: "current",
@@ -557,13 +562,6 @@
 
 		RegisterLlndkLibraryTxtType(ctx)
 	}),
-
-	// Additional files needed in tests that disallow non-existent source files.
-	// This includes files that are needed by all, or at least most, instances of a cc module type.
-	android.MockFS{
-		// Needed for ndk_prebuilt_(shared|static)_stl.
-		"defaults/cc/common/current/sources/cxx-stl/llvm-libc++/libs": nil,
-	}.AddToFixture(),
 )
 
 // Preparer that will define default cc modules, e.g. standard prebuilt modules.
@@ -572,17 +570,17 @@
 
 	// Additional files needed in tests that disallow non-existent source.
 	android.MockFS{
-		"defaults/cc/common/libc.map.txt":                nil,
-		"defaults/cc/common/libdl.map.txt":               nil,
-		"defaults/cc/common/libft2.map.txt":              nil,
-		"defaults/cc/common/libm.map.txt":                nil,
-		"defaults/cc/common/ndk_libc++_shared":           nil,
-		"defaults/cc/common/crtbegin_so.c":               nil,
-		"defaults/cc/common/crtbegin.c":                  nil,
-		"defaults/cc/common/crtend_so.c":                 nil,
-		"defaults/cc/common/crtend.c":                    nil,
-		"defaults/cc/common/crtbrand.c":                  nil,
-		"external/compiler-rt/lib/cfi/cfi_blocklist.txt": nil,
+		"defaults/cc/common/libc.map.txt":                   nil,
+		"defaults/cc/common/libdl.map.txt":                  nil,
+		"defaults/cc/common/libft2.map.txt":                 nil,
+		"defaults/cc/common/libm.map.txt":                   nil,
+		"defaults/cc/common/ndk_libc++_shared_include_dirs": nil,
+		"defaults/cc/common/crtbegin_so.c":                  nil,
+		"defaults/cc/common/crtbegin.c":                     nil,
+		"defaults/cc/common/crtend_so.c":                    nil,
+		"defaults/cc/common/crtend.c":                       nil,
+		"defaults/cc/common/crtbrand.c":                     nil,
+		"external/compiler-rt/lib/cfi/cfi_blocklist.txt":    nil,
 
 		"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
 		"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a":   nil,
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 2dc8c21..8c0d111 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -16,7 +16,6 @@
 
 import (
 	"os"
-	"path/filepath"
 	"testing"
 
 	"android/soong/android"
@@ -147,8 +146,8 @@
 
 	output := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
 
-	stampFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/staging_dir.stamp")
-	fileListFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/file_list.txt")
+	stampFile := "out/target/product/test_device/obj/PACKAGING/system_intermediates/staging_dir.stamp"
+	fileListFile := "out/target/product/test_device/obj/PACKAGING/system_intermediates/file_list.txt"
 	android.AssertStringListContains(t, "deps of filesystem must include the staging dir stamp file", output.Implicits.Strings(), stampFile)
 	android.AssertStringListContains(t, "deps of filesystem must include the staging dir file list", output.Implicits.Strings(), fileListFile)
 }
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 0c6e7f4..3a9a64d 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -59,7 +59,7 @@
 
 	// List of filesystem modules that this vbmeta has descriptors for. The filesystem modules
 	// have to be signed (use_avb: true).
-	Partitions []string
+	Partitions proptools.Configurable[[]string]
 
 	// List of chained partitions that this vbmeta deletages the verification.
 	Chained_partitions []chainedPartitionProperties
@@ -110,7 +110,7 @@
 var vbmetaPartitionDep = vbmetaDep{kind: "partition"}
 
 func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
-	ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions...)
+	ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
 }
 
 func (v *vbmeta) installFileName() string {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 5b40768..2557922 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -139,7 +139,8 @@
 	Export_include_dirs []string
 
 	// list of input files
-	Srcs []string `android:"path,arch_variant"`
+	Srcs         proptools.Configurable[[]string] `android:"path,arch_variant"`
+	ResolvedSrcs []string                         `blueprint:"mutated"`
 
 	// input files to exclude
 	Exclude_srcs []string `android:"path,arch_variant"`
@@ -382,7 +383,8 @@
 		}
 		return srcFiles
 	}
-	srcFiles := addLabelsForInputs("srcs", g.properties.Srcs, g.properties.Exclude_srcs)
+	g.properties.ResolvedSrcs = g.properties.Srcs.GetOrDefault(ctx, nil)
+	srcFiles := addLabelsForInputs("srcs", g.properties.ResolvedSrcs, g.properties.Exclude_srcs)
 	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()})
 
 	var copyFrom android.Paths
@@ -589,7 +591,7 @@
 // Collect information for opening IDE project files in java/jdeps.go.
 func (g *Module) IDEInfo(dpInfo *android.IdeInfo) {
 	dpInfo.Srcs = append(dpInfo.Srcs, g.Srcs().Strings()...)
-	for _, src := range g.properties.Srcs {
+	for _, src := range g.properties.ResolvedSrcs {
 		if strings.HasPrefix(src, ":") {
 			src = strings.Trim(src, ":")
 			dpInfo.Deps = append(dpInfo.Deps, src)
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index fba9aec..444aedb 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -694,7 +694,7 @@
 	android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0])
 
 	expectedSrcs := []string{"in1"}
-	android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.Srcs)
+	android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.ResolvedSrcs)
 }
 
 func TestGenruleAllowMissingDependencies(t *testing.T) {
diff --git a/java/aar.go b/java/aar.go
index b69b7c2..5c82872 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -76,7 +76,7 @@
 	// list of directories relative to the Blueprints file containing
 	// Android resources.  Defaults to ["res"] if a directory called res exists.
 	// Set to [] to disable the default.
-	Resource_dirs []string
+	Resource_dirs []string `android:"path"`
 
 	// list of zip files containing Android resources.
 	Resource_zips []string `android:"path"`
@@ -166,7 +166,11 @@
 func (a *aapt) useResourceProcessorBusyBox(ctx android.BaseModuleContext) bool {
 	return BoolDefault(a.aaptProperties.Use_resource_processor, ctx.Config().UseResourceProcessorByDefault()) &&
 		// TODO(b/331641946): remove this when ResourceProcessorBusyBox supports generating shared libraries.
-		!slices.Contains(a.aaptProperties.Aaptflags, "--shared-lib")
+		!slices.Contains(a.aaptProperties.Aaptflags, "--shared-lib") &&
+		// Use the legacy resource processor in kythe builds.
+		// The legacy resource processor creates an R.srcjar, which kythe can use for generating crossrefs.
+		// TODO(b/354854007): Re-enable BusyBox in kythe builds
+		!ctx.Config().EmitXrefRules()
 }
 
 func (a *aapt) filterProduct() string {
diff --git a/java/app_import.go b/java/app_import.go
index fa87997..045a89a 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -431,6 +431,9 @@
 	var extraArgs []string
 	if a.Privileged() {
 		extraArgs = append(extraArgs, "--privileged")
+		if ctx.Config().UncompressPrivAppDex() {
+			extraArgs = append(extraArgs, "--uncompress-priv-app-dex")
+		}
 	}
 	if proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
 		extraArgs = append(extraArgs, "--skip-preprocessed-apk-checks")
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 496fc13..54a5e75 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -777,30 +777,79 @@
 }
 
 func TestAndroidAppImport_Preprocessed(t *testing.T) {
-	ctx, _ := testJava(t, `
-		android_app_import {
-			name: "foo",
-			apk: "prebuilts/apk/app.apk",
-			presigned: true,
-			preprocessed: true,
-		}
-		`)
+	for _, dontUncompressPrivAppDexs := range []bool{false, true} {
+		name := fmt.Sprintf("dontUncompressPrivAppDexs:%t", dontUncompressPrivAppDexs)
+		t.Run(name, func(t *testing.T) {
+			result := android.GroupFixturePreparers(
+				PrepareForTestWithJavaDefaultModules,
+				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+					variables.UncompressPrivAppDex = proptools.BoolPtr(!dontUncompressPrivAppDexs)
+				}),
+			).RunTestWithBp(t, `
+				android_app_import {
+					name: "foo",
+					apk: "prebuilts/apk/app.apk",
+					presigned: true,
+					preprocessed: true,
+				}
 
-	apkName := "foo.apk"
-	variant := ctx.ModuleForTests("foo", "android_common")
-	outputBuildParams := variant.Output(apkName).BuildParams
-	if outputBuildParams.Rule.String() != android.Cp.String() {
-		t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
-	}
+				android_app_import {
+					name: "bar",
+					apk: "prebuilts/apk/app.apk",
+					presigned: true,
+					privileged: true,
+					preprocessed: true,
+				}
+			`)
 
-	// Make sure compression and aligning were validated.
-	if outputBuildParams.Validation == nil {
-		t.Errorf("Expected validation rule, but was not found")
-	}
+			// non-privileged app
+			apkName := "foo.apk"
+			variant := result.ModuleForTests("foo", "android_common")
+			outputBuildParams := variant.Output(apkName).BuildParams
+			if outputBuildParams.Rule.String() != android.Cp.String() {
+				t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+			}
 
-	validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams
-	if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
-		t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+			// Make sure compression and aligning were validated.
+			if outputBuildParams.Validation == nil {
+				t.Errorf("Expected validation rule, but was not found")
+			}
+
+			validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams
+			if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
+				t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+			}
+
+			expectedScriptArgs := "--preprocessed"
+			actualScriptArgs := validationBuildParams.Args["extraArgs"]
+			android.AssertStringEquals(t, "check script extraArgs", expectedScriptArgs, actualScriptArgs)
+
+			// privileged app
+			apkName = "bar.apk"
+			variant = result.ModuleForTests("bar", "android_common")
+			outputBuildParams = variant.Output(apkName).BuildParams
+			if outputBuildParams.Rule.String() != android.Cp.String() {
+				t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+			}
+
+			// Make sure compression and aligning were validated.
+			if outputBuildParams.Validation == nil {
+				t.Errorf("Expected validation rule, but was not found")
+			}
+
+			validationBuildParams = variant.Output("validated-prebuilt/check.stamp").BuildParams
+			if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
+				t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+			}
+
+			expectedScriptArgs = "--privileged"
+			if !dontUncompressPrivAppDexs {
+				expectedScriptArgs += " --uncompress-priv-app-dex"
+			}
+			expectedScriptArgs += " --preprocessed"
+			actualScriptArgs = validationBuildParams.Args["extraArgs"]
+			android.AssertStringEquals(t, "check script extraArgs", expectedScriptArgs, actualScriptArgs)
+		})
 	}
 }
 
diff --git a/java/app_set_test.go b/java/app_set_test.go
index 10bc5de..c02b359 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -56,7 +56,7 @@
 	mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0]
 	actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"]
 	expectedInstallFile := []string{
-		strings.Replace(params.ImplicitOutputs[0].String(), android.OutSoongDir, result.Config.SoongOutDir(), 1),
+		strings.Replace(params.ImplicitOutputs[0].String(), android.TestOutSoongDir, result.Config.SoongOutDir(), 1),
 	}
 	if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) {
 		t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',",
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 77ddf5c..029f6f6 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -196,7 +196,7 @@
 type BootclasspathNestedAPIProperties struct {
 	// java_library or preferably, java_sdk_library modules providing stub classes that define the
 	// APIs provided by this bootclasspath_fragment.
-	Stub_libs []string
+	Stub_libs proptools.Configurable[[]string]
 }
 
 // BootclasspathAPIProperties defines properties for defining the API provided by parts of the
@@ -229,11 +229,11 @@
 
 // apiScopeToStubLibs calculates the stub library modules for each relevant *HiddenAPIScope from the
 // Stub_libs properties.
-func (p BootclasspathAPIProperties) apiScopeToStubLibs() map[*HiddenAPIScope][]string {
+func (p BootclasspathAPIProperties) apiScopeToStubLibs(ctx android.BaseModuleContext) map[*HiddenAPIScope][]string {
 	m := map[*HiddenAPIScope][]string{}
 	for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
-		m[apiScope] = p.Api.Stub_libs
+		m[apiScope] = p.Api.Stub_libs.GetOrDefault(ctx, nil)
 	}
-	m[CorePlatformHiddenAPIScope] = p.Core_platform_api.Stub_libs
+	m[CorePlatformHiddenAPIScope] = p.Core_platform_api.Stub_libs.GetOrDefault(ctx, nil)
 	return m
 }
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 16209b7..bce507a 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -445,7 +445,7 @@
 func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies onto all the modules that provide the API stubs for classes on this
 	// bootclasspath fragment.
-	hiddenAPIAddStubLibDependencies(ctx, b.properties.apiScopeToStubLibs())
+	hiddenAPIAddStubLibDependencies(ctx, b.properties.apiScopeToStubLibs(ctx))
 
 	for _, additionalStubModule := range b.properties.Additional_stubs {
 		for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
@@ -933,8 +933,8 @@
 	b.Filtered_flags_path = android.OptionalPathForPath(hiddenAPIInfo.FilteredFlagsPath)
 
 	// Copy stub_libs properties.
-	b.Stub_libs = module.properties.Api.Stub_libs
-	b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs
+	b.Stub_libs = module.properties.Api.Stub_libs.GetOrDefault(mctx, nil)
+	b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs.GetOrDefault(mctx, nil)
 
 	// Copy fragment properties.
 	b.Fragments = module.properties.Fragments
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 7949244..ddb89e9 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -616,10 +616,8 @@
 	return installPath, relDir, installBase
 }
 
-// RuleBuilder.Install() adds output-to-install copy pairs to a list for Make. To share this
-// information with PackagingSpec in soong, call PackageFile for them.
-// The install path and the target install partition of the module must be the same.
-func packageFile(ctx android.ModuleContext, install android.RuleBuilderInstall) {
+// installFile will install the file if `install` path and the target install partition are the same.
+func installFile(ctx android.ModuleContext, install android.RuleBuilderInstall) {
 	installPath, relDir, name := getModuleInstallPathInfo(ctx, install.To)
 	// Empty name means the install partition is not for the target image.
 	// For the system image, files for "apex" and "system_other" are skipped here.
@@ -628,7 +626,7 @@
 	// TODO(b/320196894): Files for "system_other" are skipped because soong creates the system
 	// image only for now.
 	if name != "" {
-		ctx.PackageFile(installPath.Join(ctx, relDir), name, install.From)
+		ctx.InstallFile(installPath.Join(ctx, relDir), name, install.From)
 	}
 }
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index defa82c..56e007b 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -491,6 +491,11 @@
 	// Build path to a config file that Soong writes for Make (to be used in makefiles that install
 	// the default boot image).
 	dexpreoptConfigForMake android.WritablePath
+
+	// Build path to the boot framework profile.
+	// This is used as the `OutputFile` in `AndroidMkEntries`.
+	// A non-nil value ensures that this singleton module does not get skipped in AndroidMkEntries processing.
+	bootFrameworkProfile android.WritablePath
 }
 
 func (dbj *dexpreoptBootJars) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -603,7 +608,8 @@
 		installs := generateBootImage(ctx, config)
 		profileInstalls = append(profileInstalls, installs...)
 		if config == d.defaultBootImage {
-			_, installs := bootFrameworkProfileRule(ctx, config)
+			bootProfile, installs := bootFrameworkProfileRule(ctx, config)
+			d.bootFrameworkProfile = bootProfile
 			profileInstalls = append(profileInstalls, installs...)
 		}
 	}
@@ -613,7 +619,7 @@
 			profileLicenseMetadataFile: android.OptionalPathForPath(ctx.LicenseMetadataFile()),
 		})
 		for _, install := range profileInstalls {
-			packageFile(ctx, install)
+			installFile(ctx, install)
 		}
 	}
 }
@@ -939,24 +945,21 @@
 	}
 
 	for _, install := range image.installs {
-		packageFile(ctx, install)
+		installFile(ctx, install)
 	}
 
 	for _, install := range image.vdexInstalls {
-		if image.target.Arch.ArchType.Name != ctx.DeviceConfig().DeviceArch() {
-			// Note that the vdex files are identical between architectures. If the target image is
-			// not for the primary architecture create symlinks to share the vdex of the primary
-			// architecture with the other architectures.
-			//
-			// Assuming that the install path has the architecture name with it, replace the
-			// architecture name with the primary architecture name to find the source vdex file.
-			installPath, relDir, name := getModuleInstallPathInfo(ctx, install.To)
-			if name != "" {
-				srcRelDir := strings.Replace(relDir, image.target.Arch.ArchType.Name, ctx.DeviceConfig().DeviceArch(), 1)
-				ctx.InstallSymlink(installPath.Join(ctx, relDir), name, installPath.Join(ctx, srcRelDir, name))
-			}
-		} else {
-			packageFile(ctx, install)
+		installPath, relDir, name := getModuleInstallPathInfo(ctx, install.To)
+		if name == "" {
+			continue
+		}
+		// Note that the vdex files are identical between architectures. Copy the vdex to a no arch directory
+		// and create symlinks for both the primary and secondary arches.
+		ctx.InstallSymlink(installPath.Join(ctx, relDir), name, installPath.Join(ctx, "framework", name))
+		if image.target.Arch.ArchType.Name == ctx.DeviceConfig().DeviceArch() {
+			// Copy the vdex from the primary arch to the no-arch directory
+			// e.g. /system/framework/$bootjar.vdex
+			ctx.InstallFile(installPath.Join(ctx, "framework"), name, install.From)
 		}
 	}
 }
@@ -1234,7 +1237,7 @@
 
 	profile := bootImageProfileRuleCommon(ctx, image.name, image.dexPathsDeps.Paths(), image.getAnyAndroidVariant().dexLocationsDeps)
 
-	if image == defaultBootImageConfig(ctx) {
+	if image == defaultBootImageConfig(ctx) && profile != nil {
 		rule := android.NewRuleBuilder(pctx, ctx)
 		rule.Install(profile, "/system/etc/boot-image.prof")
 		return profile, rule.Installs()
@@ -1380,3 +1383,12 @@
 		ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(getImageNames(), " "))
 	}
 }
+
+// Add one of the outputs in `OutputFile`
+// This ensures that this singleton module does not get skipped when writing out/soong/Android-*.mk
+func (d *dexpreoptBootJars) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(d.bootFrameworkProfile),
+	}}
+}
diff --git a/java/ravenwood.go b/java/ravenwood.go
index 908619d..a52f405 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -33,6 +33,8 @@
 var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"}
 var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"}
 var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"}
+var ravenwoodDataTag = dependencyTag{name: "ravenwooddata"}
+var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"}
 
 const ravenwoodUtilsName = "ravenwood-utils"
 const ravenwoodRuntimeName = "ravenwood-runtime"
@@ -53,6 +55,13 @@
 
 type ravenwoodTestProperties struct {
 	Jni_libs []string
+
+	// Specify another android_app module here to copy it to the test directory, so that
+	// the ravenwood test can access it.
+	// TODO: For now, we simply refer to another android_app module and copy it to the
+	// test directory. Eventually, android_ravenwood_test should support all the resource
+	// related properties and build resources from the `res/` directory.
+	Resource_apk *string
 }
 
 type ravenwoodTest struct {
@@ -114,6 +123,11 @@
 	for _, lib := range r.ravenwoodTestProperties.Jni_libs {
 		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
 	}
+
+	// Resources APK
+	if resourceApk := proptools.String(r.ravenwoodTestProperties.Resource_apk); resourceApk != "" {
+		ctx.AddVariationDependencies(nil, ravenwoodTestResourceApkTag, resourceApk)
+	}
 }
 
 func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -175,6 +189,14 @@
 		installDeps = append(installDeps, installJni)
 	}
 
+	resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks")
+	if resApk := ctx.GetDirectDepsWithTag(ravenwoodTestResourceApkTag); len(resApk) > 0 {
+		for _, installFile := range resApk[0].FilesToInstall() {
+			installResApk := ctx.InstallFile(resApkInstallPath, "ravenwood-res.apk", installFile)
+			installDeps = append(installDeps, installResApk)
+		}
+	}
+
 	// Install our JAR with all dependencies
 	ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
 }
@@ -198,6 +220,9 @@
 	Libs []string
 
 	Jni_libs []string
+
+	// We use this to copy framework-res.apk to the ravenwood runtime directory.
+	Data []string
 }
 
 type ravenwoodLibgroup struct {
@@ -236,6 +261,9 @@
 	for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs {
 		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
 	}
+	for _, data := range r.ravenwoodLibgroupProperties.Data {
+		ctx.AddVariationDependencies(nil, ravenwoodDataTag, data)
+	}
 }
 
 func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -257,6 +285,14 @@
 	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
 	for _, lib := range r.ravenwoodLibgroupProperties.Libs {
 		libModule := ctx.GetDirectDepWithTag(lib, ravenwoodLibContentTag)
+		if libModule == nil {
+			if ctx.Config().AllowMissingDependencies() {
+				ctx.AddMissingDependencies([]string{lib})
+			} else {
+				ctx.PropertyErrorf("lib", "missing dependency %q", lib)
+			}
+			continue
+		}
 		libJar := android.OutputFileForModule(ctx, libModule, "")
 		ctx.InstallFile(installPath, lib+".jar", libJar)
 	}
@@ -266,6 +302,13 @@
 		ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path)
 	}
 
+	dataInstallPath := installPath.Join(ctx, "ravenwood-data")
+	for _, data := range r.ravenwoodLibgroupProperties.Data {
+		libModule := ctx.GetDirectDepWithTag(data, ravenwoodDataTag)
+		file := android.OutputFileForModule(ctx, libModule, "")
+		ctx.InstallFile(dataInstallPath, file.Base(), file)
+	}
+
 	// Normal build should perform install steps
 	ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install"))
 }
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
index 5961264..d26db93 100644
--- a/java/ravenwood_test.go
+++ b/java/ravenwood_test.go
@@ -57,6 +57,14 @@
 			name: "framework-rules.ravenwood",
 			srcs: ["Rules.java"],
 		}
+		android_app {
+			name: "app1",
+            sdk_version: "current",
+		}
+		android_app {
+			name: "app2",
+            sdk_version: "current",
+		}
 		android_ravenwood_libgroup {
 			name: "ravenwood-runtime",
 			libs: [
@@ -67,6 +75,9 @@
 				"ravenwood-runtime-jni1",
 				"ravenwood-runtime-jni2",
 			],
+			data: [
+				"app1",
+			],
 		}
 		android_ravenwood_libgroup {
 			name: "ravenwood-utils",
@@ -102,6 +113,7 @@
 	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so")
 	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so")
 	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/ravenwood-data/app1.apk")
 	utils := ctx.ModuleForTests("ravenwood-utils", "android_common")
 	utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar")
 }
@@ -143,6 +155,7 @@
 				"jni-lib2",
 				"ravenwood-runtime-jni2",
 			],
+			resource_apk: "app2",
 			sdk_version: "test_current",
 		}
 	`)
@@ -169,6 +182,7 @@
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib1.so")
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so")
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so")
+	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk")
 
 	// ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted.
 	for _, o := range module.AllOutputs() {
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index f9c3dd5..911e8b1 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -920,6 +920,7 @@
 	}
 
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
+		`all_apex_contributions`,
 		`dex2oatd`,
 		`prebuilt_sdklib.stubs`,
 		`prebuilt_sdklib.stubs.source.test`,
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 9e8ba6e..2dac27a 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -388,7 +388,9 @@
 		},
 	}
 
+	t.Parallel()
 	t.Run("basic", func(t *testing.T) {
+		t.Parallel()
 		testClasspathTestCases(t, classpathTestcases, false)
 	})
 
@@ -404,6 +406,7 @@
 		}
 
 		t.Run(testcase.name, func(t *testing.T) {
+			t.Parallel()
 			moduleType := "java_library"
 			if testcase.moduleType != "" {
 				moduleType = testcase.moduleType
diff --git a/phony/phony.go b/phony/phony.go
index b421176..807b95b 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -20,6 +20,8 @@
 	"strings"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -88,14 +90,15 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 
-	properties PhonyProperties
+	phonyDepsModuleNames []string
+	properties           PhonyProperties
 }
 
 type PhonyProperties struct {
 	// The Phony_deps is the set of all dependencies for this target,
 	// and it can function similarly to .PHONY in a makefile.
 	// Additionally, dependencies within it can even include genrule.
-	Phony_deps []string
+	Phony_deps proptools.Configurable[[]string]
 }
 
 // The phony_rule provides functionality similar to the .PHONY in a makefile.
@@ -109,13 +112,14 @@
 }
 
 func (p *PhonyRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.phonyDepsModuleNames = p.properties.Phony_deps.GetOrDefault(ctx, nil)
 }
 
 func (p *PhonyRule) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-			if len(p.properties.Phony_deps) > 0 {
-				depModulesStr := strings.Join(p.properties.Phony_deps, " ")
+			if len(p.phonyDepsModuleNames) > 0 {
+				depModulesStr := strings.Join(p.phonyDepsModuleNames, " ")
 				fmt.Fprintln(w, ".PHONY:", name)
 				fmt.Fprintln(w, name, ":", depModulesStr)
 			}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index f1579cc..d412ea1 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -285,7 +285,7 @@
 	if isCpp {
 		cflags = append(cflags, "-x c++")
 		// Add any C++ only flags.
-		cflags = append(cflags, esc(b.ClangProperties.Cppflags)...)
+		cflags = append(cflags, esc(b.ClangProperties.Cppflags.GetOrDefault(ctx, nil))...)
 	} else {
 		cflags = append(cflags, "-x c")
 	}
diff --git a/rust/config/darwin_host.go b/rust/config/darwin_host.go
index a4bc187..df8c6ac 100644
--- a/rust/config/darwin_host.go
+++ b/rust/config/darwin_host.go
@@ -15,6 +15,7 @@
 package config
 
 import (
+	"runtime"
 	"strings"
 
 	"android/soong/android"
@@ -35,13 +36,15 @@
 	registerToolchainFactory(android.Darwin, android.Arm64, darwinArm64ToolchainFactory)
 	registerToolchainFactory(android.Darwin, android.X86_64, darwinX8664ToolchainFactory)
 
-	pctx.StaticVariable("DarwinToolchainRustFlags", strings.Join(DarwinRustFlags, " "))
-	pctx.StaticVariable("DarwinToolchainLinkFlags", strings.Join(DarwinRustLinkFlags, " "))
+	if runtime.GOOS == "darwin" {
+		pctx.StaticVariable("DarwinToolchainRustFlags", strings.Join(DarwinRustFlags, " "))
+		pctx.StaticVariable("DarwinToolchainLinkFlags", strings.Join(DarwinRustLinkFlags, " "))
 
-	pctx.StaticVariable("DarwinToolchainArm64RustFlags", strings.Join(darwinArm64Rustflags, " "))
-	pctx.StaticVariable("DarwinToolchainArm64LinkFlags", strings.Join(darwinArm64Linkflags, " "))
-	pctx.StaticVariable("DarwinToolchainX8664RustFlags", strings.Join(darwinX8664Rustflags, " "))
-	pctx.StaticVariable("DarwinToolchainX8664LinkFlags", strings.Join(darwinX8664Linkflags, " "))
+		pctx.StaticVariable("DarwinToolchainArm64RustFlags", strings.Join(darwinArm64Rustflags, " "))
+		pctx.StaticVariable("DarwinToolchainArm64LinkFlags", strings.Join(darwinArm64Linkflags, " "))
+		pctx.StaticVariable("DarwinToolchainX8664RustFlags", strings.Join(darwinX8664Rustflags, " "))
+		pctx.StaticVariable("DarwinToolchainX8664LinkFlags", strings.Join(darwinX8664Linkflags, " "))
+	}
 
 }
 
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 91aa195..3d81b83 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -306,12 +306,6 @@
 }
 
 python_binary_host {
-    name: "buildinfo",
-    main: "buildinfo.py",
-    srcs: ["buildinfo.py"],
-}
-
-python_binary_host {
     name: "extra_install_zips_file_list",
     main: "extra_install_zips_file_list.py",
     srcs: ["extra_install_zips_file_list.py"],
diff --git a/scripts/buildinfo.py b/scripts/buildinfo.py
deleted file mode 100755
index 8a24b63..0000000
--- a/scripts/buildinfo.py
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-#
-"""A tool for generating buildinfo.prop"""
-
-import argparse
-import contextlib
-import json
-import os
-import subprocess
-
-TEST_KEY_DIR = "build/make/target/product/security"
-
-def get_build_variant(product_config):
-  if product_config["Eng"]:
-    return "eng"
-  elif product_config["Debuggable"]:
-    return "userdebug"
-  else:
-    return "user"
-
-def get_build_flavor(product_config):
-  build_flavor = product_config["DeviceProduct"] + "-" + get_build_variant(product_config)
-  if "address" in product_config.get("SanitizeDevice", []) and "_asan" not in build_flavor:
-    build_flavor += "_asan"
-  return build_flavor
-
-def get_build_keys(product_config):
-  default_cert = product_config.get("DefaultAppCertificate", "")
-  if default_cert == "" or default_cert == os.path.join(TEST_KEY_DIR, "testKey"):
-    return "test-keys"
-  return "dev-keys"
-
-def parse_args():
-  """Parse commandline arguments."""
-  parser = argparse.ArgumentParser()
-  parser.add_argument('--build-hostname-file', required=True, type=argparse.FileType('r')),
-  parser.add_argument('--build-number-file', required=True, type=argparse.FileType('r'))
-  parser.add_argument('--build-thumbprint-file', type=argparse.FileType('r'))
-  parser.add_argument('--build-username', required=True)
-  parser.add_argument('--date-file', required=True, type=argparse.FileType('r'))
-  parser.add_argument('--platform-preview-sdk-fingerprint-file',
-                      required=True,
-                      type=argparse.FileType('r'))
-  parser.add_argument('--product-config', required=True, type=argparse.FileType('r'))
-  parser.add_argument('--out', required=True, type=argparse.FileType('w'))
-
-  option = parser.parse_args()
-
-  product_config = json.load(option.product_config)
-  build_flags = product_config["BuildFlags"]
-
-  option.build_flavor = get_build_flavor(product_config)
-  option.build_keys = get_build_keys(product_config)
-  option.build_id = product_config["BuildId"]
-  option.build_type = product_config["BuildType"]
-  option.build_variant = get_build_variant(product_config)
-  option.build_version_tags = product_config["BuildVersionTags"]
-  option.cpu_abis = product_config["DeviceAbi"]
-  option.default_locale = None
-  if len(product_config.get("ProductLocales", [])) > 0:
-    option.default_locale = product_config["ProductLocales"][0]
-  option.default_wifi_channels = product_config.get("ProductDefaultWifiChannels", [])
-  option.device = product_config["DeviceName"]
-  option.display_build_number = product_config["DisplayBuildNumber"]
-  option.platform_base_os = product_config["Platform_base_os"]
-  option.platform_display_version = product_config["Platform_display_version_name"]
-  option.platform_min_supported_target_sdk_version = build_flags["RELEASE_PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION"]
-  option.platform_preview_sdk_version = product_config["Platform_preview_sdk_version"]
-  option.platform_sdk_version = product_config["Platform_sdk_version"]
-  option.platform_security_patch = product_config["Platform_security_patch"]
-  option.platform_version = product_config["Platform_version_name"]
-  option.platform_version_codename = product_config["Platform_sdk_codename"]
-  option.platform_version_all_codenames = product_config["Platform_version_active_codenames"]
-  option.platform_version_known_codenames = product_config["Platform_version_known_codenames"]
-  option.platform_version_last_stable = product_config["Platform_version_last_stable"]
-  option.product = product_config["DeviceProduct"]
-  option.use_vbmeta_digest_in_fingerprint = product_config["BoardUseVbmetaDigestInFingerprint"]
-
-  return option
-
-def main():
-  option = parse_args()
-
-  build_hostname = option.build_hostname_file.read().strip()
-  build_number = option.build_number_file.read().strip()
-  build_version_tags_list = option.build_version_tags
-  if option.build_type == "debug":
-    build_version_tags_list.append("debug")
-  build_version_tags_list.append(option.build_keys)
-  build_version_tags = ",".join(sorted(set(build_version_tags_list)))
-
-  raw_date = option.date_file.read().strip()
-  date = subprocess.check_output(["date", "-d", f"@{raw_date}"], text=True).strip()
-  date_utc = subprocess.check_output(["date", "-d", f"@{raw_date}", "+%s"], text=True).strip()
-
-  # build_desc is human readable strings that describe this build. This has the same info as the
-  # build fingerprint.
-  # e.g. "aosp_cf_x86_64_phone-userdebug VanillaIceCream MAIN eng.20240319.143939 test-keys"
-  build_desc = f"{option.product}-{option.build_variant} {option.platform_version} " \
-               f"{option.build_id} {build_number} {build_version_tags}"
-
-  platform_preview_sdk_fingerprint = option.platform_preview_sdk_fingerprint_file.read().strip()
-
-  with contextlib.redirect_stdout(option.out):
-    print("# begin build properties")
-    print("# autogenerated by buildinfo.py")
-
-    # The ro.build.id will be set dynamically by init, by appending the unique vbmeta digest.
-    if option.use_vbmeta_digest_in_fingerprint:
-      print(f"ro.build.legacy.id={option.build_id}")
-    else:
-      print(f"ro.build.id?={option.build_id}")
-
-    # ro.build.display.id is shown under Settings -> About Phone
-    if option.build_variant == "user":
-      # User builds should show:
-      # release build number or branch.buld_number non-release builds
-
-      # Dev. branches should have DISPLAY_BUILD_NUMBER set
-      if option.display_build_number:
-        print(f"ro.build.display.id?={option.build_id}.{build_number} {option.build_keys}")
-      else:
-        print(f"ro.build.display.id?={option.build_id} {option.build_keys}")
-    else:
-      # Non-user builds should show detailed build information (See build desc above)
-      print(f"ro.build.display.id?={build_desc}")
-    print(f"ro.build.version.incremental={build_number}")
-    print(f"ro.build.version.sdk={option.platform_sdk_version}")
-    print(f"ro.build.version.preview_sdk={option.platform_preview_sdk_version}")
-    print(f"ro.build.version.preview_sdk_fingerprint={platform_preview_sdk_fingerprint}")
-    print(f"ro.build.version.codename={option.platform_version_codename}")
-    print(f"ro.build.version.all_codenames={','.join(option.platform_version_all_codenames)}")
-    print(f"ro.build.version.known_codenames={option.platform_version_known_codenames}")
-    print(f"ro.build.version.release={option.platform_version_last_stable}")
-    print(f"ro.build.version.release_or_codename={option.platform_version}")
-    print(f"ro.build.version.release_or_preview_display={option.platform_display_version}")
-    print(f"ro.build.version.security_patch={option.platform_security_patch}")
-    print(f"ro.build.version.base_os={option.platform_base_os}")
-    print(f"ro.build.version.min_supported_target_sdk={option.platform_min_supported_target_sdk_version}")
-    print(f"ro.build.date={date}")
-    print(f"ro.build.date.utc={date_utc}")
-    print(f"ro.build.type={option.build_variant}")
-    print(f"ro.build.user={option.build_username}")
-    print(f"ro.build.host={build_hostname}")
-    # TODO: Remove any tag-related optional property declarations once the goals
-    # from go/arc-android-sigprop-changes have been achieved.
-    print(f"ro.build.tags?={build_version_tags}")
-    # ro.build.flavor are used only by the test harness to distinguish builds.
-    # Only add _asan for a sanitized build if it isn't already a part of the
-    # flavor (via a dedicated lunch config for example).
-    print(f"ro.build.flavor={option.build_flavor}")
-
-    # These values are deprecated, use "ro.product.cpu.abilist"
-    # instead (see below).
-    print(f"# ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete,")
-    print(f"# use ro.product.cpu.abilist instead.")
-    print(f"ro.product.cpu.abi={option.cpu_abis[0]}")
-    if len(option.cpu_abis) > 1:
-      print(f"ro.product.cpu.abi2={option.cpu_abis[1]}")
-
-    if option.default_locale:
-      print(f"ro.product.locale={option.default_locale}")
-    print(f"ro.wifi.channels={' '.join(option.default_wifi_channels)}")
-
-    print(f"# ro.build.product is obsolete; use ro.product.device")
-    print(f"ro.build.product={option.device}")
-
-    print(f"# Do not try to parse description or thumbprint")
-    print(f"ro.build.description?={build_desc}")
-    if option.build_thumbprint_file:
-      build_thumbprint = option.build_thumbprint_file.read().strip()
-      print(f"ro.build.thumbprint={build_thumbprint}")
-
-    print(f"# end build properties")
-
-if __name__ == "__main__":
-  main()
diff --git a/scripts/check_prebuilt_presigned_apk.py b/scripts/check_prebuilt_presigned_apk.py
index abedfb7..abab2e1 100755
--- a/scripts/check_prebuilt_presigned_apk.py
+++ b/scripts/check_prebuilt_presigned_apk.py
@@ -37,7 +37,7 @@
                     sys.exit(args.apk + ': Contains compressed JNI libraries')
                 return True
             # It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides
-            if args.privileged:
+            if args.privileged and args.uncompress_priv_app_dex:
                 if info.filename.endswith('.dex') and info.compress_type != zipfile.ZIP_STORED:
                     if fail:
                         sys.exit(args.apk + ': Contains compressed dex files and is privileged')
@@ -52,6 +52,7 @@
     parser.add_argument('--skip-preprocessed-apk-checks', action = 'store_true', help = "the value of the soong property with the same name")
     parser.add_argument('--preprocessed', action = 'store_true', help = "the value of the soong property with the same name")
     parser.add_argument('--privileged', action = 'store_true', help = "the value of the soong property with the same name")
+    parser.add_argument('--uncompress-priv-app-dex', action = 'store_true', help = "the value of the product variable with the same name")
     parser.add_argument('apk', help = "the apk to check")
     parser.add_argument('stampfile', help = "a file to touch if successful")
     args = parser.parse_args()
diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py
index 9ea56cb..2bd246d 100644
--- a/scripts/gen_build_prop.py
+++ b/scripts/gen_build_prop.py
@@ -129,16 +129,16 @@
     print(f"ro.product.{partition}.name={config['DeviceProduct']}")
 
   if partition != "system":
-    if config["ModelForAttestation"]:
-        print(f"ro.product.model_for_attestation={config['ModelForAttestation']}")
-    if config["BrandForAttestation"]:
-        print(f"ro.product.brand_for_attestation={config['BrandForAttestation']}")
-    if config["NameForAttestation"]:
-        print(f"ro.product.name_for_attestation={config['NameForAttestation']}")
-    if config["DeviceForAttestation"]:
-        print(f"ro.product.device_for_attestation={config['DeviceForAttestation']}")
-    if config["ManufacturerForAttestation"]:
-        print(f"ro.product.manufacturer_for_attestation={config['ManufacturerForAttestation']}")
+    if config["ProductModelForAttestation"]:
+        print(f"ro.product.model_for_attestation={config['ProductModelForAttestation']}")
+    if config["ProductBrandForAttestation"]:
+        print(f"ro.product.brand_for_attestation={config['ProductBrandForAttestation']}")
+    if config["ProductNameForAttestation"]:
+        print(f"ro.product.name_for_attestation={config['ProductNameForAttestation']}")
+    if config["ProductDeviceForAttestation"]:
+        print(f"ro.product.device_for_attestation={config['ProductDeviceForAttestation']}")
+    if config["ProductManufacturerForAttestation"]:
+        print(f"ro.product.manufacturer_for_attestation={config['ProductManufacturerForAttestation']}")
 
   if config["ZygoteForce64"]:
     if partition == "vendor":
@@ -237,7 +237,7 @@
 
   print(f"# Do not try to parse description or thumbprint")
   print(f"ro.build.description?={config['BuildDesc']}")
-  if "build_thumbprint" in config:
+  if "BuildThumbprint" in config:
     print(f"ro.build.thumbprint={config['BuildThumbprint']}")
 
   print(f"# end build properties")
@@ -279,7 +279,7 @@
   config = args.config
 
   # Add the product-defined properties to the build properties.
-  if config["PropertySplitEnabled"] or config["VendorImageFileSystemType"]:
+  if not config["PropertySplitEnabled"] or not config["VendorImageFileSystemType"]:
     if "PRODUCT_PROPERTY_OVERRIDES" in config:
       props += config["PRODUCT_PROPERTY_OVERRIDES"]
 
@@ -311,6 +311,7 @@
   props.append("ro.postinstall.fstab.prefix=/system")
 
   enable_target_debugging = True
+  enable_dalvik_lock_contention_logging = True
   if config["BuildVariant"] == "user" or config["BuildVariant"] == "userdebug":
     # Target is secure in user builds.
     props.append("ro.secure=1")
@@ -320,6 +321,12 @@
       # Disable debugging in plain user builds.
       props.append("ro.adb.secure=1")
       enable_target_debugging = False
+      enable_dalvik_lock_contention_logging = False
+    else:
+      # Disable debugging in userdebug builds if PRODUCT_NOT_DEBUGGABLE_IN_USERDEBUG
+      # is set.
+      if config["ProductNotDebuggableInUserdebug"]:
+        enable_target_debugging = False
 
     # Disallow mock locations by default for user builds
     props.append("ro.allow.mock.location=0")
@@ -331,10 +338,11 @@
     # Allow mock locations by default for non user builds
     props.append("ro.allow.mock.location=1")
 
-  if enable_target_debugging:
+  if enable_dalvik_lock_contention_logging:
     # Enable Dalvik lock contention logging.
     props.append("dalvik.vm.lockprof.threshold=500")
 
+  if enable_target_debugging:
     # Target is more debuggable and adbd is on by default
     props.append("ro.debuggable=1")
   else:
@@ -416,7 +424,7 @@
   # This must not be defined for the non-GRF devices.
   # The values of the GRF properties will be verified by post_process_props.py
   if config["BoardShippingApiLevel"]:
-    props.append(f"ro.board.first_api_level={config['ProductShippingApiLevel']}")
+    props.append(f"ro.board.first_api_level={config['BoardShippingApiLevel']}")
 
   # Build system set BOARD_API_LEVEL to show the api level of the vendor API surface.
   # This must not be altered outside of build system.
@@ -475,6 +483,9 @@
   if config["NoBionicPageSizeMacro"]:
     props.append(f"ro.product.build.no_bionic_page_size_macro=true")
 
+  # This is a temporary system property that controls the ART module. The plan is
+  # to remove it by Aug 2025, at which time Mainline updates of the ART module
+  # will ignore it as well.
   # If the value is "default", it will be mangled by post_process_props.py.
   props.append(f"ro.dalvik.vm.enable_uffd_gc={config['EnableUffdGc']}")
 
@@ -500,6 +511,15 @@
 
   build_prop(args, gen_build_info=True, gen_common_build_props=True, variables=variables)
 
+def build_system_ext_prop(args):
+  config = args.config
+
+  # Order matters here. When there are duplicates, the last one wins.
+  # TODO(b/117892318): don't allow duplicates so that the ordering doesn't matter
+  variables = ["PRODUCT_SYSTEM_EXT_PROPERTIES"]
+
+  build_prop(args, gen_build_info=False, gen_common_build_props=True, variables=variables)
+
 '''
 def build_vendor_prop(args):
   config = args.config
@@ -552,6 +572,8 @@
   with contextlib.redirect_stdout(args.out):
     if args.partition == "system":
       build_system_prop(args)
+    elif args.partition == "system_ext":
+      build_system_ext_prop(args)
       '''
     elif args.partition == "vendor":
       build_vendor_prop(args)
diff --git a/tests/run_tool_with_logging_test.py b/tests/run_tool_with_logging_test.py
index 57a6d62..1a946a1 100644
--- a/tests/run_tool_with_logging_test.py
+++ b/tests/run_tool_with_logging_test.py
@@ -193,7 +193,7 @@
     logger_path = self._import_executable("tool_event_logger")
 
     self._run_script_and_wait(f"""
-      TMPDIR="{self.working_dir.name}"
+      export TMPDIR="{self.working_dir.name}"
       export ANDROID_TOOL_LOGGER="{logger_path}"
       export ANDROID_TOOL_LOGGER_EXTRA_ARGS="--dry_run"
       {self.logging_script_path} "FAKE_TOOL" {test_tool.executable} arg1 arg2
@@ -206,7 +206,7 @@
     logger_path = self._import_executable("tool_event_logger")
 
     self._run_script_and_wait(f"""
-      TMPDIR="{self.working_dir.name}"
+      export TMPDIR="{self.working_dir.name}"
       export ANDROID_TOOL_LOGGER="{logger_path}"
       export ANDROID_TOOL_LOGGER_EXTRA_ARGS="--dry_run"
       {self.logging_script_path} "FAKE_TOOL" {test_tool.executable} --tool-arg1
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 8dc1630..0471853 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -70,13 +70,14 @@
   # m droid, build sbom later in case additional dependencies might be built and included in partition images.
   run_soong "${out_dir}" "droid dump.erofs lz4"
 
+  soong_sbom_out=$out_dir/soong/sbom/$target_product
   product_out=$out_dir/target/product/vsoc_x86_64
   sbom_test=$product_out/sbom_test
   mkdir -p $sbom_test
   cp $product_out/*.img $sbom_test
 
   # m sbom
-  run_soong "${out_dir}" sbom
+  run_soong "${out_dir}" "sbom"
 
   # Generate installed file list from .img files in PRODUCT_OUT
   dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
@@ -117,7 +118,7 @@
   for f in $EROFS_IMAGES; do
     partition_name=$(basename $f | cut -d. -f1)
     file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
-    files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+    files_in_soong_spdx_file="${sbom_test}/soong-sbom-${partition_name}-files-in-spdx.txt"
     rm "$file_list_file" > /dev/null 2>&1 || true
     all_dirs="/"
     while [ ! -z "$all_dirs" ]; do
@@ -145,22 +146,23 @@
     done
     sort -n -o "$file_list_file" "$file_list_file"
 
-    grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' > "$files_in_spdx_file"
+    # Diff the file list from image and file list in SBOM created by Soong
+    grep "FileName: /${partition_name}/" $soong_sbom_out/sbom.spdx | sed 's/^FileName: //' > "$files_in_soong_spdx_file"
     if [ "$partition_name" = "system" ]; then
       # system partition is mounted to /, so include FileName starts with /root/ too.
-      grep "FileName: /root/" $product_out/sbom.spdx | sed 's/^FileName: \/root//' >> "$files_in_spdx_file"
+      grep "FileName: /root/" $soong_sbom_out/sbom.spdx | sed 's/^FileName: \/root//' >> "$files_in_soong_spdx_file"
     fi
-    sort -n -o "$files_in_spdx_file" "$files_in_spdx_file"
+    sort -n -o "$files_in_soong_spdx_file" "$files_in_soong_spdx_file"
 
-    echo ============ Diffing files in $f and SBOM
-    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
+    echo ============ Diffing files in $f and SBOM created by Soong
+    diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" ""
   done
 
   RAMDISK_IMAGES="$product_out/ramdisk.img"
   for f in $RAMDISK_IMAGES; do
     partition_name=$(basename $f | cut -d. -f1)
     file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
-    files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+    files_in_soong_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-soong-spdx.txt"
     # lz4 decompress $f to stdout
     # cpio list all entries like ls -l
     # grep filter normal files and symlinks
@@ -168,13 +170,15 @@
     # sed remove partition name from entry names
     $lz4 -c -d $f | cpio -tv 2>/dev/null | grep '^[-l]' | awk -F ' ' '{print $9}' | sed "s:^:/$partition_name/:" | sort -n > "$file_list_file"
 
-    grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"
+    grep "FileName: /${partition_name}/" $soong_sbom_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_soong_spdx_file"
 
-    echo ============ Diffing files in $f and SBOM
-    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
+    echo ============ Diffing files in $f and SBOM created by Soong
+    diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" ""
   done
 
-  verify_package_verification_code "$product_out/sbom.spdx"
+  verify_package_verification_code "$soong_sbom_out/sbom.spdx"
+
+  verify_packages_licenses "$soong_sbom_out/sbom.spdx"
 
   # Teardown
   cleanup "${out_dir}"
@@ -213,6 +217,41 @@
   fi
 }
 
+function verify_packages_licenses {
+  local sbom_file="$1"; shift
+
+  num_of_packages=$(grep 'PackageName:' $sbom_file | wc -l)
+  num_of_declared_licenses=$(grep 'PackageLicenseDeclared:' $sbom_file | wc -l)
+  if [ "$num_of_packages" = "$num_of_declared_licenses" ]
+  then
+    echo "Number of packages with declared license is correct."
+  else
+    echo "Number of packages with declared license is WRONG."
+    exit 1
+  fi
+
+  # PRODUCT and 7 prebuilt packages have "PackageLicenseDeclared: NOASSERTION"
+  # All other packages have declared licenses
+  num_of_packages_with_noassertion_license=$(grep 'PackageLicenseDeclared: NOASSERTION' $sbom_file | wc -l)
+  if [ $num_of_packages_with_noassertion_license = 15 ]
+  then
+    echo "Number of packages with NOASSERTION license is correct."
+  else
+    echo "Number of packages with NOASSERTION license is WRONG."
+    exit 1
+  fi
+
+  num_of_files=$(grep 'FileName:' $sbom_file | wc -l)
+  num_of_concluded_licenses=$(grep 'LicenseConcluded:' $sbom_file | wc -l)
+  if [ "$num_of_files" = "$num_of_concluded_licenses" ]
+  then
+    echo "Number of files with concluded license is correct."
+  else
+    echo "Number of files with concluded license is WRONG."
+    exit 1
+  fi
+}
+
 function test_sbom_unbundled_apex {
   # Setup
   out_dir="$(setup)"
@@ -274,7 +313,7 @@
 
 target_product=aosp_cf_x86_64_phone
 target_release=trunk_staging
-target_build_variant=userdebug
+target_build_variant=eng
 for i in "$@"; do
   case $i in
     TARGET_PRODUCT=*)
diff --git a/ui/build/build.go b/ui/build/build.go
index c7319ed..49ac791 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -211,9 +211,38 @@
 	}
 }
 
+func abfsBuildStarted(ctx Context, config Config) {
+	abfsBox := config.PrebuiltBuildTool("abfsbox")
+	cmdArgs := []string{"build-started", "--"}
+	cmdArgs = append(cmdArgs, config.Arguments()...)
+	cmd := Command(ctx, config, "abfsbox", abfsBox, cmdArgs...)
+	cmd.Sandbox = noSandbox
+	cmd.RunAndPrintOrFatal()
+}
+
+func abfsBuildFinished(ctx Context, config Config, finished bool) {
+	var errMsg string
+	if !finished {
+		errMsg = "build was interrupted"
+	}
+	abfsBox := config.PrebuiltBuildTool("abfsbox")
+	cmdArgs := []string{"build-finished", "-e", errMsg, "--"}
+	cmdArgs = append(cmdArgs, config.Arguments()...)
+	cmd := Command(ctx, config, "abfsbox", abfsBox, cmdArgs...)
+	cmd.RunAndPrintOrFatal()
+}
+
 // Build the tree. Various flags in `config` govern which components of
 // the build to run.
 func Build(ctx Context, config Config) {
+	done := false
+	if config.UseABFS() {
+		abfsBuildStarted(ctx, config)
+		defer func() {
+			abfsBuildFinished(ctx, config, done)
+		}()
+	}
+
 	ctx.Verboseln("Starting build with args:", config.Arguments())
 	ctx.Verboseln("Environment:", config.Environment().Environ())
 
@@ -351,6 +380,7 @@
 	if what&RunDistActions != 0 {
 		runDistActions(ctx, config)
 	}
+	done = true
 }
 
 func updateBuildIdDir(ctx Context, config Config) {
diff --git a/ui/build/config.go b/ui/build/config.go
index 2470f84..b8fcb6b 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -1270,9 +1270,25 @@
 	if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
 		return false
 	}
+	if c.UseABFS() {
+		return false
+	}
 	return true
 }
 
+func (c *configImpl) UseABFS() bool {
+	if v, ok := c.environ.Get("NO_ABFS"); ok {
+		v = strings.ToLower(strings.TrimSpace(v))
+		if v == "true" || v == "1" {
+			return false
+		}
+	}
+
+	abfsBox := c.PrebuiltBuildTool("abfsbox")
+	err := exec.Command(abfsBox, "hash", srcDirFileCheck).Run()
+	return err == nil
+}
+
 func (c *configImpl) UseRBE() bool {
 	// These alternate modes of running Soong do not use RBE / reclient.
 	if c.Queryview() || c.JsonModuleGraph() {
@@ -1325,8 +1341,7 @@
 }
 
 func (c *configImpl) rbeTmpDir() string {
-	buildTmpDir := shared.TempDirForOutDir(c.SoongOutDir())
-	return filepath.Join(buildTmpDir, "rbe")
+	return filepath.Join(c.SoongOutDir(), "rbe")
 }
 
 func (c *configImpl) rbeCacheDir() string {
@@ -1585,6 +1600,23 @@
 	}
 }
 
+func (c *configImpl) KatiBin() string {
+	binName := "ckati"
+	if c.UseABFS() {
+		binName = "ckati-wrap"
+	}
+
+	return c.PrebuiltBuildTool(binName)
+}
+
+func (c *configImpl) NinjaBin() string {
+	binName := "ninja"
+	if c.UseABFS() {
+		binName = "ninjago"
+	}
+	return c.PrebuiltBuildTool(binName)
+}
+
 func (c *configImpl) PrebuiltBuildTool(name string) string {
 	if v, ok := c.environ.Get("SANITIZE_HOST"); ok {
 		if sanitize := strings.Fields(v); inList("address", sanitize) {
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index b1222fe..b42edb0 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -22,6 +22,7 @@
 	"os"
 	"path/filepath"
 	"reflect"
+	"runtime"
 	"strings"
 	"testing"
 
@@ -1043,12 +1044,13 @@
 			},
 		},
 		{
+			// RBE is only supported on linux.
 			name:    "use rbe",
 			environ: Environment{"USE_RBE=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
 				ForceUseGoma:          proto.Bool(false),
 				UseGoma:               proto.Bool(false),
-				UseRbe:                proto.Bool(true),
+				UseRbe:                proto.Bool(runtime.GOOS == "linux"),
 				NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index e77df44..5df3a95 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -93,7 +93,7 @@
 	defer tool.Finish()
 
 	cmd := Command(ctx, config, "dumpvars",
-		config.PrebuiltBuildTool("ckati"),
+		config.KatiBin(),
 		"-f", "build/make/core/config.mk",
 		"--color_warnings",
 		"--kati_stats",
diff --git a/ui/build/kati.go b/ui/build/kati.go
index d599c99..a0efd2c 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -84,7 +84,7 @@
 // arguments, and a custom function closure to mutate the environment Kati runs
 // in.
 func runKati(ctx Context, config Config, extraSuffix string, args []string, envFunc func(*Environment)) {
-	executable := config.PrebuiltBuildTool("ckati")
+	executable := config.KatiBin()
 	// cKati arguments.
 	args = append([]string{
 		// Instead of executing commands directly, generate a Ninja file.
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 1935e72..b5e74b4 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -49,7 +49,7 @@
 	nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
 	defer nr.Close()
 
-	executable := config.PrebuiltBuildTool("ninja")
+	executable := config.NinjaBin()
 	args := []string{
 		"-d", "keepdepfile",
 		"-d", "keeprsp",
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 8fa147f..0a0f956 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -65,7 +65,7 @@
 		"RBE_platform":         "container-image=" + remoteexec.DefaultImage,
 	}
 	if config.StartRBE() {
-		name, err := config.rbeSockAddr(absPath(ctx, config.TempDir()))
+		name, err := config.rbeSockAddr(absPath(ctx, config.rbeTmpDir()))
 		if err != nil {
 			ctx.Fatalf("Error retrieving socket address: %v", err)
 			return nil
diff --git a/ui/build/rbe_test.go b/ui/build/rbe_test.go
index 266f76b..d1b8e26 100644
--- a/ui/build/rbe_test.go
+++ b/ui/build/rbe_test.go
@@ -19,6 +19,7 @@
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"testing"
 
@@ -26,6 +27,10 @@
 )
 
 func TestDumpRBEMetrics(t *testing.T) {
+	// RBE is only supported on linux.
+	if runtime.GOOS != "linux" {
+		t.Skip("RBE is only supported on linux")
+	}
 	ctx := testContext()
 	tests := []struct {
 		description string
@@ -82,6 +87,10 @@
 }
 
 func TestDumpRBEMetricsErrors(t *testing.T) {
+	// RBE is only supported on linux.
+	if runtime.GOOS != "linux" {
+		t.Skip("RBE is only supported on linux")
+	}
 	ctx := testContext()
 	tests := []struct {
 		description      string
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index edb3b66..c38174c 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -48,7 +48,11 @@
 	}
 )
 
-const nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
+const (
+	nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
+	abfsSrcDir = "/src"
+	abfsOutDir = "/src/out"
+)
 
 var sandboxConfig struct {
 	once sync.Once
@@ -145,6 +149,22 @@
 	return sandboxConfig.working
 }
 
+func (c *Cmd) srcDirArg() string {
+	if !c.config.UseABFS() {
+		return sandboxConfig.srcDir
+	}
+
+	return sandboxConfig.srcDir + ":" + abfsSrcDir
+}
+
+func (c *Cmd) outDirArg() string {
+	if !c.config.UseABFS() {
+		return sandboxConfig.outDir
+	}
+
+	return sandboxConfig.outDir + ":" + abfsOutDir
+}
+
 func (c *Cmd) wrapSandbox() {
 	wd, _ := os.Getwd()
 
@@ -188,10 +208,10 @@
 		"-B", "/tmp",
 
 		// Mount source
-		c.config.sandboxConfig.SrcDirMountFlag(), sandboxConfig.srcDir,
+		c.config.sandboxConfig.SrcDirMountFlag(), c.srcDirArg(),
 
 		//Mount out dir as read-write
-		"-B", sandboxConfig.outDir,
+		"-B", c.outDirArg(),
 
 		// Disable newcgroup for now, since it may require newer kernels
 		// TODO: try out cgroups
@@ -200,6 +220,9 @@
 		// Only log important warnings / errors
 		"-q",
 	}
+	if c.config.UseABFS() {
+		sandboxArgs = append(sandboxArgs, "-B", "{ABFS_DIR}")
+	}
 
 	// Mount srcDir RW allowlists as Read-Write
 	if len(c.config.sandboxConfig.SrcDirRWAllowlist()) > 0 && !c.config.sandboxConfig.SrcDirIsRO() {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index e18cc25..2ccdfec 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -661,7 +661,7 @@
 		}
 
 		ninjaArgs = append(ninjaArgs, targets...)
-		ninjaCmd := config.PrebuiltBuildTool("ninja")
+		ninjaCmd := config.NinjaBin()
 		if config.useN2 {
 			ninjaCmd = config.PrebuiltBuildTool("n2")
 		}
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 687ad6f..3faa94d 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -15,14 +15,16 @@
 package build
 
 import (
-	"android/soong/ui/metrics"
-	"android/soong/ui/status"
 	"bufio"
 	"fmt"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"sort"
 	"strings"
+
+	"android/soong/ui/metrics"
+	"android/soong/ui/status"
 )
 
 // Checks for files in the out directory that have a rule that depends on them but no rule to
@@ -84,6 +86,10 @@
 	// before running soong and ninja.
 	releaseConfigDir := filepath.Join(outDir, "soong", "release-config")
 
+	// out/target/product/<xxxxx>/build_fingerprint.txt is a source file created in sysprop.mk
+	// ^out/target/product/[^/]+/build_fingerprint.txt$
+	buildFingerPrintFilePattern := regexp.MustCompile("^" + filepath.Join(outDir, "target", "product") + "/[^/]+/build_fingerprint.txt$")
+
 	danglingRules := make(map[string]bool)
 
 	scanner := bufio.NewScanner(stdout)
@@ -100,7 +106,8 @@
 			line == dexpreoptConfigFilePath ||
 			line == buildDatetimeFilePath ||
 			line == bpglob ||
-			strings.HasPrefix(line, releaseConfigDir) {
+			strings.HasPrefix(line, releaseConfigDir) ||
+			buildFingerPrintFilePattern.MatchString(line) {
 			// Leaf node is in one of Soong's bootstrap directories, which do not have
 			// full build rules in the primary build.ninja file.
 			continue