Merge "Skip unknown check in bootclasspath_fragment (source version) if prebuilt version is in use." into main
diff --git a/Android.bp b/Android.bp
index 63de015..b1db8e9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -130,3 +130,8 @@
     // Currently, only microdroid can refer to buildinfo.prop
     visibility: ["//packages/modules/Virtualization/microdroid"],
 }
+
+// container for apex_contributions selected using build flags
+all_apex_contributions {
+    name: "all_apex_contributions",
+}
diff --git a/OWNERS b/OWNERS
index c52231e..e5374ed 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 99142
 # This file is included by several other projects as the list of people
 # approving build related projects.
 
diff --git a/aconfig/cc_aconfig_library.go b/aconfig/cc_aconfig_library.go
index 5b0fb4a..8aa696b 100644
--- a/aconfig/cc_aconfig_library.go
+++ b/aconfig/cc_aconfig_library.go
@@ -39,7 +39,14 @@
 	Aconfig_declarations string
 
 	// whether to generate test mode version of the library
+	// TODO: remove "Test" property when "Mode" can be used in all the branches
 	Test *bool
+
+	// default mode is "production", the other accepted modes are:
+	// "test": to generate test mode version of the library
+	// "exported": to generate exported mode version of the library
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type CcAconfigLibraryCallbacks struct {
@@ -121,11 +128,16 @@
 	}
 	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
 
-	var mode string
+	if this.properties.Mode != nil && this.properties.Test != nil {
+		ctx.PropertyErrorf("test", "test prop should not be specified when mode prop is set")
+	}
+	mode := proptools.StringDefault(this.properties.Mode, "production")
+	if !isModeSupported(mode) {
+		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
+	}
+	// TODO: remove "Test" property
 	if proptools.Bool(this.properties.Test) {
 		mode = "test"
-	} else {
-		mode = "production"
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:  cppRule,
diff --git a/aconfig/cc_aconfig_library_test.go b/aconfig/cc_aconfig_library_test.go
index 6f17c75..9a819e5 100644
--- a/aconfig/cc_aconfig_library_test.go
+++ b/aconfig/cc_aconfig_library_test.go
@@ -22,16 +22,17 @@
 	"android/soong/cc"
 )
 
