Merge "Add support for kotlin plugins" into main
diff --git a/Android.bp b/Android.bp
index bd4b40f..d0f97db 100644
--- a/Android.bp
+++ b/Android.bp
@@ -147,6 +147,16 @@
 // Framework guests.
 cc_defaults {
     name: "cc_baremetal_defaults",
+    arch: {
+        arm64: {
+            cflags: [
+                // Prevent the compiler from optimizing code using SVE, as the
+                // baremetal environment might not have configured the hardware.
+                "-Xclang -target-feature",
+                "-Xclang -sve",
+            ],
+        },
+    },
     defaults_visibility: ["//visibility:public"],
 }
 
diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go
index c308ed4..2f6c1a6 100644
--- a/aconfig/codegen/cc_aconfig_library_test.go
+++ b/aconfig/codegen/cc_aconfig_library_test.go
@@ -211,7 +211,7 @@
 
 	module := result.ModuleForTests("my_cc_library", "android_vendor_arm64_armv8-a_shared").Module()
 
-	entry := android.AndroidMkInfoForTest(t, result.TestContext, module).PrimaryInfo
+	entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
 
 	makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
 	android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb")
diff --git a/android/androidmk.go b/android/androidmk.go
index 590cce3..cac2cfe 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -463,18 +463,18 @@
 func generateDistContributionsForMake(distContributions *distContributions) []string {
 	var ret []string
 	for _, d := range distContributions.copiesForGoals {
-		ret = append(ret, fmt.Sprintf(".PHONY: %s", d.goals))
+		ret = append(ret, fmt.Sprintf(".PHONY: %s\n", d.goals))
 		// Create dist-for-goals calls for each of the copy instructions.
 		for _, c := range d.copies {
 			if distContributions.licenseMetadataFile != nil {
 				ret = append(
 					ret,
-					fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))",
+					fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
 						c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
 			}
 			ret = append(
 				ret,
-				fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)", d.goals, c.from.String(), c.dest))
+				fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest))
 		}
 	}
 
@@ -523,7 +523,7 @@
 	a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...)
 
 	for _, distString := range a.GetDistForGoals(mod) {
-		fmt.Fprintln(&a.header, distString)
+		fmt.Fprintf(&a.header, distString)
 	}
 
 	fmt.Fprintf(&a.header, "\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))
@@ -807,8 +807,9 @@
 	// Additional cases here require review for correct license propagation to make.
 	var err error
 
-	if info, ok := OtherModuleProvider(ctx, mod, AndroidMkInfoProvider); ok {
-		err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, info)
+	if info, ok := ctx.otherModuleProvider(mod, AndroidMkInfoProvider); ok {
+		androidMkEntriesInfos := info.(*AndroidMkProviderInfo)
+		err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, androidMkEntriesInfos)
 	} else {
 		switch x := mod.(type) {
 		case AndroidMkDataProvider:
@@ -1099,10 +1100,6 @@
 	EntryOrder []string
 }
 
-type AndroidMkProviderInfoProducer interface {
-	PrepareAndroidMKProviderInfo(config Config) *AndroidMkProviderInfo
-}
-
 // TODO: rename it to AndroidMkEntriesProvider after AndroidMkEntriesProvider interface is gone.
 var AndroidMkInfoProvider = blueprint.NewProvider[*AndroidMkProviderInfo]()
 
@@ -1275,7 +1272,7 @@
 		a.HeaderStrings = append(a.HeaderStrings, distString)
 	}
 
-	a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod)))
+	a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod)))
 
 	// Collect make variable assignment entries.
 	helperInfo.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
@@ -1303,14 +1300,6 @@
 		helperInfo.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
 	}
 
-	if info.UncheckedModule {
-		helperInfo.SetBool("LOCAL_DONT_CHECK_MODULE", true)
-	} else if info.CheckbuildTarget != nil {
-		helperInfo.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget)
-	} else {
-		helperInfo.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile)
-	}
-
 	if len(info.TestData) > 0 {
 		helperInfo.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
 	}
@@ -1375,6 +1364,25 @@
 		helperInfo.SetString("LOCAL_IS_HOST_MODULE", "true")
 	}
 
+	prefix := ""
+	if base.ArchSpecific() {
+		switch base.Os().Class {
+		case Host:
+			if base.Target().HostCross {
+				prefix = "HOST_CROSS_"
+			} else {
+				prefix = "HOST_"
+			}
+		case Device:
+			prefix = "TARGET_"
+
+		}
+
+		if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType {
+			prefix = "2ND_" + prefix
+		}
+	}
+
 	if licenseMetadata, ok := OtherModuleProvider(ctx, mod, LicenseMetadataProvider); ok {
 		helperInfo.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
 	}
@@ -1415,8 +1423,8 @@
 		return
 	}
 
-	combinedHeaderString := strings.Join(a.HeaderStrings, "\n") + "\n"
-	combinedFooterString := strings.Join(a.FooterStrings, "\n") + "\n"
+	combinedHeaderString := strings.Join(a.HeaderStrings, "\n")
+	combinedFooterString := strings.Join(a.FooterStrings, "\n")
 	w.Write([]byte(combinedHeaderString))
 	for _, name := range a.EntryOrder {
 		AndroidMkEmitAssignList(w, name, a.EntryMap[name])
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index f63b227..c37eeab 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -195,7 +195,8 @@
 $(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))
 $(call dist-for-goals,my_goal,one.out:one.out)
 $(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))
