Merge "Create an empty system_ext partition for aosp_cf_*" into main
diff --git a/android/Android.bp b/android/Android.bp
index eb8c64d..44cddcc 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -89,7 +89,6 @@
         "prebuilt.go",
         "prebuilt_build_tool.go",
         "product_config.go",
-        "product_config_to_bp.go",
         "proto.go",
         "provider.go",
         "raw_files.go",
diff --git a/android/defaults.go b/android/defaults.go
index 8fe2879..510ebe0 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -273,8 +273,8 @@
 }
 
 func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
-	ctx.BottomUp("defaults", defaultsMutator).Parallel().UsesCreateModule()
+	ctx.BottomUp("defaults_deps", defaultsDepsMutator)
+	ctx.BottomUp("defaults", defaultsMutator).UsesCreateModule()
 }
 
 func defaultsDepsMutator(ctx BottomUpMutatorContext) {
diff --git a/android/licenses.go b/android/licenses.go
index be1eede..949d678 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -106,19 +106,19 @@
 //
 // This goes before defaults expansion so the defaults can pick up the package default.
 func RegisterLicensesPackageMapper(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("licensesPackageMapper", licensesPackageMapper).Parallel()
+	ctx.BottomUp("licensesPackageMapper", licensesPackageMapper)
 }
 
 // Registers the function that gathers the license dependencies for each module.
 //
 // This goes after defaults expansion so that it can pick up default licenses and before visibility enforcement.
 func RegisterLicensesPropertyGatherer(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer).Parallel()
+	ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer)
 }
 
 // Registers the function that verifies the licenses and license_kinds dependency types for each module.
 func RegisterLicensesDependencyChecker(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker).Parallel()
+	ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker)
 }
 
 // Maps each package to its default applicable licenses.
diff --git a/android/mutator.go b/android/mutator.go
index 0da3ec7..6bd2e60 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -211,10 +211,7 @@
 	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
 	// dependency (some entries may be nil).
 	//
-	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
-	// new dependencies have had the current mutator called on them.  If the mutator is not
-	// parallel this method does not affect the ordering of the current mutator pass, but will
-	// be ordered correctly for all future mutator passes.
+	// This method will pause until the new dependencies have had the current mutator called on them.
 	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
 
 	// AddReverseDependency adds a dependency from the destination to the given module.
@@ -230,10 +227,7 @@
 	// each dependency (some entries may be nil).  A variant of the dependency must exist that matches
 	// all the non-local variations of the current module, plus the variations argument.
 	//
-	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
-	// new dependencies have had the current mutator called on them.  If the mutator is not
-	// parallel this method does not affect the ordering of the current mutator pass, but will
-	// be ordered correctly for all future mutator passes.
+	// This method will pause until the new dependencies have had the current mutator called on them.
 	AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) []blueprint.Module
 
 	// AddReverseVariationDependency adds a dependency from the named module to the current
@@ -256,10 +250,7 @@
 	// Unlike AddVariationDependencies, the variations of the current module are ignored - the
 	// dependency only needs to match the supplied variations.
 	//
-	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
-	// new dependencies have had the current mutator called on them.  If the mutator is not
-	// parallel this method does not affect the ordering of the current mutator pass, but will
-	// be ordered correctly for all future mutator passes.
+	// This method will pause until the new dependencies have had the current mutator called on them.
 	AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []blueprint.Module
 
 	// ReplaceDependencies finds all the variants of the module with the specified name, then
@@ -628,9 +619,6 @@
 	}
 
 	// Forward booleans set on the MutatorHandle to the blueprint.MutatorHandle.
-	if mutator.parallel {
-		handle.Parallel()
-	}
 	if mutator.usesRename {
 		handle.UsesRename()
 	}
@@ -655,6 +643,7 @@
 	// Parallel sets the mutator to visit modules in parallel while maintaining ordering.  Calling any
 	// method on the mutator context is thread-safe, but the mutator must handle synchronization
 	// for any modifications to global state or any modules outside the one it was invoked on.
+	// Deprecated: all Mutators are parallel by default.
 	Parallel() MutatorHandle
 
 	// UsesRename marks the mutator as using the BottomUpMutatorContext.Rename method, which prevents
@@ -683,7 +672,6 @@
 }
 
 func (mutator *mutator) Parallel() MutatorHandle {
-	mutator.parallel = true
 	return mutator
 }
 