-var codegenModeTestData = []struct {
+var ccCodegenModeTestData = []struct {
 	setting, expected string
 }{
 	{"", "production"},
-	{"test: false,", "production"},
-	{"test: true,", "test"},
+	{"mode: `production`,", "production"},
+	{"mode: `test`,", "test"},
+	{"mode: `exported`,", "exported"},
 }
 
 func TestCCCodegenMode(t *testing.T) {
-	for _, testData := range codegenModeTestData {
+	for _, testData := range ccCodegenModeTestData {
 		testCCCodegenModeHelper(t, testData.setting, testData.expected)
 	}
 }
@@ -65,3 +66,43 @@
 	rule := module.Rule("cc_aconfig_library")
 	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
 }
+
+var incorrectCCCodegenModeTestData = []struct {
+	setting, expectedErr string
+}{
+	{"mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode"},
+	// TODO: remove this test case when test prop is removed
+	{"mode: `test`, test: true", "test prop should not be specified when mode prop is set"},
+}
+
+func TestIncorrectCCCodegenMode(t *testing.T) {
+	for _, testData := range incorrectCCCodegenModeTestData {
+		testIncorrectCCCodegenModeHelper(t, testData.setting, testData.expectedErr)
+	}
+}
+
+func testIncorrectCCCodegenModeHelper(t *testing.T, bpMode string, err string) {
+	t.Helper()
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		cc.PrepareForTestWithCcDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			cc_library {
+    		name: "server_configurable_flags",
+    		srcs: ["server_configurable_flags.cc"],
+			}
+
+			cc_aconfig_library {
+				name: "my_cc_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+}
diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go
index f7f8db8..b6c90fc 100644
--- a/aconfig/java_aconfig_library.go
+++ b/aconfig/java_aconfig_library.go
@@ -30,12 +30,21 @@
 
 var declarationsTag = declarationsTagType{}
 
+var aconfigSupportedModes = []string{"production", "test", "exported"}
+
 type JavaAconfigDeclarationsLibraryProperties struct {
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
 
 	// whether to generate test mode version of the library
+	// TODO: remove "Test" property when "Mode" can be used in all the branches
 	Test *bool
+
+	// default mode is "production", the other accepted modes are:
+	// "test": to generate test mode version of the library
+	// "exported": to generate exported mode version of the library
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type JavaAconfigDeclarationsLibraryCallbacks struct {
@@ -72,12 +81,19 @@
 
 	// Generate the action to build the srcjar
 	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
-	var mode string
+
+	if callbacks.properties.Mode != nil && callbacks.properties.Test != nil {
+		ctx.PropertyErrorf("test", "test prop should not be specified when mode prop is set")
+	}
+	mode := proptools.StringDefault(callbacks.properties.Mode, "production")
+	if !isModeSupported(mode) {
+		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
+	}
+	// TODO: remove "Test" property
 	if proptools.Bool(callbacks.properties.Test) {
 		mode = "test"
-	} else {
-		mode = "production"
 	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        javaRule,
 		Input:       declarations.IntermediatePath,
@@ -95,9 +111,12 @@
 	return srcJarPath
 }
 
+func isModeSupported(mode string) bool {
+	return android.InList(mode, aconfigSupportedModes)
+}
+
 type bazelJavaAconfigLibraryAttributes struct {
 	Aconfig_declarations bazel.LabelAttribute
-	Test                 *bool
 	Sdk_version          *string
 	Libs                 bazel.LabelListAttribute
 }
@@ -138,7 +157,6 @@
 
 	attrs := bazelJavaAconfigLibraryAttributes{
 		Aconfig_declarations: *bazel.MakeLabelAttribute(android.BazelLabelForModuleDepSingle(ctx, callbacks.properties.Aconfig_declarations).Label),
-		Test:                 callbacks.properties.Test,
 		Sdk_version:          &sdkVersion,
 		Libs:                 libs,
 	}
diff --git a/aconfig/java_aconfig_library_test.go b/aconfig/java_aconfig_library_test.go
index af50848..05532e7 100644
--- a/aconfig/java_aconfig_library_test.go
+++ b/aconfig/java_aconfig_library_test.go
@@ -178,14 +178,48 @@
 	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
 }
 
+func testCodegenModeWithError(t *testing.T, bpMode string, err string) {
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			java_aconfig_library {
+				name: "my_java_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+}
+
 func TestDefaultProdMode(t *testing.T) {
 	testCodegenMode(t, "", "production")
 }
 
 func TestProdMode(t *testing.T) {
-	testCodegenMode(t, "test: false,", "production")
+	testCodegenMode(t, "mode: `production`,", "production")
 }
 
 func TestTestMode(t *testing.T) {
-	testCodegenMode(t, "test: true,", "test")
+	testCodegenMode(t, "mode: `test`,", "test")
+}
+
+func TestExportedMode(t *testing.T) {
+	testCodegenMode(t, "mode: `exported`,", "exported")
+}
+
+func TestUnsupportedMode(t *testing.T) {
+	testCodegenModeWithError(t, "mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode")
+}
+
+// TODO: remove this test case when test prop is removed
+func TestBothModeAndTestAreSet(t *testing.T) {
+	testCodegenModeWithError(t, "mode: `test`, test: true",
+		"test prop should not be specified when mode prop is set")
 }
diff --git a/aconfig/rust_aconfig_library.go b/aconfig/rust_aconfig_library.go
index de41776..43078b6 100644
--- a/aconfig/rust_aconfig_library.go
+++ b/aconfig/rust_aconfig_library.go
@@ -1,9 +1,10 @@
 package aconfig
 
 import (
+	"fmt"
+
 	"android/soong/android"
 	"android/soong/rust"
-	"fmt"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -18,7 +19,16 @@
 type RustAconfigLibraryProperties struct {
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
-	Test                 *bool
+
+	// whether to generate test mode version of the library
+	// TODO: remove "Test" property when "Mode" can be used in all the branches
+	Test *bool
+
+	// default mode is "production", the other accepted modes are:
+	// "test": to generate test mode version of the library
+	// "exported": to generate exported mode version of the library
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type aconfigDecorator struct {
@@ -60,7 +70,15 @@
 	}
 	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
 
-	mode := "production"
+	if a.Properties.Mode != nil && a.Properties.Test != nil {
+		ctx.PropertyErrorf("test", "test prop should not be specified when mode prop is set")
+	}
+	mode := proptools.StringDefault(a.Properties.Mode, "production")
+	if !isModeSupported(mode) {
+		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
+	}
+
+	// TODO: remove "Test" property
 	if proptools.Bool(a.Properties.Test) {
 		mode = "test"
 	}
@@ -84,6 +102,7 @@
 func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps {
 	deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps)
 	deps.Rustlibs = append(deps.Rustlibs, "libflags_rust")
+	deps.Rustlibs = append(deps.Rustlibs, "liblazy_static")
 	ctx.AddDependency(ctx.Module(), rustDeclarationsTag, a.Properties.Aconfig_declarations)
 	return deps
 }
diff --git a/aconfig/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go
index 17385c3..5e630b5 100644
--- a/aconfig/rust_aconfig_library_test.go
+++ b/aconfig/rust_aconfig_library_test.go
@@ -1,10 +1,11 @@
 package aconfig
 
 import (
-	"android/soong/android"
-	"android/soong/rust"
 	"fmt"
 	"testing"
+
+	"android/soong/android"
+	"android/soong/rust"
 )
 
 func TestRustAconfigLibrary(t *testing.T) {
@@ -22,6 +23,11 @@
 				crate_name: "flags_rust",
 				srcs: ["lib.rs"],
 			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+			}
 			aconfig_declarations {
 				name: "my_aconfig_declarations",
 				package: "com.example.package",
@@ -58,3 +64,98 @@
 		)
 	}
 }
+
+var rustCodegenModeTestData = []struct {
+	setting, expected string
+}{
+	{"", "production"},
+	{"mode: `production`,", "production"},
+	{"mode: `test`,", "test"},
+	{"mode: `exported`,", "exported"},
+}
+
+func TestRustCodegenMode(t *testing.T) {
+	for _, testData := range rustCodegenModeTestData {
+		testRustCodegenModeHelper(t, testData.setting, testData.expected)
+	}
+}
+
+func testRustCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) {
+	t.Helper()
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		rust.PrepareForTestWithRustIncludeVndk).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library",
+				crate_name: "my_rust_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+
+	module := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source")
+	rule := module.Rule("rust_aconfig_library")
+	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
+}
+
+var incorrectRustCodegenModeTestData = []struct {
+	setting, expectedErr string
+}{
+	{"mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode"},
+	// TODO: remove this test case when test prop is removed
+	{"mode: `test`, test: true", "test prop should not be specified when mode prop is set"},
+}
+
+func TestIncorrectRustCodegenMode(t *testing.T) {
+	for _, testData := range incorrectRustCodegenModeTestData {
+		testIncorrectRustCodegenModeHelper(t, testData.setting, testData.expectedErr)
+	}
+}
+
+func testIncorrectRustCodegenModeHelper(t *testing.T, bpMode string, err string) {
+	t.Helper()
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		rust.PrepareForTestWithRustIncludeVndk).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
+		RunTestWithBp(t, fmt.Sprintf(`
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library",
+				crate_name: "my_rust_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+}
diff --git a/android/Android.bp b/android/Android.bp
index f5bb785..7fbba43 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -32,6 +32,7 @@
     srcs: [
         "androidmk.go",
         "apex.go",
+        "apex_contributions.go",
         "api_domain.go",
         "api_levels.go",
         "arch.go",
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
new file mode 100644
index 0000000..6eaca8b
--- /dev/null
+++ b/android/apex_contributions.go
@@ -0,0 +1,175 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	RegisterApexContributionsBuildComponents(InitRegistrationContext)
+}
+
+func RegisterApexContributionsBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("apex_contributions", apexContributionsFactory)
+	ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory)
+}
+
+type apexContributions struct {
+	ModuleBase
+	properties contributionProps
+}
+
+type contributionProps struct {
+	// Name of the mainline module
+	Api_domain *string
+	// A list of module names that should be used when this contribution
+	// is selected via product_config
+	// The name should be explicit (foo or prebuilt_foo)
+	Contents []string
+}
+
+func (m *apexContributions) ApiDomain() string {
+	return proptools.String(m.properties.Api_domain)
+}
+
+func (m *apexContributions) Contents() []string {
+	return m.properties.Contents
+}
+
+// apex_contributions contains a list of module names (source or
+// prebuilt) belonging to the mainline module
+// An apex can have multiple apex_contributions modules
+// with different combinations of source or prebuilts, but only one can be
+// selected via product_config.
+func apexContributionsFactory() Module {
+	module := &apexContributions{}
+	module.AddProperties(&module.properties)
+	InitAndroidModule(module)
+	return module
+}
+
+// This module type does not have any build actions.
+// It provides metadata that is used in post-deps mutator phase for source vs
+// prebuilts selection.
+func (m *apexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+// A container for apex_contributions.
+// Based on product_config, it will create a dependency on the selected
+// apex_contributions per mainline module
+type allApexContributions struct {
+	SingletonModuleBase
+}
+
+func allApexContributionsFactory() SingletonModule {
+	module := &allApexContributions{}
+	InitAndroidModule(module)
+	return module
+}
+
+type apexContributionsDepTag struct {
+	blueprint.BaseDependencyTag
+}
+
+var (
+	acDepTag = apexContributionsDepTag{}
+)
+
+// Creates a dep to each selected apex_contributions
+func (a *allApexContributions) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), acDepTag, ctx.Config().AllApexContributions()...)
+}
+
+// Set PrebuiltSelectionInfoProvider in post deps phase
+func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) {
+	addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) {
+		for _, content := range m.Contents() {
+			if !ctx.OtherModuleExists(content) {
+				ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name())
+			}
+			pi := &PrebuiltSelectionInfo{
+				baseModuleName:     RemoveOptionalPrebuiltPrefix(content),
+				selectedModuleName: content,
+				metadataModuleName: m.Name(),
+				apiDomain:          m.ApiDomain(),
+			}
+			p.Add(ctx, pi)
+		}
+	}
+
+	if ctx.Config().Bp2buildMode() { // Skip bp2build
+		return
+	}
+	p := PrebuiltSelectionInfoMap{}
+	ctx.VisitDirectDepsWithTag(acDepTag, func(child Module) {
+		if m, ok := child.(*apexContributions); ok {
+			addContentsToProvider(&p, m)
+		} else {
+			ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name())
+		}
+	})
+	ctx.SetProvider(PrebuiltSelectionInfoProvider, p)
+}
+
+// A provider containing metadata about whether source or prebuilt should be used
+// This provider will be used in prebuilt_select mutator to redirect deps
+var PrebuiltSelectionInfoProvider = blueprint.NewMutatorProvider(PrebuiltSelectionInfoMap{}, "prebuilt_select")
+
+// Map of baseModuleName to the selected source or prebuilt
+type PrebuiltSelectionInfoMap map[string]PrebuiltSelectionInfo
+
+// Add a new entry to the map with some validations
+func (pm *PrebuiltSelectionInfoMap) Add(ctx BaseModuleContext, p *PrebuiltSelectionInfo) {
+	if p == nil {
+		return
+	}
+	// Do not allow dups. If the base module (without the prebuilt_) has been added before, raise an exception.
+	if old, exists := (*pm)[p.baseModuleName]; exists {
+		ctx.ModuleErrorf("Cannot use Soong module: %s from apex_contributions: %s because it has been added previously as: %s from apex_contributions: %s\n",
+			p.selectedModuleName, p.metadataModuleName, old.selectedModuleName, old.metadataModuleName,
+		)
+	}
+	(*pm)[p.baseModuleName] = *p
+}
+
+type PrebuiltSelectionInfo struct {
+	// e.g. libc
+	baseModuleName string
+	// e.g. (libc|prebuilt_libc)
+	selectedModuleName string
+	// Name of the apex_contributions module
+	metadataModuleName string
+	// e.g. com.android.runtime
+	apiDomain string
+}
+
+// Returns true if `name` is explicitly requested using one of the selected
+// apex_contributions metadata modules.
+func (p *PrebuiltSelectionInfoMap) IsSelected(baseModuleName, name string) bool {
+	if i, exists := (*p)[baseModuleName]; exists {
+		return i.selectedModuleName == name
+	} else {
+		return false
+	}
+}
+
+// This module type does not have any build actions.
+func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (a *allApexContributions) GenerateSingletonBuildActions(ctx SingletonContext) {
+}
diff --git a/android/config.go b/android/config.go
index 8300ef9..bf0b9de 100644
--- a/android/config.go
+++ b/android/config.go
@@ -99,7 +99,7 @@
 
 	UseBazelProxy bool
 
-	BuildFromTextStub bool
+	BuildFromSourceStub bool
 
 	EnsureAllowlistIntegrity bool
 }
@@ -167,8 +167,7 @@
 }
 
 // DisableHiddenApiChecks returns true if hiddenapi checks have been disabled.
-// For 'eng' target variant hiddenapi checks are disabled by default for performance optimisation
-// Hiddenapi checks are also disabled when RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE is set to false
+// For 'eng' target variant hiddenapi checks are disabled by default for performance optimisation,
 // but can be enabled by setting environment variable ENABLE_HIDDENAPI_FLAGS=true.
 // For other target variants hiddenapi check are enabled by default but can be disabled by
 // setting environment variable UNSAFE_DISABLE_HIDDENAPI_FLAGS=true.
@@ -177,8 +176,16 @@
 func (c Config) DisableHiddenApiChecks() bool {
 	return !c.IsEnvTrue("ENABLE_HIDDENAPI_FLAGS") &&
 		(c.IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") ||
-			Bool(c.productVariables.Eng) ||
-			!c.ReleaseDefaultModuleBuildFromSource())
+			Bool(c.productVariables.Eng))
+}
+
+// DisableVerifyOverlaps returns true if verify_overlaps is skipped.
+// Mismatch in version of apexes and module SDK is required for mainline prebuilts to work in
+// trunk stable.
+// Thus, verify_overlaps is disabled when RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE is set to false.
+// TODO(b/308174018): Re-enable verify_overlaps for both builr from source/mainline prebuilts.
+func (c Config) DisableVerifyOverlaps() bool {
+	return c.IsEnvTrue("DISABLE_VERIFY_OVERLAPS") || !c.ReleaseDefaultModuleBuildFromSource()
 }
 
 // MaxPageSizeSupported returns the max page size supported by the device. This
@@ -337,9 +344,9 @@
 	// unix sockets, instead of spawning Bazel as a subprocess.
 	UseBazelProxy bool
 
-	// If buildFromTextStub is true then the Java API stubs are
-	// built from the signature text files, not the source Java files.
-	buildFromTextStub bool
+	// If buildFromSourceStub is true then the Java API stubs are
+	// built from the source Java files, not the signature text files.
+	buildFromSourceStub bool
 
 	// If ensureAllowlistIntegrity is true, then the presence of any allowlisted
 	// modules that aren't mixed-built for at least one variant will cause a build
@@ -556,7 +563,7 @@
 		MultitreeBuild: cmdArgs.MultitreeBuild,
 		UseBazelProxy:  cmdArgs.UseBazelProxy,
 
-		buildFromTextStub: cmdArgs.BuildFromTextStub,
+		buildFromSourceStub: cmdArgs.BuildFromSourceStub,
 	}
 
 	config.deviceConfig = &deviceConfig{
@@ -2072,11 +2079,11 @@
 	// TODO: b/302320354 - Remove the coverage build specific logic once the
 	// robust solution for handling native properties in from-text stub build
 	// is implemented.
-	return c.buildFromTextStub && !c.JavaCoverageEnabled()
+	return !c.buildFromSourceStub && !c.JavaCoverageEnabled()
 }
 
 func (c *config) SetBuildFromTextStub(b bool) {
-	c.buildFromTextStub = b
+	c.buildFromSourceStub = !b
 	c.productVariables.Build_from_text_stub = boolPtr(b)
 }
 
@@ -2117,3 +2124,46 @@
 func (c *deviceConfig) HideFlaggedApis() bool {
 	return c.NextReleaseHideFlaggedApi() && !c.ReleaseExposeFlaggedApi()
 }
+
+func (c *config) GetBuildFlag(name string) (string, bool) {
+	val, ok := c.productVariables.BuildFlags[name]
+	return val, ok
+}
+
+var (
+	mainlineApexContributionBuildFlags = []string{
+		"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES",
+		"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH",
+		"RELEASE_APEX_CONTRIBUTIONS_ART",
+		"RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH",
+		"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE",
+		"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY",
+		"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT",
+		"RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY",
+		"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK",
+		"RELEASE_APEX_CONTRIBUTIONS_HEALTHFITNESS",
+		"RELEASE_APEX_CONTRIBUTIONS_IPSEC",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIA",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER",
+		"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION",
+		"RELEASE_APEX_CONTRIBUTIONS_PERMISSION",
+		"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING",
+		"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING",
+		"RELEASE_APEX_CONTRIBUTIONS_SDKEXTENSIONS",
+		"RELEASE_APEX_CONTRIBUTIONS_STATSD",
+		"RELEASE_APEX_CONTRIBUTIONS_UWB",
+		"RELEASE_APEX_CONTRIBUTIONS_WIFI",
+	}
+)
+
+// Returns the list of _selected_ apex_contributions
+// Each mainline module will have one entry in the list
+func (c *config) AllApexContributions() []string {
+	ret := []string{}
+	for _, f := range mainlineApexContributionBuildFlags {
+		if val, exists := c.GetBuildFlag(f); exists && val != "" {
+			ret = append(ret, val)
+		}
+	}
+	return ret
+}
diff --git a/android/module.go b/android/module.go
index 250161f..0d405eb 100644
--- a/android/module.go
+++ b/android/module.go
@@ -3231,6 +3231,8 @@
 		return true
 	} else if tag == licensesTag {
 		return true
+	} else if tag == acDepTag {
+		return true
 	}
 	return false
 }
diff --git a/android/neverallow.go b/android/neverallow.go
index 2be6a74..f721b94 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -169,6 +169,8 @@
 		"external/kotlinx.coroutines",
 		"external/robolectric-shadows",
 		"external/robolectric",
+		"frameworks/base/ravenwood",
+		"frameworks/base/tools/hoststubgen",
 		"frameworks/layoutlib",
 	}
 
diff --git a/android/prebuilt.go b/android/prebuilt.go
index e7b7979..91c0aa1 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -387,7 +387,7 @@
 
 func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel()
-	ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
+	ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
 	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
 }
 
@@ -406,6 +406,8 @@
 
 // PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the
 // corresponding source module, if one exists for the same variant.
+// Add a dependency from the prebuilt to `all_apex_contributions`
+// The metadata will be used for source vs prebuilts selection
 func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
 	// If this module is a prebuilt, is enabled and has not been renamed to source then add a
@@ -416,6 +418,14 @@
 			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
 			p.properties.SourceExists = true
 		}
+		// Add a dependency from the prebuilt to the `all_apex_contributions`
+		// metadata module
+		// TODO: When all branches contain this singleton module, make this strict
+		// TODO: Add this dependency only for mainline prebuilts and not every prebuilt module
+		if ctx.OtherModuleExists("all_apex_contributions") {
+			ctx.AddDependency(m, acDepTag, "all_apex_contributions")
+		}
+
 	}
 }
 
@@ -435,7 +445,11 @@
 
 // PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or
 // because the source module doesn't exist.  It also disables installing overridden source modules.
-func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
+//
+// If the visited module is the metadata module `all_apex_contributions`, it sets a
+// provider containing metadata about whether source or prebuilt of mainline modules should be used.
+// This logic was added here to prevent the overhead of creating a new mutator.
+func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
 	if p := GetEmbeddedPrebuilt(m); p != nil {
 		if p.srcsSupplier == nil && p.srcsPropertyName == "" {
@@ -444,6 +458,17 @@
 		if !p.properties.SourceExists {
 			p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil, m)
 		}
+		// Propagate the provider received from `all_apex_contributions`
+		// to the source module
+		ctx.VisitDirectDepsWithTag(acDepTag, func(am Module) {
+			if ctx.Config().Bp2buildMode() {
+				// This provider key is not applicable in bp2build
+				return
+			}
+			psi := ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
+			ctx.SetProvider(PrebuiltSelectionInfoProvider, psi)
+		})
+
 	} else if s, ok := ctx.Module().(Module); ok {
 		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
 			p := GetEmbeddedPrebuilt(prebuiltModule)
@@ -455,6 +480,11 @@
 			}
 		})
 	}
+	// If this is `all_apex_contributions`, set a provider containing
+	// metadata about source vs prebuilts selection
+	if am, ok := m.(*allApexContributions); ok {
+		am.SetPrebuiltSelectionInfoProvider(ctx)
+	}
 }
 
 // PrebuiltPostDepsMutator replaces dependencies on the source module with dependencies on the
@@ -480,9 +510,66 @@
 	}
 }
 
+// A wrapper around PrebuiltSelectionInfoMap.IsSelected with special handling for java_sdk_library
+// java_sdk_library is a macro that creates
+// 1. top-level impl library
+// 2. stub libraries (suffixed with .stubs...)
+//
+// java_sdk_library_import is a macro that creates
+// 1. top-level "impl" library
+// 2. stub libraries (suffixed with .stubs...)
+//
+// the impl of java_sdk_library_import is a "hook" for hiddenapi and dexpreopt processing. It does not have an impl jar, but acts as a shim
+// to provide the jar deapxed from the prebuilt apex
+//
+// isSelected uses `all_apex_contributions` to supersede source vs prebuilts selection of the stub libraries. It does not supersede the
+// selection of the top-level "impl" library so that this hook can work
+//
+// TODO (b/308174306) - Fix this when we need to support multiple prebuilts in main
+func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool {
+	if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
+		sln := proptools.String(sdkLibrary.SdkLibraryName())
+		// This is the top-level library
+		// Do not supersede the existing prebuilts vs source selection mechanisms
+		if sln == m.base().BaseModuleName() {
+			return false
+		}
+
+		// Stub library created by java_sdk_library_import
+		if p := GetEmbeddedPrebuilt(m); p != nil {
+			return psi.IsSelected(sln, PrebuiltNameFromSource(sln))
+		}
+
+		// Stub library created by java_sdk_library
+		return psi.IsSelected(sln, sln)
+	}
+	return psi.IsSelected(m.base().BaseModuleName(), m.Name())
+}
+
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
-func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module, prebuilt Module) bool {
+func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool {
+	// Use `all_apex_contributions` for source vs prebuilt selection.
+	psi := PrebuiltSelectionInfoMap{}
+	ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(am Module) {
+		if ctx.OtherModuleHasProvider(am, PrebuiltSelectionInfoProvider) {
+			psi = ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
+		}
+	})
+
+	// If the source module is explicitly listed in the metadata module, use that
+	if source != nil && isSelected(psi, source) {
+		return false
+	}
+	// If the prebuilt module is explicitly listed in the metadata module, use that
+	if isSelected(psi, prebuilt) {
+		return true
+	}
+
+	// If the baseModuleName could not be found in the metadata module,
+	// fall back to the existing source vs prebuilt selection.
+	// TODO: Drop the fallback mechanisms
+
 	if !ctx.Config().Bp2buildMode() {
 		if p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 {
 			return false
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index fc47cfd..953258e 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -335,6 +335,78 @@
 			prebuilt: []OsType{Android, buildOS},
 		},
 		{
+			name: "apex_contributions supersedes any source preferred via use_source_config_var",
+			modules: `
+				source {
+					name: "bar",
+				}
+
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}
+				apex_contributions {
+					name: "my_mainline_module_contribution",
+					api_domain: "apexfoo",
+					// this metadata module contains prebuilt
+					contents: ["prebuilt_bar"],
+				}
+				all_apex_contributions {
+					name: "all_apex_contributions",
+				}
+				`,
+			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "true",
+					},
+				}
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution",
+				}
+			}),
+			// use_source_config_var indicates that source should be used
+			// but this is superseded by `my_mainline_module_contribution`
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "apex_contributions supersedes any prebuilt preferred via use_source_config_var",
+			modules: `
+				source {
+					name: "bar",
+				}
+
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}
+				apex_contributions {
+					name: "my_mainline_module_contribution",
+					api_domain: "apexfoo",
+					// this metadata module contains source
+					contents: ["bar"],
+				}
+				all_apex_contributions {
+					name: "all_apex_contributions",
+				}
+				`,
+			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "false",
+					},
+				}
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution",
+				}
+			}),
+			// use_source_config_var indicates that prebuilt should be used
+			// but this is superseded by `my_mainline_module_contribution`
+			prebuilt: nil,
+		},
+		{
 			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true",
 			modules: `
 				source {
@@ -497,7 +569,7 @@
 	}
 }
 
-func testPrebuiltError(t *testing.T, expectedError, bp string) {
+func testPrebuiltErrorWithFixture(t *testing.T, expectedError, bp string, fixture FixturePreparer) {
 	t.Helper()
 	fs := MockFS{
 		"prebuilt_file": nil,
@@ -508,9 +580,15 @@
 		PrepareForTestWithOverrides,
 		fs.AddToFixture(),
 		FixtureRegisterWithContext(registerTestPrebuiltModules),
+		OptionalFixturePreparer(fixture),
 	).
 		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)).
 		RunTestWithBp(t, bp)
+
+}
+
+func testPrebuiltError(t *testing.T, expectedError, bp string) {
+	testPrebuiltErrorWithFixture(t, expectedError, bp, nil)
 }
 
 func TestPrebuiltShouldNotChangePartition(t *testing.T) {
@@ -559,6 +637,7 @@
 	ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
 	ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
 	ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
+	RegisterApexContributionsBuildComponents(ctx)
 }
 
 type prebuiltModule struct {
@@ -653,3 +732,33 @@
 	InitOverrideModule(m)
 	return m
 }
+
+func TestPrebuiltErrorCannotListBothSourceAndPrebuiltInContributions(t *testing.T) {
+	selectMainlineModuleContritbutions := GroupFixturePreparers(
+		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_apex_contributions",
+			}
+		}),
+	)
+	testPrebuiltErrorWithFixture(t, `Cannot use Soong module: prebuilt_foo from apex_contributions: my_apex_contributions because it has been added previously as: foo from apex_contributions: my_apex_contributions`, `
+		source {
+			name: "foo",
+		}
+		prebuilt {
+			name: "foo",
+			srcs: ["prebuilt_file"],
+		}
+		apex_contributions {
+			name: "my_apex_contributions",
+			api_domain: "my_mainline_module",
+			contents: [
+			  "foo",
+			  "prebuilt_foo",
+			],
+		}
+		all_apex_contributions {
+			name: "all_apex_contributions",
+		}
+		`, selectMainlineModuleContritbutions)
+}
diff --git a/android/util.go b/android/util.go
index 5375373..f687bca 100644
--- a/android/util.go
+++ b/android/util.go
@@ -61,17 +61,39 @@
 // JoinWithPrefixAndSeparator prepends the prefix to each string in the list and
 // returns them joined together with the given separator.
 func JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string {
+	return JoinWithPrefixSuffixAndSeparator(strs, prefix, "", sep)
+}
+
+// JoinWithSuffixAndSeparator appends the suffix to each string in the list and
+// returns them joined together with the given separator.
+func JoinWithSuffixAndSeparator(strs []string, suffix string, sep string) string {
+	return JoinWithPrefixSuffixAndSeparator(strs, "", suffix, sep)
+}
+
+// JoinWithPrefixSuffixAndSeparator appends the prefix/suffix to each string in the list and
+// returns them joined together with the given separator.
+func JoinWithPrefixSuffixAndSeparator(strs []string, prefix, suffix, sep string) string {
 	if len(strs) == 0 {
 		return ""
 	}
 
+	// Pre-calculate the length of the result
+	length := 0
+	for _, s := range strs {
+		length += len(s)
+	}
+	length += (len(prefix)+len(suffix))*len(strs) + len(sep)*(len(strs)-1)
+
 	var buf strings.Builder
+	buf.Grow(length)
 	buf.WriteString(prefix)
 	buf.WriteString(strs[0])
+	buf.WriteString(suffix)
 	for i := 1; i < len(strs); i++ {
 		buf.WriteString(sep)
 		buf.WriteString(prefix)
 		buf.WriteString(strs[i])
+		buf.WriteString(suffix)
 	}
 	return buf.String()
 }