-$(call dist-for-goals,my_goal,two.out:other.out)`, strings.Join(makeOutput, "\n"))
+$(call dist-for-goals,my_goal,two.out:other.out)
+`, strings.Join(makeOutput, ""))
 }
 
 func TestGetDistForGoals(t *testing.T) {
@@ -234,28 +235,28 @@
 			`
 
 	expectedAndroidMkLines := []string{
-		".PHONY: my_second_goal",
-		"$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_second_goal,two.out:two.out)",
-		"$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_second_goal,three/four.out:four.out)",
-		".PHONY: my_third_goal",
-		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)",
-		".PHONY: my_fourth_goal",
-		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)",
-		".PHONY: my_fifth_goal",
-		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_fifth_goal,one.out:new-name)",
-		".PHONY: my_sixth_goal",
-		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)",
-		".PHONY: my_goal my_other_goal",
-		"$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)",
-		"$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))",
-		"$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)",
+		".PHONY: my_second_goal\n",
+		"$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
+		"$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
+		".PHONY: my_third_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
+		".PHONY: my_fourth_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
+		".PHONY: my_fifth_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
+		".PHONY: my_sixth_goal\n",
+		"$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
+		".PHONY: my_goal my_other_goal\n",
+		"$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
+		"$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
+		"$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
 	}
 
 	ctx, module := buildContextAndCustomModuleFoo(t, bp)
diff --git a/android/config.go b/android/config.go
index 06d71c0..5132c62 100644
--- a/android/config.go
+++ b/android/config.go
@@ -324,6 +324,9 @@
 	AndroidCommonTarget      Target // the Target for common modules for the Android device
 	AndroidFirstDeviceTarget Target // the first Target for modules for the Android device
 
+	// Flags for Partial Compile, derived from SOONG_PARTIAL_COMPILE.
+	partialCompileFlags partialCompileFlags
+
 	// multilibConflicts for an ArchType is true if there is earlier configured
 	// device architecture with the same multilib value.
 	multilibConflicts map[ArchType]bool
@@ -373,6 +376,16 @@
 	ensureAllowlistIntegrity bool
 }
 
+type partialCompileFlags struct {
+	// Is partial compilation enabled at all?
+	enabled bool
+
+	// Whether to use d8 instead of r8
+	use_d8 bool
+
+	// Add others as needed.
+}
+
 type deviceConfig struct {
 	config *config
 	OncePer
@@ -382,6 +395,88 @@
 	SetDefaultConfig()
 }
 
+// Parse SOONG_PARTIAL_COMPILE.
+//
+// SOONG_PARTIAL_COMPILE determines which features are enabled or disabled in
+// rule generation.  Changing this environment variable causes reanalysis.
+//
+// SOONG_USE_PARTIAL_COMPILE determines whether or not we **use** PARTIAL_COMPILE.
+// Rule generation must support both cases, since changing it does not cause
+// reanalysis.
+//
+// The user-facing documentation shows:
+//
+// - empty or not set: "The current default state"
+// - "true" or "on": enable all stable partial compile features.
+// - "false" or "off": disable partial compile completely.
+//
+// What we actually allow is a comma separated list of tokens, whose first
+// character may be "+" (enable) or "-" (disable).  If neither is present, "+"
+// is assumed.  For example, "on,+use_d8" will enable partial compilation, and
+// additionally set the use_d8 flag (regardless of whether it is opt-in or
+// opt-out).
+//
+// To add a new feature to the list, add the field in the struct
+// `partialCompileFlags` above, and then add the name of the field in the
+// switch statement below.
+func (c *config) parsePartialCompileFlags() (partialCompileFlags, error) {
+	defaultFlags := partialCompileFlags{
+		// Set any opt-out flags here.  Opt-in flags are off by default.
+		enabled: false,
+	}
+	value := c.Getenv("SOONG_PARTIAL_COMPILE")
+
+	if value == "" {
+		return defaultFlags, nil
+	}
+
+	ret := defaultFlags
+	tokens := strings.Split(strings.ToLower(value), ",")
+	makeVal := func(state string, defaultValue bool) bool {
+		switch state {
+		case "":
+			return defaultValue
+		case "-":
+			return false
+		case "+":
+			return true
+		}
+		return false
+	}
+	for _, tok := range tokens {
+		var state string
+		if len(tok) == 0 {
+			continue
+		}
+		switch tok[0:1] {
+		case "":
+			// Ignore empty tokens.
+			continue
+		case "-", "+":
+			state = tok[0:1]
+			tok = tok[1:]
+		default:
+			// Treat `feature` as `+feature`.
+			state = "+"
+		}
+		switch tok {
+		case "true":
+			ret = defaultFlags
+			ret.enabled = true
+		case "false":
+			// Set everything to false.
+			ret = partialCompileFlags{}
+		case "enabled":
+			ret.enabled = makeVal(state, defaultFlags.enabled)
+		case "use_d8":
+			ret.use_d8 = makeVal(state, defaultFlags.use_d8)
+		default:
+			return partialCompileFlags{}, fmt.Errorf("Unknown SOONG_PARTIAL_COMPILE value: %v", value)
+		}
+	}
+	return ret, nil
+}
+
 func loadConfig(config *config) error {
 	return loadFromConfigFile(&config.productVariables, absolutePath(config.ProductVariablesFileName))
 }
@@ -568,6 +663,11 @@
 		return Config{}, err
 	}
 
+	config.partialCompileFlags, err = config.parsePartialCompileFlags()
+	if err != nil {
+		return Config{}, err
+	}
+
 	// Make the CommonOS OsType available for all products.
 	targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
 
@@ -999,6 +1099,10 @@
 	return ApiLevelOrPanic(ctx, codename)
 }
 
+func (c *config) PartialCompileFlags() partialCompileFlags {
+	return c.partialCompileFlags
+}
+
 func (c *config) AppsDefaultVersionName() string {
 	return String(c.productVariables.AppsDefaultVersionName)
 }
diff --git a/android/filegroup.go b/android/filegroup.go
index ff0f74e..a8b4f00 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -139,3 +139,15 @@
 
 	return module
 }
+
+// Collect information for opening IDE project files in java/jdeps.go.
+// Copied from build/soong/genrule/genrule.go
+func (fg *fileGroup) IDEInfo(ctx BaseModuleContext, dpInfo *IdeInfo) {
+	dpInfo.Srcs = append(dpInfo.Srcs, fg.Srcs().Strings()...)
+	for _, src := range fg.properties.Srcs.GetOrDefault(ctx, nil) {
+		if mod, _ := SrcIsModuleWithTag(src); mod != "" {
+			// Register the module name without any tags in `Deps`
+			dpInfo.Deps = append(dpInfo.Deps, mod)
+		}
+	}
+}
diff --git a/android/module.go b/android/module.go
index ea59b3b..e3dabcc 100644
--- a/android/module.go
+++ b/android/module.go
@@ -543,13 +543,6 @@
 	}
 }
 
-func (t *CommonTestOptions) SetAndroidMkInfoEntries(entries *AndroidMkInfo) {
-	entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(t.Unit_test))
-	if len(t.Tags) > 0 {
-		entries.AddStrings("LOCAL_TEST_OPTIONS_TAGS", t.Tags...)
-	}
-}
-
 // The key to use in TaggedDistFiles when a Dist structure does not specify a
 // tag property. This intentionally does not use "" as the default because that
 // would mean that an empty tag would have a different meaning when used in a dist
@@ -2092,10 +2085,6 @@
 		SetProvider(ctx, HostToolProviderKey, HostToolProviderData{
 			HostToolPath: h.HostToolPath()})
 	}
-
-	if p, ok := m.module.(AndroidMkProviderInfoProducer); ok && !shouldSkipAndroidMkProcessing(ctx, m) {
-		SetProvider(ctx, AndroidMkInfoProvider, p.PrepareAndroidMKProviderInfo(ctx.Config()))
-	}
 }
 
 func SetJarJarPrefixHandler(handler func(ModuleContext)) {
diff --git a/android/testing.go b/android/testing.go
index 3be8e54..7440869 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -1152,25 +1152,6 @@
 	return entriesList
 }
 
-func AndroidMkInfoForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) *AndroidMkProviderInfo {
-	t.Helper()
-	var ok bool
-	if _, ok = mod.(AndroidMkProviderInfoProducer); !ok {
-		t.Errorf("module does not implement AndroidMkProviderInfoProducer: " + mod.Name())
-	}
-
-	info := OtherModuleProviderOrDefault(ctx, mod, AndroidMkInfoProvider)
-	aconfigUpdateAndroidMkInfos(ctx, mod.(Module), info)
-	info.PrimaryInfo.fillInEntries(ctx, mod)
-	if len(info.ExtraInfo) > 0 {
-		for _, ei := range info.ExtraInfo {
-			ei.fillInEntries(ctx, mod)
-		}
-	}
-
-	return info
-}
-
 func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData {
 	t.Helper()
 	var p AndroidMkDataProvider
diff --git a/apex/androidmk.go b/apex/androidmk.go
index ec5ca15..933682a 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -297,7 +297,7 @@
 				fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String())
 			}
 			for _, dist := range data.Entries.GetDistForGoals(a) {
-				fmt.Fprintln(w, dist)
+				fmt.Fprintf(w, dist)
 			}
 
 			distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 042b43d..68978b2 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -9270,7 +9270,7 @@
 
 					type modAndMkEntries struct {
 						mod       *cc.Module
-						mkEntries android.AndroidMkInfo
+						mkEntries android.AndroidMkEntries
 					}
 					entries := []*modAndMkEntries{}
 
@@ -9284,10 +9284,7 @@
 							if !mod.Enabled(android.PanickingConfigAndErrorContext(ctx)) || mod.IsHideFromMake() {
 								continue
 							}
-							info := android.AndroidMkInfoForTest(t, ctx, mod)
-							ents := []android.AndroidMkInfo{info.PrimaryInfo}
-							ents = append(ents, info.ExtraInfo...)
-							for _, ent := range ents {
+							for _, ent := range android.AndroidMkEntriesForTest(t, ctx, mod) {
 								if ent.Disabled {
 									continue
 								}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 920b58b..6966f76 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -36,7 +36,7 @@
 type AndroidMkContext interface {
 	BaseModuleName() string
 	Target() android.Target
-	subAndroidMk(android.Config, *android.AndroidMkInfo, interface{})
+	subAndroidMk(*android.AndroidMkEntries, interface{})
 	Arch() android.Arch
 	Os() android.OsType
 	Host() bool
@@ -48,120 +48,112 @@
 	InRecovery() bool
 	NotInPlatform() bool
 	InVendorOrProduct() bool
-	ArchSpecific() bool
 }
 
-type subAndroidMkProviderInfoProducer interface {
-	prepareAndroidMKProviderInfo(android.Config, AndroidMkContext, *android.AndroidMkInfo)
+type subAndroidMkProvider interface {
+	AndroidMkEntries(AndroidMkContext, *android.AndroidMkEntries)
 }
 
-type subAndroidMkFooterInfoProducer interface {
-	prepareAndroidMKFooterInfo(android.Config, AndroidMkContext, *android.AndroidMkInfo)
-}
-
-func (c *Module) subAndroidMk(config android.Config, entries *android.AndroidMkInfo, obj interface{}) {
+func (c *Module) subAndroidMk(entries *android.AndroidMkEntries, obj interface{}) {
 	if c.subAndroidMkOnce == nil {
-		c.subAndroidMkOnce = make(map[subAndroidMkProviderInfoProducer]bool)
+		c.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
 	}
-	if androidmk, ok := obj.(subAndroidMkProviderInfoProducer); ok {
+	if androidmk, ok := obj.(subAndroidMkProvider); ok {
 		if !c.subAndroidMkOnce[androidmk] {
 			c.subAndroidMkOnce[androidmk] = true
-			androidmk.prepareAndroidMKProviderInfo(config, c, entries)
+			androidmk.AndroidMkEntries(c, entries)
 		}
 	}
 }
 
-var _ android.AndroidMkProviderInfoProducer = (*Module)(nil)
-
-func (c *Module) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
+func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
 	if c.hideApexVariantFromMake || c.Properties.HideFromMake {
-		return &android.AndroidMkProviderInfo{
-			PrimaryInfo: android.AndroidMkInfo{
-				Disabled: true,
-			},
-		}
+		return []android.AndroidMkEntries{{
+			Disabled: true,
+		}}
 	}
 
-	providerData := android.AndroidMkProviderInfo{
-		PrimaryInfo: android.AndroidMkInfo{
-			OutputFile:   c.outputFile,
-			Required:     c.Properties.AndroidMkRuntimeLibs,
-			OverrideName: c.BaseModuleName(),
-			Include:      "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
-			EntryMap:     make(map[string][]string),
+	entries := android.AndroidMkEntries{
+		OutputFile: c.outputFile,
+		// TODO(jiyong): add the APEXes providing shared libs to the required
+		// modules Currently, adding c.Properties.ApexesProvidingSharedLibs is
+		// causing multiple ART APEXes (com.android.art and com.android.art.debug)
+		// to be installed. And this is breaking some older devices (like marlin)
+		// where system.img is small.
+		Required:     c.Properties.AndroidMkRuntimeLibs,
+		OverrideName: c.BaseModuleName(),
+		Include:      "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
+
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				if len(c.Properties.Logtags) > 0 {
+					entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...)
+				}
+				// Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make
+				// world, even if it is an empty list. In the Make world,
+				// LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded
+				// to the default list of system shared libs by the build system.
+				// Soong computes the exact list of system shared libs, so we have to
+				// override the default value when the list of libs is actually empty.
+				entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " "))
+				if len(c.Properties.AndroidMkSharedLibs) > 0 {
+					entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
+				}
+				if len(c.Properties.AndroidMkRuntimeLibs) > 0 {
+					entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...)
+				}
+				entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
+				if c.InVendor() {
+					entries.SetBool("LOCAL_IN_VENDOR", true)
+				} else if c.InProduct() {
+					entries.SetBool("LOCAL_IN_PRODUCT", true)
+				}
+				if c.Properties.SdkAndPlatformVariantVisibleToMake {
+					// Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
+					// dependencies to the .sdk suffix when building a module that uses the SDK.
+					entries.SetString("SOONG_SDK_VARIANT_MODULES",
+						"$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
+				}
+				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall())
+			},
+		},
+		ExtraFooters: []android.AndroidMkExtraFootersFunc{
+			func(w io.Writer, name, prefix, moduleDir string) {
+				if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
+					c.CcLibraryInterface() && c.Shared() {
+					// Using the SDK variant as a JNI library needs a copy of the .so that
+					// is not named .sdk.so so that it can be packaged into the APK with
+					// the right name.
+					fmt.Fprintln(w, "$(eval $(call copy-one-file,",
+						"$(LOCAL_BUILT_MODULE),",
+						"$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")
+				}
+			},
 		},
 	}
 
-	entries := &providerData.PrimaryInfo
-	if len(c.Properties.Logtags) > 0 {
-		entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...)
-	}
-	// Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make
-	// world, even if it is an empty list. In the Make world,
-	// LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded
-	// to the default list of system shared libs by the build system.
-	// Soong computes the exact list of system shared libs, so we have to
-	// override the default value when the list of libs is actually empty.
-	entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " "))
-	if len(c.Properties.AndroidMkSharedLibs) > 0 {
-		entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
-	}
-	if len(c.Properties.AndroidMkRuntimeLibs) > 0 {
-		entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...)
-	}
-	entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
-	if c.InVendor() {
-		entries.SetBool("LOCAL_IN_VENDOR", true)
-	} else if c.InProduct() {
-		entries.SetBool("LOCAL_IN_PRODUCT", true)
-	}
-	if c.Properties.SdkAndPlatformVariantVisibleToMake {
-		// Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
-		// dependencies to the .sdk suffix when building a module that uses the SDK.
-		entries.SetString("SOONG_SDK_VARIANT_MODULES",
-			"$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
-	}
-	entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall())
-
 	for _, feature := range c.features {
-		c.subAndroidMk(config, entries, feature)
+		c.subAndroidMk(&entries, feature)
 	}
 
-	c.subAndroidMk(config, entries, c.compiler)
-	c.subAndroidMk(config, entries, c.linker)
+	c.subAndroidMk(&entries, c.compiler)
+	c.subAndroidMk(&entries, c.linker)
 	if c.sanitize != nil {
-		c.subAndroidMk(config, entries, c.sanitize)
+		c.subAndroidMk(&entries, c.sanitize)
 	}
-	c.subAndroidMk(config, entries, c.installer)
+	c.subAndroidMk(&entries, c.installer)
 
 	entries.SubName += c.Properties.SubName
 
-	if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
-		c.CcLibraryInterface() && c.Shared() {
-		// Using the SDK variant as a JNI library needs a copy of the .so that
-		// is not named .sdk.so so that it can be packaged into the APK with
-		// the right name.
-		entries.FooterStrings = []string{
-			fmt.Sprintf("%s %s %s", "$(eval $(call copy-one-file,",
-				"$(LOCAL_BUILT_MODULE),",
-				"$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")}
-	}
-
-	for _, obj := range []interface{}{c.compiler, c.linker, c.sanitize, c.installer} {
-		if obj == nil {
-			continue
-		}
-		if p, ok := obj.(subAndroidMkFooterInfoProducer); ok {
-			p.prepareAndroidMKFooterInfo(config, c, entries)
-		}
-	}
-
-	return &providerData
+	return []android.AndroidMkEntries{entries}
 }
 
-func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkInfo) {
+func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) {
 	if len(extraTestConfigs) > 0 {
-		entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
+		entries.ExtraEntries = append(entries.ExtraEntries,
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
+			})
 	}
 }
 
@@ -177,7 +169,7 @@
 	return overrides
 }
 
-func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkInfo) {
+func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) {
 	var exportedFlags []string
 	var includeDirs android.Paths
 	var systemIncludeDirs android.Paths
@@ -208,7 +200,7 @@
 	}
 }
 
-func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkInfo) {
+func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
 	if !library.static() {
 		entries.AddPaths("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff)
 	}
@@ -221,21 +213,23 @@
 	}
 }
 
-func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	if library.static() {
 		entries.Class = "STATIC_LIBRARIES"
 	} else if library.shared() {
 		entries.Class = "SHARED_LIBRARIES"
-		entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
-		if !library.buildStubs() && library.unstrippedOutputFile != nil {
-			entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
-		}
-		if len(library.Properties.Overrides) > 0 {
-			entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
-		}
-		if len(library.postInstallCmds) > 0 {
-			entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.postInstallCmds, "&& "))
-		}
+		entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+			entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
+			if !library.buildStubs() && library.unstrippedOutputFile != nil {
+				entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
+			}
+			if len(library.Properties.Overrides) > 0 {
+				entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
+			}
+			if len(library.postInstallCmds) > 0 {
+				entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.postInstallCmds, "&& "))
+			}
+		})
 	} else if library.header() {
 		entries.Class = "HEADER_LIBRARIES"
 	}
@@ -244,30 +238,34 @@
 		entries.DistFiles = android.MakeDefaultDistFiles(library.distFile)
 	}
 
-	library.androidMkWriteExportedFlags(entries)
-	library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		library.androidMkWriteExportedFlags(entries)
+		library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
 
-	if entries.OutputFile.Valid() {
-		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
-		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
-	}
+		if entries.OutputFile.Valid() {
+			_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
+			entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		}
 
-	if library.coverageOutputFile.Valid() {
-		entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
-	}
+		if library.coverageOutputFile.Valid() {
+			entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
+		}
+	})
 
 	if library.shared() && !library.buildStubs() {
-		ctx.subAndroidMk(config, entries, library.baseInstaller)
+		ctx.subAndroidMk(entries, library.baseInstaller)
 	} else {
 		if library.buildStubs() && library.stubsVersion() != "" {
 			entries.SubName = "." + library.stubsVersion()
 		}
-		// library.makeUninstallable() depends on this to bypass HideFromMake() for
-		// static libraries.
-		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-		if library.buildStubs() {
-			entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
-		}
+		entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+			// library.makeUninstallable() depends on this to bypass HideFromMake() for
+			// static libraries.
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+			if library.buildStubs() {
+				entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+			}
+		})
 	}
 	// If a library providing a stub is included in an APEX, the private APIs of the library
 	// is accessible only inside the APEX. From outside of the APEX, clients can only use the
@@ -286,136 +284,124 @@
 	}
 }
 
-func (object *objectLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+func (object *objectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	entries.Class = "STATIC_LIBRARIES"
+	entries.ExtraFooters = append(entries.ExtraFooters,
+		func(w io.Writer, name, prefix, moduleDir string) {
+			out := entries.OutputFile.Path()
+			varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
+
+			fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
+			fmt.Fprintln(w, ".KATI_READONLY: "+varname)
+		})
 }
 
-func (object *objectLinker) prepareAndroidMKFooterInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	out := entries.OutputFile.Path()
-	name := ctx.BaseModuleName()
-	if entries.OverrideName != "" {
-		name = entries.OverrideName
-	}
-
-	prefix := ""
-	if ctx.ArchSpecific() {
-		switch ctx.Os().Class {
-		case android.Host:
-			if ctx.Target().HostCross {
-				prefix = "HOST_CROSS_"
-			} else {
-				prefix = "HOST_"
-			}
-		case android.Device:
-			prefix = "TARGET_"
-
+func (test *testDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		if len(test.InstallerProperties.Test_suites) > 0 {
+			entries.AddCompatibilityTestSuites(test.InstallerProperties.Test_suites...)
 		}
-
-		if ctx.Arch().ArchType != config.Targets[ctx.Os()][0].Arch.ArchType {
-			prefix = "2ND_" + prefix
-		}
-	}
-
-	varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
-
-	entries.FooterStrings = append(entries.FooterStrings,
-		fmt.Sprintf("\n%s := %s\n.KATI_READONLY: %s", varname, out.String(), varname))
+	})
 }
 
-func (test *testDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	if len(test.InstallerProperties.Test_suites) > 0 {
-		entries.AddCompatibilityTestSuites(test.InstallerProperties.Test_suites...)
-	}
-}
-
-func (binary *binaryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	ctx.subAndroidMk(config, entries, binary.baseInstaller)
+func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, binary.baseInstaller)
 
 	entries.Class = "EXECUTABLES"
 	entries.DistFiles = binary.distFiles
-	entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
-	if len(binary.symlinks) > 0 {
-		entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...)
-	}
+	entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
+		if len(binary.symlinks) > 0 {
+			entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...)
+		}
 
-	if binary.coverageOutputFile.Valid() {
-		entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String())
-	}
+		if binary.coverageOutputFile.Valid() {
+			entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String())
+		}
 
-	if len(binary.Properties.Overrides) > 0 {
-		entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
-	}
-	if len(binary.postInstallCmds) > 0 {
-		entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.postInstallCmds, "&& "))
-	}
+		if len(binary.Properties.Overrides) > 0 {
+			entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
+		}
+		if len(binary.postInstallCmds) > 0 {
+			entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.postInstallCmds, "&& "))
+		}
+	})
 }
 
-func (benchmark *benchmarkDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	ctx.subAndroidMk(config, entries, benchmark.binaryDecorator)
+func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, benchmark.binaryDecorator)
 	entries.Class = "NATIVE_TESTS"
-	if len(benchmark.Properties.Test_suites) > 0 {
-		entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
-	}
-	if benchmark.testConfig != nil {
-		entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
-	}
-	entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
-	if !BoolDefault(benchmark.Properties.Auto_gen_config, true) {
-		entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
-	}
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		if len(benchmark.Properties.Test_suites) > 0 {
+			entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
+		}
+		if benchmark.testConfig != nil {
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
+		}
+		entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
+		if !BoolDefault(benchmark.Properties.Auto_gen_config, true) {
+			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
+		}
+	})
 }
 
-func (test *testBinary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	ctx.subAndroidMk(config, entries, test.binaryDecorator)
-	ctx.subAndroidMk(config, entries, test.testDecorator)
+func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, test.binaryDecorator)
+	ctx.subAndroidMk(entries, test.testDecorator)
 
 	entries.Class = "NATIVE_TESTS"
-	if test.testConfig != nil {
-		entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
-	}
-	if !BoolDefault(test.Properties.Auto_gen_config, true) {
-		entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
-	}
-	entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		if test.testConfig != nil {
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
+		}
+		if !BoolDefault(test.Properties.Auto_gen_config, true) {
+			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
+		}
+		entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
 
-	entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory))
-	if len(test.Properties.Data_bins) > 0 {
-		entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
-	}
+		entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory))
+		if len(test.Properties.Data_bins) > 0 {
+			entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
+		}
 
-	test.Properties.Test_options.CommonTestOptions.SetAndroidMkInfoEntries(entries)
+		test.Properties.Test_options.CommonTestOptions.SetAndroidMkEntries(entries)
+	})
 
 	androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries)
 }
 
-func (fuzz *fuzzBinary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	ctx.subAndroidMk(config, entries, fuzz.binaryDecorator)
+func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, fuzz.binaryDecorator)
 
-	entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
-	if fuzz.installedSharedDeps != nil {
-		// TOOD: move to install dep
-		entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
-	}
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
+		if fuzz.installedSharedDeps != nil {
+			// TOOD: move to install dep
+			entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
+		}
+	})
 }
 
-func (test *testLibrary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	ctx.subAndroidMk(config, entries, test.libraryDecorator)
-	ctx.subAndroidMk(config, entries, test.testDecorator)
+func (test *testLibrary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, test.libraryDecorator)
+	ctx.subAndroidMk(entries, test.testDecorator)
 }
 
-func (installer *baseInstaller) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	if installer.path == (android.InstallPath{}) {
 		return
 	}
 
-	path, file := filepath.Split(installer.path.String())
-	stem, suffix, _ := android.SplitFileExt(file)
-	entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
-	entries.SetString("LOCAL_MODULE_PATH", path)
-	entries.SetString("LOCAL_MODULE_STEM", stem)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		path, file := filepath.Split(installer.path.String())
+		stem, suffix, _ := android.SplitFileExt(file)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+	})
 }
 
-func (c *stubDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String()
 	entries.Class = "SHARED_LIBRARIES"
 
@@ -424,75 +410,85 @@
 		return
 	}
 
-	path, file := filepath.Split(c.installPath.String())
-	stem, suffix, _ := android.SplitFileExt(file)
-	entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
-	entries.SetString("LOCAL_MODULE_PATH", path)
-	entries.SetString("LOCAL_MODULE_STEM", stem)
-	entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
-	if c.parsedCoverageXmlPath.String() != "" {
-		entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String())
-	}
-	entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		path, file := filepath.Split(c.installPath.String())
+		stem, suffix, _ := android.SplitFileExt(file)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+		if c.parsedCoverageXmlPath.String() != "" {
+			entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String())
+		}
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed
+	})
 }
 
-func (c *vndkPrebuiltLibraryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	entries.Class = "SHARED_LIBRARIES"
 
 	entries.SubName = c.androidMkSuffix
 
-	c.libraryDecorator.androidMkWriteExportedFlags(entries)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
 
-	// Specifying stem is to pass check_elf_files when vendor modules link against vndk prebuilt.
-	// We can't use install path because VNDKs are not installed. Instead, Srcs is directly used.
-	_, file := filepath.Split(c.properties.Srcs[0])
-	stem, suffix, ext := android.SplitFileExt(file)
-	entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
-	entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
-	entries.SetString("LOCAL_MODULE_STEM", stem)
+		// Specifying stem is to pass check_elf_files when vendor modules link against vndk prebuilt.
+		// We can't use install path because VNDKs are not installed. Instead, Srcs is directly used.
+		_, file := filepath.Split(c.properties.Srcs[0])
+		stem, suffix, ext := android.SplitFileExt(file)
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
 
-	if c.tocFile.Valid() {
-		entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
-	}
+		if c.tocFile.Valid() {
+			entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
+		}
 
-	// VNDK libraries available to vendor are not installed because
-	// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
-	entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+		// VNDK libraries available to vendor are not installed because
+		// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+	})
 }
 
-func (p *prebuiltLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	if p.properties.Check_elf_files != nil {
-		entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
-	} else {
-		// soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default
-		// because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well.
-		// In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
-		// true if `p.properties.Check_elf_files` is not specified.
-		entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
-	}
+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 {
+			entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
+		} else {
+			// soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default
+			// because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well.
+			// In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
+			// true if `p.properties.Check_elf_files` is not specified.
+			entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
+		}
+	})
 }
 
-func (p *prebuiltLibraryLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	ctx.subAndroidMk(config, entries, p.libraryDecorator)
+func (p *prebuiltLibraryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, p.libraryDecorator)
 	if p.shared() {
-		ctx.subAndroidMk(config, entries, &p.prebuiltLinker)
+		ctx.subAndroidMk(entries, &p.prebuiltLinker)
 		androidMkWritePrebuiltOptions(p.baseLinker, entries)
 	}
 }
 
-func (p *prebuiltBinaryLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
-	ctx.subAndroidMk(config, entries, p.binaryDecorator)
-	ctx.subAndroidMk(config, entries, &p.prebuiltLinker)
+func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, p.binaryDecorator)
+	ctx.subAndroidMk(entries, &p.prebuiltLinker)
 	androidMkWritePrebuiltOptions(p.baseLinker, entries)
 }
 
-func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkInfo) {
+func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkEntries) {
 	allow := linker.Properties.Allow_undefined_symbols
 	if allow != nil {
-		entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow)
+		entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow)
+		})
 	}
 	ignore := linker.Properties.Ignore_max_page_size
 	if ignore != nil {
-		entries.SetBool("LOCAL_IGNORE_MAX_PAGE_SIZE", *ignore)
+		entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_IGNORE_MAX_PAGE_SIZE", *ignore)
+		})
 	}
 }
diff --git a/cc/cc.go b/cc/cc.go
index 80ae6a0..9c514ee 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -878,7 +878,7 @@
 
 	cachedToolchain config.Toolchain
 
-	subAndroidMkOnce map[subAndroidMkProviderInfoProducer]bool
+	subAndroidMkOnce map[subAndroidMkProvider]bool
 
 	// Flags used to compile this module
 	flags Flags
diff --git a/cc/cc_preprocess_no_configuration.go b/cc/cc_preprocess_no_configuration.go
index 3d1d0a5..3d4b077 100644
--- a/cc/cc_preprocess_no_configuration.go
+++ b/cc/cc_preprocess_no_configuration.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"slices"
 	"strings"
 )
 
@@ -78,6 +79,12 @@
 		return
 	}
 
+	cflags := slices.Clone(m.properties.Cflags)
+
+	// Match behavior of other cc modules:
+	// https://cs.android.com/android/platform/superproject/main/+/main:build/soong/cc/compiler.go;l=422;drc=7297f05ee8cda422ccb32c4af4d9d715d6bac10e
+	cflags = append(cflags, "-I"+ctx.ModuleDir())
+
 	var ccCmd string
 	switch src.Ext() {
 	case ".c":
@@ -99,7 +106,7 @@
 		Output:      outFile,
 		Input:       src,
 		Args: map[string]string{
-			"cFlags": strings.Join(m.properties.Cflags, " "),
+			"cFlags": strings.Join(cflags, " "),
 			"ccCmd":  ccCmd,
 		},
 	})
diff --git a/cc/cc_preprocess_no_configuration_test.go b/cc/cc_preprocess_no_configuration_test.go
index 43e726d..c6eae4c 100644
--- a/cc/cc_preprocess_no_configuration_test.go
+++ b/cc/cc_preprocess_no_configuration_test.go
@@ -20,21 +20,24 @@
 )
 
 func TestCcPreprocessNoConfiguration(t *testing.T) {
+	bp := `
+	cc_preprocess_no_configuration {
+		name: "foo",
+		srcs: ["main.cc"],
+		cflags: ["-E", "-DANDROID"],
+	}
+	`
+
 	fixture := android.GroupFixturePreparers(
 		android.PrepareForIntegrationTestWithAndroid,
 		android.FixtureRegisterWithContext(RegisterCCPreprocessNoConfiguration),
+		android.FixtureAddTextFile("foo/bar/Android.bp", bp),
 	)
 
-	result := fixture.RunTestWithBp(t, `
-cc_preprocess_no_configuration {
-	name: "foo",
-	srcs: ["main.cc"],
-	cflags: ["-E", "-DANDROID"],
-}
-`)
+	result := fixture.RunTest(t)
 
 	foo := result.ModuleForTests("foo", "")
 	actual := foo.Rule("cc").Args["cFlags"]
-	expected := "-E -DANDROID"
+	expected := "-E -DANDROID -Ifoo/bar"
 	android.AssertStringEquals(t, "cflags should be correct", expected, actual)
 }
diff --git a/cc/cc_test.go b/cc/cc_test.go
index d7ad6bc..2e6c152 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
 	"reflect"
 	"regexp"
 	"runtime"
+	"slices"
 	"strings"
 	"testing"
 
@@ -381,7 +382,7 @@
 	if !strings.HasSuffix(outputPath, "/main_test") {
 		t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
 	}
-	entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
+	entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
 	if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
 		t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
 			" but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
@@ -409,7 +410,7 @@
 	ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext
 	module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
 
-	entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
+	entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
 	compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"]
 	if len(compatEntries) != 2 {
 		t.Errorf("expected two elements in LOCAL_COMPATIBILITY_SUITE. got %d", len(compatEntries))
@@ -441,7 +442,7 @@
 	ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext
 	module := ctx.ModuleForTests("main_test_lib", "android_arm_armv7-a-neon_shared").Module()
 
-	entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
+	entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
 	compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"]
 	if len(compatEntries) != 2 {
 		t.Errorf("expected two elements in LOCAL_COMPATIBILITY_SUITE. got %d", len(compatEntries))
@@ -1430,7 +1431,7 @@
 	if !strings.HasSuffix(outputPath, "/main_test") {
 		t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
 	}
-	entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo
+	entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
 	if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
 		t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
 			" but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
@@ -2742,10 +2743,18 @@
 		"${config.ArmToolchainCflags}",
 		"${config.ArmArmv7ANeonCflags}",
 		"${config.ArmGenericCflags}",
+	}
+
+	expectedTargetNDKFlags := []string{
 		"-target",
 		"armv7a-linux-androideabi21",
 	}
 
+	expectedTargetPlatformFlags := []string{
+		"-target",
+		"armv7a-linux-androideabi10000",
+	}
+
 	expectedIncludes := []string{
 		"external/foo/android_arm_export_include_dirs",
 		"external/foo/lib32_export_include_dirs",
@@ -2773,6 +2782,9 @@
 		"external/foo/libarm",
 		"external/foo/lib32",
 		"external/foo/libandroid_arm",
+	}
+
+	expectedNDKSTLIncludes := []string{
 		"defaults/cc/common/ndk_libc++_shared_include_dirs",
 	}
 
@@ -2783,38 +2795,89 @@
 	cstd := []string{"-std=gnu17", "-std=conly"}
 	cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"}
 
-	lastIncludes := []string{
+	lastNDKIncludes := []string{
 		"out/soong/ndk/sysroot/usr/include",
 		"out/soong/ndk/sysroot/usr/include/arm-linux-androideabi",
 	}
 
-	combineSlices := func(slices ...[]string) []string {
-		var ret []string
-		for _, s := range slices {
-			ret = append(ret, s...)
-		}
-		return ret
+	lastPlatformIncludes := []string{
+		"${config.CommonGlobalIncludes}",
 	}
 
 	testCases := []struct {
-		name     string
-		src      string
-		expected []string
+		name             string
+		src              string
+		expectedNDK      []string
+		expectedPlatform []string
 	}{
 		{
-			name:     "c",
-			src:      "foo.c",
-			expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+			name: "c",
+			src:  "foo.c",
+			expectedNDK: slices.Concat(
+				baseExpectedFlags,
+				expectedTargetNDKFlags,
+				conly,
+				expectedIncludes,
+				expectedNDKSTLIncludes,
+				cflags,
+				cstd,
+				lastNDKIncludes,
+				[]string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+			),
+			expectedPlatform: slices.Concat(
+				baseExpectedFlags,
+				expectedTargetPlatformFlags,
+				conly,
+				expectedIncludes,
+				cflags,
+				cstd,
+				lastPlatformIncludes,
+				[]string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+			),
 		},
 		{
-			name:     "cc",
-			src:      "foo.cc",
-			expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+			name: "cc",
+			src:  "foo.cc",
+			expectedNDK: slices.Concat(
+				baseExpectedFlags,
+				expectedTargetNDKFlags,
+				cppOnly,
+				expectedIncludes,
+				expectedNDKSTLIncludes,
+				cflags,
+				cppstd,
+				lastNDKIncludes,
+				[]string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+			),
+			expectedPlatform: slices.Concat(
+				baseExpectedFlags,
+				expectedTargetPlatformFlags,
+				cppOnly,
+				expectedIncludes,
+				cflags,
+				cppstd,
+				lastPlatformIncludes,
+				[]string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"},
+			),
 		},
 		{
-			name:     "assemble",
-			src:      "foo.s",
-			expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, lastIncludes),
+			name: "assemble",
+			src:  "foo.s",
+			expectedNDK: slices.Concat(
+				baseExpectedFlags,
+				expectedTargetNDKFlags,
+				[]string{"${config.CommonGlobalAsflags}"},
+				expectedIncludes,
+				expectedNDKSTLIncludes,
+				lastNDKIncludes,
+			),
+			expectedPlatform: slices.Concat(
+				baseExpectedFlags,
+				expectedTargetPlatformFlags,
+				[]string{"${config.CommonGlobalAsflags}"},
+				expectedIncludes,
+				lastPlatformIncludes,
+			),
 		},
 	}
 
@@ -2909,25 +2972,34 @@
 		`, lib, lib)
 			}
 