@@ -718,7 +706,7 @@
 }
 
 func RegisterComponentsMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("component-deps", componentDepsMutator).Parallel()
+	ctx.BottomUp("component-deps", componentDepsMutator)
 }
 
 // A special mutator that runs just prior to the deps mutator to allow the dependencies
@@ -736,7 +724,7 @@
 }
 
 func registerDepsMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("deps", depsMutator).Parallel().UsesReverseDependencies()
+	ctx.BottomUp("deps", depsMutator).UsesReverseDependencies()
 }
 
 // android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that
diff --git a/android/mutator_test.go b/android/mutator_test.go
index 33fca9e..1d5f890 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -17,6 +17,8 @@
 import (
 	"fmt"
 	"strings"
+	"sync"
+	"sync/atomic"
 	"testing"
 
 	"github.com/google/blueprint"
@@ -220,7 +222,7 @@
 		}
 	`
 
-	finalGot := map[string]int{}
+	finalGot := sync.Map{}
 
 	GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -251,9 +253,11 @@
 					}
 				})
 				ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
-					finalGot[ctx.Module().String()] += 1
+					counter, _ := finalGot.LoadOrStore(ctx.Module().String(), &atomic.Int64{})
+					counter.(*atomic.Int64).Add(1)
 					ctx.VisitDirectDeps(func(mod Module) {
-						finalGot[fmt.Sprintf("%s -> %s", ctx.Module().String(), mod)] += 1
+						counter, _ := finalGot.LoadOrStore(fmt.Sprintf("%s -> %s", ctx.Module().String(), mod), &atomic.Int64{})
+						counter.(*atomic.Int64).Add(1)
 					})
 				})
 			})
@@ -276,7 +280,13 @@
 		"foo{variant:b} -> common_dep_2{variant:a}": 1,
 	}
 
-	AssertDeepEquals(t, "final", finalWant, finalGot)
+	finalGotMap := make(map[string]int)
+	finalGot.Range(func(k, v any) bool {
+		finalGotMap[k.(string)] = int(v.(*atomic.Int64).Load())
+		return true
+	})
+
+	AssertDeepEquals(t, "final", finalWant, finalGotMap)
 }
 
 func TestTransitionMutatorInFinalDeps(t *testing.T) {
diff --git a/android/namespace.go b/android/namespace.go
index 866d125..8b3ebc4 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -457,7 +457,7 @@
 }
 
 func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("namespace_deps", namespaceMutator).Parallel().MutatesGlobalState()
+	ctx.BottomUp("namespace_deps", namespaceMutator).MutatesGlobalState()
 }
 
 func namespaceMutator(ctx BottomUpMutatorContext) {
diff --git a/android/neverallow.go b/android/neverallow.go
index e135f57..e93763b 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -44,7 +44,7 @@
 // - it has none of the "Without" properties matched (same rules as above)
 
 func registerNeverallowMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("neverallow", neverallowMutator).Parallel()
+	ctx.BottomUp("neverallow", neverallowMutator)
 }
 
 var neverallows = []Rule{}
diff --git a/android/override_module.go b/android/override_module.go
index d844da6..50ddc9b 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -234,18 +234,18 @@
 // Mutators for override/overridable modules. All the fun happens in these functions. It is critical
 // to keep them in this order and not put any order mutators between them.
 func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel().MutatesDependencies() // modifies deps via addOverride
+	ctx.BottomUp("override_deps", overrideModuleDepsMutator).MutatesDependencies() // modifies deps via addOverride
 	ctx.Transition("override", &overrideTransitionMutator{})
-	ctx.BottomUp("override_apply", overrideApplyMutator).Parallel().MutatesDependencies()
+	ctx.BottomUp("override_apply", overrideApplyMutator).MutatesDependencies()
 	// overridableModuleDepsMutator calls OverridablePropertiesDepsMutator so that overridable modules can
 	// add deps from overridable properties.
-	ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel()
+	ctx.BottomUp("overridable_deps", overridableModuleDepsMutator)
 	// Because overridableModuleDepsMutator is run after PrebuiltPostDepsMutator,
 	// prebuilt's ReplaceDependencies doesn't affect to those deps added by overridable properties.
 	// By running PrebuiltPostDepsMutator again after overridableModuleDepsMutator, deps via overridable properties
 	// can be replaced with prebuilts.
-	ctx.BottomUp("replace_deps_on_prebuilts_for_overridable_deps_again", PrebuiltPostDepsMutator).Parallel().UsesReplaceDependencies()
-	ctx.BottomUp("replace_deps_on_override", replaceDepsOnOverridingModuleMutator).Parallel().UsesReplaceDependencies()
+	ctx.BottomUp("replace_deps_on_prebuilts_for_overridable_deps_again", PrebuiltPostDepsMutator).UsesReplaceDependencies()
+	ctx.BottomUp("replace_deps_on_override", replaceDepsOnOverridingModuleMutator).UsesReplaceDependencies()
 }
 
 type overrideBaseDependencyTag struct {
diff --git a/android/path_properties.go b/android/path_properties.go
index 6210aee..d80a8ed 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -27,7 +27,7 @@
 // to the output file of the referenced module.
 
 func registerPathDepsMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("pathdeps", pathDepsMutator).Parallel()
+	ctx.BottomUp("pathdeps", pathDepsMutator)
 }
 
 // The pathDepsMutator automatically adds dependencies on any module that is listed with the
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 0b0c517..19f12f0 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -400,13 +400,13 @@
 }
 
 func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel().UsesRename()
+	ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).UsesRename()
 }
 
 func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel().UsesReverseDependencies()
-	ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
-	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel().UsesReplaceDependencies()
+	ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).UsesReverseDependencies()
+	ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator)
+	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).UsesReplaceDependencies()
 }
 
 // Returns the name of the source module corresponding to a prebuilt module
diff --git a/android/product_config_to_bp.go b/android/product_config_to_bp.go
deleted file mode 100644
index 680328f..0000000
--- a/android/product_config_to_bp.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2024 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-func init() {
-	ctx := InitRegistrationContext
-	ctx.RegisterParallelSingletonType("product_config_to_bp_singleton", productConfigToBpSingletonFactory)
-}
-
-type productConfigToBpSingleton struct{}
-
-func (s *productConfigToBpSingleton) GenerateBuildActions(ctx SingletonContext) {
-	// TODO: update content from make-based product config
-	var content string
-	generatedBp := PathForOutput(ctx, "soong_generated_product_config.bp")
-	WriteFileRule(ctx, generatedBp, content)
-	ctx.Phony("product_config_to_bp", generatedBp)
-}
-
-// productConfigToBpSingleton generates a bp file from make-based product config
-func productConfigToBpSingletonFactory() Singleton {
-	return &productConfigToBpSingleton{}
-}
diff --git a/android/register.go b/android/register.go
index 94d875d..bb1ead7 100644
--- a/android/register.go
+++ b/android/register.go
@@ -92,7 +92,6 @@
 	topDownMutator    blueprint.TopDownMutator
 	transitionMutator blueprint.TransitionMutator
 
-	parallel                bool
 	usesRename              bool
 	usesReverseDependencies bool
 	usesReplaceDependencies bool
diff --git a/android/variable.go b/android/variable.go
index 4210f67..73c0d0e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -29,7 +29,7 @@
 
 func registerVariableBuildComponents(ctx RegistrationContext) {
 	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
-		ctx.BottomUp("variable", VariableMutator).Parallel()
+		ctx.BottomUp("variable", VariableMutator)
 	})
 }
 
diff --git a/android/visibility.go b/android/visibility.go
index 61f2200..cee465e 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -268,7 +268,7 @@
 // The rule checker needs to be registered before defaults expansion to correctly check that
 // //visibility:xxx isn't combined with other packages in the same list in any one module.
 func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
+	ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker)
 }
 
 // Registers the function that gathers the visibility rules for each module.
@@ -278,12 +278,12 @@
 // the complete visibility lists from flat lists and after the package info is gathered to ensure
 // that default_visibility is available.
 func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
+	ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer)
 }
 
 // This must be registered after the deps have been resolved.
 func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
+	ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer)
 }
 
 // Checks the per-module visibility rule lists before defaults expansion.
diff --git a/apex/apex.go b/apex/apex.go
index 6bb2a1a..30b16ee 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -55,20 +55,20 @@
 }
 
 func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel().UsesReverseDependencies()
+	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).UsesReverseDependencies()
 }
 
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.TopDown("apex_info", apexInfoMutator).Parallel()
-	ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
-	ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
-	ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
+	ctx.TopDown("apex_info", apexInfoMutator)
+	ctx.BottomUp("apex_unique", apexUniqueVariationsMutator)
+	ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator)
+	ctx.BottomUp("apex_test_for", apexTestForMutator)
 	// Run mark_platform_availability before the apexMutator as the apexMutator needs to know whether
 	// it should create a platform variant.
-	ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
+	ctx.BottomUp("mark_platform_availability", markPlatformAvailability)
 	ctx.Transition("apex", &apexTransitionMutator{})
-	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel().MutatesDependencies()
-	ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel()
+	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).MutatesDependencies()
+	ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator)
 }
 
 type apexBundleProperties struct {
diff --git a/cc/cc.go b/cc/cc.go
index 1b7624d..9c514ee 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -48,10 +48,10 @@
 
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.Transition("sdk", &sdkTransitionMutator{})
-		ctx.BottomUp("llndk", llndkMutator).Parallel()
+		ctx.BottomUp("llndk", llndkMutator)
 		ctx.Transition("link", &linkageTransitionMutator{})
 		ctx.Transition("version", &versionTransitionMutator{})
-		ctx.BottomUp("begin", BeginMutator).Parallel()
+		ctx.BottomUp("begin", BeginMutator)
 	})
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -59,10 +59,10 @@
 			san.registerMutators(ctx)
 		}
 
-		ctx.BottomUp("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel()
-		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
+		ctx.BottomUp("sanitize_runtime_deps", sanitizerRuntimeDepsMutator)
+		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator)
 
-		ctx.BottomUp("fuzz_deps", fuzzMutatorDeps)
+		ctx.Transition("fuzz", &fuzzTransitionMutator{})
 
 		ctx.Transition("coverage", &coverageTransitionMutator{})
 
@@ -72,8 +72,8 @@
 
 		ctx.Transition("lto", &ltoTransitionMutator{})
 
-		ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel()
-		ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries).Parallel()
+		ctx.BottomUp("check_linktype", checkLinkTypeMutator)
+		ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries)
 	})
 
 	ctx.PostApexMutators(func(ctx android.RegisterMutatorsContext) {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 3f3347b..a479cb3 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1903,11 +1903,11 @@
 
 	moduleName = "afl_fuzz_static_lib"
 	checkPcGuardFlag(moduleName, variant+"_static", false)
-	checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
+	checkPcGuardFlag(moduleName, variant+"_static_fuzzer_afl", true)
 
 	moduleName = "second_static_lib"
 	checkPcGuardFlag(moduleName, variant+"_static", false)
-	checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
+	checkPcGuardFlag(moduleName, variant+"_static_fuzzer_afl", true)
 
 	ctx.ModuleForTests("afl_fuzz_shared_lib",
 		"android_arm64_armv8-a_shared").Rule("cc")
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 3f21bc6..0aa9d4b 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -57,38 +57,76 @@
 	return []interface{}{&fuzzer.Properties}
 }
 
-func fuzzMutatorDeps(mctx android.BottomUpMutatorContext) {
-	currentModule, ok := mctx.Module().(*Module)
+// fuzzTransitionMutator creates variants to propagate the FuzzFramework value down to dependencies.
+type fuzzTransitionMutator struct{}
+
+func (f *fuzzTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+	return []string{""}
+}
+
+func (f *fuzzTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	m, ok := ctx.Module().(*Module)
+	if !ok {
+		return ""
+	}
+
+	if m.fuzzer == nil {
+		return ""
+	}
+
+	if m.sanitize == nil {
+		return ""
+	}
+
+	isFuzzerPointer := m.sanitize.getSanitizerBoolPtr(Fuzzer)
+	if isFuzzerPointer == nil || !*isFuzzerPointer {
+		return ""
+	}
+
+	if m.fuzzer.Properties.FuzzFramework != "" {
+		return m.fuzzer.Properties.FuzzFramework.Variant()
+	}
+
+	return sourceVariation
+}
+
+func (f *fuzzTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	m, ok := ctx.Module().(*Module)
+	if !ok {
+		return ""
+	}
+
+	if m.fuzzer == nil {
+		return ""
+	}
+
+	if m.sanitize == nil {
+		return ""
+	}
+
+	isFuzzerPointer := m.sanitize.getSanitizerBoolPtr(Fuzzer)
+	if isFuzzerPointer == nil || !*isFuzzerPointer {
+		return ""
+	}
+
+	return incomingVariation
+}
+
+func (f *fuzzTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	m, ok := ctx.Module().(*Module)
 	if !ok {
 		return
 	}
 
-	if currentModule.fuzzer == nil {
+	if m.fuzzer == nil {
 		return
 	}
 
-	mctx.WalkDeps(func(child android.Module, parent android.Module) bool {
-		c, ok := child.(*Module)
-		if !ok {
-			return false
-		}
-
-		if c.sanitize == nil {
-			return false
-		}
-
-		isFuzzerPointer := c.sanitize.getSanitizerBoolPtr(Fuzzer)
-		if isFuzzerPointer == nil || !*isFuzzerPointer {
-			return false
-		}
-
-		if c.fuzzer == nil {
-			return false
-		}
-
-		c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework
-		return true
-	})
+	if variation != "" {
+		m.fuzzer.Properties.FuzzFramework = fuzz.FrameworkFromVariant(variation)
+		m.SetHideFromMake()
+		m.SetPreventInstall()
+	}
 }
 
 // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 498ef7c..118580e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -176,7 +176,7 @@
 	switch t {
 	case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack:
 		sanitizer := &sanitizerSplitMutator{t}
-		ctx.BottomUp(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator).Parallel()
+		ctx.BottomUp(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
 		ctx.Transition(t.variationName(), sanitizer)
 	case Memtag_heap, Memtag_globals, intOverflow:
 		// do nothing
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 5ab1b9b..e97fce6 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -15,13 +15,18 @@
 package fsgen
 
 import (
-	"android/soong/android"
-	"android/soong/filesystem"
 	"crypto/sha256"
 	"fmt"
+	"slices"
 	"strconv"
+	"strings"
+	"sync"
+
+	"android/soong/android"
+	"android/soong/filesystem"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/parser"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -33,6 +38,56 @@
 
 func registerBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("soong_filesystem_creator", filesystemCreatorFactory)
+	ctx.PreDepsMutators(RegisterCollectFileSystemDepsMutators)
+}
+
+func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
+}
+
+var collectFsDepsOnceKey = android.NewOnceKey("CollectFsDeps")
+var depCandidatesOnceKey = android.NewOnceKey("DepCandidates")
+
+func collectDepsMutator(mctx android.BottomUpMutatorContext) {
+	// These additional deps are added according to the cuttlefish system image bp.
+	fsDeps := mctx.Config().Once(collectFsDepsOnceKey, func() interface{} {
+		deps := []string{
+			"android_vintf_manifest",
+			"com.android.apex.cts.shim.v1_prebuilt",
+			"dex_bootjars",
+			"framework_compatibility_matrix.device.xml",
+			"idc_data",
+			"init.environ.rc-soong",
+			"keychars_data",
+			"keylayout_data",
+			"libclang_rt.asan",
+			"libcompiler_rt",
+			"libdmabufheap",
+			"libgsi",
+			"llndk.libraries.txt",
+			"logpersist.start",
+			"preloaded-classes",
+			"public.libraries.android.txt",
+			"update_engine_sideload",
+		}
+		return &deps
+	}).(*[]string)
+
+	depCandidates := mctx.Config().Once(depCandidatesOnceKey, func() interface{} {
+		partitionVars := mctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+		candidates := slices.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug)
+		return &candidates
+	}).(*[]string)
+
+	m := mctx.Module()
+	mutex := &sync.Mutex{}
+	if slices.Contains(*depCandidates, m.Name()) {
+		if installInSystem(mctx, m) {
+			mutex.Lock()
+			*fsDeps = append(*fsDeps, m.Name())
+			mutex.Unlock()
+		}
+	}
 }
 
 type filesystemCreatorProps struct {
@@ -233,6 +288,11 @@
 	}
 	f.HideFromMake()
 
+	content := generateBpContent(ctx, "system")
+	generatedBp := android.PathForOutput(ctx, "soong_generated_product_config.bp")
+	android.WriteFileRule(ctx, generatedBp, content)
+	ctx.Phony("product_config_to_bp", generatedBp)
+
 	var diffTestFiles []android.Path
 	for _, partitionType := range f.properties.Generated_partition_types {
 		diffTestFiles = append(diffTestFiles, f.createDiffTest(ctx, partitionType))
@@ -242,3 +302,42 @@
 	}
 	ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...)
 }
+
+func installInSystem(ctx android.BottomUpMutatorContext, m android.Module) bool {
+	return m.PartitionTag(ctx.DeviceConfig()) == "system" && !m.InstallInData() &&
+		!m.InstallInTestcases() && !m.InstallInSanitizerDir() && !m.InstallInVendorRamdisk() &&
+		!m.InstallInDebugRamdisk() && !m.InstallInRecovery() && !m.InstallInOdm() &&
+		!m.InstallInVendor()
+}
+
+// TODO: assemble baseProps and fsProps here
+func generateBpContent(ctx android.EarlyModuleContext, partitionType string) string {
+	// Currently only system partition is supported
+	if partitionType != "system" {
+		return ""
+	}
+
+	deps := ctx.Config().Get(collectFsDepsOnceKey).(*[]string)
+	depProps := &android.PackagingProperties{
+		Deps: android.NewSimpleConfigurable(android.SortedUniqueStrings(*deps)),
+	}
+
+	result, err := proptools.RepackProperties([]interface{}{depProps})
+	if err != nil {
+		ctx.ModuleErrorf(err.Error())
+	}
+
+	file := &parser.File{
+		Defs: []parser.Definition{
+			&parser.Module{
+				Type: "module",
+				Map:  *result,
+			},
+		},
+	}
+	bytes, err := parser.Print(file)
+	if err != nil {
+		ctx.ModuleErrorf(err.Error())
+	}
+	return strings.TrimSpace(string(bytes))
+}
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index a059837..42fd228 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -44,6 +44,32 @@
 	UnknownFramework Framework = "unknownframework"
 )
 
+func (f Framework) Variant() string {
+	switch f {
+	case AFL:
+		return "afl"
+	case LibFuzzer:
+		return "libfuzzer"
+	case Jazzer:
+		return "jazzer"
+	default:
+		panic(fmt.Errorf("unknown fuzzer %q when getting variant", f))
+	}
+}
+
+func FrameworkFromVariant(v string) Framework {
+	switch v {
+	case "afl":
+		return AFL
+	case "libfuzzer":
+		return LibFuzzer
+	case "jazzer":
+		return Jazzer
+	default:
+		panic(fmt.Errorf("unknown variant %q when getting fuzzer", v))
+	}
+}
+
 var BoolDefault = proptools.BoolDefault
 
 type FuzzModule struct {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8721f15..c029167 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -63,7 +63,7 @@
 	ctx.RegisterModuleType("genrule", GenRuleFactory)
 
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel()
+		ctx.BottomUp("genrule_tool_deps", toolDepsMutator)
 	})
 }
 
diff --git a/go.mod b/go.mod
index aa43066..57b59c0 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module android/soong
 
-go 1.22
+go 1.23
 
 require (
 	github.com/google/blueprint v0.0.0
diff --git a/go.work b/go.work
index 46a135b..e538915 100644
--- a/go.work
+++ b/go.work
@@ -1,4 +1,4 @@
-go 1.22
+go 1.23
 
 use (
 	.
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 029f6f6..3413cf3 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -29,7 +29,7 @@
 
 func registerBootclasspathBuildComponents(ctx android.RegistrationContext) {
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator).Parallel()
+		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator)
 	})
 }
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 14e201a..8c60d23 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -465,7 +465,7 @@
 	ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
 	ctx.RegisterModuleType("art_boot_images", artBootImagesFactory)
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator).Parallel()
+		ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator)
 	})
 }
 
diff --git a/java/java.go b/java/java.go
index d972887..0b48873 100644
--- a/java/java.go
+++ b/java/java.go
@@ -70,9 +70,9 @@
 	// established, to not get the dependencies split into the wrong variants and
 	// to support the checks in dexpreoptDisabled().
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
+		ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator)
 		// needs access to ApexInfoProvider which is available after variant creation
-		ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel()
+		ctx.BottomUp("jacoco_deps", jacocoDepsMutator)
 	})
 
 	ctx.RegisterParallelSingletonType("kythe_java_extract", kytheExtractJavaFactory)
diff --git a/rust/rust.go b/rust/rust.go
index a044a99..b22ebf7 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -47,11 +47,11 @@
 func registerPreDepsMutators(ctx android.RegisterMutatorsContext) {
 	ctx.Transition("rust_libraries", &libraryTransitionMutator{})
 	ctx.Transition("rust_stdlinkage", &libstdTransitionMutator{})
-	ctx.BottomUp("rust_begin", BeginMutator).Parallel()
+	ctx.BottomUp("rust_begin", BeginMutator)
 }
 
 func registerPostDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
+	ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator)
 }
 
 type Flags struct {