diff --git a/android/util_test.go b/android/util_test.go
index 20161e5..699135b 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -811,7 +811,7 @@
 			if !reflect.DeepEqual(slice, testCase.expected) {
 				t.Errorf("expected %#v, got %#v", testCase.expected, slice)
 			}
-			if slice != nil && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) {
+			if cap(slice) > 0 && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) {
 				t.Errorf("expected slices to have different backing arrays")
 			}
 		})
diff --git a/android/variable.go b/android/variable.go
index 9896f20..648e4cf 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -492,6 +492,8 @@
 	NextReleaseHideFlaggedApi *bool `json:",omitempty"`
 
 	Release_expose_flagged_api *bool `json:",omitempty"`
+
+	BuildFlags map[string]string `json:",omitempty"`
 }
 
 type PartitionQualifiedVariablesType struct {
diff --git a/apex/apex.go b/apex/apex.go
index f2e8a06..2f664e1 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -3037,59 +3037,6 @@
 	//
 	// Module separator
 	//
-	m["com.android.appsearch"] = []string{
-		"icing-java-proto-lite",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.btservices"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.cellbroadcast"] = []string{}
-	//
-	// Module separator
-	//
-	m["com.android.extservices"] = []string{
-		"ExtServices-core",
-		"libtextclassifier-java",
-		"textclassifier-statsd",
-		"TextClassifierNotificationLibNoManifest",
-		"TextClassifierServiceLibNoManifest",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.neuralnetworks"] = []string{
-		"android.hardware.neuralnetworks@1.0",
-		"android.hardware.neuralnetworks@1.1",
-		"android.hardware.neuralnetworks@1.2",
-		"android.hardware.neuralnetworks@1.3",
-		"android.hidl.allocator@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.safe_union@1.0",
-		"libarect",
-		"libprocpartition",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media.swcodec"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
 	m["com.android.mediaprovider"] = []string{
 		"MediaProvider",
 		"MediaProviderGoogle",
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e6581cf..ddb9a40 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5459,7 +5459,7 @@
 
 	checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
 		t.Helper()
-		s := ctx.ModuleForTests("platform-bootclasspath", "android_common")
+		s := ctx.ModuleForTests("dex_bootjars", "android_common")
 		foundLibfooJar := false
 		base := stem + ".jar"
 		for _, output := range s.AllOutputs() {
@@ -5909,8 +5909,8 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar")
+		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libfoo.jar")
+		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
diff --git a/apex/builder.go b/apex/builder.go
index d75cc1d..afbfa1c 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -75,9 +75,11 @@
 	pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests")
 	pctx.HostBinToolVariable("deapexer", "deapexer")
 	pctx.HostBinToolVariable("debugfs_static", "debugfs_static")
+	pctx.HostBinToolVariable("fsck_erofs", "fsck.erofs")
 	pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
 	pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config")
 	pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf")
+	pctx.HostBinToolVariable("apex_elf_checker", "apex_elf_checker")
 }
 
 var (
@@ -237,6 +239,12 @@
 		CommandDeps: []string{"${assemble_vintf}"},
 		Description: "run assemble_vintf",
 	})
+
+	apexElfCheckerUnwantedRule = pctx.StaticRule("apexElfCheckerUnwantedRule", blueprint.RuleParams{
+		Command:     `${apex_elf_checker} --tool_path ${tool_path} --unwanted ${unwanted} ${in} && touch ${out}`,
+		CommandDeps: []string{"${apex_elf_checker}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}", "${config.ClangBin}/llvm-readelf"},
+		Description: "run apex_elf_checker --unwanted",
+	}, "tool_path", "unwanted")
 )
 
 // buildManifest creates buile rules to modify the input apex_manifest.json to add information
@@ -886,6 +894,10 @@
 	if suffix == imageApexSuffix && ext4 == a.payloadFsType {
 		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
 	}
+	if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 {
+		validations = append(validations,
+			runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "signapk",
@@ -1164,3 +1176,17 @@
 	})
 	return timestamp
 }