-			ctx := android.GroupFixturePreparers(
-				PrepareForIntegrationTestWithCc,
-				android.FixtureAddTextFile("external/foo/Android.bp", bp),
-			).RunTest(t)
-			cflags := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_sdk_static").Output("obj/external/foo/foo.o").Args["cFlags"]
+			runTest := func(t *testing.T, variant string, expected []string) {
+				ctx := android.GroupFixturePreparers(
+					PrepareForIntegrationTestWithCc,
+					android.FixtureAddTextFile("external/foo/Android.bp", bp),
+				).RunTest(t)
+				cflags := ctx.ModuleForTests("libfoo", variant).Output("obj/external/foo/foo.o").Args["cFlags"]
 
-			var includes []string
-			flags := strings.Split(cflags, " ")
-			for _, flag := range flags {
-				if strings.HasPrefix(flag, "-I") {
-					includes = append(includes, strings.TrimPrefix(flag, "-I"))
-				} else if flag == "-isystem" {
-					// skip isystem, include next
-				} else if len(flag) > 0 {
-					includes = append(includes, flag)
+				var includes []string
+				flags := strings.Split(cflags, " ")
+				for _, flag := range flags {
+					if strings.HasPrefix(flag, "-I") {
+						includes = append(includes, strings.TrimPrefix(flag, "-I"))
+					} else if flag == "-isystem" {
+						// skip isystem, include next
+					} else if len(flag) > 0 {
+						includes = append(includes, flag)
+					}
 				}
+
+				android.AssertArrayString(t, "includes", expected, includes)
 			}
 
-			android.AssertArrayString(t, "includes", tc.expected, includes)
+			t.Run("platform", func(t *testing.T) {
+				runTest(t, "android_arm_armv7-a-neon_static", tc.expectedPlatform)
+			})
+			t.Run("ndk", func(t *testing.T) {
+				runTest(t, "android_arm_armv7-a-neon_sdk_static", tc.expectedNDK)
+			})
 		})
 	}
 