+
+func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.OutputPath, unwanted []string) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "apex_elf_unwanted.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexElfCheckerUnwantedRule,
+		Input:  apexFile,
+		Output: timestamp,
+		Args: map[string]string{
+			"unwanted":  android.JoinWithSuffixAndSeparator(unwanted, ".so", ":"),
+			"tool_path": ctx.Config().HostToolPath(ctx, "").String() + ":${config.ClangBin}",
+		},
+	})
+	return timestamp
+}
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 2cabdc8..b789590 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -79,7 +79,7 @@
 	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
 		return getMacTools(ctx).sdkRoot
 	})
-	pctx.StaticVariable("macMinVersion", "10.13")
+	pctx.StaticVariable("macMinVersion", "10.14")
 	pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
 		return getMacTools(ctx).arPath
 	})
diff --git a/cc/config/global.go b/cc/config/global.go
index 892a86c..2ca9df9 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -174,9 +174,6 @@
 		"-Werror=format-security",
 		"-nostdlibinc",
 
-		// Enable MLGO for register allocation.
-		"-mllvm -regalloc-enable-advisor=release",
-
 		// Emit additional debug info for AutoFDO
 		"-fdebug-info-for-profiling",
 	}
@@ -205,8 +202,6 @@
 		"-Wl,--exclude-libs,libgcc_stripped.a",
 		"-Wl,--exclude-libs,libunwind_llvm.a",
 		"-Wl,--exclude-libs,libunwind.a",
-		// Enable MLGO for register allocation.
-		"-Wl,-mllvm,-regalloc-enable-advisor=release",
 	}
 
 	deviceGlobalLldflags = append(append(deviceGlobalLdflags, commonGlobalLldflags...),
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 9f093bb..00a395f 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -33,6 +33,8 @@
 		"-Wl,--hash-style=gnu",
 	}
 
+	X86_64Lldflags = x86_64Ldflags
+
 	x86_64ArchVariantCflags = map[string][]string{
 		"": []string{
 			"-march=x86-64",
@@ -94,10 +96,23 @@
 	exportedVars.ExportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"})
 
 	exportedVars.ExportStringListStaticVariable("X86_64Ldflags", x86_64Ldflags)
-	exportedVars.ExportStringListStaticVariable("X86_64Lldflags", x86_64Ldflags)
+	exportedVars.ExportStringList("X86_64Lldflags", X86_64Lldflags)
+	pctx.VariableFunc("X86_64Lldflags", func(ctx android.PackageVarContext) string {
+		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
+		flags := append(X86_64Lldflags, maxPageSizeFlag)
+		return strings.Join(flags, " ")
+	})
 
 	// Clang cflags
-	exportedVars.ExportStringListStaticVariable("X86_64Cflags", x86_64Cflags)
+	exportedVars.ExportStringList("X86_64Cflags", x86_64Cflags)
+	pctx.VariableFunc("X86_64Cflags", func(ctx android.PackageVarContext) string {
+		flags := x86_64Cflags
+		if ctx.Config().PageSizeAgnostic() {
+			flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO")
+		}
+		return strings.Join(flags, " ")
+	})
+
 	exportedVars.ExportStringListStaticVariable("X86_64Cppflags", x86_64Cppflags)
 
 	// Yasm flags
diff --git a/cc/lto.go b/cc/lto.go
index 20e4f24..fb3b485 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -147,10 +147,15 @@
 			}
 		}
 
-		// For ML training
-		if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
-			ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
-			ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
+		// Register allocation MLGO flags for ARM64.
+		if ctx.Arch().ArchType == android.Arm64 {
+			ltoCFlags = append(ltoCFlags, "-mllvm -regalloc-enable-advisor=release")
+			ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
+			// Flags for training MLGO model.
+			if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
+				ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
+				ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
+			}
 		}
 
 		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 568a6f8..5abbdb7 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -84,7 +84,7 @@
 	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
 	flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
 	flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
-	flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files")
+	flag.BoolVar(&cmdlineArgs.BuildFromSourceStub, "build-from-source-stub", false, "build Java stubs from source files instead of API text files")
 	flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
 	// Flags that probably shouldn't be flags of soong_build, but we haven't found
 	// the time to remove them yet
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 18cba77..c94ff07 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -182,8 +182,12 @@
 		CriticalPath: criticalPath,
 	}}
 
-	config := c.config(buildCtx, args...)
-	config.SetLogsPrefix(c.logsPrefix)
+	freshConfig := func() build.Config {
+		config := c.config(buildCtx, args...)
+		config.SetLogsPrefix(c.logsPrefix)
+		return config
+	}
+	config := freshConfig()
 	logsDir := config.LogsDir()
 	buildStarted = config.BuildStartedTimeOrDefault(buildStarted)
 
@@ -213,6 +217,15 @@
 		log.Verbosef("  [%d] %s", i, arg)
 	}
 
+	// We need to call preProductConfigSetup before we can do product config, which is how we get
+	// PRODUCT_CONFIG_RELEASE_MAPS set for the final product config for the build.
+	// When product config uses a declarative language, we won't need to rerun product config.
+	preProductConfigSetup(buildCtx, config)
+	if build.SetProductReleaseConfigMaps(buildCtx, config) {
+		log.Verbose("Product release config maps found\n")
+		config = freshConfig()
+	}
+
 	defer func() {
 		stat.Finish()
 		criticalPath.WriteToMetrics(met)
@@ -225,7 +238,9 @@
 
 }
 