diff --git a/cc/compiler.go b/cc/compiler.go
index 022b712..7bba962 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -695,7 +695,9 @@
 
 	if ctx.optimizeForSize() {
 		flags.Local.CFlags = append(flags.Local.CFlags, "-Oz")
-		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-enable-ml-inliner=release")
+		if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-enable-ml-inliner=release")
+		}
 	}
 
 	// Exclude directories from manual binder interface allowed list.
diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go
index 5a45767..1924b2f 100644
--- a/cc/library_headers_test.go
+++ b/cc/library_headers_test.go
@@ -46,7 +46,7 @@
 
 			// Test that there's a valid AndroidMk entry.
 			headers := ctx.ModuleForTests("headers", "android_arm64_armv8-a").Module()
-			e := android.AndroidMkInfoForTest(t, ctx, headers).PrimaryInfo
+			e := android.AndroidMkEntriesForTest(t, ctx, headers)[0]
 
 			// This duplicates the tests done in AndroidMkEntries.write. It would be
 			// better to test its output, but there are no test functions that capture that.
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 3214fb4..acbbabc 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -50,7 +50,6 @@
 		cc_prebuilt_library_shared {
 			name: "liba",
 			srcs: ["liba.so"],
-			prefer: true,
 		}
 
 		cc_library {
@@ -60,7 +59,6 @@
 		cc_prebuilt_library_static {
 			name: "libb",
 			srcs: ["libb.a"],
-			prefer: true,
 		}
 
 		cc_library_shared {
@@ -171,9 +169,9 @@
 		t.Errorf("crtx missing dependency on prebuilt_crtx")
 	}
 
-	entries := android.AndroidMkInfoForTest(t, ctx, prebuiltLiba).PrimaryInfo
+	entries := android.AndroidMkEntriesForTest(t, ctx, prebuiltLiba)[0]
 	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
-	entries = android.AndroidMkInfoForTest(t, ctx, prebuiltLibb).PrimaryInfo
+	entries = android.AndroidMkEntriesForTest(t, ctx, prebuiltLibb)[0]
 	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_static", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
 }
 
@@ -488,7 +486,7 @@
 		expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module()
 		android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency))
 		// check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N>
-		entries := android.AndroidMkInfoForTest(t, ctx, libfoo).PrimaryInfo
+		entries := android.AndroidMkEntriesForTest(t, ctx, libfoo)[0]
 		android.AssertStringListContains(t, "Version should not be present in LOCAL_SHARED_LIBRARIES", entries.EntryMap["LOCAL_SHARED_LIBRARIES"], "libbar")
 
 		// check installation rules
@@ -498,7 +496,7 @@
 
 		// check LOCAL_MODULE of the selected module name
 		// the prebuilt should have the same LOCAL_MODULE when exported to make
-		entries = android.AndroidMkInfoForTest(t, ctx, libbar).PrimaryInfo
+		entries = android.AndroidMkEntriesForTest(t, ctx, libbar)[0]
 		android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "libbar", entries.EntryMap["LOCAL_MODULE"][0])
 	}
 }
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 124dda4..118580e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -992,7 +992,7 @@
 	return flags
 }
 
-func (s *sanitize) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
+func (s *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
 	// both the sanitized and non-sanitized variants to make without a name conflict.
 	if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
@@ -1905,13 +1905,11 @@
 	ctx.SetOutputFiles(android.Paths{txt.outputFile}, "")
 }
 