-func logAndSymlinkSetup(buildCtx build.Context, config build.Config) {
+// This function must not modify config, since product config may cause us to recreate the config,
+// and we won't call this function a second time.
+func preProductConfigSetup(buildCtx build.Context, config build.Config) {
 	log := buildCtx.ContextImpl.Logger
 	logsPrefix := config.GetLogsPrefix()
 	build.SetupOutDir(buildCtx, config)
@@ -311,7 +326,6 @@
 }
 
 func dumpVar(ctx build.Context, config build.Config, args []string) {
-	logAndSymlinkSetup(ctx, config)
 	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
 	flags.SetOutput(ctx.Writer)
 
@@ -364,7 +378,6 @@
 }
 
 func dumpVars(ctx build.Context, config build.Config, args []string) {
-	logAndSymlinkSetup(ctx, config)
 
 	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
 	flags.SetOutput(ctx.Writer)
@@ -544,7 +557,6 @@
 }
 
 func runMake(ctx build.Context, config build.Config, _ []string) {
-	logAndSymlinkSetup(ctx, config)
 	logsDir := config.LogsDir()
 	if config.IsVerbose() {
 		writer := ctx.Writer
@@ -680,9 +692,11 @@
 	}
 
 	ctx.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
-	if limits.Cur == limits.Max {
-		return
-	}
+
+	// Go 1.21 modifies the file limit but restores the original when
+	// execing subprocesses if it hasn't be overridden.  Call Setrlimit
+	// here even if it doesn't appear to be necessary so that the
+	// syscall package considers it set.
 
 	limits.Cur = limits.Max
 	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index ba41f4a..c871e85 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -32,7 +32,7 @@
 	DisablePreoptBootImages bool     // disable prepot for boot images
 	DisablePreoptModules    []string // modules with preopt disabled by product-specific config
 
-	OnlyPreoptBootImageAndSystemServer bool // only preopt jars in the boot image or system server
+	OnlyPreoptArtBootImage bool // only preopt jars in the ART boot image
 
 	PreoptWithUpdatableBcp bool // If updatable boot jars are included in dexpreopt or not.
 
@@ -691,45 +691,45 @@
 
 func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig {
 	return &GlobalConfig{
-		DisablePreopt:                      false,
-		DisablePreoptModules:               nil,
-		OnlyPreoptBootImageAndSystemServer: false,
-		HasSystemOther:                     false,
-		PatternsOnSystemOther:              nil,
-		DisableGenerateProfile:             false,
-		ProfileDir:                         "",
-		BootJars:                           android.EmptyConfiguredJarList(),
-		ApexBootJars:                       android.EmptyConfiguredJarList(),
-		ArtApexJars:                        android.EmptyConfiguredJarList(),
-		TestOnlyArtBootImageJars:           android.EmptyConfiguredJarList(),
-		SystemServerJars:                   android.EmptyConfiguredJarList(),
-		SystemServerApps:                   nil,
-		ApexSystemServerJars:               android.EmptyConfiguredJarList(),
-		StandaloneSystemServerJars:         android.EmptyConfiguredJarList(),
-		ApexStandaloneSystemServerJars:     android.EmptyConfiguredJarList(),
-		SpeedApps:                          nil,
-		PreoptFlags:                        nil,
-		DefaultCompilerFilter:              "",
-		SystemServerCompilerFilter:         "",
-		GenerateDMFiles:                    false,
-		NoDebugInfo:                        false,
-		DontResolveStartupStrings:          false,
-		AlwaysSystemServerDebugInfo:        false,
-		NeverSystemServerDebugInfo:         false,
-		AlwaysOtherDebugInfo:               false,
-		NeverOtherDebugInfo:                false,
-		IsEng:                              false,
-		SanitizeLite:                       false,
-		DefaultAppImages:                   false,
-		Dex2oatXmx:                         "",
-		Dex2oatXms:                         "",
-		EmptyDirectory:                     "empty_dir",
-		CpuVariant:                         nil,
-		InstructionSetFeatures:             nil,
-		BootImageProfiles:                  nil,
-		BootFlags:                          "",
-		Dex2oatImageXmx:                    "",
-		Dex2oatImageXms:                    "",
+		DisablePreopt:                  false,
+		DisablePreoptModules:           nil,
+		OnlyPreoptArtBootImage:         false,
+		HasSystemOther:                 false,
+		PatternsOnSystemOther:          nil,
+		DisableGenerateProfile:         false,
+		ProfileDir:                     "",
+		BootJars:                       android.EmptyConfiguredJarList(),
+		ApexBootJars:                   android.EmptyConfiguredJarList(),
+		ArtApexJars:                    android.EmptyConfiguredJarList(),
+		TestOnlyArtBootImageJars:       android.EmptyConfiguredJarList(),
+		SystemServerJars:               android.EmptyConfiguredJarList(),
+		SystemServerApps:               nil,
+		ApexSystemServerJars:           android.EmptyConfiguredJarList(),
+		StandaloneSystemServerJars:     android.EmptyConfiguredJarList(),
+		ApexStandaloneSystemServerJars: android.EmptyConfiguredJarList(),
+		SpeedApps:                      nil,
+		PreoptFlags:                    nil,
+		DefaultCompilerFilter:          "",
+		SystemServerCompilerFilter:     "",
+		GenerateDMFiles:                false,
+		NoDebugInfo:                    false,
+		DontResolveStartupStrings:      false,
+		AlwaysSystemServerDebugInfo:    false,
+		NeverSystemServerDebugInfo:     false,
+		AlwaysOtherDebugInfo:           false,
+		NeverOtherDebugInfo:            false,
+		IsEng:                          false,
+		SanitizeLite:                   false,
+		DefaultAppImages:               false,
+		Dex2oatXmx:                     "",
+		Dex2oatXms:                     "",
+		EmptyDirectory:                 "empty_dir",
+		CpuVariant:                     nil,
+		InstructionSetFeatures:         nil,
+		BootImageProfiles:              nil,
+		BootFlags:                      "",
+		Dex2oatImageXmx:                "",
+		Dex2oatImageXms:                "",
 	}
 }
 
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 29ae188..c13e14a 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -124,12 +124,7 @@
 		return true
 	}
 
-	// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
-	// Also preopt system server jars since selinux prevents system server from loading anything from
-	// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
-	// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
-	if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
-		!global.AllSystemServerJars(ctx).ContainsJar(module.Name) && !module.PreoptExtractedApk {
+	if global.OnlyPreoptArtBootImage && !module.PreoptExtractedApk {
 		return true
 	}
 
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 275d9c3..b7d2971 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -150,8 +150,9 @@
 	sourceFilePath android.Path
 	outputFilePath android.OutputPath
 	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
-	installDirBase   string
-	installDirBase64 string
+	installDirBase               string
+	installDirBase64             string
+	installAvoidMultilibConflict bool
 	// The base install location when soc_specific property is set to true, e.g. "firmware" for
 	// prebuilt_firmware.
 	socInstallDirBase      string
@@ -355,6 +356,10 @@
 	if p.SocSpecific() && p.socInstallDirBase != "" {
 		installBaseDir = p.socInstallDirBase
 	}
+	if p.installAvoidMultilibConflict && !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
+		installBaseDir = filepath.Join(installBaseDir, ctx.Arch().ArchType.String())
+	}
+
 	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
 
 	// Call InstallFile even when uninstallable to make the module included in the package
@@ -590,6 +595,7 @@
 	module := &PrebuiltEtc{}
 	module.makeClass = "RENDERSCRIPT_BITCODE"
 	module.installDirBase64 = "lib64"
+	module.installAvoidMultilibConflict = true
 	InitPrebuiltEtcModule(module, "lib")
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index f2efd46..3d49114 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -350,13 +350,16 @@
 		addStr("avb_algorithm", algorithm)
 		key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
 		addPath("avb_key_path", key)
+		partitionName := proptools.StringDefault(f.properties.Partition_name, f.Name())
+		addStr("partition_name", partitionName)
 		avb_add_hashtree_footer_args := "--do_not_generate_fec"
 		if hashAlgorithm := proptools.String(f.properties.Avb_hash_algorithm); hashAlgorithm != "" {
 			avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
 		}
+		securityPatchKey := "com.android.build." + partitionName + ".security_patch"
+		securityPatchValue := ctx.Config().PlatformSecurityPatch()
+		avb_add_hashtree_footer_args += " --prop " + securityPatchKey + ":" + securityPatchValue
 		addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args)
-		partitionName := proptools.StringDefault(f.properties.Partition_name, f.Name())
-		addStr("partition_name", partitionName)
 		addStr("avb_salt", f.salt())
 	}
 
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 9cc98f5..bf50a94 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -19,30 +19,6 @@
 		// go/keep-sorted start
 		"depfile_allowed_for_test",
 		"gen_uwb_core_proto",
-		"libtextclassifier_fbgen_actions_actions-entity-data",
-		"libtextclassifier_fbgen_actions_actions_model",
-		"libtextclassifier_fbgen_annotator_datetime_datetime",
-		"libtextclassifier_fbgen_annotator_entity-data",
-		"libtextclassifier_fbgen_annotator_experimental_experimental",
-		"libtextclassifier_fbgen_annotator_model",
-		"libtextclassifier_fbgen_annotator_person_name_person_name_model",
-		"libtextclassifier_fbgen_lang_id_common_flatbuffers_embedding-network",
-		"libtextclassifier_fbgen_lang_id_common_flatbuffers_model",
-		"libtextclassifier_fbgen_utils_codepoint-range",
-		"libtextclassifier_fbgen_utils_container_bit-vector",
-		"libtextclassifier_fbgen_utils_flatbuffers_flatbuffers",
-		"libtextclassifier_fbgen_utils_flatbuffers_flatbuffers_test",
-		"libtextclassifier_fbgen_utils_grammar_rules",
-		"libtextclassifier_fbgen_utils_grammar_semantics_expression",
-		"libtextclassifier_fbgen_utils_grammar_testing_value",
-		"libtextclassifier_fbgen_utils_i18n_language-tag",
-		"libtextclassifier_fbgen_utils_intents_intent-config",
-		"libtextclassifier_fbgen_utils_lua_utils_tests",
-		"libtextclassifier_fbgen_utils_normalization",
-		"libtextclassifier_fbgen_utils_resources",
-		"libtextclassifier_fbgen_utils_tflite_text_encoder_config",
-		"libtextclassifier_fbgen_utils_tokenizer",
-		"libtextclassifier_fbgen_utils_zlib_buffer",
 		"tflite_support_metadata_schema",
 		"tflite_support_spm_config",
 		"tflite_support_spm_encoder_config",