-func (txt *sanitizerLibrariesTxtModule) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
-	return &android.AndroidMkProviderInfo{
-		PrimaryInfo: android.AndroidMkInfo{
-			Class:      "ETC",
-			OutputFile: android.OptionalPathForPath(txt.outputFile),
-		},
-	}
+func (txt *sanitizerLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(txt.outputFile),
+	}}
 }
 
 // PrebuiltEtcModule interface
diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go
index d7bb654..199c845 100644
--- a/filesystem/fsverity_metadata.go
+++ b/filesystem/fsverity_metadata.go
@@ -15,6 +15,7 @@
 package filesystem
 
 import (
+	"fmt"
 	"path/filepath"
 	"strings"
 
@@ -121,8 +122,13 @@
 
 	// STEP 2-2: generate BuildManifest.apk (unsigned)
 	aapt2Path := ctx.Config().HostToolPath(ctx, "aapt2")
-	apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", "BuildManifest.apk")
-	idsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", "BuildManifest.apk.idsig")
+	apkNameSuffix := ""
+	if f.PartitionType() == "system_ext" {
+		//https://source.corp.google.com/h/googleplex-android/platform/build/+/e392d2b486c2d4187b20a72b1c67cc737ecbcca5:core/Makefile;l=3410;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0
+		apkNameSuffix = "SystemExt"
+	}
+	apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix))
+	idsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix))
 	manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml")
 	libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs)
 	cmd.Implicit(aapt2Path)
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index ed954ac..1d64796 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -213,6 +213,7 @@
 	ctx.InstallFile(v.installDir, v.installFileName(), v.output)
 
 	ctx.SetOutputFiles([]android.Path{v.output}, "")
+	android.SetProvider(ctx, android.AndroidMkInfoProvider, v.prepareAndroidMKProviderInfo())
 }
 
 // Returns the embedded shell command that prints the rollback index
@@ -265,9 +266,7 @@
 	return result
 }
 
-var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil)
-
-func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
+func (v *vbmeta) prepareAndroidMKProviderInfo() *android.AndroidMkProviderInfo {
 	providerData := android.AndroidMkProviderInfo{
 		PrimaryInfo: android.AndroidMkInfo{
 			Class:      "ETC",
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index f446c2b..dc7becb 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -124,10 +124,19 @@
 					"public.libraries.android.txt": defaultDepCandidateProps(ctx.Config()),
 					"update_engine_sideload":       defaultDepCandidateProps(ctx.Config()),
 				},
-				"vendor":     newMultilibDeps(),
-				"odm":        newMultilibDeps(),
-				"product":    newMultilibDeps(),
-				"system_ext": newMultilibDeps(),
+				"vendor":  newMultilibDeps(),
+				"odm":     newMultilibDeps(),
+				"product": newMultilibDeps(),
+				"system_ext": &map[string]*depCandidateProps{
+					// VNDK apexes are automatically included.
+					// This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated.
+					// https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7
+					"com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
+					"com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
+				},
 			},
 			soongGeneratedPartitions: generatedPartitions,
 			fsDepsMutex:              sync.Mutex{},
@@ -226,43 +235,48 @@
 	soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions)
 	m := mctx.Module()
 	if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok {
-		depsStruct := packagingPropsStruct{}
-		for depName, depProps := range *fsDeps[partition] {
-			bitness := getBitness(depProps.Arch)
-			fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
-			if android.InList("32", bitness) && android.InList("64", bitness) {
-				// If both 32 and 64 bit variants are enabled for this module
-				switch depProps.Multilib {
-				case string(android.MultilibBoth):
-					depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
-				case string(android.MultilibCommon), string(android.MultilibFirst):
-					depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
-				case "32":
-					depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
-				case "64", "darwin_universal":
-					depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
-				case "prefer32", "first_prefer32":
-					depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
-				default:
-					depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
-				}
-			} else if android.InList("64", bitness) {
-				// If only 64 bit variant is enabled
-				depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
-			} else if android.InList("32", bitness) {
-				// If only 32 bit variant is enabled
-				depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
-			} else {
-				// If only common variant is enabled
-				depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
-			}
-		}
-		if err := proptools.AppendMatchingProperties(m.GetProperties(), &depsStruct, nil); err != nil {
+		depsStruct := generateDepStruct(*fsDeps[partition])
+		if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
 			mctx.ModuleErrorf(err.Error())
 		}
 	}
 }
 
+func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct {
+	depsStruct := packagingPropsStruct{}
+	for depName, depProps := range deps {
+		bitness := getBitness(depProps.Arch)
+		fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
+		if android.InList("32", bitness) && android.InList("64", bitness) {
+			// If both 32 and 64 bit variants are enabled for this module
+			switch depProps.Multilib {
+			case string(android.MultilibBoth):
+				depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+			case string(android.MultilibCommon), string(android.MultilibFirst):
+				depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
+			case "32":
+				depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+			case "64", "darwin_universal":
+				depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+			case "prefer32", "first_prefer32":
+				depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
+			default:
+				depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
+			}
+		} else if android.InList("64", bitness) {
+			// If only 64 bit variant is enabled
+			depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
+		} else if android.InList("32", bitness) {
+			// If only 32 bit variant is enabled
+			depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
+		} else {
+			// If only common variant is enabled
+			depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
+		}
+	}
+	return &depsStruct
+}
+
 type filesystemCreatorProps struct {
 	Generated_partition_types   []string `blueprint:"mutated"`
 	Unsupported_partition_types []string `blueprint:"mutated"`
@@ -331,10 +345,18 @@
 	ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps)
 }
 
-var (
-	// https://source.corp.google.com/h/googleplex-android/platform/build/+/639d79f5012a6542ab1f733b0697db45761ab0f3:core/packaging/flags.mk;l=21;drc=5ba8a8b77507f93aa48cc61c5ba3f31a4d0cbf37;bpv=1;bpt=0
-	partitionsWithAconfig = []string{"system", "product", "vendor"}
-)
+func partitionSpecificFsProps(fsProps *filesystem.FilesystemProperties, partitionType string) {
+	switch partitionType {
+	case "system":
+		fsProps.Build_logtags = proptools.BoolPtr(true)
+		// https://source.corp.google.com/h/googleplex-android/platform/build//639d79f5012a6542ab1f733b0697db45761ab0f3:core/packaging/flags.mk;l=21;drc=5ba8a8b77507f93aa48cc61c5ba3f31a4d0cbf37;bpv=1;bpt=0
+		fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
+	case "product":
+		fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
+	case "vendor":
+		fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
+	}
+}
 
 // Creates a soong module to build the given partition. Returns false if we can't support building
 // it.