@@ -51,13 +27,11 @@
 
 	SandboxingDenyModuleList = []string{
 		// go/keep-sorted start
-		"CompilationTestCases_package-dex-usage",
 		"ControlEnvProxyServerProto_cc",
 		"ControlEnvProxyServerProto_h",
 		"CtsApkVerityTestDebugFiles",
 		"FrontendStub_cc",
 		"FrontendStub_h",
-		"HeadlessBuildTimestamp",
 		"ImageProcessing-rscript",
 		"ImageProcessing2-rscript",
 		"ImageProcessingJB-rscript",
@@ -90,7 +64,6 @@
 		"atest_integration_fake_src",
 		"authfs_test_apk_assets",
 		"awkgram.tab.h",
-		"bluetooth_core_rust_packets",
 		"c2hal_test_genc++",
 		"c2hal_test_genc++_headers",
 		"camera-its",
@@ -111,8 +84,6 @@
 		"fdt_test_tree_multiple_memory_ranges_dtb",
 		"fdt_test_tree_one_memory_range_dtb",
 		"futility_cmds",
-		"gd_hci_packets_python3_gen",
-		"gd_smp_packets_python3_gen",
 		"gen_corrupt_rebootless_apex",
 		"gen_corrupt_superblock_apex",
 		"gen_key_mismatch_capex",
@@ -124,21 +95,6 @@
 		"gles2_extensions_functions_hdr",
 		"gles31_only_functions_hdr",
 		"gles3_only_functions_hdr",
-		"hci_packets_python3_gen",
-		"hidl2aidl_test_gen_aidl",
-		"hidl2aidl_translate_cpp_test_gen_headers",
-		"hidl2aidl_translate_cpp_test_gen_src",
-		"hidl2aidl_translate_java_test_gen_src",
-		"hidl2aidl_translate_ndk_test_gen_headers",
-		"hidl2aidl_translate_ndk_test_gen_src",
-		"hidl_cpp_impl_test_gen-headers",
-		"hidl_cpp_impl_test_gen-sources",
-		"hidl_error_test_gen",
-		"hidl_export_test_gen-headers",
-		"hidl_format_test_diff",
-		"hidl_hash_test_gen",
-		"hidl_hash_version_gen",
-		"hidl_java_impl_test_gen",
 		"lib-test-profile-text-protos",
 		"libbssl_sys_src_nostd",
 		"libc_musl_sysroot_bits",
@@ -148,46 +104,14 @@
 		"libmojo_jni_headers",
 		"libxml2_schema_fuzz_corpus",
 		"libxml2_xml_fuzz_corpus",
-		"link_layer_packets_python3_gen",
-		"llcp_packets_python3_gen",
 		"measure_io_as_jar",
-		"nos_app_avb_service_genc++",
-		"nos_app_avb_service_genc++_headers",
-		"nos_app_avb_service_genc++_mock",
-		"nos_app_identity_service_genc++",
-		"nos_app_identity_service_genc++_headers",
-		"nos_app_identity_service_genc++_mock",
-		"nos_app_keymaster_service_genc++",
-		"nos_app_keymaster_service_genc++_headers",
-		"nos_app_keymaster_service_genc++_mock",
-		"nos_app_weaver_service_genc++",
-		"nos_app_weaver_service_genc++_headers",
-		"nos_app_weaver_service_genc++_mock",
-		"nos_generator_test_service_genc++",
-		"nos_generator_test_service_genc++_headers",
-		"nos_generator_test_service_genc++_mock",
-		"openwrt_rootfs_combined_aarch64",
-		"openwrt_rootfs_combined_x86_64",
-		"openwrt_rootfs_customization_aarch64",
-		"openwrt_rootfs_customization_x86_64",
 		"pandora-python-gen-src",
-		"pdl_cxx_canonical_be_src_gen",
-		"pdl_cxx_canonical_be_test_gen",
-		"pdl_cxx_canonical_le_src_gen",
-		"pdl_cxx_canonical_le_test_gen",
-		"pdl_python_generator_be_test_gen",
-		"pdl_python_generator_le_test_gen",
-		"pdl_rust_noalloc_le_test_backend_srcs",
-		"pdl_rust_noalloc_le_test_gen_harness",
 		"pixelatoms_defs.h",
 		"pixelstatsatoms.cpp",
 		"pixelstatsatoms.h",
 		"pvmfw_fdt_template_rs",
 		"r8retrace-dexdump-sample-app",
 		"r8retrace-run-retrace",
-		"rootcanal_bredr_bb_packets_cxx_gen",
-		"rootcanal_hci_packets_cxx_gen",
-		"rootcanal_link_layer_packets_cxx_gen",
 		"sample-profile-text-protos",
 		"seller-frontend-service-stub-lite",
 		"services.core.protologsrc",
diff --git a/java/app.go b/java/app.go
index 7b9e6bb..2271378 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1584,7 +1584,7 @@
 	// non-linux build platforms where dexpreopt is generally disabled (the check may fail due to
 	// various unrelated reasons, such as a failure to get manifest from an APK).
 	global := dexpreopt.GetGlobalConfig(ctx)
-	if global.DisablePreopt || global.OnlyPreoptBootImageAndSystemServer {
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage {
 		return inputFile
 	}
 
diff --git a/java/config/droidstubs.go b/java/config/droidstubs.go
index 59cee1d..b7aab5a 100644
--- a/java/config/droidstubs.go
+++ b/java/config/droidstubs.go
@@ -24,8 +24,6 @@
 		"--repeat-errors-max 10",
 		"--hide UnresolvedImport",
 		"--hide InvalidNullabilityOverride",
-		// b/223382732
-		"--hide ChangedDefault",
 
 		// Force metalava to ignore classes on the classpath when an API file contains missing classes.
 		// See b/285140653 for more information.
@@ -54,8 +52,6 @@
 		"--hide AnnotationExtraction",
 		// b/222738070
 		"--hide BannedThrow",
-		// b/223382732
-		"--hide ChangedDefault",
 	}
 
 	MetalavaAnnotationsWarningsFlags = strings.Join(metalavaAnnotationsWarningsFlags, " ")
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index c0f73af..5fb36df 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -610,7 +610,8 @@
 	profile := bootImageProfileRule(ctx, imageConfig)
 
 	// If dexpreopt of boot image jars should be skipped, stop after generating a profile.
-	if SkipDexpreoptBootJars(ctx) {
+	global := dexpreopt.GetGlobalConfig(ctx)
+	if SkipDexpreoptBootJars(ctx) || (global.OnlyPreoptArtBootImage && imageConfig.name != "art") {
 		return
 	}
 
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 7499481..33be603 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -68,7 +68,7 @@
 
 	// The check should be skipped on unbundled builds because system server jars are not preopted on
 	// unbundled builds since the artifacts are installed into the system image, not the APEXes.
-	if global.DisablePreopt || len(targets) == 0 || ctx.Config().UnbundledBuild() {
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage || len(targets) == 0 || ctx.Config().UnbundledBuild() {
 		return
 	}
 
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 29551ef..2bd696c 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -210,57 +210,18 @@
 	return false
 }
 
-// Apex boot config allows to access build/install paths of apex boot jars without going
-// through the usual trouble of registering dependencies on those modules and extracting build paths
-// from those dependencies.
-type apexBootConfig struct {
-	// A list of apex boot jars.
-	modules android.ConfiguredJarList
-
-	// A list of predefined build paths to apex boot jars. They are configured very early,
-	// before the modules for these jars are processed and the actual paths are generated, and
-	// later on a singleton adds commands to copy actual jars to the predefined paths.
-	dexPaths android.WritablePaths
-
-	// Map from module name (without prebuilt_ prefix) to the predefined build path.
-	dexPathsByModule map[string]android.WritablePath
-
-	// A list of dex locations (a.k.a. on-device paths) to the boot jars.
-	dexLocations []string
-}
-
-var updatableBootConfigKey = android.NewOnceKey("apexBootConfig")
-
-// Returns apex boot config.
-func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
-	return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
-		apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
-		dir := android.PathForOutput(ctx, getDexpreoptDirName(ctx), "apex_bootjars")
-		dexPaths := apexBootJars.BuildPaths(ctx, dir)
-		dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
-
-		dexLocations := apexBootJars.DevicePaths(ctx.Config(), android.Android)
-
-		return apexBootConfig{apexBootJars, dexPaths, dexPathsByModuleName, dexLocations}
-	}).(apexBootConfig)
-}
-
 // Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be
 // passed in -Xbootclasspath and -Xbootclasspath-locations arguments for dex2oat).
 func bcpForDexpreopt(ctx android.PathContext, withUpdatable bool) (android.WritablePaths, []string) {
-	// Non-updatable boot jars (they are used both in the boot image and in dexpreopt).
 	bootImage := defaultBootImageConfig(ctx)
+	if withUpdatable {
+		bootImage = mainlineBootImageConfig(ctx)
+	}
+
 	dexPaths := bootImage.dexPathsDeps
 	// The dex locations for all Android variants are identical.
 	dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
 
-	if withUpdatable {
-		// Apex boot jars (they are used only in dexpreopt, but not in the boot image).
-		apexBootConfig := GetApexBootConfig(ctx)
-		dexPaths = append(dexPaths, apexBootConfig.dexPaths...)
-		dexLocations = append(dexLocations, apexBootConfig.dexLocations...)
-	}
-
 	return dexPaths, dexLocations
 }
 
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 81be33d..fbc0197 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -358,7 +358,7 @@
 
 	// If there are stub flag files that have been generated by fragments on which this depends then
 	// use them to validate the stub flag file generated by the rules created by this method.
-	if len(stubFlagSubsets) > 0 {
+	if !ctx.Config().DisableVerifyOverlaps() && len(stubFlagSubsets) > 0 {
 		validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets,
 			HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
 
@@ -1006,7 +1006,7 @@
 
 	// If there are flag files that have been generated by fragments on which this depends then use
 	// them to validate the flag file generated by the rules created by this method.
-	if len(flagSubsets) > 0 {
+	if !ctx.Config().DisableVerifyOverlaps() && len(flagSubsets) > 0 {
 		validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets,
 			HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
 
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 02a2298..0d52614 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -202,8 +202,6 @@
 
 	bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
 	buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule)
-
-	b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
 }
 
 // Generate classpaths.proto config
@@ -415,10 +413,3 @@
 	// INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
 	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String())
 }
-
-// Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps.
-func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) {
-	config := GetApexBootConfig(ctx)
-	apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
-	copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
-}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 1de8972..ea45174 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -618,6 +618,10 @@
 	Api_lint struct {
 		// Enable api linting.
 		Enabled *bool
+
+		// If API lint is enabled, this flag controls whether a set of legitimate lint errors
+		// are turned off. The default is true.
+		Legacy_errors_allowed *bool
 	}
 
 	// TODO: determines whether to create HTML doc or not
@@ -1747,13 +1751,15 @@
 			android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
 	}
 	droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