@@ -406,8 +428,6 @@
 
 	fsProps.Base_dir = proptools.StringPtr(partitionType)
 
-	fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(android.InList(partitionType, partitionsWithAconfig))
-
 	fsProps.Is_auto_generated = proptools.BoolPtr(true)
 
 	// Identical to that of the generic_system_image
@@ -420,6 +440,9 @@
 		"framework/*/*",     // framework/{arch}
 		"framework/oat/*/*", // framework/oat/{arch}
 	}
+	fsProps.Fsverity.Libs = []string{":framework-res{.export-package.apk}"}
+
+	partitionSpecificFsProps(fsProps, partitionType)
 
 	// system_image properties that are not set:
 	// - filesystemProperties.Avb_hash_algorithm
@@ -431,7 +454,6 @@
 	// - filesystemProperties.Mount_point
 	// - filesystemProperties.Include_make_built_files
 	// - filesystemProperties.Build_logtags
-	// - filesystemProperties.Fsverity.Libs
 	// - systemImageProperties.Linker_config_src
 
 	return fsProps, true
@@ -499,10 +521,14 @@
 
 	var diffTestFiles []android.Path
 	for _, partitionType := range f.properties.Generated_partition_types {
-		diffTestFiles = append(diffTestFiles, f.createDiffTest(ctx, partitionType))
+		diffTestFile := f.createDiffTest(ctx, partitionType)
+		diffTestFiles = append(diffTestFiles, diffTestFile)
+		ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile)
 	}
 	for _, partitionType := range f.properties.Unsupported_partition_types {
-		diffTestFiles = append(diffTestFiles, createFailingCommand(ctx, fmt.Sprintf("Couldn't build %s partition", partitionType)))
+		diffTestFile := createFailingCommand(ctx, fmt.Sprintf("Couldn't build %s partition", partitionType))
+		diffTestFiles = append(diffTestFiles, diffTestFile)
+		ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile)
 	}
 	ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...)
 }
@@ -512,14 +538,14 @@
 	if partitionType != "system" {
 		return ""
 	}
+	fsProps, fsTypeSupported := generateFsProps(ctx, partitionType)
+	if !fsTypeSupported {
+		return ""
+	}
 
 	baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType)))
-	fsProps, _ := generateFsProps(ctx, partitionType)
-
-	deps := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps
-	depProps := &android.PackagingProperties{
-		Deps: android.NewSimpleConfigurable(fullyQualifiedModuleNames(deps[partitionType])),
-	}
+	deps := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps[partitionType]
+	depProps := generateDepStruct(*deps)
 
 	result, err := proptools.RepackProperties([]interface{}{baseProps, fsProps, depProps})
 	if err != nil {
diff --git a/java/app.go b/java/app.go
index dd99675..69fdc47 100644
--- a/java/app.go
+++ b/java/app.go
@@ -30,7 +30,6 @@
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
-	"android/soong/genrule"
 	"android/soong/tradefed"
 )
 
@@ -679,7 +678,7 @@
 		a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
 	}
 	a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex
-	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries(ctx)
 	a.dexpreopter.classLoaderContexts = a.classLoaderContexts
 	a.dexpreopter.manifestFile = a.mergedManifestFile
 	a.dexpreopter.preventInstall = a.appProperties.PreventInstall
@@ -908,10 +907,10 @@
 	// Process all building blocks, from AAPT to certificates.
 	a.aaptBuildActions(ctx)
 	// The decision to enforce <uses-library> checks is made before adding implicit SDK libraries.
-	a.usesLibrary.freezeEnforceUsesLibraries()
+	a.usesLibrary.freezeEnforceUsesLibraries(ctx)
 
 	// Check that the <uses-library> list is coherent with the manifest.
-	if a.usesLibrary.enforceUsesLibraries() {
+	if a.usesLibrary.enforceUsesLibraries(ctx) {
 		manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(
 			ctx, a.mergedManifestFile, &a.classLoaderContexts)
 		apkDeps = append(apkDeps, manifestCheckFile)
@@ -1333,7 +1332,7 @@
 			Srcs:  []string{":" + a.Name() + "{.apk}"},
 			Cmd:   proptools.StringPtr("$(location characteristics_rro_generator) $$($(location aapt2) dump packagename $(in)) $(out)"),
 		}
-		ctx.CreateModule(genrule.GenRuleFactory, &rroManifestProperties)
+		ctx.CreateModule(GenRuleFactory, &rroManifestProperties)
 
 		rroProperties := struct {
 			Name           *string
@@ -1687,11 +1686,11 @@
 
 type UsesLibraryProperties struct {
 	// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file.
-	Uses_libs []string
+	Uses_libs proptools.Configurable[[]string]
 
 	// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file with
 	// required=false.
-	Optional_uses_libs []string
+	Optional_uses_libs proptools.Configurable[[]string]
 
 	// If true, the list of uses_libs and optional_uses_libs modules must match the AndroidManifest.xml file.  Defaults
 	// to true if either uses_libs or optional_uses_libs is set.  Will unconditionally default to true in the future.
@@ -1739,7 +1738,7 @@
 
 func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps bool) {
 	if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() {
-		ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs...)
+		ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs.GetOrDefault(ctx, nil)...)
 		presentOptionalUsesLibs := u.presentOptionalUsesLibs(ctx)
 		ctx.AddVariationDependencies(nil, usesLibOptTag, presentOptionalUsesLibs...)
 		// Only add these extra dependencies if the module is an app that depends on framework
@@ -1752,17 +1751,17 @@
 			ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
 			ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
 		}
-		_, diff, _ := android.ListSetDifference(u.usesLibraryProperties.Optional_uses_libs, presentOptionalUsesLibs)
+		_, diff, _ := android.ListSetDifference(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil), presentOptionalUsesLibs)
 		u.usesLibraryProperties.Missing_optional_uses_libs = diff
 	} else {
-		ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs...)
+		ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs.GetOrDefault(ctx, nil)...)
 		ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.presentOptionalUsesLibs(ctx)...)
 	}
 }
 
 // presentOptionalUsesLibs returns optional_uses_libs after filtering out libraries that don't exist in the source tree.
 func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string {
-	optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs, func(s string) bool {
+	optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil), func(s string) bool {
 		exists := ctx.OtherModuleExists(s)
 		if !exists && !android.InList(ctx.ModuleName(), ctx.Config().BuildWarningBadOptionalUsesLibsAllowlist()) {
 			fmt.Printf("Warning: Module '%s' depends on non-existing optional_uses_libs '%s'\n", ctx.ModuleName(), s)
@@ -1828,15 +1827,15 @@
 // enforceUsesLibraries returns true of <uses-library> tags should be checked against uses_libs and optional_uses_libs
 // properties.  Defaults to true if either of uses_libs or optional_uses_libs is specified.  Will default to true
 // unconditionally in the future.
-func (u *usesLibrary) enforceUsesLibraries() bool {
-	defaultEnforceUsesLibs := len(u.usesLibraryProperties.Uses_libs) > 0 ||
-		len(u.usesLibraryProperties.Optional_uses_libs) > 0
+func (u *usesLibrary) enforceUsesLibraries(ctx android.ModuleContext) bool {
+	defaultEnforceUsesLibs := len(u.usesLibraryProperties.Uses_libs.GetOrDefault(ctx, nil)) > 0 ||
+		len(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) > 0
 	return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, u.enforce || defaultEnforceUsesLibs)
 }
 
 // Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`.
-func (u *usesLibrary) freezeEnforceUsesLibraries() {
-	enforce := u.enforceUsesLibraries()
+func (u *usesLibrary) freezeEnforceUsesLibraries(ctx android.ModuleContext) {
+	enforce := u.enforceUsesLibraries(ctx)
 	u.usesLibraryProperties.Enforce_uses_libs = &enforce
 }
 
diff --git a/java/app_import.go b/java/app_import.go
index f5d9f3e..6b88f1c 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -364,13 +364,13 @@
 	a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
 	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
 
-	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries(ctx)
 	a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 	if a.usesLibrary.shouldDisableDexpreopt {
 		a.dexpreopter.disableDexpreopt()
 	}
 
-	if a.usesLibrary.enforceUsesLibraries() {
+	if a.usesLibrary.enforceUsesLibraries(ctx) {
 		a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk, &a.dexpreopter.classLoaderContexts)
 	}
 
diff --git a/java/base.go b/java/base.go
index 19f6c5d..f075dbd 100644
--- a/java/base.go
+++ b/java/base.go
@@ -865,7 +865,7 @@
 					// explicitly listed in the optional_uses_libs property.
 					tag := usesLibReqTag
 					if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) ||
-						android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs) {
+						android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) {
 						tag = usesLibOptTag
 					}
 					ctx.AddVariationDependencies(nil, tag, *lib)
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 637da36..5928446 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -562,7 +562,7 @@
 	// TODO(b/346662300): Let dexpreopter generate the installPath for dexpreopt files instead of
 	// using the dex location to generate the installPath.
 	if isApexSystemServerJar {
-		dexpreoptPartition = "system"
+		dexpreoptPartition = dexpreoptConfig.ApexPartition
 	}
 	for _, install := range dexpreoptRule.Installs() {
 		// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
diff --git a/java/java.go b/java/java.go
index 288042b..8b30262 100644
--- a/java/java.go
+++ b/java/java.go
@@ -3343,7 +3343,7 @@
 	if sdkLib != nil {
 		optional := false
 		if module, ok := ctx.Module().(ModuleWithUsesLibrary); ok {
-			if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs) {
+			if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) {
 				optional = true
 			}
 		}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 7fa6ddb..0d2acae 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -298,10 +298,10 @@
 	platformBootclasspath := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
 	entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
 	goals := entries[0].GetDistForGoals(platformBootclasspath)
-	android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore", goals[0])
+	android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
 	android.AssertStringDoesContain(t, "platform dist goals meta check", goals[1], "$(if $(strip $(ALL_TARGETS.")
 	android.AssertStringDoesContain(t, "platform dist goals meta assign", goals[1], "),,$(eval ALL_TARGETS.")
-	android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)", android.StringRelativeToTop(result.Config, goals[2]))
+	android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[2]))
 }
 
 func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) {
diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go
index ca088cf..768e57a 100644
--- a/java/sdk_library_internal.go
+++ b/java/sdk_library_internal.go
@@ -566,7 +566,7 @@
 		Min_device_sdk            *string
 		Max_device_sdk            *string
 		Sdk_library_min_api_level *string
-		Uses_libs_dependencies    []string
+		Uses_libs_dependencies    proptools.Configurable[[]string]
 	}{
 		Name:                      proptools.StringPtr(module.xmlPermissionsModuleName()),
 		Enabled:                   module.EnabledProperty(),
@@ -577,7 +577,7 @@
 		Min_device_sdk:            module.commonSdkLibraryProperties.Min_device_sdk,
 		Max_device_sdk:            module.commonSdkLibraryProperties.Max_device_sdk,
 		Sdk_library_min_api_level: &moduleMinApiLevelStr,
-		Uses_libs_dependencies:    module.usesLibraryProperties.Uses_libs,
+		Uses_libs_dependencies:    module.usesLibraryProperties.Uses_libs.Clone(),
 	}
 
 	mctx.CreateModule(sdkLibraryXmlFactory, &props)