-	disabledWarnings := []string{
-		"BroadcastBehavior",
-		"DeprecationMismatch",
-		"HiddenSuperclass",
-		"MissingPermission",
-		"SdkConstant",
-		"Todo",
+	disabledWarnings := []string{"HiddenSuperclass"}
+	if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) {
+		disabledWarnings = append(disabledWarnings,
+			"BroadcastBehavior",
+			"DeprecationMismatch",
+			"MissingPermission",
+			"SdkConstant",
+			"Todo",
+		)
 	}
 	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
 
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 21f0bab..82f8a4d 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -1068,6 +1068,137 @@
 	})
 }
 
+// If a module is listed in `mainline_module_contributions, it should be used
+// It will supersede any other source vs prebuilt selection mechanism like `prefer` attribute
+func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) {
+	bp := `
+		apex_contributions {
+			name: "my_mainline_module_contributions",
+			api_domain: "my_mainline_module",
+			contents: [
+				// legacy mechanism prefers the prebuilt
+				// mainline_module_contributions supersedes this since source is listed explicitly
+				"sdklib.prebuilt_preferred_using_legacy_flags",
+
+				// legacy mechanism prefers the source
+				// mainline_module_contributions supersedes this since prebuilt is listed explicitly
+				"prebuilt_sdklib.source_preferred_using_legacy_flags",
+			],
+		}
+		all_apex_contributions {
+			name: "all_apex_contributions",
+		}
+		java_sdk_library {
+			name: "sdklib.prebuilt_preferred_using_legacy_flags",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			}
+		}
+		java_sdk_library_import {
+			name: "sdklib.prebuilt_preferred_using_legacy_flags",
+			prefer: true, // prebuilt is preferred using legacy mechanism
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+			system: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+		java_sdk_library {
+			name: "sdklib.source_preferred_using_legacy_flags",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			}
+		}
+		java_sdk_library_import {
+			name: "sdklib.source_preferred_using_legacy_flags",
+			prefer: false, // source is preferred using legacy mechanism
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+			system: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+
+		// rdeps
+		java_library {
+			name: "public",
+			srcs: ["a.java"],
+			libs: [
+				// this should get source since source is listed in my_mainline_module_contributions
+				"sdklib.prebuilt_preferred_using_legacy_flags.stubs",
+				"sdklib.prebuilt_preferred_using_legacy_flags.stubs.system",
+
+				// this should get prebuilt since source is listed in my_mainline_module_contributions
+				"sdklib.source_preferred_using_legacy_flags.stubs",
+				"sdklib.source_preferred_using_legacy_flags.stubs.system",
+
+			],
+		}
+	`
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("sdklib.source_preferred_using_legacy_flags", "sdklib.prebuilt_preferred_using_legacy_flags"),
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			android.RegisterApexContributionsBuildComponents(ctx)
+		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
+			}
+		}),
+	).RunTestWithBp(t, bp)
+
+	// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
+	public := result.ModuleForTests("public", "android_common")
+	rule := public.Output("javac/public.jar")
+	inputs := rule.Implicits.Strings()
+	expectedInputs := []string{
+		// source
+		"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.jar",
+		"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system.jar",
+
+		// prebuilt
+		"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.jar",
+		"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs.system/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.system.jar",
+	}
+	for _, expected := range expectedInputs {
+		if !android.InList(expected, inputs) {
+			t.Errorf("expected %q to contain %q", inputs, expected)
+		}
+	}
+}
+
 func TestJavaSdkLibraryEnforce(t *testing.T) {
 	partitionToBpOption := func(partition string) string {
 		switch partition {
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index 0d14019..ef0f44a 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -19,9 +19,11 @@
     exit 1
 fi
 
+# Note: NDK doesn't support flagging APIs, so we hardcode it to trunk_staging.
 # TODO: remove ALLOW_MISSING_DEPENDENCIES=true when all the riscv64
 # dependencies exist (currently blocked by http://b/273792258).
 # TODO: remove BUILD_BROKEN_DISABLE_BAZEL=1 when bazel supports riscv64 (http://b/262192655).
+TARGET_RELEASE=trunk_staging \
 ALLOW_MISSING_DEPENDENCIES=true \
 BUILD_BROKEN_DISABLE_BAZEL=1 \
     TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index c6e6e30..ed3fbb7 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -149,6 +149,11 @@
     else:
         sys.exit(f'Unknown type: {args.type}')
 
+    # Reject contributions field at build time while keeping the runtime behavior for GRF.
+    if getattr(pb, 'contributions'):
+        sys.exit(f"{args.input}: 'contributions' is set. "
+                 "It's deprecated. Instead, make the APEX 'visible' and use android_dlopen_ext().")
+
 
 def ValidateAndWriteAsPbFile(pb, output_path):
     ValidateConfiguration(pb)
diff --git a/ui/build/config.go b/ui/build/config.go
index c33312b..d345415 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -31,6 +31,7 @@
 	"time"
 
 	"android/soong/shared"
+	"android/soong/ui/metrics"
 
 	"google.golang.org/protobuf/proto"
 
@@ -85,7 +86,7 @@
 	searchApiDir             bool // Scan the Android.bp files generated in out/api_surfaces
 	skipMetricsUpload        bool
 	buildStartedTime         int64 // For metrics-upload-only - manually specify a build-started time
-	buildFromTextStub        bool
+	buildFromSourceStub      bool
 	ensureAllowlistIntegrity bool   // For CI builds - make sure modules are mixed-built
 	bazelExitCode            int32  // For b runs - necessary for updating NonZeroExit
 	besId                    string // For b runs, to identify the BuildEventService logs
@@ -461,6 +462,42 @@
 	return NewConfig(ctx, getConfigArgs(action, dir, ctx, args)...)
 }
 
+// Prepare for getting make variables.  For them to be accurate, we need to have
+// obtained PRODUCT_RELEASE_CONFIG_MAPS.
+//
+// Returns:
+//
+//	Whether config should be called again.
+//
+// TODO: when converting product config to a declarative language, make sure
+// that PRODUCT_RELEASE_CONFIG_MAPS is properly handled as a separate step in
+// that process.
+func SetProductReleaseConfigMaps(ctx Context, config Config) bool {
+	ctx.BeginTrace(metrics.RunKati, "SetProductReleaseConfigMaps")
+	defer ctx.EndTrace()
+
+	if config.SkipConfig() {
+		// This duplicates the logic from Build to skip product config
+		// if the user has explicitly said to.
+		return false
+	}
+
+	releaseConfigVars := []string{
+		"PRODUCT_RELEASE_CONFIG_MAPS",
+	}
+
+	origValue, _ := config.environ.Get("PRODUCT_RELEASE_CONFIG_MAPS")
+	// Get the PRODUCT_RELEASE_CONFIG_MAPS for this product, to avoid polluting the environment
+	// when we run product config to get the rest of the make vars.
+	releaseMapVars, err := dumpMakeVars(ctx, config, nil, releaseConfigVars, false, "")
+	if err != nil {
+		ctx.Fatalln("Error getting PRODUCT_RELEASE_CONFIG_MAPS:", err)
+	}
+	productReleaseConfigMaps := releaseMapVars["PRODUCT_RELEASE_CONFIG_MAPS"]
+	os.Setenv("PRODUCT_RELEASE_CONFIG_MAPS", productReleaseConfigMaps)
+	return origValue != productReleaseConfigMaps
+}
+
 // storeConfigMetrics selects a set of configuration information and store in
 // the metrics system for further analysis.
 func storeConfigMetrics(ctx Context, config Config) {
@@ -783,8 +820,8 @@
 			} else {
 				ctx.Fatalf("unknown option for ninja_weight_source: %s", source)
 			}
-		} else if arg == "--build-from-text-stub" {
-			c.buildFromTextStub = true
+		} else if arg == "--build-from-source-stub" {
+			c.buildFromSourceStub = true
 		} else if strings.HasPrefix(arg, "--build-command=") {
 			buildCmd := strings.TrimPrefix(arg, "--build-command=")
 			// remove quotations
@@ -1119,7 +1156,7 @@
 }
 
 func (c *configImpl) BuildFromTextStub() bool {
-	return c.buildFromTextStub
+	return !c.buildFromSourceStub
 }
 
 func (c *configImpl) TargetProduct() string {
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index efe7478..d364542 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -191,6 +191,9 @@
 		"TARGET_BUILD_APPS",
 		"TARGET_BUILD_UNBUNDLED",
 
+		// Additional release config maps
+		"PRODUCT_RELEASE_CONFIG_MAPS",
+
 		// compiler wrappers set up by make
 		"CC_WRAPPER",
 		"CXX_WRAPPER",
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 90f1798..667f0c9 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -193,8 +193,8 @@
 	if pb.config.multitreeBuild {
 		commonArgs = append(commonArgs, "--multitree-build")
 	}
-	if pb.config.buildFromTextStub {
-		commonArgs = append(commonArgs, "--build-from-text-stub")
+	if pb.config.buildFromSourceStub {
+		commonArgs = append(commonArgs, "--build-from-source-stub")
 	}
 
 	commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list"))
@@ -310,8 +310,8 @@
 	if config.MultitreeBuild() {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--multitree-build")
 	}
-	if config.buildFromTextStub {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-text-stub")
+	if config.buildFromSourceStub {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-source-stub")
 	}
 	if config.ensureAllowlistIntegrity {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--ensure-allowlist-integrity")