@@ -742,7 +742,7 @@
 	// Uses-libs dependencies that the shared library requires to work correctly.
 	//
 	// This will add dependency="foo:bar" to the <library> section.
-	Uses_libs_dependencies []string
+	Uses_libs_dependencies proptools.Configurable[[]string]
 }
 
 // java_sdk_library_xml builds the permission xml file for a java_sdk_library.
@@ -864,7 +864,7 @@
 	implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
 	minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
 	maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
-	dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies)
+	dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies.GetOrDefault(ctx, nil))
 	// <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
 	// similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T
 	var libraryTag string
diff --git a/ui/build/config.go b/ui/build/config.go
index 75edfcd..9ec04a0 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -98,7 +98,6 @@
 	buildFromSourceStub      bool
 	incrementalBuildActions  bool
 	ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
-	partialCompileFlags      partialCompileFlags
 
 	// From the product config
 	katiArgs        []string
@@ -138,16 +137,6 @@
 	ninjaCommand ninjaCommandType
 }
 
-type partialCompileFlags struct {
-	// Is partial compilation enabled at all?
-	enabled bool
-
-	// Whether to use d8 instead of r8
-	use_d8 bool
-
-	// Add others as needed.
-}
-
 type NinjaWeightListSource uint
 
 const (
@@ -304,12 +293,24 @@
 		ret.sandboxConfig.SetSrcDirIsRO(srcDirIsWritable == "false")
 	}
 
-	ret.partialCompileFlags = parsePartialCompileFlags(ctx)
-
 	if os.Getenv("GENERATE_SOONG_DEBUG") == "true" {
 		ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json"))
 	}
 
+	// If SOONG_USE_PARTIAL_COMPILE is set, make it one of "true" or the empty string.
+	// This simplifies the generated Ninja rules, so that they only need to check for the empty string.
+	if value, ok := os.LookupEnv("SOONG_USE_PARTIAL_COMPILE"); ok {
+		if value == "true" || value == "1" || value == "y" || value == "yes" {
+			value = "true"
+		} else {
+			value = ""
+		}
+		err = os.Setenv("SOONG_USE_PARTIAL_COMPILE", value)
+		if err != nil {
+			ctx.Fatalln("Failed to set SOONG_USE_PARTIAL_COMPILE: %v", err)
+		}
+	}
+
 	ret.ninjaCommand = NINJA_NINJA
 	switch os.Getenv("SOONG_NINJA") {
 	case "n2":
@@ -382,7 +383,6 @@
 		// Use config.ninjaCommand instead.
 		"SOONG_NINJA",
 		"SOONG_USE_N2",
-		"SOONG_PARTIAL_COMPILE",
 	)
 
 	if ret.UseGoma() || ret.ForceUseGoma() {
@@ -501,78 +501,6 @@
 	return c
 }
 
-// Parse SOONG_PARTIAL_COMPILE.
-//
-// The user-facing documentation shows:
-//
-// - empty or not set: "The current default state"
-// - "true" or "on": enable all stable partial compile features.
-// - "false" or "off": disable partial compile completely.
-//
-// What we actually allow is a comma separated list of tokens, whose first
-// character may be "+" (enable) or "-" (disable).  If neither is present, "+"
-// is assumed.  For example, "on,+use_d8" will enable partial compilation, and
-// additionally set the use_d8 flag (regardless of whether it is opt-in or
-// opt-out).
-//
-// To add a new feature to the list, add the field in the struct
-// `partialCompileFlags` above, and then add the name of the field in the
-// switch statement below.
-func parsePartialCompileFlags(ctx Context) partialCompileFlags {
-	defaultFlags := partialCompileFlags{
-		// Set any opt-out flags here.  Opt-in flags are off by default.
-		enabled: false,
-	}
-	value, ok := os.LookupEnv("SOONG_PARTIAL_COMPILE")
-
-	if !ok {
-		return defaultFlags
-	}
-
-	ret := defaultFlags
-	tokens := strings.Split(strings.ToLower(value), ",")
-	makeVal := func(state string, defaultValue bool) bool {
-		switch state {
-		case "":
-			return defaultValue
-		case "-":
-			return false
-		case "+":
-			return true
-		}
-		return false
-	}
-	for _, tok := range tokens {
-		var state string
-		switch tok[0:1] {
-		case "":
-			// Ignore empty tokens.
-			continue
-		case "-", "+":
-			state = tok[0:1]
-			tok = tok[1:]
-		default:
-			// Treat `feature` as `+feature`.
-			state = "+"
-		}
-		switch tok {
-		case "true", "on", "yes":
-			ret = defaultFlags
-			ret.enabled = true
-		case "false", "off", "no":
-			// Set everything to false.
-			ret = partialCompileFlags{}
-		case "enabled":
-			ret.enabled = makeVal(state, defaultFlags.enabled)
-		case "use_d8":
-			ret.use_d8 = makeVal(state, defaultFlags.use_d8)
-		default:
-			ctx.Fatalln("Unknown SOONG_PARTIAL_COMPILE value:", value)
-		}
-	}
-	return ret
-}
-
 // NewBuildActionConfig returns a build configuration based on the build action. The arguments are
 // processed based on the build action and extracts any arguments that belongs to the build action.
 func NewBuildActionConfig(action BuildAction, dir string, ctx Context, args ...string) Config {
@@ -1855,10 +1783,6 @@
 	return c.ensureAllowlistIntegrity
 }
 
-func (c *configImpl) PartialCompileFlags() partialCompileFlags {
-	return c.partialCompileFlags
-}
-
 // Returns a Time object if one was passed via a command-line flag.
 // Otherwise returns the passed default.
 func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time {
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 5743ff7..4dfb710 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -183,6 +183,23 @@
 		username = usernameFromEnv
 	}
 
+	// SOONG_USE_PARTIAL_COMPILE may be used in makefiles, but both cases must be supported.
+	//
+	// In general, the partial compile features will be implemented in Soong-based rules. We
+	// also allow them to be used in makefiles.  Clear the environment variable when calling
+	// kati so that we avoid reanalysis when the user changes it.  We will pass it to Ninja.
+	// As a result, rules where we want to allow the developer to toggle the feature ("use
+	// the partial compile feature" vs "legacy, aka full compile behavior") need to use this
+	// in the rule, since changing it will not cause reanalysis.
+	//
+	// Shell syntax in the rule might look something like this:
+	//     if [[ -n ${SOONG_USE_PARTIAL_COMPILE} ]]; then
+	//         # partial compile behavior
+	//     else
+	//         # legacy behavior
+	//     fi
+	cmd.Environment.Unset("SOONG_USE_PARTIAL_COMPILE")
+
 	hostname, ok := cmd.Environment.Get("BUILD_HOSTNAME")
 	// Unset BUILD_HOSTNAME during kati run to avoid kati rerun, kati will use BUILD_HOSTNAME from a file.
 	cmd.Environment.Unset("BUILD_HOSTNAME")
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index def0783..f5f637f 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -241,6 +241,9 @@
 			"SOONG_USE_N2",
 			"RUST_BACKTRACE",
 			"RUST_LOG",
+
+			// SOONG_USE_PARTIAL_COMPILE only determines which half of the rule we execute.
+			"SOONG_USE_PARTIAL_COMPILE",
 		}, config.BuildBrokenNinjaUsesEnvVars()...)...)
 	}