Merge "Add a check for -fno-integrated-as" into main
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 9b638e7..250fd56 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -219,11 +219,4 @@
 	android.SetProvider(ctx, android.AconfigReleaseDeclarationsProviderKey, providerData)
 }
 
-func (module *DeclarationsModule) BuildActionProviderKeys() []blueprint.AnyProviderKey {
-	return []blueprint.AnyProviderKey{
-		android.AconfigDeclarationsProviderKey,
-		android.AconfigReleaseDeclarationsProviderKey,
-	}
-}
-
 var _ blueprint.Incremental = &DeclarationsModule{}
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
index ec0a6b6..b5cf687 100644
--- a/aconfig/codegen/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -156,7 +156,7 @@
 		Args: map[string]string{
 			"gendir": this.generatedDir.String(),
 			"mode":   mode,
-			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorageCc()),
+			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
 		},
 	})
 
diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go
index 6182e14..98d288f 100644
--- a/aconfig/codegen/init.go
+++ b/aconfig/codegen/init.go
@@ -64,11 +64,12 @@
 				` && ${aconfig} create-rust-lib` +
 				`    --mode ${mode}` +
 				`    --cache ${in}` +
+				`    --allow-instrumentation ${debug}` +
 				`    --out ${gendir}`,
 			CommandDeps: []string{
 				"$aconfig",
 			},
-		}, "gendir", "mode")
+		}, "gendir", "mode", "debug")
 )
 
 func init() {
diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
index ad8d632..4b896c3 100644
--- a/aconfig/codegen/rust_aconfig_library.go
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -2,6 +2,7 @@
 
 import (
 	"fmt"
+	"strconv"
 
 	"android/soong/android"
 	"android/soong/rust"
@@ -82,6 +83,7 @@
 		Args: map[string]string{
 			"gendir": generatedDir.String(),
 			"mode":   mode,
+			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
 		},
 	})
 	a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
diff --git a/aconfig/init.go b/aconfig/init.go
index 5fa7e76..6f91d8e 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -15,8 +15,6 @@
 package aconfig
 
 import (
-	"encoding/gob"
-
 	"android/soong/android"
 
 	"github.com/google/blueprint"
@@ -108,10 +106,6 @@
 	RegisterBuildComponents(android.InitRegistrationContext)
 	pctx.HostBinToolVariable("aconfig", "aconfig")
 	pctx.HostBinToolVariable("soong_zip", "soong_zip")
-
-	gob.Register(android.AconfigDeclarationsProviderData{})
-	gob.Register(android.AconfigReleaseDeclarationsProviderData{})
-	gob.Register(android.ModuleOutPath{})
 }
 
 func RegisterBuildComponents(ctx android.RegistrationContext) {
diff --git a/android/Android.bp b/android/Android.bp
index 78eca11..16a34b7 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -59,6 +59,7 @@
         "gen_notice.go",
         "hooks.go",
         "image.go",
+        "init.go",
         "license.go",
         "license_kind.go",
         "license_metadata.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 68a6415..6426835 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -554,6 +554,14 @@
 		a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
 	}
 
+	if info.UncheckedModule {
+		a.SetBool("LOCAL_DONT_CHECK_MODULE", true)
+	} else if info.CheckbuildTarget != nil {
+		a.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget)
+	} else {
+		a.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile)
+	}
+
 	if len(info.TestData) > 0 {
 		a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
 	}
@@ -912,6 +920,7 @@
 		case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
 		case "*selinux.selinuxContextsModule": // license properties written
 		case "*sysprop.syspropLibrary": // license properties written
+		case "*vintf.vintfCompatibilityMatrixRule": // use case like phony
 		default:
 			if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") {
 				return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
diff --git a/android/apex.go b/android/apex.go
index 79ee0a8..114fe29 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"slices"
 	"sort"
 	"strconv"
@@ -87,6 +88,9 @@
 
 	// Returns the name of the overridden apex (com.android.foo)
 	BaseApexName string
+
+	// Returns the value of `apex_available_name`
+	ApexAvailableName string
 }
 
 // AllApexInfo holds the ApexInfo of all apexes that include this module.
@@ -145,6 +149,17 @@
 	return false
 }
 
+// To satisfy the comparable interface
+func (i ApexInfo) Equal(other any) bool {
+	otherApexInfo, ok := other.(ApexInfo)
+	return ok && i.ApexVariationName == otherApexInfo.ApexVariationName &&
+		i.MinSdkVersion == otherApexInfo.MinSdkVersion &&
+		i.Updatable == otherApexInfo.Updatable &&
+		i.UsePlatformApis == otherApexInfo.UsePlatformApis &&
+		reflect.DeepEqual(i.InApexVariants, otherApexInfo.InApexVariants) &&
+		reflect.DeepEqual(i.InApexModules, otherApexInfo.InApexModules)
+}
+
 // ApexTestForInfo stores the contents of APEXes for which this module is a test - although this
 // module is not part of the APEX - and thus has access to APEX internals.
 type ApexTestForInfo struct {
@@ -700,7 +715,7 @@
 	base.ApexProperties.InAnyApex = true
 	base.ApexProperties.DirectlyInAnyApex = inApex == directlyInApex
 
-	if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) {
+	if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() {
 		// Do not install the module for platform, but still allow it to output
 		// uninstallable AndroidMk entries in certain cases when they have side
 		// effects.  TODO(jiyong): move this routine to somewhere else
diff --git a/android/api_levels.go b/android/api_levels.go
index dc17238..2b1d01d 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -444,26 +444,27 @@
 
 func getApiLevelsMapReleasedVersions() (map[string]int, error) {
 	return map[string]int{
-		"G":              9,
-		"I":              14,
-		"J":              16,
-		"J-MR1":          17,
-		"J-MR2":          18,
-		"K":              19,
-		"L":              21,
-		"L-MR1":          22,
-		"M":              23,
-		"N":              24,
-		"N-MR1":          25,
-		"O":              26,
-		"O-MR1":          27,
-		"P":              28,
-		"Q":              29,
-		"R":              30,
-		"S":              31,
-		"S-V2":           32,
-		"Tiramisu":       33,
-		"UpsideDownCake": 34,
+		"G":               9,
+		"I":               14,
+		"J":               16,
+		"J-MR1":           17,
+		"J-MR2":           18,
+		"K":               19,
+		"L":               21,
+		"L-MR1":           22,
+		"M":               23,
+		"N":               24,
+		"N-MR1":           25,
+		"O":               26,
+		"O-MR1":           27,
+		"P":               28,
+		"Q":               29,
+		"R":               30,
+		"S":               31,
+		"S-V2":            32,
+		"Tiramisu":        33,
+		"UpsideDownCake":  34,
+		"VanillaIceCream": 35,
 	}, nil
 }
 
diff --git a/android/arch_list.go b/android/arch_list.go
index f1289a3..2937092 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -159,6 +159,9 @@
 		"armv9-a": {
 			"dotprod",
 		},
+		"armv9-2a": {
+			"dotprod",
+		},
 	},
 	X86: {
 		"amberlake": {
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index a7b65e0..38f1382 100644
--- a/android/compliance_metadata.go
+++ b/android/compliance_metadata.go
@@ -17,6 +17,7 @@
 import (
 	"bytes"
 	"encoding/csv"
+	"encoding/gob"
 	"fmt"
 	"slices"
 	"strconv"
@@ -131,6 +132,28 @@
 	}
 }
 
+func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := encoder.Encode(c.properties)
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (c *ComplianceMetadataInfo) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := decoder.Decode(&c.properties)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func (c *ComplianceMetadataInfo) SetStringValue(propertyName string, value string) {
 	if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) {
 		panic(fmt.Errorf("Unknown metadata property: %s.", propertyName))
diff --git a/android/config.go b/android/config.go
index bbb08dd..b682c2e 100644
--- a/android/config.go
+++ b/android/config.go
@@ -270,6 +270,11 @@
 		Bool(c.config.productVariables.HiddenapiExportableStubs)
 }
 
+// Enable read flag from new storage
+func (c Config) ReleaseReadFromNewStorage() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE")
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
@@ -1490,11 +1495,6 @@
 		}
 	}
 	if coverage && len(c.config.productVariables.NativeCoverageExcludePaths) > 0 {
-		// Workaround coverage boot failure.
-		// http://b/269981180
-		if strings.HasPrefix(path, "external/protobuf") {
-			coverage = false
-		}
 		if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
 			coverage = false
 		}
@@ -1828,10 +1828,6 @@
 	return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
 }
 
-func (c *deviceConfig) BuildBrokenUsesSoongPython2Modules() bool {
-	return c.config.productVariables.BuildBrokenUsesSoongPython2Modules
-}
-
 func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
 	return c.config.productVariables.BuildDebugfsRestrictionsEnabled
 }
@@ -1962,6 +1958,10 @@
 	return c.productVariables.GetBuildFlagBool("RELEASE_USE_RESOURCE_PROCESSOR_BY_DEFAULT")
 }
 
+func (c *config) UseTransitiveJarsInClasspath() bool {
+	return c.productVariables.GetBuildFlagBool("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH")
+}
+
 var (
 	mainlineApexContributionBuildFlagsToApexNames = map[string]string{
 		"RELEASE_APEX_CONTRIBUTIONS_ADBD":                    "com.android.adbd",
@@ -2064,3 +2064,19 @@
 func (c *config) EnableUffdGc() string {
 	return String(c.productVariables.EnableUffdGc)
 }
+
+func (c *config) DeviceFrameworkCompatibilityMatrixFile() []string {
+	return c.productVariables.DeviceFrameworkCompatibilityMatrixFile
+}
+
+func (c *config) DeviceProductCompatibilityMatrixFile() []string {
+	return c.productVariables.DeviceProductCompatibilityMatrixFile
+}
+
+func (c *config) BoardAvbEnable() bool {
+	return Bool(c.productVariables.BoardAvbEnable)
+}
+
+func (c *config) BoardAvbSystemAddHashtreeFooterArgs() []string {
+	return c.productVariables.BoardAvbSystemAddHashtreeFooterArgs
+}
diff --git a/android/container.go b/android/container.go
index 722b241..c048d6c 100644
--- a/android/container.go
+++ b/android/container.go
@@ -15,8 +15,10 @@
 package android
 
 import (
+	"fmt"
 	"reflect"
 	"slices"
+	"strings"
 
 	"github.com/google/blueprint"
 )
@@ -398,6 +400,40 @@
 
 var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
 
+func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m, dep Module) bool {
+	for _, label := range allowedExceptionLabels {
+		if exceptionHandleFunctionsTable[label](ctx, m, dep) {
+			return true
+		}
+	}
+	return false
+}
+
+func (c *ContainersInfo) GetViolations(mctx ModuleContext, m, dep Module, depInfo ContainersInfo) []string {
+	var violations []string
+
+	// Any containers that the module belongs to but the dependency does not belong to must be examined.
+	_, containersUniqueToModule, _ := ListSetDifference(c.belongingContainers, depInfo.belongingContainers)
+
+	// Apex container should be examined even if both the module and the dependency belong to
+	// the apex container to check that the two modules belong to the same apex.
+	if InList(ApexContainer, c.belongingContainers) && !InList(ApexContainer, containersUniqueToModule) {
+		containersUniqueToModule = append(containersUniqueToModule, ApexContainer)
+	}
+
+	for _, containerUniqueToModule := range containersUniqueToModule {
+		for _, restriction := range containerUniqueToModule.restricted {
+			if InList(restriction.dependency, depInfo.belongingContainers) {
+				if !satisfyAllowedExceptions(mctx, restriction.allowedExceptions, m, dep) {
+					violations = append(violations, restriction.errorMessage)
+				}
+			}
+		}
+	}
+
+	return violations
+}
+
 func generateContainerInfo(ctx ModuleContext) ContainersInfo {
 	var containers []*container
 
@@ -439,3 +475,32 @@
 		SetProvider(ctx, ContainersInfoProvider, containersInfo)
 	}
 }
+
+func checkContainerViolations(ctx ModuleContext) {
+	if _, ok := ctx.Module().(InstallableModule); ok {
+		containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
+		ctx.VisitDirectDepsIgnoreBlueprint(func(dep Module) {
+			if !dep.Enabled(ctx) {
+				return
+			}
+
+			// Pre-existing violating dependencies are tracked in containerDependencyViolationAllowlist.
+			// If this dependency is allowlisted, do not check for violation.
+			// If not, check if this dependency matches any restricted dependency and
+			// satisfies any exception functions, which allows bypassing the
+			// restriction. If all of the exceptions are not satisfied, throw an error.
+			if depContainersInfo, ok := getContainerModuleInfo(ctx, dep); ok {
+				if allowedViolations, ok := ContainerDependencyViolationAllowlist[ctx.ModuleName()]; ok && InList(dep.Name(), allowedViolations) {
+					return
+				} else {
+					violations := containersInfo.GetViolations(ctx, ctx.Module(), dep, depContainersInfo)
+					if len(violations) > 0 {
+						errorMessage := fmt.Sprintf("%s cannot depend on %s. ", ctx.ModuleName(), dep.Name())
+						errorMessage += strings.Join(violations, " ")
+						ctx.ModuleErrorf(errorMessage)
+					}
+				}
+			}
+		})
+	}
+}
diff --git a/android/container_violations.go b/android/container_violations.go
index e67533d..4251484 100644
--- a/android/container_violations.go
+++ b/android/container_violations.go
@@ -169,6 +169,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsAppStartTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsAppTestStubsApp2": {
 		"framework", // cts -> unstable
 	},
@@ -273,6 +277,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsDocumentContentTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsDreamsTestCases": {
 		"framework", // cts -> unstable
 	},
@@ -281,6 +289,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsEmptyTestApp_RejectedByVerifier": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsEphemeralTestsEphemeralApp1": {
 		"framework", // cts -> unstable
 	},
@@ -301,10 +313,18 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsFgsTimeoutTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsFileDescriptorTestCases": {
 		"framework", // cts -> unstable
 	},
 
+	"CtsFingerprintTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsHostsideCompatChangeTestsApp": {
 		"framework", // cts -> unstable
 	},
@@ -433,6 +453,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsMediaProviderTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsMediaProviderTranscodeTests": {
 		"framework", // cts -> unstable
 	},
@@ -501,6 +525,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsOnDeviceIntelligenceServiceTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsOnDevicePersonalizationTestCases": {
 		"framework", // cts -> unstable
 	},
@@ -521,6 +549,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsPackageWatchdogTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsPermissionsSyncTestApp": {
 		"framework", // cts -> unstable
 	},
@@ -669,6 +701,10 @@
 		"framework", // cts -> unstable
 	},
 
+	"CtsTvTunerTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"CtsUsageStatsTestCases": {
 		"framework", // cts -> unstable
 	},
@@ -799,6 +835,11 @@
 		"ondevicepersonalization_flags_lib", // apex [com.android.ondevicepersonalization] -> system
 	},
 
+	"framework-pdf-v.impl": {
+		"app-compat-annotations",      // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+		"modules-utils-preconditions", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
+	},
+
 	"framework-pdf.impl": {
 		"modules-utils-preconditions", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi]
 	},
@@ -837,14 +878,54 @@
 		"libnativeloader_vendor_shared_lib", // system -> vendor
 	},
 
+	"MctsMediaBetterTogetherTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaCodecTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaDecoderTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"MctsMediaDrmFrameworkTestCases": {
 		"framework", // cts -> unstable
 	},
 
+	"MctsMediaEncoderTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaExtractorTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaMiscTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaMuxerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaPlayerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaRecorderTestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"MctsMediaTranscodingTestCases": {
 		"framework", // cts -> unstable
 	},
 
+	"MctsMediaV2TestCases": {
+		"framework", // cts -> unstable
+	},
+
 	"MediaProvider": {
 		"app-compat-annotations", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
 	},
diff --git a/android/defs.go b/android/defs.go
index 78cdea2..9f3fb1e 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -16,7 +16,6 @@
 
 import (
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 )
 
 var (
@@ -120,8 +119,3 @@
 		return ctx.Config().RBEWrapper()
 	})
 }
-
-// GlobToListFileRule creates a rule that writes a list of files matching a pattern to a file.
-func GlobToListFileRule(ctx ModuleContext, pattern string, excludes []string, file WritablePath) {
-	bootstrap.GlobFile(ctx.blueprintModuleContext(), pattern, excludes, file.String())
-}
diff --git a/android/depset_generic.go b/android/depset_generic.go
index 45c1937..690987a 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -15,6 +15,9 @@
 package android
 
 import (
+	"bytes"
+	"encoding/gob"
+	"errors"
 	"fmt"
 )
 
@@ -65,6 +68,30 @@
 	transitive []*DepSet[T]
 }
 
+func (d *DepSet[T]) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(d.preorder), encoder.Encode(d.reverse),
+		encoder.Encode(d.order), encoder.Encode(d.direct), encoder.Encode(d.transitive))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (d *DepSet[T]) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&d.preorder), decoder.Decode(&d.reverse),
+		decoder.Decode(&d.order), decoder.Decode(&d.direct), decoder.Decode(&d.transitive))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 // NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
 func NewDepSet[T depSettableType](order DepSetOrder, direct []T, transitive []*DepSet[T]) *DepSet[T] {
 	var directCopy []T
diff --git a/android/init.go b/android/init.go
new file mode 100644
index 0000000..d5b486b
--- /dev/null
+++ b/android/init.go
@@ -0,0 +1,22 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import "encoding/gob"
+
+func init() {
+	gob.Register(ModuleOutPath{})
+	gob.Register(unstableInfo{})
+}
diff --git a/android/module.go b/android/module.go
index 9f73729..009b0df 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,6 +15,9 @@
 package android
 
 import (
+	"bytes"
+	"encoding/gob"
+	"errors"
 	"fmt"
 	"net/url"
 	"path/filepath"
@@ -492,6 +495,10 @@
 
 	// vintf_fragment Modules required from this module.
 	Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"`
+
+	// List of module names that are prevented from being installed when this module gets
+	// installed.
+	Overrides []string
 }
 
 type distProperties struct {
@@ -1545,26 +1552,43 @@
 	return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
 }
 
+func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) {
+	namespacePrefix := ctx.Namespace().id
+	if namespacePrefix != "" {
+		namespacePrefix = namespacePrefix + "-"
+	}
+
+	if !ctx.uncheckedModule {
+		name := namespacePrefix + ctx.ModuleName() + "-" + ctx.ModuleSubDir() + "-checkbuild"
+		ctx.Phony(name, ctx.checkbuildFiles...)
+		ctx.checkbuildTarget = PathForPhony(ctx, name)
+	}
+
+}
+
 func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) {
 	var allInstalledFiles InstallPaths
-	var allCheckbuildFiles Paths
+	var allCheckbuildTargets Paths
 	ctx.VisitAllModuleVariants(func(module Module) {
 		a := module.base()
-		var checkBuilds Paths
+		var checkbuildTarget Path
+		var uncheckedModule bool
 		if a == m {
 			allInstalledFiles = append(allInstalledFiles, ctx.installFiles...)
-			checkBuilds = ctx.checkbuildFiles
+			checkbuildTarget = ctx.checkbuildTarget
+			uncheckedModule = ctx.uncheckedModule
 		} else {
 			info := OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider)
 			allInstalledFiles = append(allInstalledFiles, info.InstallFiles...)
-			checkBuilds = info.CheckbuildFiles
+			checkbuildTarget = info.CheckbuildTarget
+			uncheckedModule = info.UncheckedModule
 		}
 		// A module's -checkbuild phony targets should
 		// not be created if the module is not exported to make.
 		// Those could depend on the build target and fail to compile
 		// for the current build target.
-		if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a) {
-			allCheckbuildFiles = append(allCheckbuildFiles, checkBuilds...)
+		if (!ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a)) && !uncheckedModule && checkbuildTarget != nil {
+			allCheckbuildTargets = append(allCheckbuildTargets, checkbuildTarget)
 		}
 	})
 
@@ -1585,11 +1609,10 @@
 		deps = append(deps, info.InstallTarget)
 	}
 
-	if len(allCheckbuildFiles) > 0 {
+	if len(allCheckbuildTargets) > 0 {
 		name := namespacePrefix + ctx.ModuleName() + "-checkbuild"
-		ctx.Phony(name, allCheckbuildFiles...)
-		info.CheckbuildTarget = PathForPhony(ctx, name)
-		deps = append(deps, info.CheckbuildTarget)
+		ctx.Phony(name, allCheckbuildTargets...)
+		deps = append(deps, PathForPhony(ctx, name))
 	}
 
 	if len(deps) > 0 {
@@ -1706,9 +1729,11 @@
 }
 
 type InstallFilesInfo struct {
-	InstallFiles    InstallPaths
-	CheckbuildFiles Paths
-	PackagingSpecs  []PackagingSpec
+	InstallFiles     InstallPaths
+	CheckbuildFiles  Paths
+	CheckbuildTarget Path
+	UncheckedModule  bool
+	PackagingSpecs   []PackagingSpec
 	// katiInstalls tracks the install rules that were created by Soong but are being exported
 	// to Make to convert to ninja rules so that Make can add additional dependencies.
 	KatiInstalls             katiInstalls
@@ -1755,6 +1780,9 @@
 	}
 
 	setContainerInfo(ctx)
+	if ctx.Config().Getenv("DISABLE_CONTAINER_CHECK") != "true" {
+		checkContainerViolations(ctx)
+	}
 
 	ctx.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
 
@@ -1876,61 +1904,16 @@
 			return
 		}
 
-		incrementalAnalysis := false
-		incrementalEnabled := false
-		var cacheKey *blueprint.BuildActionCacheKey = nil
-		var incrementalModule *blueprint.Incremental = nil
-		if ctx.bp.GetIncrementalEnabled() {
-			if im, ok := m.module.(blueprint.Incremental); ok {
-				incrementalModule = &im
-				incrementalEnabled = im.IncrementalSupported()
-				incrementalAnalysis = ctx.bp.GetIncrementalAnalysis() && incrementalEnabled
-			}
-		}
-		if incrementalEnabled {
-			hash, err := proptools.CalculateHash(m.GetProperties())
-			if err != nil {
-				ctx.ModuleErrorf("failed to calculate properties hash: %s", err)
-				return
-			}
-			cacheInput := new(blueprint.BuildActionCacheInput)
-			cacheInput.PropertiesHash = hash
-			ctx.VisitDirectDeps(func(module Module) {
-				cacheInput.ProvidersHash =
-					append(cacheInput.ProvidersHash, ctx.bp.OtherModuleProviderInitialValueHashes(module))
-			})
-			hash, err = proptools.CalculateHash(&cacheInput)
-			if err != nil {
-				ctx.ModuleErrorf("failed to calculate cache input hash: %s", err)
-				return
-			}
-			cacheKey = &blueprint.BuildActionCacheKey{
-				Id:        ctx.bp.ModuleCacheKey(),
-				InputHash: hash,
-			}
+		m.module.GenerateAndroidBuildActions(ctx)
+		if ctx.Failed() {
+			return
 		}
 
-		restored := false
-		if incrementalAnalysis && cacheKey != nil {
-			restored = ctx.bp.RestoreBuildActions(cacheKey)
-		}
-
-		if !restored {
-			m.module.GenerateAndroidBuildActions(ctx)
-			if ctx.Failed() {
-				return
-			}
-
-			if x, ok := m.module.(IDEInfo); ok {
-				var result IdeInfo
-				x.IDEInfo(ctx, &result)
-				result.BaseModuleName = x.BaseModuleName()
-				SetProvider(ctx, IdeInfoProviderKey, result)
-			}
-		}
-
-		if incrementalEnabled && cacheKey != nil {
-			ctx.bp.CacheBuildActions(cacheKey, incrementalModule)
+		if x, ok := m.module.(IDEInfo); ok {
+			var result IdeInfo
+			x.IDEInfo(ctx, &result)
+			result.BaseModuleName = x.BaseModuleName()
+			SetProvider(ctx, IdeInfoProviderKey, result)
 		}
 
 		// Create the set of tagged dist files after calling GenerateAndroidBuildActions
@@ -1942,9 +1925,13 @@
 			return
 		}
 
+		m.generateVariantTarget(ctx)
+
 		installFiles.LicenseMetadataFile = ctx.licenseMetadataFile
 		installFiles.InstallFiles = ctx.installFiles
 		installFiles.CheckbuildFiles = ctx.checkbuildFiles
+		installFiles.CheckbuildTarget = ctx.checkbuildTarget
+		installFiles.UncheckedModule = ctx.uncheckedModule
 		installFiles.PackagingSpecs = ctx.packagingSpecs
 		installFiles.KatiInstalls = ctx.katiInstalls
 		installFiles.KatiSymlinks = ctx.katiSymlinks
@@ -2010,7 +1997,7 @@
 			TargetDependencies: targetRequired,
 			HostDependencies:   hostRequired,
 			Data:               data,
-			Required:           m.RequiredModuleNames(ctx),
+			Required:           append(m.RequiredModuleNames(ctx), m.VintfFragmentModuleNames(ctx)...),
 		}
 		SetProvider(ctx, ModuleInfoJSONProvider, ctx.moduleInfoJSON)
 	}
@@ -2113,11 +2100,61 @@
 	absFrom string
 }
 
+func (p *katiInstall) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.from), encoder.Encode(p.to),
+		encoder.Encode(p.implicitDeps), encoder.Encode(p.orderOnlyDeps),
+		encoder.Encode(p.executable), encoder.Encode(p.extraFiles),
+		encoder.Encode(p.absFrom))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *katiInstall) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.from), decoder.Decode(&p.to),
+		decoder.Decode(&p.implicitDeps), decoder.Decode(&p.orderOnlyDeps),
+		decoder.Decode(&p.executable), decoder.Decode(&p.extraFiles),
+		decoder.Decode(&p.absFrom))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 type extraFilesZip struct {
 	zip Path
 	dir InstallPath
 }
 
+func (p *extraFilesZip) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.zip), encoder.Encode(p.dir))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *extraFilesZip) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.zip), decoder.Decode(&p.dir))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 type katiInstalls []katiInstall
 
 // BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a
diff --git a/android/module_context.go b/android/module_context.go
index c677f94..3889e40 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -122,6 +122,16 @@
 	// dependency tags for which IsInstallDepNeeded returns true.
 	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
 
+	// InstallFileWithoutCheckbuild creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies, but does not add the file to the list of files to build
+	// during `m checkbuild`.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
+
 	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
 	// directory, and also unzip a zip file containing extra files to install into the same
 	// directory.
@@ -168,7 +178,8 @@
 	// dependency tags for which IsInstallDepNeeded returns true.
 	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
 
-	CheckbuildFile(srcPath Path)
+	CheckbuildFile(srcPaths ...Path)
+	UncheckedModule()
 
 	InstallInData() bool
 	InstallInTestcases() bool
@@ -237,11 +248,13 @@
 type moduleContext struct {
 	bp blueprint.ModuleContext
 	baseModuleContext
-	packagingSpecs  []PackagingSpec
-	installFiles    InstallPaths
-	checkbuildFiles Paths
-	module          Module
-	phonies         map[string]Paths
+	packagingSpecs   []PackagingSpec
+	installFiles     InstallPaths
+	checkbuildFiles  Paths
+	checkbuildTarget Path
+	uncheckedModule  bool
+	module           Module
+	phonies          map[string]Paths
 	// outputFiles stores the output of a module by tag and is used to set
 	// the OutputFilesProvider in GenerateBuildActions
 	outputFiles OutputFilesInfo
@@ -512,17 +525,22 @@
 
 func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
 	deps ...InstallPath) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, false, true, nil)
+	return m.installFile(installPath, name, srcPath, deps, false, true, true, nil)
+}
+
+func (m *moduleContext) InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path,
+	deps ...InstallPath) InstallPath {
+	return m.installFile(installPath, name, srcPath, deps, false, true, false, nil)
 }
 
 func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
 	deps ...InstallPath) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, true, true, nil)
+	return m.installFile(installPath, name, srcPath, deps, true, true, true, nil)
 }
 
 func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
 	extraZip Path, deps ...InstallPath) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, false, true, &extraFilesZip{
+	return m.installFile(installPath, name, srcPath, deps, false, true, true, &extraFilesZip{
 		zip: extraZip,
 		dir: installPath,
 	})
@@ -543,6 +561,7 @@
 
 func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
 	licenseFiles := m.Module().EffectiveLicenseFiles()
+	overrides := CopyOf(m.Module().base().commonProperties.Overrides)
 	spec := PackagingSpec{
 		relPathInPackage:      Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
 		srcPath:               srcPath,
@@ -553,13 +572,15 @@
 		skipInstall:           m.skipInstall(),
 		aconfigPaths:          m.getAconfigPaths(),
 		archType:              m.target.Arch.ArchType,
+		overrides:             &overrides,
+		owner:                 m.ModuleName(),
 	}
 	m.packagingSpecs = append(m.packagingSpecs, spec)
 	return spec
 }
 
 func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath,
-	executable bool, hooks bool, extraZip *extraFilesZip) InstallPath {
+	executable bool, hooks bool, checkbuild bool, extraZip *extraFilesZip) InstallPath {
 
 	fullInstallPath := installPath.Join(m, name)
 	if hooks {
@@ -626,7 +647,9 @@
 
 	m.packageFile(fullInstallPath, srcPath, executable)
 
-	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+	if checkbuild {
+		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+	}
 
 	return fullInstallPath
 }
@@ -667,9 +690,9 @@
 		}
 
 		m.installFiles = append(m.installFiles, fullInstallPath)
-		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 	}
 
+	overrides := CopyOf(m.Module().base().commonProperties.Overrides)
 	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
 		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
 		srcPath:          nil,
@@ -679,6 +702,8 @@
 		skipInstall:      m.skipInstall(),
 		aconfigPaths:     m.getAconfigPaths(),
 		archType:         m.target.Arch.ArchType,
+		overrides:        &overrides,
+		owner:            m.ModuleName(),
 	})
 
 	return fullInstallPath
@@ -714,6 +739,7 @@
 		m.installFiles = append(m.installFiles, fullInstallPath)
 	}
 
+	overrides := CopyOf(m.Module().base().commonProperties.Overrides)
 	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
 		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
 		srcPath:          nil,
@@ -723,6 +749,8 @@
 		skipInstall:      m.skipInstall(),
 		aconfigPaths:     m.getAconfigPaths(),
 		archType:         m.target.Arch.ArchType,
+		overrides:        &overrides,
+		owner:            m.ModuleName(),
 	})
 
 	return fullInstallPath
@@ -734,15 +762,21 @@
 	ret := make(InstallPaths, 0, len(data))
 	for _, d := range data {
 		relPath := d.ToRelativeInstallPath()
-		installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, nil)
+		installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, true, nil)
 		ret = append(ret, installed)
 	}
 
 	return ret
 }
 
-func (m *moduleContext) CheckbuildFile(srcPath Path) {
-	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+// CheckbuildFile specifies the output files that should be built by checkbuild.
+func (m *moduleContext) CheckbuildFile(srcPaths ...Path) {
+	m.checkbuildFiles = append(m.checkbuildFiles, srcPaths...)
+}
+
+// UncheckedModule marks the current module has having no files that should be built by checkbuild.
+func (m *moduleContext) UncheckedModule() {
+	m.uncheckedModule = true
 }
 
 func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
diff --git a/android/neverallow.go b/android/neverallow.go
index a68f5ea..b89d150 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -60,6 +60,7 @@
 	AddNeverAllowRules(createCcStubsRule())
 	AddNeverAllowRules(createJavaExcludeStaticLibsRule())
 	AddNeverAllowRules(createProhibitHeaderOnlyRule())
+	AddNeverAllowRules(createLimitNdkExportRule()...)
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -182,6 +183,7 @@
 		"packages/modules/SdkExtensions/derive_sdk",
 		// These are for apps and shouldn't be used by non-SDK variant modules.
 		"prebuilts/ndk",
+		"frameworks/native/libs/binder/ndk",
 		"tools/test/graphicsbenchmark/apps/sample_app",
 		"tools/test/graphicsbenchmark/functional_tests/java",
 		"vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests",
@@ -266,6 +268,22 @@
 		Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules")
 }
 
+func createLimitNdkExportRule() []Rule {
+	reason := "If the headers you're trying to export are meant to be a part of the NDK, they should be exposed by an ndk_headers module. If the headers shouldn't be a part of the NDK, the headers should instead be exposed from a separate `cc_library_headers` which consumers depend on."
+	// DO NOT ADD HERE - please consult danalbert@
+	// b/357711733
+	return []Rule{
+		NeverAllow().
+			NotIn("frameworks/native/libs/binder/ndk").
+			ModuleType("ndk_library").
+			WithMatcher("export_header_libs", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_generated_headers", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_include_dirs", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_shared_lib_headers", isSetMatcherInstance).Because(reason),
+		NeverAllow().ModuleType("ndk_library").WithMatcher("export_static_lib_headers", isSetMatcherInstance).Because(reason),
+	}
+}
+
 func neverallowMutator(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
diff --git a/android/packaging.go b/android/packaging.go
index 42009d5..0909936 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -15,6 +15,9 @@
 package android
 
 import (
+	"bytes"
+	"encoding/gob"
+	"errors"
 	"fmt"
 	"path/filepath"
 	"sort"
@@ -56,6 +59,42 @@
 
 	// ArchType of the module which produced this packaging spec
 	archType ArchType
+
+	// List of module names that this packaging spec overrides
+	overrides *[]string
+
+	// Name of the module where this packaging spec is output of
+	owner string
+}
+
+func (p *PackagingSpec) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.relPathInPackage), encoder.Encode(p.srcPath),
+		encoder.Encode(p.symlinkTarget), encoder.Encode(p.executable),
+		encoder.Encode(p.effectiveLicenseFiles), encoder.Encode(p.partition),
+		encoder.Encode(p.skipInstall), encoder.Encode(p.aconfigPaths),
+		encoder.Encode(p.archType))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *PackagingSpec) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.relPathInPackage), decoder.Decode(&p.srcPath),
+		decoder.Decode(&p.symlinkTarget), decoder.Decode(&p.executable),
+		decoder.Decode(&p.effectiveLicenseFiles), decoder.Decode(&p.partition),
+		decoder.Decode(&p.skipInstall), decoder.Decode(&p.aconfigPaths),
+		decoder.Decode(&p.archType))
+	if err != nil {
+		return err
+	}
+
+	return nil
 }
 
 func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
@@ -325,7 +364,10 @@
 }
 
 func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
-	m := make(map[string]PackagingSpec)
+	// all packaging specs gathered from the dep.
+	var all []PackagingSpec
+	// list of module names overridden
+	var overridden []string
 
 	var arches []ArchType
 	for _, target := range getSupportedTargets(ctx) {
@@ -357,17 +399,33 @@
 					continue
 				}
 			}
-			dstPath := ps.relPathInPackage
-			if existingPs, ok := m[dstPath]; ok {
-				if !existingPs.Equals(&ps) {
-					ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
-				}
-				continue
+			all = append(all, ps)
+			if ps.overrides != nil {
+				overridden = append(overridden, *ps.overrides...)
 			}
-
-			m[dstPath] = ps
 		}
 	})
+
+	// all minus packaging specs that are overridden
+	var filtered []PackagingSpec
+	for _, ps := range all {
+		if ps.owner != "" && InList(ps.owner, overridden) {
+			continue
+		}
+		filtered = append(filtered, ps)
+	}
+
+	m := make(map[string]PackagingSpec)
+	for _, ps := range filtered {
+		dstPath := ps.relPathInPackage
+		if existingPs, ok := m[dstPath]; ok {
+			if !existingPs.Equals(&ps) {
+				ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
+			}
+			continue
+		}
+		m[dstPath] = ps
+	}
 	return m
 }
 
diff --git a/android/packaging_test.go b/android/packaging_test.go
index 19b46fe..0f7bb39 100644
--- a/android/packaging_test.go
+++ b/android/packaging_test.go
@@ -28,6 +28,7 @@
 	props struct {
 		Deps         []string
 		Skip_install *bool
+		Overrides    []string
 	}
 }
 
@@ -650,3 +651,64 @@
 		runPackagingTest(t, config, bp, tc.expected)
 	}
 }
+
+func TestOverrides(t *testing.T) {
+	bpTemplate := `
+		component {
+			name: "foo",
+			deps: ["bar"],
+		}
+
+		component {
+			name: "bar",
+		}
+
+		component {
+			name: "bar_override",
+			overrides: ["bar"],
+		}
+
+		component {
+			name: "baz",
+			deps: ["bar_override"],
+		}
+
+		package_module {
+			name: "package",
+			deps: %DEPS%,
+		}
+	`
+	testcases := []struct {
+		deps     []string
+		expected []string
+	}{
+		{
+			deps:     []string{"foo"},
+			expected: []string{"lib64/foo", "lib64/bar"},
+		},
+		{
+			deps:     []string{"foo", "bar_override"},
+			expected: []string{"lib64/foo", "lib64/bar_override"},
+		},
+		{
+			deps:     []string{"foo", "bar", "bar_override"},
+			expected: []string{"lib64/foo", "lib64/bar_override"},
+		},
+		{
+			deps:     []string{"bar", "bar_override"},
+			expected: []string{"lib64/bar_override"},
+		},
+		{
+			deps:     []string{"foo", "baz"},
+			expected: []string{"lib64/foo", "lib64/baz", "lib64/bar_override"},
+		},
+	}
+	for _, tc := range testcases {
+		config := testConfig{
+			multiTarget:                true,
+			depsCollectFirstTargetOnly: false,
+		}
+		bp := strings.Replace(bpTemplate, "%DEPS%", `["`+strings.Join(tc.deps, `", "`)+`"]`, -1)
+		runPackagingTest(t, config, bp, tc.expected)
+	}
+}
diff --git a/android/paths.go b/android/paths.go
index d20b84a..e457959 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1766,6 +1766,32 @@
 	fullPath string
 }
 
+func (p *InstallPath) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+	err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.soongOutDir),
+		encoder.Encode(p.partitionDir), encoder.Encode(p.partition),
+		encoder.Encode(p.makePath), encoder.Encode(p.fullPath))
+	if err != nil {
+		return nil, err
+	}
+
+	return w.Bytes(), nil
+}
+
+func (p *InstallPath) GobDecode(data []byte) error {
+	r := bytes.NewBuffer(data)
+	decoder := gob.NewDecoder(r)
+	err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.soongOutDir),
+		decoder.Decode(&p.partitionDir), decoder.Decode(&p.partition),
+		decoder.Decode(&p.makePath), decoder.Decode(&p.fullPath))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 // Will panic if called from outside a test environment.
 func ensureTestOnly() {
 	if PrefixInList(os.Args, "-test.") {
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 95e2b92..18bbcab 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -463,6 +463,8 @@
 	r.build(name, desc, true)
 }
 
+var sandboxEnvOnceKey = NewOnceKey("sandbox_environment_variables")
+
 func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
 	name = ninjaNameEscape(name)
 
@@ -580,16 +582,44 @@
 				})
 			}
 
-			// Set OUT_DIR to the relative path of the sandboxed out directory.
-			// Otherwise, OUT_DIR will be inherited from the rest of the build,
-			// which will allow scripts to escape the sandbox if OUT_DIR is an
-			// absolute path.
-			command.Env = append(command.Env, &sbox_proto.EnvironmentVariable{
-				Name: proto.String("OUT_DIR"),
-				State: &sbox_proto.EnvironmentVariable_Value{
-					Value: sboxOutSubDir,
-				},
-			})
+			// Only allow the build to access certain environment variables
+			command.DontInheritEnv = proto.Bool(true)
+			command.Env = r.ctx.Config().Once(sandboxEnvOnceKey, func() interface{} {
+				// The list of allowed variables was found by running builds of all
+				// genrules and seeing what failed
+				var result []*sbox_proto.EnvironmentVariable
+				inheritedVars := []string{
+					"PATH",
+					"JAVA_HOME",
+					"TMPDIR",
+					// Allow RBE variables because the art tests invoke RBE manually
+					"RBE_log_dir",
+					"RBE_platform",
+					"RBE_server_address",
+					// TODO: RBE_exec_root is set to the absolute path to the root of the source
+					// tree, which we don't want sandboxed actions to find. Remap it to ".".
+					"RBE_exec_root",
+				}
+				for _, v := range inheritedVars {
+					result = append(result, &sbox_proto.EnvironmentVariable{
+						Name: proto.String(v),
+						State: &sbox_proto.EnvironmentVariable_Inherit{
+							Inherit: true,
+						},
+					})
+				}
+				// Set OUT_DIR to the relative path of the sandboxed out directory.
+				// Otherwise, OUT_DIR will be inherited from the rest of the build,
+				// which will allow scripts to escape the sandbox if OUT_DIR is an
+				// absolute path.
+				result = append(result, &sbox_proto.EnvironmentVariable{
+					Name: proto.String("OUT_DIR"),
+					State: &sbox_proto.EnvironmentVariable_Value{
+						Value: sboxOutSubDir,
+					},
+				})
+				return result
+			}).([]*sbox_proto.EnvironmentVariable)
 			command.Chdir = proto.Bool(true)
 		}
 
diff --git a/android/selects_test.go b/android/selects_test.go
index fc020a4..90d7091 100644
--- a/android/selects_test.go
+++ b/android/selects_test.go
@@ -1009,6 +1009,28 @@
 			},
 			expectedError: `variable already set in inherited scope, previous assignment:`,
 		},
+		{
+			name: "Basic string list postprocessor",
+			bp: `
+my_defaults {
+	name: "defaults_a",
+	my_string_list: ["a", "b", "c"],
+	string_list_postprocessor_add_to_elements: "1",
+}
+my_defaults {
+	name: "defaults_b",
+	my_string_list: ["d", "e", "f"],
+	string_list_postprocessor_add_to_elements: "2",
+}
+my_module_type {
+	name: "foo",
+	defaults: ["defaults_a", "defaults_b"],
+}
+`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"d2", "e2", "f2", "a1", "b1", "c1"},
+			},
+		},
 	}
 
 	for _, tc := range testCases {
@@ -1161,9 +1183,15 @@
 	return m
 }
 
+type selectsMockDefaultsProperties struct {
+	String_list_postprocessor_add_to_elements string
+}
+
 type selectsMockModuleDefaults struct {
 	ModuleBase
 	DefaultsModuleBase
+	myProperties       selectsMockModuleProperties
+	defaultsProperties selectsMockDefaultsProperties
 }
 
 func (d *selectsMockModuleDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -1173,10 +1201,22 @@
 	module := &selectsMockModuleDefaults{}
 
 	module.AddProperties(
-		&selectsMockModuleProperties{},
+		&module.myProperties,
+		&module.defaultsProperties,
 	)
 
 	InitDefaultsModule(module)
 
+	AddLoadHook(module, func(lhc LoadHookContext) {
+		if module.defaultsProperties.String_list_postprocessor_add_to_elements != "" {
+			module.myProperties.My_string_list.AddPostProcessor(func(x []string) []string {
+				for i := range x {
+					x[i] = x[i] + module.defaultsProperties.String_list_postprocessor_add_to_elements
+				}
+				return x
+			})
+		}
+	})
+
 	return module
 }
diff --git a/android/singleton_module.go b/android/singleton_module.go
index 2351738..43028e8 100644
--- a/android/singleton_module.go
+++ b/android/singleton_module.go
@@ -68,7 +68,7 @@
 func (smb *SingletonModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
 	smb.lock.Lock()
 	if smb.variant != "" {
-		ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only  have one variant", smb.variant)
+		ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only have one variant", smb.variant)
 	}
 	smb.variant = ctx.ModuleSubDir()
 	smb.lock.Unlock()
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
index dd7dc2c..d2595ed 100644
--- a/android/updatable_modules.go
+++ b/android/updatable_modules.go
@@ -33,4 +33,4 @@
 // * AOSP            - xx9990000
 // * x-mainline-prod - xx9990000
 // * master          - 990090000
-const DefaultUpdatableModuleVersion = "350090000"
+const DefaultUpdatableModuleVersion = "352090000"
diff --git a/android/variable.go b/android/variable.go
index 14f1756..8ca75ee 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -445,7 +445,6 @@
 	GenruleSandboxing                   *bool    `json:",omitempty"`
 	BuildBrokenEnforceSyspropOwner      bool     `json:",omitempty"`
 	BuildBrokenTrebleSyspropNeverallow  bool     `json:",omitempty"`
-	BuildBrokenUsesSoongPython2Modules  bool     `json:",omitempty"`
 	BuildBrokenVendorPropertyNamespace  bool     `json:",omitempty"`
 	BuildBrokenIncorrectPartitionImages bool     `json:",omitempty"`
 	BuildBrokenInputDirModules          []string `json:",omitempty"`
@@ -515,6 +514,11 @@
 	OdmPropFiles       []string `json:",omitempty"`
 
 	EnableUffdGc *string `json:",omitempty"`
+
+	BoardAvbEnable                         *bool    `json:",omitempty"`
+	BoardAvbSystemAddHashtreeFooterArgs    []string `json:",omitempty"`
+	DeviceFrameworkCompatibilityMatrixFile []string `json:",omitempty"`
+	DeviceProductCompatibilityMatrixFile   []string `json:",omitempty"`
 }
 
 type PartitionQualifiedVariablesType struct {
diff --git a/androidmk/parser/ast.go b/androidmk/parser/ast.go
index d5d1354..c3d198f 100644
--- a/androidmk/parser/ast.go
+++ b/androidmk/parser/ast.go
@@ -84,6 +84,7 @@
 	Prerequisites *MakeString
 	RecipePos     Pos
 	Recipe        string
+	RecipeEndPos  Pos
 }
 
 func (x *Rule) Dump() string {
@@ -95,7 +96,7 @@
 }
 
 func (x *Rule) Pos() Pos { return x.Target.Pos() }
-func (x *Rule) End() Pos { return Pos(int(x.RecipePos) + len(x.Recipe)) }
+func (x *Rule) End() Pos { return x.RecipeEndPos }
 
 type Variable struct {
 	Name *MakeString
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index 8a20bb0..f2477db 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -448,6 +448,7 @@
 			Prerequisites: prerequisites,
 			Recipe:        recipe,
 			RecipePos:     recipePos,
+			RecipeEndPos:  p.pos(),
 		})
 	}
 }
diff --git a/androidmk/parser/parser_test.go b/androidmk/parser/parser_test.go
index fb03c23..e238f8b 100644
--- a/androidmk/parser/parser_test.go
+++ b/androidmk/parser/parser_test.go
@@ -124,3 +124,25 @@
 		})
 	}
 }
+
+func TestRuleEnd(t *testing.T) {
+	name := "ruleEndTest"
+	in := `all:
+ifeq (A, A)
+	echo foo
+	echo foo
+	echo foo
+	echo foo
+endif
+	echo bar
+`
+	p := NewParser(name, bytes.NewBufferString(in))
+	got, errs := p.Parse()
+	if len(errs) != 0 {
+		t.Fatalf("Unexpected errors while parsing: %v", errs)
+	}
+
+	if got[0].End() < got[len(got) -1].Pos() {
+		t.Errorf("Rule's end (%d) is smaller than directive that inside of rule's start (%v)\n", got[0].End(), got[len(got) -1].Pos())
+	}
+}
diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go
index 14c0b63..bb811f5 100644
--- a/apex/aconfig_test.go
+++ b/apex/aconfig_test.go
@@ -74,6 +74,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 		},
 		{
@@ -122,6 +124,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 		},
 		{
@@ -345,6 +349,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 			expectedError: `.*my_java_library_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
 		},
@@ -392,6 +398,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
 		},
@@ -693,6 +701,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
 		},
@@ -769,6 +779,8 @@
 					apex_available: [
 						"myapex",
 					],
+					sdk_version: "none",
+					system_modules: "none",
 				}`,
 		},
 	}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 4112108..933682a 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -136,6 +136,11 @@
 		fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", filepath.Join(modulePath, fi.stem()))
 		fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", fi.builtFile.String()+":"+filepath.Join(modulePath, fi.stem()))
 		fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
+		if fi.checkbuildTarget != nil {
+			fmt.Fprintln(w, "LOCAL_CHECKED_MODULE :=", fi.checkbuildTarget.String())
+		} else {
+			fmt.Fprintln(w, "LOCAL_CHECKED_MODULE :=", fi.builtFile.String())
+		}
 		fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
 		if fi.module != nil {
 			// This apexFile's module comes from Soong
diff --git a/apex/apex.go b/apex/apex.go
index d5776b5..1f4a99b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -577,6 +577,8 @@
 	customStem string
 	symlinks   []string // additional symlinks
 
+	checkbuildTarget android.Path
+
 	// Info for Android.mk Module name of `module` in AndroidMk. Note the generated AndroidMk
 	// module for apexFile is named something like <AndroidMk module name>.<apex name>[<apex
 	// suffix>]
@@ -612,6 +614,9 @@
 		module:              module,
 	}
 	if module != nil {
+		if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok {
+			ret.checkbuildTarget = installFilesInfo.CheckbuildTarget
+		}
 		ret.moduleDir = ctx.OtherModuleDir(module)
 		ret.partition = module.PartitionTag(ctx.DeviceConfig())
 		ret.requiredModuleNames = module.RequiredModuleNames(ctx)
@@ -1073,6 +1078,7 @@
 		ApexContents:      []*android.ApexContents{apexContents},
 		TestApexes:        testApexes,
 		BaseApexName:      mctx.ModuleName(),
+		ApexAvailableName: proptools.String(a.properties.Apex_available_name),
 	}
 	mctx.WalkDeps(func(child, parent android.Module) bool {
 		if !continueApexDepsWalk(child, parent) {
@@ -1937,8 +1943,6 @@
 
 	// visitor skips these from this list of module names
 	unwantedTransitiveDeps []string
-
-	aconfigFiles []android.Path
 }
 
 func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
@@ -2005,7 +2009,6 @@
 				fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
-				addAconfigFiles(vctx, ctx, child)
 				// Collect the list of stub-providing libs except:
 				// - VNDK libs are only for vendors
 				// - bootstrap bionic libs are treated as provided by system
@@ -2017,7 +2020,6 @@
 				fi := apexFileForRustLibrary(ctx, ch)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
@@ -2026,11 +2028,9 @@
 			switch ch := child.(type) {
 			case *cc.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			case *rust.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf("binaries",
@@ -2070,7 +2070,6 @@
 					return false
 				}
 				vctx.filesInfo = append(vctx.filesInfo, af)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
@@ -2079,14 +2078,11 @@
 			switch ap := child.(type) {
 			case *java.AndroidApp:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			case *java.AndroidAppImport:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-				addAconfigFiles(vctx, ctx, child)
 			case *java.AndroidTestHelperApp:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
-				addAconfigFiles(vctx, ctx, child)
 			case *java.AndroidAppSet:
 				appDir := "app"
 				if ap.Privileged() {
@@ -2100,7 +2096,6 @@
 				af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
 				af.certificate = java.PresignedCertificate
 				vctx.filesInfo = append(vctx.filesInfo, af)
-				addAconfigFiles(vctx, ctx, child)
 			default:
 				ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 			}
@@ -2132,7 +2127,6 @@
 				for _, etcFile := range filesToCopy {
 					vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
 				}
-				addAconfigFiles(vctx, ctx, child)
 			} else {
 				ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
 			}
@@ -2147,7 +2141,6 @@
 				af := apexFileForExecutable(ctx, ccTest)
 				af.class = nativeTest
 				vctx.filesInfo = append(vctx.filesInfo, af)
-				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			} else {
 				ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
@@ -2227,7 +2220,6 @@
 			}
 
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		} else if rm, ok := child.(*rust.Module); ok {
 			if !android.IsDepInSameApex(ctx, am, am) {
@@ -2237,7 +2229,6 @@
 			af := apexFileForRustLibrary(ctx, rm)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		}
 	} else if cc.IsHeaderDepTag(depTag) {
@@ -2260,7 +2251,6 @@
 			af := apexFileForRustLibrary(ctx, rustm)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		}
 	} else if rust.IsRlibDepTag(depTag) {
@@ -2279,7 +2269,6 @@
 				return false
 			}
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		default:
 			ctx.PropertyErrorf("bootclasspath_fragments",
@@ -2294,7 +2283,6 @@
 			if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil {
 				vctx.filesInfo = append(vctx.filesInfo, *profileAf)
 			}
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		default:
 			ctx.PropertyErrorf("systemserverclasspath_fragments",
@@ -2312,19 +2300,6 @@
 	return false
 }
 
-func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) {
-	if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigPropagatingProviderKey); ok {
-		if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
-			vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
-		}
-	}
-
-	validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
-	if validationFlag == "error" || validationFlag == "warning" {
-		android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), module, validationFlag == "error")
-	}
-}
-
 func (a *apexBundle) shouldCheckDuplicate(ctx android.ModuleContext) bool {
 	// TODO(b/263308293) remove this
 	if a.properties.IsCoverageVariant {
@@ -2406,13 +2381,16 @@
 	// 3) some fields in apexBundle struct are configured
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = vctx.filesInfo
-	a.aconfigFiles = android.FirstUniquePaths(vctx.aconfigFiles)
 
 	a.setPayloadFsType(ctx)
 	a.setSystemLibLink(ctx)
 	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
 
 	////////////////////////////////////////////////////////////////////////////////////////////
+	// 3.a) some artifacts are generated from the collected files
+	a.filesInfo = append(a.filesInfo, a.buildAconfigFiles(ctx)...)
+
+	////////////////////////////////////////////////////////////////////////////////////////////
 	// 4) generate the build rules to create the APEX. This is done in builder.go.
 	a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs)
 	a.buildApex(ctx)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8d34e9f..685cb37 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -267,6 +267,7 @@
 }
 
 func ensureMatches(t *testing.T, result string, expectedRex string) {
+	t.Helper()
 	ok, err := regexp.MatchString(expectedRex, result)
 	if err != nil {
 		t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", result, expectedRex, err)
@@ -277,6 +278,14 @@
 	}
 }
 
+func ensureListContainsMatch(t *testing.T, result []string, expectedRex string) {
+	t.Helper()
+	p := regexp.MustCompile(expectedRex)
+	if android.IndexListPred(func(s string) bool { return p.MatchString(s) }, result) == -1 {
+		t.Errorf("%q is not found in %v", expectedRex, result)
+	}
+}
+
 func ensureListContains(t *testing.T, result []string, expected string) {
 	t.Helper()
 	if !android.InList(expected, result) {
@@ -4929,6 +4938,7 @@
 		java_import {
 			name: "libfoo",
 			jars: ["libfoo.jar"],
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -4969,6 +4979,22 @@
 	t.Run("prebuilt with source preferred", func(t *testing.T) {
 
 		bp := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: false,
+			java_libs: [
+				"libfoo",
+				"libbar",
+			],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -4985,10 +5011,21 @@
 		java_import {
 			name: "libfoo",
 			jars: ["libfoo.jar"],
+			apex_available: [
+				"myapex",
+			],
+			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
 			name: "libfoo",
+			srcs: ["foo/bar/MyClass.java"],
+			apex_available: [
+				"myapex",
+			],
+			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -4996,12 +5033,21 @@
 			public: {
 				jars: ["libbar.jar"],
 			},
+			apex_available: [
+				"myapex",
+			],
+			compile_dex: true,
 		}
 
 		java_sdk_library {
 			name: "libbar",
 			srcs: ["foo/bar/MyClass.java"],
 			unsafe_ignore_missing_latest_api: true,
+			apex_available: [
+				"myapex",
+			],
+			compile_dex: true,
+			sdk_version: "core_current",
 		}
 	`
 
@@ -5010,11 +5056,9 @@
 
 		checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
 		checkDexJarInstallPath(t, ctx, "prebuilt_libfoo")
-		ensureNoSourceVariant(t, ctx, "libfoo")
 
 		checkDexJarBuildPath(t, ctx, "prebuilt_libbar")
 		checkDexJarInstallPath(t, ctx, "prebuilt_libbar")
-		ensureNoSourceVariant(t, ctx, "libbar")
 	})
 
 	t.Run("prebuilt preferred with source", func(t *testing.T) {
@@ -5040,6 +5084,7 @@
 
 		java_library {
 			name: "libfoo",
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5166,6 +5211,7 @@
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5320,12 +5366,14 @@
 			name: "libfoo",
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			sdk_version: "core_current",
 		}
 
 		java_library {
 			name: "libfoo",
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5417,6 +5465,7 @@
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -5424,6 +5473,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5514,6 +5564,7 @@
 			name: "libfoo",
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -5522,6 +5573,7 @@
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5540,6 +5592,7 @@
 			apex_available: ["myapex"],
 			permitted_packages: ["bar"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 	`
 
@@ -6134,6 +6187,7 @@
 			name: "TesterHelpAppFoo",
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: [ "myapex" ],
+			sdk_version: "test_current",
 		}
 
 	`)
@@ -7736,7 +7790,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			libs: ["myotherjar"],
+			static_libs: ["myotherjar"],
 			apex_available: [
 				"myapex",
 				"myapex.updatable",
@@ -8397,6 +8451,7 @@
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "current",
 		}
 
 		systemserverclasspath_fragment {
@@ -9439,6 +9494,7 @@
 			srcs: ["mybootclasspathlib.java"],
 			apex_available: ["myapex"],
 			compile_dex: true,
+			sdk_version: "current",
 		}
 
 		systemserverclasspath_fragment {
@@ -9754,6 +9810,7 @@
 				unsafe_ignore_missing_latest_api: true,
 				min_sdk_version: "31",
 				static_libs: ["util"],
+				sdk_version: "core_current",
 			}
 
 			java_library {
@@ -9762,6 +9819,7 @@
 				apex_available: ["myapex"],
 				min_sdk_version: "31",
 				static_libs: ["another_util"],
+				sdk_version: "core_current",
 			}
 
 			java_library {
@@ -9769,6 +9827,7 @@
                 srcs: ["a.java"],
 				min_sdk_version: "31",
 				apex_available: ["myapex"],
+				sdk_version: "core_current",
 			}
 		`)
 	})
@@ -9824,7 +9883,7 @@
 	})
 
 	t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
-		preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)).
+		preparer.
 			RunTestWithBp(t, `
 				apex {
 					name: "myapex",
@@ -9855,6 +9914,8 @@
 					apex_available: ["myapex"],
 					compile_dex: true,
 					unsafe_ignore_missing_latest_api: true,
+					sdk_version: "current",
+					min_sdk_version: "30",
 				}
 		`)
 	})
@@ -10107,6 +10168,9 @@
 			key: "myapex.key",
 			bootclasspath_fragments: ["mybootclasspathfragment"],
 			min_sdk_version: "29",
+			java_libs: [
+				"jacocoagent",
+			],
 		}
 		apex_key {
 			name: "myapex.key",
@@ -10736,14 +10800,14 @@
 	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
-	if len(copyCmds) != 8 {
-		t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s)
+	if len(copyCmds) != 12 {
+		t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s)
 	}
 
-	ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[5], "^cp -f .*/package.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[6], "^cp -f .*/flag.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[7], "^cp -f .*/flag.val .*/image.apex/etc$")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
 
 	inputs := []string{
 		"my_aconfig_declarations_foo/intermediate.pb",
@@ -10871,14 +10935,14 @@
 	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
-	if len(copyCmds) != 12 {
-		t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s)
+	if len(copyCmds) != 16 {
+		t.Fatalf("Expected 16 commands, got %d in:\n%s", len(copyCmds), s)
 	}
 
-	ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[9], "^cp -f .*/package.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[10], "^cp -f .*/flag.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[11], "^cp -f .*/flag.val .*/image.apex/etc$")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
 
 	inputs := []string{
 		"my_aconfig_declarations_foo/intermediate.pb",
@@ -11039,14 +11103,14 @@
 	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
-	if len(copyCmds) != 32 {
-		t.Fatalf("Expected 28 commands, got %d in:\n%s", len(copyCmds), s)
+	if len(copyCmds) != 36 {
+		t.Fatalf("Expected 36 commands, got %d in:\n%s", len(copyCmds), s)
 	}
 
-	ensureMatches(t, copyCmds[28], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[29], "^cp -f .*/package.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[30], "^cp -f .*/flag.map .*/image.apex/etc$")
-	ensureMatches(t, copyCmds[31], "^cp -f .*/flag.val .*/image.apex/etc$")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/package.map .*/image.apex/etc/package.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.map .*/image.apex/etc/flag.map")
+	ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.val .*/image.apex/etc/flag.val")
 
 	inputs := []string{
 		"my_aconfig_declarations_foo/intermediate.pb",
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 25131ee..df7857f 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -104,6 +104,7 @@
 			test: {
 				enabled: true,
 			},
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -749,6 +750,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library {
@@ -833,6 +835,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"art-bootclasspath-fragment",
 		"bar",
 		"dex2oatd",
@@ -922,6 +925,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1003,6 +1007,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"android-non-updatable.stubs",
 		"android-non-updatable.stubs.module_lib",
 		"android-non-updatable.stubs.system",
@@ -1093,6 +1098,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1174,6 +1180,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"android-non-updatable.stubs",
 		"android-non-updatable.stubs.system",
 		"android-non-updatable.stubs.test",
@@ -1245,6 +1252,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1326,6 +1334,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"all_apex_contributions",
 		"art-bootclasspath-fragment",
 		"bar",
 		"dex2oatd",
diff --git a/apex/builder.go b/apex/builder.go
index 0d08483..437189f 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -83,6 +83,7 @@
 	pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf")
 	pctx.HostBinToolVariable("apex_elf_checker", "apex_elf_checker")
 	pctx.HostBinToolVariable("aconfig", "aconfig")
+	pctx.HostBinToolVariable("host_apex_verifier", "host_apex_verifier")
 }
 
 type createStorageStruct struct {
@@ -249,6 +250,13 @@
 		Description: "run apex_linkerconfig_validation",
 	}, "image_dir")
 
+	apexHostVerifierRule = pctx.StaticRule("apexHostVerifierRule", blueprint.RuleParams{
+		Command: `${host_apex_verifier} --deapexer=${deapexer} --debugfs=${debugfs_static} ` +
+			`--fsckerofs=${fsck_erofs} --apex=${in} && touch ${out}`,
+		CommandDeps: []string{"${host_apex_verifier}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}"},
+		Description: "run host_apex_verifier",
+	})
+
 	assembleVintfRule = pctx.StaticRule("assembleVintfRule", blueprint.RuleParams{
 		Command:     `rm -f $out && VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i $in -o $out`,
 		CommandDeps: []string{"${assemble_vintf}"},
@@ -262,6 +270,58 @@
 	}, "tool_path", "unwanted")
 )
 
+func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile {
+	var aconfigFiles android.Paths
+	for _, file := range a.filesInfo {
+		if file.module == nil {
+			continue
+		}
+		if dep, ok := android.OtherModuleProvider(ctx, file.module, android.AconfigPropagatingProviderKey); ok {
+			if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
+				aconfigFiles = append(aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
+			}
+		}
+
+		validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
+		if validationFlag == "error" || validationFlag == "warning" {
+			android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), file.module, validationFlag == "error")
+		}
+	}
+	aconfigFiles = android.FirstUniquePaths(aconfigFiles)
+
+	var files []apexFile
+	if len(aconfigFiles) > 0 {
+		apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        aconfig.AllDeclarationsRule,
+			Inputs:      aconfigFiles,
+			Output:      apexAconfigFile,
+			Description: "combine_aconfig_declarations",
+			Args: map[string]string{
+				"cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "),
+			},
+		})
+		files = append(files, newApexFile(ctx, apexAconfigFile, "aconfig_flags", "etc", etc, nil))
+
+		for _, info := range createStorageInfo {
+			outputFile := android.PathForModuleOut(ctx, info.Output_file)
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        aconfig.CreateStorageRule,
+				Inputs:      aconfigFiles,
+				Output:      outputFile,
+				Description: info.Desc,
+				Args: map[string]string{
+					"container":   ctx.ModuleName(),
+					"file_type":   info.File_type,
+					"cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "),
+				},
+			})
+			files = append(files, newApexFile(ctx, outputFile, info.File_type, "etc", etc, nil))
+		}
+	}
+	return files
+}
+
 // buildManifest creates buile rules to modify the input apex_manifest.json to add information
 // gathered by the build system such as provided/required native libraries. Two output files having
 // different formats are generated. a.manifestJsonOut is JSON format for Q devices, and
@@ -644,48 +704,10 @@
 	outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
 
-	defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"}
-	aconfigDest := imageDir.Join(ctx, "etc").String()
-	if len(a.aconfigFiles) > 0 {
-		apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        aconfig.AllDeclarationsRule,
-			Inputs:      a.aconfigFiles,
-			Output:      apexAconfigFile,
-			Description: "combine_aconfig_declarations",
-			Args: map[string]string{
-				"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
-			},
-		})
-
-		copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+aconfigDest)
-		implicitInputs = append(implicitInputs, apexAconfigFile)
-		defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+apexAconfigFile.Base())
-
-		for _, info := range createStorageInfo {
-			outputFile := android.PathForModuleOut(ctx, info.Output_file)
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        aconfig.CreateStorageRule,
-				Inputs:      a.aconfigFiles,
-				Output:      outputFile,
-				Description: info.Desc,
-				Args: map[string]string{
-					"container":   ctx.ModuleName(),
-					"file_type":   info.File_type,
-					"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
-				},
-			})
-
-			copyCommands = append(copyCommands, "cp -f "+outputFile.String()+" "+aconfigDest)
-			implicitInputs = append(implicitInputs, outputFile)
-			defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+outputFile.Base())
-		}
-	}
-
 	////////////////////////////////////////////////////////////////////////////////////
 	// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
 	// in this APEX. The file will be used by apexer in later steps.
-	cannedFsConfig := a.buildCannedFsConfig(ctx, defaultReadOnlyFiles)
+	cannedFsConfig := a.buildCannedFsConfig(ctx)
 	implicitInputs = append(implicitInputs, cannedFsConfig)
 
 	////////////////////////////////////////////////////////////////////////////////////
@@ -952,6 +974,9 @@
 		validations = append(validations,
 			runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
 	}
+	if !a.testApex && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
+		validations = append(validations, runApexHostVerifier(ctx, unsignedOutputFile.OutputPath))
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "signapk",
@@ -1139,8 +1164,8 @@
 	a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
 }
 
-func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext, defaultReadOnlyFiles []string) android.OutputPath {
-	var readOnlyPaths = defaultReadOnlyFiles
+func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
+	var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
 	var executablePaths []string // this also includes dirs
 	var appSetDirs []string
 	appSetFiles := make(map[string]android.Path)
@@ -1246,3 +1271,13 @@
 	})
 	return timestamp
 }
+
+func runApexHostVerifier(ctx android.ModuleContext, apexFile android.OutputPath) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "host_apex_verifier.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexHostVerifierRule,
+		Input:  apexFile,
+		Output: timestamp,
+	})
+	return timestamp
+}
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index b9a9198..9e1ac94 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -92,6 +92,7 @@
 			],
 			srcs: ["b.java"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
diff --git a/apex/container_test.go b/apex/container_test.go
index 3931174..d28b1a6 100644
--- a/apex/container_test.go
+++ b/apex/container_test.go
@@ -30,7 +30,7 @@
 	result := android.GroupFixturePreparers(
 		prepareForApexTest,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
-		java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+		java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
@@ -68,16 +68,17 @@
 			],
 			compile_dex: true,
 			static_libs: [
-				"foo",
+				"food",
 				"baz",
 			],
 			libs: [
-				"bar",
+				"bar.stubs",
 			],
 			min_sdk_version: "30",
+			sdk_version: "current",
 		}
 		java_library {
-			name: "foo",
+			name: "food",
 			srcs:[
 				"A.java",
 			],
@@ -85,13 +86,15 @@
 				"myapex",
 			],
 			min_sdk_version: "30",
+			sdk_version: "core_current",
 		}
-		java_library {
+		java_sdk_library {
 			name: "bar",
 			srcs:[
 				"A.java",
 			],
 			min_sdk_version: "30",
+			sdk_version: "core_current",
 		}
 		java_library {
 			name: "baz",
@@ -103,6 +106,7 @@
 				"myapex",
 			],
 			min_sdk_version: "30",
+			sdk_version: "core_current",
 		}
 	`)
 	testcases := []struct {
@@ -130,7 +134,7 @@
 			isApexContainer:   false,
 		},
 		{
-			moduleName:        "foo",
+			moduleName:        "food",
 			variant:           "android_common_apex30",
 			isSystemContainer: true,
 			isApexContainer:   true,
@@ -162,7 +166,7 @@
 	result := android.GroupFixturePreparers(
 		prepareForApexTest,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
-		java.FixtureWithLastReleaseApis("mybootclasspathlib"),
+		java.FixtureWithLastReleaseApis("mybootclasspathlib", "bar"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
@@ -199,26 +203,30 @@
 			],
 			compile_dex: true,
 			static_libs: [
-				"foo",
+				"food",
 			],
 			libs: [
-				"bar",
+				"bar.stubs",
 			],
+			sdk_version: "current",
 		}
 		java_library {
-			name: "foo",
+			name: "food",
 			srcs:[
 				"A.java",
 			],
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "core_current",
 		}
-		java_library {
+		java_sdk_library {
 			name: "bar",
 			srcs:[
 				"A.java",
 			],
+			sdk_version: "none",
+			system_modules: "none",
 		}
 	`)
 	testcases := []struct {
@@ -246,7 +254,7 @@
 			isApexContainer:   false,
 		},
 		{
-			moduleName:        "foo",
+			moduleName:        "food",
 			variant:           "android_common_apex10000",
 			isSystemContainer: true,
 			isApexContainer:   true,
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 17ade1d..9c2d899 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -293,6 +293,7 @@
 			],
 			srcs: ["b.java"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		// Add a java_import that is not preferred and so won't have an appropriate apex variant created
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index 452a43e..fd9020b 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -80,6 +80,7 @@
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "core_current",
 		}
 
 		systemserverclasspath_fragment {
@@ -350,6 +351,7 @@
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "core_current",
 		}
 
 		systemserverclasspath_fragment {
diff --git a/cc/cc.go b/cc/cc.go
index 927935c..b534737 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2507,8 +2507,14 @@
 		}
 
 		if c.isNDKStubLibrary() {
-			// ndk_headers do not have any variations
-			actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib)
+			variationExists := actx.OtherModuleDependencyVariantExists(nil, lib)
+			if variationExists {
+				actx.AddVariationDependencies(nil, depTag, lib)
+			} else {
+				// dependencies to ndk_headers fall here as ndk_headers do not have
+				// any variants.
+				actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib)
+			}
 		} else if c.IsStubs() && !c.isImportedApiLibrary() {
 			actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
 				depTag, lib)
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index beb68e1..761afcf 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -41,11 +41,18 @@
 		"armv8-2a-dotprod": []string{
 			"-march=armv8.2-a+dotprod",
 		},
+		// On ARMv9 and later, Pointer Authentication Codes (PAC) are mandatory,
+		// so -fstack-protector is unnecessary.
 		"armv9-a": []string{
 			"-march=armv8.2-a+dotprod",
 			"-mbranch-protection=standard",
 			"-fno-stack-protector",
 		},
+		"armv9-2a": []string{
+			"-march=armv9.2-a",
+			"-mbranch-protection=standard",
+			"-fno-stack-protector",
+		},
 	}
 
 	arm64Ldflags = []string{
diff --git a/cc/library.go b/cc/library.go
index 65a923a..03f7174 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1264,14 +1264,6 @@
 func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string {
 	var includeDirs, systemIncludeDirs []string
 
-	// The ABI checker does not need the preprocess which adds macro guards to function declarations.
-	preprocessedDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings()
-	if Bool(library.Properties.Llndk.Export_headers_as_system) {
-		systemIncludeDirs = append(systemIncludeDirs, preprocessedDirs...)
-	} else {
-		includeDirs = append(includeDirs, preprocessedDirs...)
-	}
-
 	if library.Properties.Llndk.Override_export_include_dirs != nil {
 		includeDirs = append(includeDirs, android.PathsForModuleSrc(
 			ctx, library.Properties.Llndk.Override_export_include_dirs).Strings()...)
@@ -1579,25 +1571,6 @@
 	}
 }
 
-func processLLNDKHeaders(ctx ModuleContext, srcHeaderDir string, outDir android.ModuleGenPath) (timestamp android.Path, installPaths android.WritablePaths) {
-	srcDir := android.PathForModuleSrc(ctx, srcHeaderDir)
-	srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil)
-
-	for _, header := range srcFiles {
-		headerDir := filepath.Dir(header.String())
-		relHeaderDir, err := filepath.Rel(srcDir.String(), headerDir)
-		if err != nil {
-			ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s",
-				srcDir.String(), headerDir, err)
-			continue
-		}
-
-		installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base()))
-	}
-
-	return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths), installPaths
-}
-
 // link registers actions to link this library, and sets various fields
 // on this library to reflect information that should be exported up the build
 // tree (for example, exported flags and include paths).
@@ -1605,26 +1578,6 @@
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
 	if ctx.IsLlndk() {
-		if len(library.Properties.Llndk.Export_preprocessed_headers) > 0 {
-			// This is the vendor variant of an LLNDK library with preprocessed headers.
-			genHeaderOutDir := android.PathForModuleGen(ctx, "include")
-
-			var timestampFiles android.Paths
-			for _, dir := range library.Properties.Llndk.Export_preprocessed_headers {
-				timestampFile, installPaths := processLLNDKHeaders(ctx, dir, genHeaderOutDir)
-				timestampFiles = append(timestampFiles, timestampFile)
-				library.addExportedGeneratedHeaders(installPaths.Paths()...)
-			}
-
-			if Bool(library.Properties.Llndk.Export_headers_as_system) {
-				library.reexportSystemDirs(genHeaderOutDir)
-			} else {
-				library.reexportDirs(genHeaderOutDir)
-			}
-
-			library.reexportDeps(timestampFiles...)
-		}
-
 		// override the module's export_include_dirs with llndk.override_export_include_dirs
 		// if it is set.
 		if override := library.Properties.Llndk.Override_export_include_dirs; override != nil {
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 5ece78a..c7950f9 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -36,10 +36,6 @@
 	// bionic/libc.
 	Export_headers_as_system *bool
 
-	// Which headers to process with versioner. This really only handles
-	// bionic/libc/include right now.
-	Export_preprocessed_headers []string
-
 	// Whether the system library uses symbol versions.
 	Unversioned *bool
 
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index e002931..7481954 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -23,15 +23,6 @@
 )
 
 var (
-	versionBionicHeaders = pctx.AndroidStaticRule("versionBionicHeaders",
-		blueprint.RuleParams{
-			// The `&& touch $out` isn't really necessary, but Blueprint won't
-			// let us have only implicit outputs.
-			Command:     "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
-			CommandDeps: []string{"$versionerCmd"},
-		},
-		"depsPath", "srcDir", "outDir")
-
 	preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
 		blueprint.RuleParams{
 			Command:     "$preprocessor -o $out $in",
@@ -40,10 +31,6 @@
 		"preprocessor")
 )
 
-func init() {
-	pctx.SourcePathVariable("versionerCmd", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/versioner")
-}
-
 // Returns the NDK base include path for use with sdk_version current. Usable with -I.
 func getCurrentIncludePath(ctx android.PathContext) android.OutputPath {
 	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
@@ -167,126 +154,6 @@
 	return module
 }
 
-type versionedHeaderProperties struct {
-	// Base directory of the headers being installed. As an example:
-	//
-	// versioned_ndk_headers {
-	//     name: "foo",
-	//     from: "include",
-	//     to: "",
-	// }
-	//
-	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
-	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
-	From *string
-
-	// Install path within the sysroot. This is relative to usr/include.
-	To *string
-
-	// Path to the NOTICE file associated with the headers.
-	License *string
-}
-
-// Like ndk_headers, but preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
-//
-// Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
-// module does not have the srcs property, and operates on a full directory (the `from` property).
-//
-// Note that this is really only built to handle bionic/libc/include.
-type versionedHeaderModule struct {
-	android.ModuleBase
-
-	properties versionedHeaderProperties
-
-	srcPaths     android.Paths
-	installPaths android.Paths
-	licensePath  android.Path
-}
-
-// Return the glob pattern to find all .h files beneath `dir`
-func headerGlobPattern(dir string) string {
-	return filepath.Join(dir, "**", "*.h")
-}
-
-func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if String(m.properties.License) == "" {
-		ctx.PropertyErrorf("license", "field is required")
-	}
-
-	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
-
-	fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
-	toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
-	m.srcPaths = ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
-	var installPaths []android.WritablePath
-	for _, header := range m.srcPaths {
-		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
-		installPath := installDir.Join(ctx, header.Base())
-		installPaths = append(installPaths, installPath)
-		m.installPaths = append(m.installPaths, installPath)
-	}
-
-	if len(m.installPaths) == 0 {
-		ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
-	}
-
-	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
-}
-
-func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
-	srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
-	// The versioner depends on a dependencies directory to simplify determining include paths
-	// when parsing headers. This directory contains architecture specific directories as well
-	// as a common directory, each of which contains symlinks to the actually directories to
-	// be included.
-	//
-	// ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
-	// depend on these headers.
-	// TODO(http://b/35673191): Update the versioner to use a --sysroot.
-	depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
-	depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
-	for i, path := range depsGlob {
-		if ctx.IsSymlink(path) {
-			dest := ctx.Readlink(path)
-			// Additional .. to account for the symlink itself.
-			depsGlob[i] = android.PathForSource(
-				ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
-		}
-	}
-
-	timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:            versionBionicHeaders,
-		Description:     "versioner preprocess " + srcDir.Rel(),
-		Output:          timestampFile,
-		Implicits:       append(srcPaths, depsGlob...),
-		ImplicitOutputs: installPaths,
-		Args: map[string]string{
-			"depsPath": depsPath.String(),
-			"srcDir":   srcDir.String(),
-			"outDir":   outDir.String(),
-		},
-	})
-
-	return timestampFile
-}
-
-// versioned_ndk_headers preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
-// Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
-// directory level specified in `from` property. This is only used to process
-// the bionic/libc/include directory.
-func VersionedNdkHeadersFactory() android.Module {
-	module := &versionedHeaderModule{}
-
-	module.AddProperties(&module.properties)
-
-	android.InitAndroidModule(module)
-
-	return module
-}
-
 // preprocessed_ndk_header {
 //
 //	name: "foo",
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 3e35ef5..bd6dfa3 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -103,8 +103,17 @@
 	// https://github.com/android-ndk/ndk/issues/265.
 	Unversioned_until *string
 
-	// Headers presented by this library to the Public API Surface
+	// DO NOT USE THIS
+	// NDK libraries should not export their headers. Headers belonging to NDK
+	// libraries should be added to the NDK with an ndk_headers module.
 	Export_header_libs []string
+
+	// Do not add other export_* properties without consulting with danalbert@.
+	// Consumers of ndk_library modules should emulate the typical NDK build
+	// behavior as closely as possible (that is, all NDK APIs are exposed to
+	// builds via --sysroot). Export behaviors used in Soong will not be present
+	// for app developers as they don't use Soong, and reliance on these export
+	// behaviors can mask issues with the NDK sysroot.
 }
 
 type stubDecorator struct {
@@ -484,7 +493,8 @@
 // Add a dependency on the header modules of this ndk_library
 func (linker *stubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
 	return Deps{
-		HeaderLibs: linker.properties.Export_header_libs,
+		ReexportHeaderLibHeaders: linker.properties.Export_header_libs,
+		HeaderLibs:               linker.properties.Export_header_libs,
 	}
 }
 
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index f571523..92da172 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -79,7 +79,6 @@
 func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
-	ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory)
 	ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
 	ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
 }
@@ -230,17 +229,6 @@
 			licensePaths = append(licensePaths, m.licensePath)
 		}
 
-		if m, ok := module.(*versionedHeaderModule); ok {
-			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
-			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
-			// Verification intentionally not done for headers that go through
-			// versioner. It'd be nice to have, but the only user is bionic, and
-			// that one module would also need to use skip_verification, so it
-			// wouldn't help at all.
-			installPaths = append(installPaths, m.installPaths...)
-			licensePaths = append(licensePaths, m.licensePath)
-		}
-
 		if m, ok := module.(*preprocessedHeadersModule); ok {
 			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
 			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 6459ea1..f3931a4 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -275,7 +275,10 @@
 			if !state.Inherit {
 				return nil, fmt.Errorf("Can't have inherit set to false")
 			}
-			env = append(env, *envVar.Name+"="+os.Getenv(*envVar.Name))
+			val, ok := os.LookupEnv(*envVar.Name)
+			if ok {
+				env = append(env, *envVar.Name+"="+val)
+			}
 		default:
 			return nil, fmt.Errorf("Unhandled state type")
 		}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 5c7ef43..a8f97e3 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -136,6 +136,9 @@
 	// Install aconfig_flags.pb file for the modules installed in this partition.
 	Gen_aconfig_flags_pb *bool
 
+	// Update the Base_dir of the $PRODUCT_OUT directory with the packaging files.
+	Update_product_out *bool
+
 	Fsverity fsverityProperties
 }
 
@@ -331,6 +334,14 @@
 	return f.CopySpecsToDirs(ctx, builder, dirsToSpecs)
 }
 
+func (f *filesystem) copyFilesToProductOut(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) {
+	if !proptools.Bool(f.properties.Update_product_out) {
+		return
+	}
+	installPath := android.PathForModuleInPartitionInstall(ctx, f.partitionName())
+	builder.Command().Textf("cp -prf %s/* %s", rebasedDir, installPath)
+}
+
 func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
 	rebasedDir := rootDir
@@ -348,6 +359,7 @@
 	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 	f.buildEventLogtagsFile(ctx, builder, rebasedDir)
 	f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
+	f.copyFilesToProductOut(ctx, builder, rebasedDir)
 
 	// run host_init_verifier
 	// Ideally we should have a concept of pluggable linters that verify the generated image.
@@ -490,6 +502,7 @@
 	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 	f.buildEventLogtagsFile(ctx, builder, rebasedDir)
 	f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
+	f.copyFilesToProductOut(ctx, builder, rebasedDir)
 
 	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
 	cmd := builder.Command().
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 4f1b320..45a7f72 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -17,7 +17,6 @@
 var (
 	SandboxingDenyModuleList = []string{
 		// go/keep-sorted start
-		"com.google.pixel.camera.hal.manifest",
 		// go/keep-sorted end
 	}
 )
diff --git a/java/aar.go b/java/aar.go
index 1bd372f..b5e24c4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -15,10 +15,10 @@
 package java
 
 import (
+	"crypto/sha256"
 	"fmt"
 	"path/filepath"
 	"slices"
-	"strconv"
 	"strings"
 
 	"android/soong/android"
@@ -236,18 +236,20 @@
 		rroDirs = append(rroDirs, resRRODirs...)
 	}
 
+	assetDirsHasher := sha256.New()
 	var assetDeps android.Paths
-	for i, dir := range assetDirs {
+	for _, dir := range assetDirs {
 		// Add a dependency on every file in the asset directory.  This ensures the aapt2
 		// rule will be rerun if one of the files in the asset directory is modified.
-		assetDeps = append(assetDeps, androidResourceGlob(ctx, dir)...)
+		dirContents := androidResourceGlob(ctx, dir)
+		assetDeps = append(assetDeps, dirContents...)
 
-		// Add a dependency on a file that contains a list of all the files in the asset directory.
+		// Add a hash of all the files in the asset directory to the command line.
 		// This ensures the aapt2 rule will be run if a file is removed from the asset directory,
 		// or a file is added whose timestamp is older than the output of aapt2.
-		assetFileListFile := android.PathForModuleOut(ctx, "asset_dir_globs", strconv.Itoa(i)+".glob")
-		androidResourceGlobList(ctx, dir, assetFileListFile)
-		assetDeps = append(assetDeps, assetFileListFile)
+		for _, path := range dirContents.Strings() {
+			assetDirsHasher.Write([]byte(path))
+		}
 	}
 
 	assetDirStrings := assetDirs.Strings()
@@ -282,6 +284,7 @@
 	linkDeps = append(linkDeps, manifestPath)
 
 	linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A "))
+	linkFlags = append(linkFlags, fmt.Sprintf("$$(: %x)", assetDirsHasher.Sum(nil)))
 	linkDeps = append(linkDeps, assetDeps...)
 
 	// Returns the effective version for {min|target}_sdk_version
@@ -403,6 +406,7 @@
 			packageName:        a.manifestValues.applicationId,
 		}
 		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], manifestMergerParams)
+		ctx.CheckbuildFile(a.mergedManifestFile)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
 			// will be propagated to the final application and merged there.  The merged manifest for libraries is
@@ -537,6 +541,8 @@
 	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
 		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
 		opts.aconfigTextFiles)
+	ctx.CheckbuildFile(packageRes)
+
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
 	if android.PrefixInList(linkFlags, "-A ") {
@@ -881,13 +887,12 @@
 		extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
 	}
 
-	a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+	a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil)
 
 	a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
 	var res android.Paths
 	if a.androidLibraryProperties.BuildAAR {
 		BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res)
-		ctx.CheckbuildFile(a.aarFile)
 	}
 
 	prebuiltJniPackages := android.Paths{}
@@ -968,7 +973,7 @@
 	// Defaults to sdk_version if not set. See sdk_version for possible values.
 	Min_sdk_version *string
 	// List of java static libraries that the included ARR (android library prebuilts) has dependencies to.
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 	// List of java libraries that the included ARR (android library prebuilts) has dependencies to.
 	Libs []string
 	// If set to true, run Jetifier against .aar file. Defaults to false.
@@ -991,7 +996,7 @@
 	// Functionality common to Module and Import.
 	embeddableInModuleAndImport
 
-	providesTransitiveHeaderJars
+	providesTransitiveHeaderJarsForR8
 
 	properties AARImportProperties
 
@@ -1098,7 +1103,7 @@
 	}
 
 	ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...)
-	ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs.GetOrDefault(ctx, nil)...)
 
 	a.usesLibrary.deps(ctx, false)
 }
@@ -1252,10 +1257,12 @@
 	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
 	aapt2Link(ctx, exportPackage, nil, proguardOptionsFile, aaptRTxt,
 		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil)
+	ctx.CheckbuildFile(exportPackage)
 	a.exportPackage = exportPackage
 
 	rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
 	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, rJar, nil, true, nil, false)
+	ctx.CheckbuildFile(rJar)
 	a.rJar = rJar
 
 	aapt2ExtractExtraPackages(ctx, extraAaptPackagesFile, a.rJar)
@@ -1286,13 +1293,17 @@
 	android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n"))
 	a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
 
-	a.collectTransitiveHeaderJars(ctx)
+	a.collectTransitiveHeaderJarsForR8(ctx)
 
 	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 
 	var staticJars android.Paths
 	var staticHeaderJars android.Paths
 	var staticResourceJars android.Paths
+	var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsImplementationJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsResourceJars []*android.DepSet[android.Path]
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			tag := ctx.OtherModuleDependencyTag(module)
@@ -1301,63 +1312,111 @@
 				staticJars = append(staticJars, dep.ImplementationJars...)
 				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
 				staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
+				if dep.TransitiveStaticLibsImplementationJars != nil {
+					transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+				}
+				if dep.TransitiveStaticLibsResourceJars != nil {
+					transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars)
+				}
 			}
 		}
 		addCLCFromDep(ctx, module, a.classLoaderContexts)
 		addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary)
 	})
 
+	completeStaticLibsHeaderJars := android.NewDepSet(android.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsHeaderJars)
+	completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsImplementationJars)
+	completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsResourceJars)
+
 	var implementationJarFile android.Path
-	if len(staticJars) > 0 {
-		combineJars := append(android.Paths{classpathFile}, staticJars...)
-		combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName).OutputPath
-		TransformJarsToJar(ctx, combinedImplementationJar, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
-		implementationJarFile = combinedImplementationJar
+	var combineJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		combineJars = completeStaticLibsImplementationJars.ToList()
+	} else {
+		combineJars = append(android.Paths{classpathFile}, staticJars...)
+	}
+
+	if len(combineJars) > 1 {
+		implementationJarOutputPath := android.PathForModuleOut(ctx, "combined", jarName)
+		TransformJarsToJar(ctx, implementationJarOutputPath, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+		implementationJarFile = implementationJarOutputPath
 	} else {
 		implementationJarFile = classpathFile
 	}
 
 	var resourceJarFile android.Path
-	if len(staticResourceJars) > 1 {
+	var resourceJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		resourceJars = completeStaticLibsResourceJars.ToList()
+	} else {
+		resourceJars = staticResourceJars
+	}
+	if len(resourceJars) > 1 {
 		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
 			false, nil, nil)
 		resourceJarFile = combinedJar
-	} else if len(staticResourceJars) == 1 {
-		resourceJarFile = staticResourceJars[0]
+	} else if len(resourceJars) == 1 {
+		resourceJarFile = resourceJars[0]
 	}
 
 	// merge implementation jar with resources if necessary
-	implementationAndResourcesJar := implementationJarFile
-	if resourceJarFile != nil {
-		jars := android.Paths{resourceJarFile, implementationAndResourcesJar}
+	var implementationAndResourcesJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		implementationAndResourcesJars = append(slices.Clone(resourceJars), combineJars...)
+	} else {
+		implementationAndResourcesJars = android.PathsIfNonNil(resourceJarFile, implementationJarFile)
+	}
+	var implementationAndResourcesJar android.Path
+	if len(implementationAndResourcesJars) > 1 {
 		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+		TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJars, android.OptionalPath{},
 			false, nil, nil)
 		implementationAndResourcesJar = combinedJar
+	} else {
+		implementationAndResourcesJar = implementationAndResourcesJars[0]
 	}
 
 	a.implementationJarFile = implementationJarFile
 	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
 	a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel()
 
-	if len(staticHeaderJars) > 0 {
-		combineJars := append(android.Paths{classpathFile}, staticHeaderJars...)
+	var headerJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		headerJars = completeStaticLibsHeaderJars.ToList()
+	} else {
+		headerJars = append(android.Paths{classpathFile}, staticHeaderJars...)
+	}
+	if len(headerJars) > 1 {
 		headerJarFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
-		TransformJarsToJar(ctx, headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil)
+		TransformJarsToJar(ctx, headerJarFile, "combine header jars", headerJars, android.OptionalPath{}, false, nil, nil)
 		a.headerJarFile = headerJarFile
 	} else {
-		a.headerJarFile = classpathFile
+		a.headerJarFile = headerJars[0]
+	}
+
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		ctx.CheckbuildFile(classpathFile)
+	} else {
+		ctx.CheckbuildFile(a.headerJarFile)
+		ctx.CheckbuildFile(a.implementationJarFile)
 	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(a.headerJarFile),
-		ResourceJars:                   android.PathsIfNonNil(resourceJarFile),
-		TransitiveLibsHeaderJars:       a.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile),
-		ImplementationJars:             android.PathsIfNonNil(a.implementationJarFile),
-		StubsLinkType:                  Implementation,
+		HeaderJars:                             android.PathsIfNonNil(a.headerJarFile),
+		LocalHeaderJars:                        android.PathsIfNonNil(classpathFile),
+		TransitiveStaticLibsHeaderJars:         completeStaticLibsHeaderJars,
+		TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+		TransitiveStaticLibsResourceJars:       completeStaticLibsResourceJars,
+		ResourceJars:                           android.PathsIfNonNil(resourceJarFile),
+		TransitiveLibsHeaderJarsForR8:          a.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8:    a.transitiveStaticLibsHeaderJarsForR8,
+		ImplementationAndResourcesJars:         android.PathsIfNonNil(a.implementationAndResourcesJarFile),
+		ImplementationJars:                     android.PathsIfNonNil(a.implementationJarFile),
+		StubsLinkType:                          Implementation,
 		// TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 
diff --git a/java/android_resources.go b/java/android_resources.go
index 038a260..3bb3eb5 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -39,15 +39,6 @@
 	return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
 }
 
-// androidResourceGlobList creates a rule to write the list of files in the given directory, using
-// the standard exclusion patterns for Android resources, to the given output file.
-func androidResourceGlobList(ctx android.ModuleContext, dir android.Path,
-	fileListFile android.WritablePath) {
-
-	android.GlobToListFileRule(ctx, filepath.Join(dir.String(), "**/*"),
-		androidResourceIgnoreFilenames, fileListFile)
-}
-
 type overlayType int
 
 const (
diff --git a/java/app.go b/java/app.go
index abd78b7..4ac42a7 100644
--- a/java/app.go
+++ b/java/app.go
@@ -690,7 +690,7 @@
 			extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
 		}
 
-		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil)
 		if a.dexProperties.resourceShrinkingEnabled(ctx) {
 			binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk")
 			aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary")
@@ -1009,6 +1009,8 @@
 		ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
 	}
 
+	ctx.CheckbuildFile(a.outputFile)
+
 	a.buildAppDependencyInfo(ctx)
 
 	providePrebuiltInfo(ctx,
@@ -1471,7 +1473,23 @@
 	return testConfig
 }
 
+func (a *AndroidTestHelperApp) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if len(a.ApexProperties.Apex_available) == 0 && ctx.Config().IsEnvTrue("EMMA_API_MAPPER") {
+		// Instrument the android_test_helper target to log potential API calls at the run time.
+		// Contact android-xts-infra team before using the environment var EMMA_API_MAPPER.
+		ctx.AddVariationDependencies(nil, staticLibTag, "apimapper-helper-device-lib")
+		a.setApiMapper(true)
+	}
+	a.AndroidApp.DepsMutator(ctx)
+}
+
 func (a *AndroidTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if len(a.ApexProperties.Apex_available) == 0 && ctx.Config().IsEnvTrue("EMMA_API_MAPPER") {
+		// Instrument the android_test_helper target to log potential API calls at the run time.
+		// Contact android-xts-infra team before using the environment var EMMA_API_MAPPER.
+		ctx.AddVariationDependencies(nil, staticLibTag, "apimapper-helper-device-lib")
+		a.setApiMapper(true)
+	}
 	a.AndroidApp.DepsMutator(ctx)
 }
 
diff --git a/java/base.go b/java/base.go
index 4cd6021..ef299b2 100644
--- a/java/base.go
+++ b/java/base.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"encoding/gob"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -80,7 +81,7 @@
 	Libs []string `android:"arch_variant"`
 
 	// list of java libraries that will be compiled into the resulting jar
-	Static_libs []string `android:"arch_variant"`
+	Static_libs proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// list of java libraries that should not be used to build this module
 	Exclude_static_libs []string `android:"arch_variant"`
@@ -98,9 +99,6 @@
 	// if not blank, used as prefix to generate repackage rule
 	Jarjar_prefix *string
 
-	// if set to true, skip the jarjar repackaging
-	Skip_jarjar_repackage *bool
-
 	// If not blank, set the java version passed to javac as -source and -target
 	Java_version *string
 
@@ -233,6 +231,10 @@
 	// Contributing api surface of the stub module. Is not visible to bp modules, and should
 	// only be set for stub submodules generated by the java_sdk_library
 	Stub_contributing_api *string `blueprint:"mutated"`
+
+	// If true, enable the "ApiMapper" tool on the output jar. "ApiMapper" is a tool to inject
+	// bytecode to log API calls.
+	ApiMapper bool `blueprint:"mutated"`
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -459,15 +461,10 @@
 	// inserting into the bootclasspath/classpath of another compile
 	headerJarFile android.Path
 
-	repackagedHeaderJarFile android.Path
-
 	// jar file containing implementation classes including static library dependencies but no
 	// resources
 	implementationJarFile android.Path
 
-	// jar file containing only resources including from static library dependencies
-	resourceJar android.Path
-
 	// args and dependencies to package source files into a srcjar
 	srcJarArgs []string
 	srcJarDeps android.Paths
@@ -593,6 +590,13 @@
 	return j.ProductSpecific()
 }
 
+var _ android.StubsAvailableModule = (*Module)(nil)
+
+// To safisfy the StubsAvailableModule interface
+func (j *Module) IsStubsModule() bool {
+	return proptools.Bool(j.properties.Is_stubs_module)
+}
+
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
 	sdkVersion := j.SdkVersion(ctx)
 	if sdkVersion.Stable() {
@@ -732,6 +736,10 @@
 		ctx.DeviceConfig().JavaCoverageEnabledForPath(ctx.ModuleDir())
 }
 
+func (j *Module) shouldApiMapper() bool {
+	return j.properties.ApiMapper
+}
+
 func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
 	return j.properties.Supports_static_instrumentation &&
 		j.shouldInstrument(ctx) &&
@@ -760,6 +768,10 @@
 	j.properties.Instrument = value
 }
 
+func (j *Module) setApiMapper(value bool) {
+	j.properties.ApiMapper = value
+}
+
 func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
 	return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version))
 }
@@ -816,6 +828,10 @@
 	return j.ApexModuleBase.AvailableFor(what)
 }
 
+func (j *Module) staticLibs(ctx android.BaseModuleContext) []string {
+	return android.RemoveListFromList(j.properties.Static_libs.GetOrDefault(ctx, nil), j.properties.Exclude_static_libs)
+}
+
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		j.linter.deps(ctx)
@@ -832,8 +848,7 @@
 
 	libDeps := ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
 
-	j.properties.Static_libs = android.RemoveListFromList(j.properties.Static_libs, j.properties.Exclude_static_libs)
-	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, j.staticLibs(ctx)...)
 
 	// Add dependency on libraries that provide additional hidden api annotations.
 	ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
@@ -915,7 +930,7 @@
 		ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
 	}
 
-	if j.useCompose() {
+	if j.useCompose(ctx) {
 		ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag,
 			"androidx.compose.compiler_compiler-hosted")
 	}
@@ -1136,18 +1151,16 @@
 	j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path)
 }
 
-func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
+func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars, extraDepCombinedJars android.Paths) {
 	// Auto-propagating jarjar rules
 	jarjarProviderData := j.collectJarJarRules(ctx)
 	if jarjarProviderData != nil {
 		android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
-		if !proptools.Bool(j.properties.Skip_jarjar_repackage) {
-			text := getJarJarRuleText(jarjarProviderData)
-			if text != "" {
-				ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
-				android.WriteFileRule(ctx, ruleTextFile, text)
-				j.repackageJarjarRules = ruleTextFile
-			}
+		text := getJarJarRuleText(jarjarProviderData)
+		if text != "" {
+			ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
+			android.WriteFileRule(ctx, ruleTextFile, text)
+			j.repackageJarjarRules = ruleTextFile
 		}
 	}
 
@@ -1236,7 +1249,6 @@
 	// Collect .java and .kt files for AIDEGen
 	j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...)
 
-	var kotlinJars android.Paths
 	var kotlinHeaderJars android.Paths
 
 	// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
@@ -1246,6 +1258,8 @@
 
 	j.aconfigCacheFiles = append(deps.aconfigProtoFiles, j.properties.Aconfig_Cache_files...)
 
+	var localImplementationJars android.Paths
+
 	// If compiling headers then compile them and skip the rest
 	if proptools.Bool(j.properties.Headers_only) {
 		if srcFiles.HasExt(".kt") {
@@ -1255,20 +1269,43 @@
 			ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
 		}
 
-		_, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
+		transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars
+
+		localHeaderJars, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
 			extraCombinedJars)
 
-		combinedHeaderJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
-		combinedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine")
+		combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
+		if jarjared {
+			localHeaderJars = android.Paths{combinedHeaderJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
+		combinedHeaderJarFile, repackaged := j.repackageFlagsIfNecessary(ctx, combinedHeaderJarFile, jarName, "repackage-turbine")
+		if repackaged {
+			localHeaderJars = android.Paths{combinedHeaderJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
 		if ctx.Failed() {
 			return
 		}
 		j.headerJarFile = combinedHeaderJarFile
 
+		if ctx.Config().UseTransitiveJarsInClasspath() {
+			if len(localHeaderJars) > 0 {
+				ctx.CheckbuildFile(localHeaderJars...)
+			} else {
+				// There are no local sources or resources in this module, so there is nothing to checkbuild.
+				ctx.UncheckedModule()
+			}
+		} else {
+			ctx.CheckbuildFile(j.headerJarFile)
+		}
+
 		android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
 			HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
-			TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
-			TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+			LocalHeaderJars:                     localHeaderJars,
+			TransitiveStaticLibsHeaderJars:      android.NewDepSet(android.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars),
+			TransitiveLibsHeaderJarsForR8:       j.transitiveLibsHeaderJarsForR8,
+			TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
 			AidlIncludeDirs:                     j.exportAidlIncludeDirs,
 			ExportedPlugins:                     j.exportedPluginJars,
 			ExportedPluginClasses:               j.exportedPluginClasses,
@@ -1325,7 +1362,7 @@
 			kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar")
 			kotlinKapt(ctx, kaptSrcJar, kaptResJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
 			srcJars = append(srcJars, kaptSrcJar)
-			kotlinJars = append(kotlinJars, kaptResJar)
+			localImplementationJars = append(localImplementationJars, kaptResJar)
 			// Disable annotation processing in javac, it's already been handled by kapt
 			flags.processorPath = nil
 			flags.processors = nil
@@ -1338,21 +1375,24 @@
 			return
 		}
 
-		kotlinJarPath := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc")
+		kotlinJarPath, _ := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc")
 
 		// Make javac rule depend on the kotlinc rule
 		flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...)
 
-		kotlinJars = append(kotlinJars, kotlinJarPath)
+		localImplementationJars = append(localImplementationJars, kotlinJarPath)
+
 		kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
 	}
 
-	jars := slices.Clone(kotlinJars)
-
 	j.compiledSrcJars = srcJars
 
+	transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars
+
 	enableSharding := false
-	var headerJarFileWithoutDepsOrJarjar android.Path
+	var localHeaderJars android.Paths
+	var shardingHeaderJars android.Paths
+	var repackagedHeaderJarFile android.Path
 	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine {
 		if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
 			enableSharding = true
@@ -1365,11 +1405,26 @@
 		extraJars := slices.Clone(kotlinHeaderJars)
 		extraJars = append(extraJars, extraCombinedJars...)
 		var combinedHeaderJarFile android.Path
-		headerJarFileWithoutDepsOrJarjar, combinedHeaderJarFile =
-			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
+		localHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
+		shardingHeaderJars = localHeaderJars
 
-		j.headerJarFile = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
-		j.repackagedHeaderJarFile = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine")
+		var jarjared bool
+		j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine")
+		if jarjared {
+			// jarjar modifies transitive static dependencies, use the combined header jar and drop the transitive
+			// static libs header jars.
+			localHeaderJars = android.Paths{j.headerJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
+		var repackaged bool
+		repackagedHeaderJarFile, repackaged = j.repackageFlagsIfNecessary(ctx, j.headerJarFile, jarName, "turbine")
+		if repackaged {
+			// repackage modifies transitive static dependencies, use the combined header jar and drop the transitive
+			// static libs header jars.
+			// TODO(b/356688296): this shouldn't export both the unmodified and repackaged header jars
+			localHeaderJars = android.Paths{j.headerJarFile, repackagedHeaderJarFile}
+			transitiveStaticLibsHeaderJars = nil
+		}
 	}
 	if len(uniqueJavaFiles) > 0 || len(srcJars) > 0 {
 		hasErrorproneableFiles := false
@@ -1404,8 +1459,8 @@
 		}
 
 		if enableSharding {
-			if headerJarFileWithoutDepsOrJarjar != nil {
-				flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
+			if len(shardingHeaderJars) > 0 {
+				flags.classpath = append(classpath(slices.Clone(shardingHeaderJars)), flags.classpath...)
 			}
 			shardSize := int(*(j.properties.Javac_shard_size))
 			var shardSrcs []android.Paths
@@ -1414,8 +1469,8 @@
 				for idx, shardSrc := range shardSrcs {
 					classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
 						nil, flags, extraJarDeps)
-					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
-					jars = append(jars, classes)
+					classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
+					localImplementationJars = append(localImplementationJars, classes)
 				}
 			}
 			// Assume approximately 5 sources per srcjar.
@@ -1427,21 +1482,21 @@
 				for idx, shardSrcJars := range shardSrcJarsList {
 					classes := j.compileJavaClasses(ctx, jarName, startIdx+idx,
 						nil, shardSrcJars, flags, extraJarDeps)
-					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
-					jars = append(jars, classes)
+					classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
+					localImplementationJars = append(localImplementationJars, classes)
 				}
 			}
 		} else {
 			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
-			classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
-			jars = append(jars, classes)
+			classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
+			localImplementationJars = append(localImplementationJars, classes)
 		}
 		if ctx.Failed() {
 			return
 		}
 	}
 
-	jars = append(jars, extraCombinedJars...)
+	localImplementationJars = append(localImplementationJars, extraCombinedJars...)
 
 	j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
 
@@ -1468,40 +1523,18 @@
 	resArgs = append(resArgs, extraArgs...)
 	resDeps = append(resDeps, extraDeps...)
 
+	var localResourceJars android.Paths
 	if len(resArgs) > 0 {
 		resourceJar := android.PathForModuleOut(ctx, "res", jarName)
 		TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
-		j.resourceJar = resourceJar
 		if ctx.Failed() {
 			return
 		}
+		localResourceJars = append(localResourceJars, resourceJar)
 	}
 
-	var resourceJars android.Paths
-	if j.resourceJar != nil {
-		resourceJars = append(resourceJars, j.resourceJar)
-	}
 	if Bool(j.properties.Include_srcs) {
-		resourceJars = append(resourceJars, includeSrcJar)
-	}
-	resourceJars = append(resourceJars, deps.staticResourceJars...)
-
-	if len(resourceJars) > 1 {
-		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
-			false, nil, nil)
-		j.resourceJar = combinedJar
-	} else if len(resourceJars) == 1 {
-		j.resourceJar = resourceJars[0]
-	}
-
-	if len(deps.staticJars) > 0 {
-		jars = append(jars, deps.staticJars...)
-	}
-
-	manifest := j.overrideManifest
-	if !manifest.Valid() && j.properties.Manifest != nil {
-		manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest))
+		localResourceJars = append(localResourceJars, includeSrcJar)
 	}
 
 	services := android.PathsForModuleSrc(ctx, j.properties.Services)
@@ -1526,35 +1559,68 @@
 			Implicits: services,
 			Args:      args,
 		})
-		jars = append(jars, servicesJar)
+		localResourceJars = append(localResourceJars, servicesJar)
+	}
+
+	completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, localResourceJars, deps.transitiveStaticLibsResourceJars)
+
+	var combinedResourceJar android.Path
+	var resourceJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		resourceJars = completeStaticLibsResourceJars.ToList()
+	} else {
+		resourceJars = append(slices.Clone(localResourceJars), deps.staticResourceJars...)
+	}
+	if len(resourceJars) == 1 {
+		combinedResourceJar = resourceJars[0]
+	} else if len(resourceJars) > 0 {
+		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
+			false, nil, nil)
+		combinedResourceJar = combinedJar
+	}
+
+	manifest := j.overrideManifest
+	if !manifest.Valid() && j.properties.Manifest != nil {
+		manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest))
 	}
 
 	// Combine the classes built from sources, any manifests, and any static libraries into
 	// classes.jar. If there is only one input jar this step will be skipped.
 	var outputFile android.Path
 
+	completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, localImplementationJars, deps.transitiveStaticLibsImplementationJars)
+
+	var jars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		jars = completeStaticLibsImplementationJars.ToList()
+	} else {
+		jars = append(slices.Clone(localImplementationJars), deps.staticJars...)
+	}
+
+	jars = append(jars, extraDepCombinedJars...)
+
 	if len(jars) == 1 && !manifest.Valid() {
 		// Optimization: skip the combine step as there is nothing to do
 		// TODO(ccross): this leaves any module-info.class files, but those should only come from
 		// prebuilt dependencies until we support modules in the platform build, so there shouldn't be
-		// any if len(jars) == 1.
+		// any if len(extraJars) == 0.
 
 		// moduleStubLinkType determines if the module is the TopLevelStubLibrary generated
 		// from sdk_library. The TopLevelStubLibrary contains only one static lib,
 		// either with .from-source or .from-text suffix.
 		// outputFile should be agnostic to the build configuration,
-		// thus "combine" the single static lib in order to prevent the static lib from being exposed
+		// thus copy the single input static lib in order to prevent the static lib from being exposed
 		// to the copy rules.
-		stub, _ := moduleStubLinkType(j)
-
-		if stub {
-			combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
+		if stub, _ := moduleStubLinkType(j); stub {
+			copiedJar := android.PathForModuleOut(ctx, "combined", jarName)
 			ctx.Build(pctx, android.BuildParams{
 				Rule:   android.Cp,
 				Input:  jars[0],
-				Output: combinedJar,
+				Output: copiedJar,
 			})
-			outputFile = combinedJar
+			completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, android.Paths{copiedJar}, nil)
+			outputFile = copiedJar
 		} else {
 			outputFile = jars[0]
 		}
@@ -1566,13 +1632,21 @@
 	}
 
 	// jarjar implementation jar if necessary
-	jarjarFile := j.jarjarIfNecessary(ctx, outputFile, jarName, "")
+	jarjarFile, jarjarred := j.jarjarIfNecessary(ctx, outputFile, jarName, "")
+	if jarjarred {
+		localImplementationJars = android.Paths{jarjarFile}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
+	}
 	outputFile = jarjarFile
 
 	// jarjar resource jar if necessary
-	if j.resourceJar != nil {
-		resourceJarJarFile := j.jarjarIfNecessary(ctx, j.resourceJar, jarName, "resource")
-		j.resourceJar = resourceJarJarFile
+	if combinedResourceJar != nil {
+		resourceJarJarFile, jarjarred := j.jarjarIfNecessary(ctx, combinedResourceJar, jarName, "resource")
+		combinedResourceJar = resourceJarJarFile
+		if jarjarred {
+			localResourceJars = android.Paths{resourceJarJarFile}
+			completeStaticLibsResourceJars = android.NewDepSet(android.PREORDER, localResourceJars, nil)
+		}
 	}
 
 	if ctx.Failed() {
@@ -1589,6 +1663,22 @@
 			Output:      ravenizerOutput,
 		})
 		outputFile = ravenizerOutput
+		localImplementationJars = android.Paths{ravenizerOutput}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
+	}
+
+	if j.shouldApiMapper() {
+		inputFile := outputFile
+		apiMapperFile := android.PathForModuleOut(ctx, "apimapper", jarName)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        apimapper,
+			Description: "apimapper",
+			Input:       inputFile,
+			Output:      apiMapperFile,
+		})
+		outputFile = apiMapperFile
+		localImplementationJars = android.Paths{apiMapperFile}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
 	}
 
 	// Check package restrictions if necessary.
@@ -1610,6 +1700,8 @@
 			Validation: pkgckFile,
 		})
 		outputFile = packageCheckOutputFile
+		localImplementationJars = android.Paths{packageCheckOutputFile}
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
 
 		// Check packages and create a timestamp file when complete.
 		CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages)
@@ -1628,6 +1720,13 @@
 		headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName)
 		convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile)
 		j.headerJarFile = headerJarFile
+		if len(localImplementationJars) == 1 && ctx.Config().UseTransitiveJarsInClasspath() {
+			localHeaderJarFile := android.PathForModuleOut(ctx, "local-javac-header", jarName)
+			convertImplementationJarToHeaderJar(ctx, localImplementationJars[0], localHeaderJarFile)
+			localHeaderJars = append(localHeaderJars, localHeaderJarFile)
+		} else {
+			localHeaderJars = append(localHeaderJars, headerJarFile)
+		}
 	}
 
 	// enforce syntax check to jacoco filters for any build (http://b/183622051)
@@ -1641,16 +1740,27 @@
 	}
 
 	// merge implementation jar with resources if necessary
-	implementationAndResourcesJar := outputFile
-	if j.resourceJar != nil {
-		jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
-		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
-		TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
-			false, nil, nil)
-		implementationAndResourcesJar = combinedJar
+	var implementationAndResourcesJarsToCombine android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		resourceJars := completeStaticLibsResourceJars.ToList()
+		if len(resourceJars) > 0 {
+			implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJars.ToList()...)
+			implementationAndResourcesJarsToCombine = append(implementationAndResourcesJarsToCombine, extraDepCombinedJars...)
+		}
+	} else {
+		if combinedResourceJar != nil {
+			implementationAndResourcesJarsToCombine = android.Paths{combinedResourceJar, outputFile}
+		}
 	}
 
-	j.implementationAndResourcesJar = implementationAndResourcesJar
+	if len(implementationAndResourcesJarsToCombine) > 0 {
+		combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJarsToCombine, manifest,
+			false, nil, nil)
+		outputFile = combinedJar
+	}
+
+	j.implementationAndResourcesJar = outputFile
 
 	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
 	compileDex := j.dexProperties.Compile_dex
@@ -1676,7 +1786,7 @@
 				flags:         flags,
 				sdkVersion:    j.SdkVersion(ctx),
 				minSdkVersion: j.MinSdkVersion(ctx),
-				classesJar:    implementationAndResourcesJar,
+				classesJar:    outputFile,
 				jarName:       jarName,
 			}
 			if j.GetProfileGuided() && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting() {
@@ -1702,10 +1812,20 @@
 			}
 
 			// merge dex jar with resources if necessary
-			if j.resourceJar != nil {
-				jars := android.Paths{dexOutputFile, j.resourceJar}
+			var dexAndResourceJarsToCombine android.Paths
+			if ctx.Config().UseTransitiveJarsInClasspath() {
+				resourceJars := completeStaticLibsResourceJars.ToList()
+				if len(resourceJars) > 0 {
+					dexAndResourceJarsToCombine = append(android.Paths{dexOutputFile}, resourceJars...)
+				}
+			} else {
+				if combinedResourceJar != nil {
+					dexAndResourceJarsToCombine = android.Paths{dexOutputFile, combinedResourceJar}
+				}
+			}
+			if len(dexAndResourceJarsToCombine) > 0 {
 				combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName)
-				TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
+				TransformJarsToJar(ctx, combinedJar, "for dex resources", dexAndResourceJarsToCombine, android.OptionalPath{},
 					false, nil, nil)
 				if *j.dexProperties.Uncompress_dex {
 					combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName)
@@ -1733,18 +1853,17 @@
 			j.dexpreopt(ctx, libName, dexOutputFile)
 
 			outputFile = dexOutputFile
+
+			ctx.CheckbuildFile(dexOutputFile)
 		} else {
 			// There is no code to compile into a dex jar, make sure the resources are propagated
 			// to the APK if this is an app.
-			outputFile = implementationAndResourcesJar
-			j.dexJarFile = makeDexJarPathFromPath(j.resourceJar)
+			j.dexJarFile = makeDexJarPathFromPath(combinedResourceJar)
 		}
 
 		if ctx.Failed() {
 			return
 		}
-	} else {
-		outputFile = implementationAndResourcesJar
 	}
 
 	if ctx.Device() {
@@ -1776,16 +1895,34 @@
 
 	j.collectTransitiveSrcFiles(ctx, srcFiles)
 
-	ctx.CheckbuildFile(outputFile)
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		if len(localImplementationJars) > 0 || len(localResourceJars) > 0 || len(localHeaderJars) > 0 {
+			ctx.CheckbuildFile(localImplementationJars...)
+			ctx.CheckbuildFile(localResourceJars...)
+			ctx.CheckbuildFile(localHeaderJars...)
+		} else {
+			// There are no local sources or resources in this module, so there is nothing to checkbuild.
+			ctx.UncheckedModule()
+		}
+	} else {
+		ctx.CheckbuildFile(j.implementationJarFile)
+		ctx.CheckbuildFile(j.headerJarFile)
+	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
-		RepackagedHeaderJars:                android.PathsIfNonNil(j.repackagedHeaderJarFile),
-		TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+		HeaderJars:           android.PathsIfNonNil(j.headerJarFile),
+		RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile),
+
+		LocalHeaderJars:                        localHeaderJars,
+		TransitiveStaticLibsHeaderJars:         android.NewDepSet(android.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars),
+		TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+		TransitiveStaticLibsResourceJars:       completeStaticLibsResourceJars,
+
+		TransitiveLibsHeaderJarsForR8:       j.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
 		ImplementationAndResourcesJars:      android.PathsIfNonNil(j.implementationAndResourcesJar),
 		ImplementationJars:                  android.PathsIfNonNil(j.implementationJarFile),
-		ResourceJars:                        android.PathsIfNonNil(j.resourceJar),
+		ResourceJars:                        android.PathsIfNonNil(combinedResourceJar),
 		AidlIncludeDirs:                     j.exportAidlIncludeDirs,
 		SrcJarArgs:                          j.srcJarArgs,
 		SrcJarDeps:                          j.srcJarDeps,
@@ -1802,8 +1939,8 @@
 	j.outputFile = outputFile.WithoutRel()
 }
 
-func (j *Module) useCompose() bool {
-	return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
+func (j *Module) useCompose(ctx android.BaseModuleContext) bool {
+	return android.InList("androidx.compose.runtime_runtime", j.staticLibs(ctx))
 }
 
 func collectDepProguardSpecInfo(ctx android.ModuleContext) (transitiveProguardFlags, transitiveUnconditionalExportedFlags []*android.DepSet[android.Path]) {
@@ -1921,22 +2058,26 @@
 
 func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
 	deps deps, flags javaBuilderFlags, jarName string,
-	extraJars android.Paths) (headerJar android.Path, combinedHeaderJar android.Path) {
+	extraJars android.Paths) (localHeaderJars android.Paths, combinedHeaderJar android.Path) {
 
-	var jars android.Paths
 	if len(srcFiles) > 0 || len(srcJars) > 0 {
 		// Compile java sources into turbine.jar.
 		turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
 		TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
-		jars = append(jars, turbineJar)
-		headerJar = turbineJar
+		localHeaderJars = append(localHeaderJars, turbineJar)
 	}
 
-	jars = append(jars, extraJars...)
+	localHeaderJars = append(localHeaderJars, extraJars...)
 
 	// Combine any static header libraries into classes-header.jar. If there is only
 	// one input jar this step will be skipped.
-	jars = append(jars, deps.staticHeaderJars...)
+	var jars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		depSet := android.NewDepSet(android.PREORDER, localHeaderJars, deps.transitiveStaticLibsHeaderJars)
+		jars = depSet.ToList()
+	} else {
+		jars = append(slices.Clone(localHeaderJars), deps.staticHeaderJars...)
+	}
 
 	// we cannot skip the combine step for now if there is only one jar
 	// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
@@ -1944,7 +2085,7 @@
 	TransformJarsToJar(ctx, combinedHeaderJarOutputPath, "for turbine", jars, android.OptionalPath{},
 		false, nil, []string{"META-INF/TRANSITIVE"})
 
-	return headerJar, combinedHeaderJarOutputPath
+	return localHeaderJars, combinedHeaderJarOutputPath
 }
 
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1960,22 +2101,18 @@
 	return instrumentedJar
 }
 
-type providesTransitiveHeaderJars struct {
+type providesTransitiveHeaderJarsForR8 struct {
 	// set of header jars for all transitive libs deps
-	transitiveLibsHeaderJars *android.DepSet[android.Path]
+	transitiveLibsHeaderJarsForR8 *android.DepSet[android.Path]
 	// set of header jars for all transitive static libs deps
-	transitiveStaticLibsHeaderJars *android.DepSet[android.Path]
+	transitiveStaticLibsHeaderJarsForR8 *android.DepSet[android.Path]
 }
 
-func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet[android.Path] {
-	return j.transitiveLibsHeaderJars
-}
-
-func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet[android.Path] {
-	return j.transitiveStaticLibsHeaderJars
-}
-
-func (j *providesTransitiveHeaderJars) collectTransitiveHeaderJars(ctx android.ModuleContext) {
+// collectTransitiveHeaderJarsForR8 visits direct dependencies and collects all transitive libs and static_libs
+// header jars.  The semantics of the collected jars are odd (it collects combined jars that contain the static
+// libs, but also the static libs, and it collects transitive libs dependencies of static_libs), so these
+// are only used to expand the --lib arguments to R8.
+func (j *providesTransitiveHeaderJarsForR8) collectTransitiveHeaderJarsForR8(ctx android.ModuleContext) {
 	directLibs := android.Paths{}
 	directStaticLibs := android.Paths{}
 	transitiveLibs := []*android.DepSet[android.Path]{}
@@ -1998,16 +2135,17 @@
 				return
 			}
 
-			if dep.TransitiveLibsHeaderJars != nil {
-				transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
+			if dep.TransitiveLibsHeaderJarsForR8 != nil {
+				transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJarsForR8)
 			}
-			if dep.TransitiveStaticLibsHeaderJars != nil {
-				transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
+			if dep.TransitiveStaticLibsHeaderJarsForR8 != nil {
+				transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJarsForR8)
 			}
+
 		}
 	})
-	j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
-	j.transitiveStaticLibsHeaderJars = android.NewDepSet(android.POSTORDER, directStaticLibs, transitiveStaticLibs)
+	j.transitiveLibsHeaderJarsForR8 = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
+	j.transitiveStaticLibsHeaderJarsForR8 = android.NewDepSet(android.POSTORDER, directStaticLibs, transitiveStaticLibs)
 }
 
 func (j *Module) HeaderJars() android.Paths {
@@ -2062,7 +2200,7 @@
 	}
 	dpInfo.Deps = append(dpInfo.Deps, j.CompilerDeps()...)
 	dpInfo.Aidl_include_dirs = append(dpInfo.Aidl_include_dirs, j.deviceProperties.Aidl.Include_dirs...)
-	dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
+	dpInfo.Static_libs = append(dpInfo.Static_libs, j.staticLibs(ctx)...)
 	dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
 }
 
@@ -2251,29 +2389,17 @@
 func (j *Module) collectDeps(ctx android.ModuleContext) deps {
 	var deps deps
 
-	if ctx.Device() {
-		sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
-		if sdkDep.invalidVersion {
-			ctx.AddMissingDependencies(sdkDep.bootclasspath)
-			ctx.AddMissingDependencies(sdkDep.java9Classpath)
-		} else if sdkDep.useFiles {
-			// sdkDep.jar is actually equivalent to turbine header.jar.
-			deps.classpath = append(deps.classpath, sdkDep.jars...)
-			deps.dexClasspath = append(deps.dexClasspath, sdkDep.jars...)
-			deps.aidlPreprocess = sdkDep.aidl
-			// Add the sdk module dependency to `compileDepNames`.
-			// This ensures that the dependency is reported in `module_bp_java_deps.json`
-			// TODO (b/358608607): Move this to decodeSdkDep
-			sdkSpec := android.SdkContext(j).SdkVersion(ctx)
-			j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String()))
-		} else {
-			deps.aidlPreprocess = sdkDep.aidl
-		}
-	}
-
 	sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())
 
-	j.collectTransitiveHeaderJars(ctx)
+	j.collectTransitiveHeaderJarsForR8(ctx)
+
+	var transitiveBootClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveJava9ClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticJarsHeaderLibs []*android.DepSet[android.Path]
+	var transitiveStaticJarsImplementationLibs []*android.DepSet[android.Path]
+	var transitiveStaticJarsResourceLibs []*android.DepSet[android.Path]
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -2293,6 +2419,10 @@
 				depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))
 				deps.classpath = append(deps.classpath, depHeaderJars...)
 				deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...)
+
+				// TODO: SDK libraries should export a provider with TransitiveClasspathHeaderJars
+				depHeaderJarsSet := android.NewDepSet(android.PREORDER, depHeaderJars, nil)
+				transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJarsSet)
 			case staticLibTag:
 				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
 			}
@@ -2308,6 +2438,9 @@
 			switch tag {
 			case bootClasspathTag:
 				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case sdkLibTag, libTag, instrumentationForTag:
 				if _, ok := module.(*Plugin); ok {
 					ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName)
@@ -2321,8 +2454,15 @@
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
 				addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
+
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case java9LibTag:
 				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveJava9ClasspathHeaderJars = append(transitiveJava9ClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case staticLibTag:
 				if _, ok := module.(*Plugin); ok {
 					ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a static_libs dependency", otherName)
@@ -2338,6 +2478,17 @@
 				// optimization.
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
 				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
+
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+					transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, dep.TransitiveStaticLibsHeaderJars)
+				}
+				if dep.TransitiveStaticLibsImplementationJars != nil {
+					transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, dep.TransitiveStaticLibsImplementationJars)
+				}
+				if dep.TransitiveStaticLibsResourceJars != nil {
+					transitiveStaticJarsResourceLibs = append(transitiveStaticJarsResourceLibs, dep.TransitiveStaticLibsResourceJars)
+				}
 			case pluginTag:
 				if plugin, ok := module.(*Plugin); ok {
 					if plugin.pluginProperties.Processor_class != nil {
@@ -2386,11 +2537,18 @@
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
 				deps.dexClasspath = append(deps.classpath, dep.Srcs()...)
+				transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars,
+					android.NewDepSet(android.PREORDER, dep.Srcs(), nil))
 			case staticLibTag:
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
 				deps.staticJars = append(deps.staticJars, dep.Srcs()...)
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
+
+				depHeaderJars := android.NewDepSet(android.PREORDER, dep.Srcs(), nil)
+				transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJars)
+				transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, depHeaderJars)
+				transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, depHeaderJars)
 			}
 		} else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
 			switch tag {
@@ -2403,8 +2561,11 @@
 				// If a system modules dependency has been added to the bootclasspath
 				// then add its libs to the bootclasspath.
 				if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok {
-					depHeaderJars := sm.HeaderJars
-					deps.bootClasspath = append(deps.bootClasspath, depHeaderJars...)
+					deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars...)
+					if sm.TransitiveStaticLibsHeaderJars != nil {
+						transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars,
+							sm.TransitiveStaticLibsHeaderJars)
+					}
 				} else {
 					ctx.PropertyErrorf("boot classpath dependency %q does not provide SystemModulesProvider",
 						ctx.OtherModuleName(module))
@@ -2435,6 +2596,39 @@
 		addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary)
 	})
 
+	deps.transitiveStaticLibsHeaderJars = transitiveStaticJarsHeaderLibs
+	deps.transitiveStaticLibsImplementationJars = transitiveStaticJarsImplementationLibs
+	deps.transitiveStaticLibsResourceJars = transitiveStaticJarsResourceLibs
+
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		depSet := android.NewDepSet(android.PREORDER, nil, transitiveClasspathHeaderJars)
+		deps.classpath = depSet.ToList()
+		depSet = android.NewDepSet(android.PREORDER, nil, transitiveBootClasspathHeaderJars)
+		deps.bootClasspath = depSet.ToList()
+		depSet = android.NewDepSet(android.PREORDER, nil, transitiveJava9ClasspathHeaderJars)
+		deps.java9Classpath = depSet.ToList()
+	}
+
+	if ctx.Device() {
+		sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
+		if sdkDep.invalidVersion {
+			ctx.AddMissingDependencies(sdkDep.bootclasspath)
+			ctx.AddMissingDependencies(sdkDep.java9Classpath)
+		} else if sdkDep.useFiles {
+			// sdkDep.jar is actually equivalent to turbine header.jar.
+			deps.classpath = append(slices.Clone(classpath(sdkDep.jars)), deps.classpath...)
+			deps.dexClasspath = append(slices.Clone(classpath(sdkDep.jars)), deps.dexClasspath...)
+			deps.aidlPreprocess = sdkDep.aidl
+			// Add the sdk module dependency to `compileDepNames`.
+			// This ensures that the dependency is reported in `module_bp_java_deps.json`
+			// TODO (b/358608607): Move this to decodeSdkDep
+			sdkSpec := android.SdkContext(j).SdkVersion(ctx)
+			j.compileDepNames = append(j.compileDepNames, fmt.Sprintf("sdk_%s_%s_android", sdkSpec.Kind.String(), sdkSpec.ApiLevel.String()))
+		} else {
+			deps.aidlPreprocess = sdkDep.aidl
+		}
+	}
+
 	return deps
 }
 
@@ -2485,6 +2679,8 @@
 
 func init() {
 	android.SetJarJarPrefixHandler(mergeJarJarPrefixes)
+
+	gob.Register(BaseJarJarProviderData{})
 }
 
 // BaseJarJarProviderData contains information that will propagate across dependencies regardless of
@@ -2744,22 +2940,22 @@
 }
 
 // Repackage the flags if the jarjar rule txt for the flags is generated
-func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path {
+func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) {
 	if j.repackageJarjarRules == nil {
-		return infile
+		return infile, false
 	}
 	repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", info, jarName)
 	TransformJarJar(ctx, repackagedJarjarFile, infile, j.repackageJarjarRules)
-	return repackagedJarjarFile
+	return repackagedJarjarFile, true
 }
 
-func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) android.Path {
+func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) {
 	if j.expandJarjarRules == nil {
-		return infile
+		return infile, false
 	}
 	jarjarFile := android.PathForModuleOut(ctx, "jarjar", info, jarName)
 	TransformJarJar(ctx, jarjarFile, infile, j.expandJarjarRules)
-	return jarjarFile
+	return jarjarFile, true
 
 }
 
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bef3b58..fe4cc76 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -463,6 +463,12 @@
 	// Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
 	// path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
 	dexpreopt.RegisterToolDeps(ctx)
+
+	// Add a dependency to `all_apex_contributions` to determine if prebuilts are active.
+	// If prebuilts are active, `contents` validation on the source bootclasspath fragment should be disabled.
+	if _, isPrebuiltModule := ctx.Module().(*PrebuiltBootclasspathFragmentModule); !isPrebuiltModule {
+		ctx.AddDependency(b, android.AcDepTag, "all_apex_contributions")
+	}
 }
 
 func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/java/builder.go b/java/builder.go
index 49207e5..81b0feb 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -265,6 +265,13 @@
 		},
 	)
 
+	apimapper = pctx.AndroidStaticRule("apimapper",
+		blueprint.RuleParams{
+			Command:     "${apimapper} --in-jar $in --out-jar $out",
+			CommandDeps: []string{"${apimapper}"},
+		},
+	)
+
 	zipalign = pctx.AndroidStaticRule("zipalign",
 		blueprint.RuleParams{
 			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
@@ -315,6 +322,7 @@
 
 	pctx.HostBinToolVariable("aconfig", "aconfig")
 	pctx.HostBinToolVariable("ravenizer", "ravenizer")
+	pctx.HostBinToolVariable("apimapper", "apimapper")
 	pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis")
 }
 
diff --git a/java/config/config.go b/java/config/config.go
index a50c1b4..c28e070 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -52,6 +52,7 @@
 		"core-icu4j",
 		"core-oj",
 		"core-libart",
+		"wear-sdk.impl",
 	}
 )
 
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index cee7a19..1cca7ad 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -38,6 +38,7 @@
     visibility: ["//visibility:public"],
     sdk_version: "none",
     system_modules: "none",
+    is_stubs_module: true,
 }
 
 java_library {
@@ -289,6 +290,7 @@
     sdk_version: "none",
     system_modules: "none",
     patch_module: "java.base",
+    is_stubs_module: true,
 }
 
 // Same as legacy.core.platform.api.stubs, but android annotations are
@@ -307,6 +309,7 @@
         "legacy.core.platform.api.stubs",
     ],
     patch_module: "java.base",
+    is_stubs_module: true,
 }
 
 java_library {
@@ -339,6 +342,7 @@
         "stable.core.platform.api.stubs",
     ],
     patch_module: "java.base",
+    is_stubs_module: true,
 }
 
 // Used when compiling higher-level code against *.core.platform.api.stubs.
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 7cc06fc..3f4e3cd 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -96,6 +96,10 @@
 		ctx.PropertyErrorf("libs", "at least one dependency is required")
 	}
 
+	var transitiveHeaderJars []*android.DepSet[android.Path]
+	var transitiveImplementationJars []*android.DepSet[android.Path]
+	var transitiveResourceJars []*android.DepSet[android.Path]
+
 	ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) {
 		if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
 			d.headerJars = append(d.headerJars, dep.HeaderJars...)
@@ -105,6 +109,16 @@
 
 			d.srcJarArgs = append(d.srcJarArgs, dep.SrcJarArgs...)
 			d.srcJarDeps = append(d.srcJarDeps, dep.SrcJarDeps...)
+
+			if dep.TransitiveStaticLibsHeaderJars != nil {
+				transitiveHeaderJars = append(transitiveHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+			}
+			if dep.TransitiveStaticLibsImplementationJars != nil {
+				transitiveImplementationJars = append(transitiveImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+			}
+			if dep.TransitiveStaticLibsResourceJars != nil {
+				transitiveResourceJars = append(transitiveResourceJars, dep.TransitiveStaticLibsResourceJars)
+			}
 		} else {
 			ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
 		}
@@ -131,13 +145,17 @@
 	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     d.headerJars,
-		ImplementationAndResourcesJars: d.implementationAndResourceJars,
-		ImplementationJars:             d.implementationJars,
-		ResourceJars:                   d.resourceJars,
-		SrcJarArgs:                     d.srcJarArgs,
-		SrcJarDeps:                     d.srcJarDeps,
-		StubsLinkType:                  Implementation,
+		HeaderJars:                             d.headerJars,
+		LocalHeaderJars:                        d.headerJars,
+		TransitiveStaticLibsHeaderJars:         android.NewDepSet(android.PREORDER, nil, transitiveHeaderJars),
+		TransitiveStaticLibsImplementationJars: android.NewDepSet(android.PREORDER, nil, transitiveImplementationJars),
+		TransitiveStaticLibsResourceJars:       android.NewDepSet(android.PREORDER, nil, transitiveResourceJars),
+		ImplementationAndResourcesJars:         d.implementationAndResourceJars,
+		ImplementationJars:                     d.implementationJars,
+		ResourceJars:                           d.resourceJars,
+		SrcJarArgs:                             d.srcJarArgs,
+		SrcJarDeps:                             d.srcJarDeps,
+		StubsLinkType:                          Implementation,
 		// TODO: Not sure if aconfig flags that have been moved between device and host variants
 		// make sense.
 	})
diff --git a/java/dex.go b/java/dex.go
index 6c739a2..7d42efc 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -108,7 +108,7 @@
 	resourcesInput          android.OptionalPath
 	resourcesOutput         android.OptionalPath
 
-	providesTransitiveHeaderJars
+	providesTransitiveHeaderJarsForR8
 }
 
 func (d *dexer) effectiveOptimizeEnabled() bool {
@@ -307,14 +307,14 @@
 	r8Deps = append(r8Deps, flags.dexClasspath...)
 
 	transitiveStaticLibsLookupMap := map[android.Path]bool{}
-	if d.transitiveStaticLibsHeaderJars != nil {
-		for _, jar := range d.transitiveStaticLibsHeaderJars.ToList() {
+	if d.transitiveStaticLibsHeaderJarsForR8 != nil {
+		for _, jar := range d.transitiveStaticLibsHeaderJarsForR8.ToList() {
 			transitiveStaticLibsLookupMap[jar] = true
 		}
 	}
 	transitiveHeaderJars := android.Paths{}
-	if d.transitiveLibsHeaderJars != nil {
-		for _, jar := range d.transitiveLibsHeaderJars.ToList() {
+	if d.transitiveLibsHeaderJarsForR8 != nil {
+		for _, jar := range d.transitiveLibsHeaderJarsForR8.ToList() {
 			if _, ok := transitiveStaticLibsLookupMap[jar]; ok {
 				// don't include a lib if it is already packaged in the current JAR as a static lib
 				continue
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index f949b12..4734357 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -209,13 +209,18 @@
 			psi = prebuiltSelectionInfo
 		}
 	})
+
 	// Find the apex variant for this module
-	var apexVariantsWithoutTestApexes []string
+	apexVariantsWithoutTestApexes := []string{}
 	if apexInfo.BaseApexName != "" {
 		// This is a transitive dependency of an override_apex
-		apexVariantsWithoutTestApexes = []string{apexInfo.BaseApexName}
+		apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, apexInfo.BaseApexName)
 	} else {
-		_, apexVariantsWithoutTestApexes, _ = android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+		_, variants, _ := android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+		apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, variants...)
+	}
+	if apexInfo.ApexAvailableName != "" {
+		apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, apexInfo.ApexAvailableName)
 	}
 	disableSource := false
 	// find the selected apexes
@@ -489,6 +494,7 @@
 
 	d.configPath = android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "dexpreopt.config")
 	dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
+	ctx.CheckbuildFile(d.configPath)
 
 	if d.dexpreoptDisabled(ctx, libName) {
 		return
@@ -592,7 +598,8 @@
 
 			}
 		} else if !d.preventInstall {
-			ctx.InstallFile(installPath, installBase, install.From)
+			// Install without adding to checkbuild to match behavior of previous Make-based checkbuild rules
+			ctx.InstallFileWithoutCheckbuild(installPath, installBase, install.From)
 		}
 	}
 
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 73e33f4..07d0595 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -54,6 +54,7 @@
 					name: "foo",
 					installable: true,
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: true,
 		},
@@ -98,6 +99,7 @@
 				java_library {
 					name: "foo",
 					installable: true,
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -107,6 +109,7 @@
 				java_library {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -144,6 +147,7 @@
 					name: "foo",
 					srcs: ["a.java"],
 					compile_dex: true,
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -164,6 +168,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			apexVariant: true,
 			enabled:     false,
@@ -176,6 +181,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			moduleName:  "service-foo",
 			apexVariant: true,
@@ -189,6 +195,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			moduleName:  "prebuilt_service-foo",
 			apexVariant: true,
@@ -202,6 +209,7 @@
 					installable: true,
 					srcs: ["a.java"],
 					apex_available: ["com.android.apex1"],
+					sdk_version: "current",
 				}`,
 			moduleName:  "service-foo",
 			apexVariant: false,
@@ -311,6 +319,7 @@
 			installable: true,
 			srcs: ["a.java"],
 			apex_available: ["com.android.apex1"],
+			sdk_version: "current",
 		}`)
 	ctx := result.TestContext
 	module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
@@ -342,6 +351,7 @@
 			name: "foo",
 			installable: true,
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}`)
 	ctx = result.TestContext
 	module = ctx.ModuleForTests("foo", "android_common")
@@ -398,6 +408,7 @@
 			installable: true,
 			srcs: ["a.java"],
 			apex_available: ["com.android.apex1"],
+			sdk_version: "current",
 		}`)
 	ctx := result.TestContext
 	module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
@@ -429,6 +440,7 @@
 			name: "foo",
 			installable: true,
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}`)
 	ctx = result.TestContext
 	module = ctx.ModuleForTests("foo", "android_common")
@@ -454,6 +466,7 @@
 				profile: "art-profile",
 			},
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}`)
 
 	ctx := result.TestContext
diff --git a/java/droiddoc.go b/java/droiddoc.go
index f81c5ba..2929bb8 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -54,7 +54,7 @@
 	Filter_packages []string
 
 	// list of java libraries that will be in the classpath.
-	Libs []string `android:"arch_variant"`
+	Libs proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
 	Installable *bool
@@ -274,7 +274,7 @@
 		}
 	}
 
-	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs.GetOrDefault(ctx, nil)...)
 }
 
 func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index d5e6d8f..79f1b6f 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -70,14 +70,6 @@
 	module.Library.properties.Libs = append(module.Library.properties.Libs, name)
 }
 
-// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]`
-func (module *GeneratedJavaLibraryModule) AddStaticLibrary(name string) {
-	if module.depsMutatorDone {
-		panic("GeneratedJavaLibraryModule.AddStaticLibrary called after DepsMutator")
-	}
-	module.Library.properties.Static_libs = append(module.Library.properties.Static_libs, name)
-}
-
 func (module *GeneratedJavaLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	module.callbacks.DepsMutator(module, ctx)
 	module.depsMutatorDone = true
diff --git a/java/java.go b/java/java.go
index 55c878e..95f4fd8 100644
--- a/java/java.go
+++ b/java/java.go
@@ -254,16 +254,26 @@
 type JavaInfo struct {
 	// HeaderJars is a list of jars that can be passed as the javac classpath in order to link
 	// against this module.  If empty, ImplementationJars should be used instead.
+	// Unlike LocalHeaderJars, HeaderJars includes classes from static dependencies.
 	HeaderJars android.Paths
 
 	RepackagedHeaderJars android.Paths
 
 	// set of header jars for all transitive libs deps
-	TransitiveLibsHeaderJars *android.DepSet[android.Path]
+	TransitiveLibsHeaderJarsForR8 *android.DepSet[android.Path]
 
 	// set of header jars for all transitive static libs deps
+	TransitiveStaticLibsHeaderJarsForR8 *android.DepSet[android.Path]
+
+	// depset of header jars for this module and all transitive static dependencies
 	TransitiveStaticLibsHeaderJars *android.DepSet[android.Path]
 
+	// depset of implementation jars for this module and all transitive static dependencies
+	TransitiveStaticLibsImplementationJars *android.DepSet[android.Path]
+
+	// depset of resource jars for this module and all transitive static dependencies
+	TransitiveStaticLibsResourceJars *android.DepSet[android.Path]
+
 	// ImplementationAndResourceJars is a list of jars that contain the implementations of classes
 	// in the module as well as any resources included in the module.
 	ImplementationAndResourcesJars android.Paths
@@ -275,6 +285,9 @@
 	// ResourceJars is a list of jars that contain the resources included in the module.
 	ResourceJars android.Paths
 
+	// LocalHeaderJars is a list of jars that contain classes from this module, but not from any static dependencies.
+	LocalHeaderJars android.Paths
+
 	// AidlIncludeDirs is a list of directories that should be passed to the aidl tool when
 	// depending on this module.
 	AidlIncludeDirs android.Paths
@@ -553,7 +566,7 @@
 	// are provided by systemModules.
 	java9Classpath classpath
 
-	processorPath           classpath
+	processorPath           classpath ``
 	errorProneProcessorPath classpath
 	processorClasses        []string
 	staticJars              android.Paths
@@ -568,6 +581,10 @@
 	aconfigProtoFiles       android.Paths
 
 	disableTurbine bool
+
+	transitiveStaticLibsHeaderJars         []*android.DepSet[android.Path]
+	transitiveStaticLibsImplementationJars []*android.DepSet[android.Path]
+	transitiveStaticLibsResourceJars       []*android.DepSet[android.Path]
 }
 
 func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) {
@@ -980,7 +997,7 @@
 			j.dexpreopter.disableDexpreopt()
 		}
 	}
-	j.compile(ctx, nil, nil, nil)
+	j.compile(ctx, nil, nil, nil, nil)
 
 	// If this module is an impl library created from java_sdk_library,
 	// install the files under the java_sdk_library module outdir instead of this module outdir.
@@ -1008,7 +1025,7 @@
 		}
 		hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host()
 		if hostDexNeeded {
-			j.hostdexInstallFile = ctx.InstallFile(
+			j.hostdexInstallFile = ctx.InstallFileWithoutCheckbuild(
 				android.PathForHostDexInstall(ctx, "framework"),
 				j.Stem()+"-hostdex.jar", j.outputFile)
 		}
@@ -1022,7 +1039,7 @@
 		} else {
 			installDir = android.PathForModuleInstall(ctx, "framework")
 		}
-		j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
+		j.installFile = ctx.InstallFileWithoutCheckbuild(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
 }
 
@@ -1994,11 +2011,11 @@
 
 	// List of shared java libs that this module has dependencies to and
 	// should be passed as classpath in javac invocation
-	Libs []string
+	Libs proptools.Configurable[[]string]
 
 	// List of java libs that this module has static dependencies to and will be
 	// merge zipped after metalava invocation
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 
 	// Version of previously released API file for compatibility check.
 	Previous_api *string `android:"path"`
@@ -2174,8 +2191,8 @@
 
 		}
 	}
-	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
-	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs.GetOrDefault(ctx, nil)...)
+	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
 
 	for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations {
 		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName)
@@ -2359,11 +2376,14 @@
 	ctx.Phony(ctx.ModuleName(), al.stubsJar)
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(al.stubsJar),
-		ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar),
-		ImplementationJars:             android.PathsIfNonNil(al.stubsJar),
-		AidlIncludeDirs:                android.Paths{},
-		StubsLinkType:                  Stubs,
+		HeaderJars:                             android.PathsIfNonNil(al.stubsJar),
+		LocalHeaderJars:                        android.PathsIfNonNil(al.stubsJar),
+		TransitiveStaticLibsHeaderJars:         android.NewDepSet(android.PREORDER, android.PathsIfNonNil(al.stubsJar), nil),
+		TransitiveStaticLibsImplementationJars: android.NewDepSet(android.PREORDER, android.PathsIfNonNil(al.stubsJar), nil),
+		ImplementationAndResourcesJars:         android.PathsIfNonNil(al.stubsJar),
+		ImplementationJars:                     android.PathsIfNonNil(al.stubsJar),
+		AidlIncludeDirs:                        android.Paths{},
+		StubsLinkType:                          Stubs,
 		// No aconfig libraries on api libraries
 	})
 }
@@ -2406,16 +2426,16 @@
 
 func (al *ApiLibrary) IDEInfo(ctx android.BaseModuleContext, i *android.IdeInfo) {
 	i.Deps = append(i.Deps, al.ideDeps(ctx)...)
-	i.Libs = append(i.Libs, al.properties.Libs...)
-	i.Static_libs = append(i.Static_libs, al.properties.Static_libs...)
+	i.Libs = append(i.Libs, al.properties.Libs.GetOrDefault(ctx, nil)...)
+	i.Static_libs = append(i.Static_libs, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
 	i.SrcJars = append(i.SrcJars, al.stubsSrcJar.String())
 }
 
 // deps of java_api_library for module_bp_java_deps.json
 func (al *ApiLibrary) ideDeps(ctx android.BaseModuleContext) []string {
 	ret := []string{}
-	ret = append(ret, al.properties.Libs...)
-	ret = append(ret, al.properties.Static_libs...)
+	ret = append(ret, al.properties.Libs.GetOrDefault(ctx, nil)...)
+	ret = append(ret, al.properties.Static_libs.GetOrDefault(ctx, nil)...)
 	if al.properties.System_modules != nil {
 		ret = append(ret, proptools.String(al.properties.System_modules))
 	}
@@ -2459,7 +2479,7 @@
 	Libs []string
 
 	// List of static java libs that this module has dependencies to
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 
 	// List of files to remove from the jar file(s)
 	Exclude_files []string
@@ -2600,7 +2620,7 @@
 
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
-	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs.GetOrDefault(ctx, nil)...)
 
 	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
 		sdkDeps(ctx, android.SdkContext(j), j.dexer)
@@ -2634,7 +2654,13 @@
 
 	var flags javaBuilderFlags
 
-	j.collectTransitiveHeaderJars(ctx)
+	var transitiveClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveBootClasspathHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsImplementationJars []*android.DepSet[android.Path]
+	var transitiveStaticLibsResourceJars []*android.DepSet[android.Path]
+
+	j.collectTransitiveHeaderJarsForR8(ctx)
 	var staticJars android.Paths
 	var staticResourceJars android.Paths
 	var staticHeaderJars android.Paths
@@ -2645,32 +2671,67 @@
 			case libTag, sdkLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
 				flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			case staticLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
 				staticJars = append(staticJars, dep.ImplementationJars...)
 				staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
 				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+					transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
+				if dep.TransitiveStaticLibsImplementationJars != nil {
+					transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars)
+				}
+				if dep.TransitiveStaticLibsResourceJars != nil {
+					transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars)
+				}
 			case bootClasspathTag:
 				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
+				if dep.TransitiveStaticLibsHeaderJars != nil {
+					transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+				}
 			}
 		} else if dep, ok := module.(SdkLibraryDependency); ok {
 			switch tag {
 			case libTag, sdkLibTag:
-				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
+				depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))
+				flags.classpath = append(flags.classpath, depHeaderJars...)
+				transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars,
+					android.NewDepSet(android.PREORDER, depHeaderJars, nil))
 			}
 		}
 
 		addCLCFromDep(ctx, module, j.classLoaderContexts)
 	})
 
-	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
+	localJars := android.PathsForModuleSrc(ctx, j.properties.Jars)
 	jarName := j.Stem() + ".jar"
 
+	// Combine only the local jars together for use in transitive classpaths.
+	// Always pass input jar through TransformJarsToJar to strip module-info.class from prebuilts.
+	localCombinedHeaderJar := android.PathForModuleOut(ctx, "local-combined", jarName)
+	TransformJarsToJar(ctx, localCombinedHeaderJar, "combine local prebuilt implementation jars", localJars, android.OptionalPath{},
+		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+	localStrippedJars := android.Paths{localCombinedHeaderJar}
+
+	completeStaticLibsHeaderJars := android.NewDepSet(android.PREORDER, localStrippedJars, transitiveStaticLibsHeaderJars)
+	completeStaticLibsImplementationJars := android.NewDepSet(android.PREORDER, localStrippedJars, transitiveStaticLibsImplementationJars)
+	completeStaticLibsResourceJars := android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsResourceJars)
+
 	// Always pass the input jars to TransformJarsToJar, even if there is only a single jar, we need the output
 	// file of the module to be named jarName.
 	var outputFile android.Path
 	combinedImplementationJar := android.PathForModuleOut(ctx, "combined", jarName)
-	implementationJars := append(slices.Clone(jars), staticJars...)
+	var implementationJars android.Paths
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		implementationJars = completeStaticLibsImplementationJars.ToList()
+	} else {
+		implementationJars = append(slices.Clone(localJars), staticJars...)
+	}
 	TransformJarsToJar(ctx, combinedImplementationJar, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
 		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
 	outputFile = combinedImplementationJar
@@ -2693,7 +2754,12 @@
 	if reuseImplementationJarAsHeaderJar {
 		headerJar = outputFile
 	} else {
-		headerJars := append(slices.Clone(jars), staticHeaderJars...)
+		var headerJars android.Paths
+		if ctx.Config().UseTransitiveJarsInClasspath() {
+			headerJars = completeStaticLibsHeaderJars.ToList()
+		} else {
+			headerJars = append(slices.Clone(localJars), staticHeaderJars...)
+		}
 		headerOutputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
 		TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{},
 			false, j.properties.Exclude_files, j.properties.Exclude_dirs)
@@ -2712,6 +2778,11 @@
 		} else {
 			headerJar = outputFile
 		}
+
+		// Enabling jetifier requires modifying classes from transitive dependencies, disable transitive
+		// classpath and use the combined header jar instead.
+		completeStaticLibsHeaderJars = android.NewDepSet(android.PREORDER, android.Paths{headerJar}, nil)
+		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, android.Paths{outputFile}, nil)
 	}
 
 	implementationJarFile := outputFile
@@ -2735,6 +2806,12 @@
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
 
+	if ctx.Config().UseTransitiveJarsInClasspath() {
+		ctx.CheckbuildFile(localJars...)
+	} else {
+		ctx.CheckbuildFile(outputFile)
+	}
+
 	if ctx.Device() {
 		// If this is a variant created for a prebuilt_apex then use the dex implementation jar
 		// obtained from the associated deapexer module.
@@ -2801,6 +2878,7 @@
 			if ctx.Failed() {
 				return
 			}
+			ctx.CheckbuildFile(dexOutputFile)
 
 			// Initialize the hiddenapi structure.
 			j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex)
@@ -2814,14 +2892,18 @@
 	}
 
 	android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(j.combinedHeaderFile),
-		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
-		ImplementationJars:             android.PathsIfNonNil(implementationJarFile.WithoutRel()),
-		ResourceJars:                   android.PathsIfNonNil(resourceJarFile),
-		AidlIncludeDirs:                j.exportAidlIncludeDirs,
-		StubsLinkType:                  j.stubsLinkType,
+		HeaderJars:                             android.PathsIfNonNil(j.combinedHeaderFile),
+		LocalHeaderJars:                        android.PathsIfNonNil(j.combinedHeaderFile),
+		TransitiveLibsHeaderJarsForR8:          j.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8:    j.transitiveStaticLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJars:         completeStaticLibsHeaderJars,
+		TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars,
+		TransitiveStaticLibsResourceJars:       completeStaticLibsResourceJars,
+		ImplementationAndResourcesJars:         android.PathsIfNonNil(j.combinedImplementationFile),
+		ImplementationJars:                     android.PathsIfNonNil(implementationJarFile.WithoutRel()),
+		ResourceJars:                           android.PathsIfNonNil(resourceJarFile),
+		AidlIncludeDirs:                        j.exportAidlIncludeDirs,
+		StubsLinkType:                          j.stubsLinkType,
 		// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 
diff --git a/java/java_test.go b/java/java_test.go
index 9e39b51..e4e6bca 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,6 +20,7 @@
 	"path/filepath"
 	"reflect"
 	"runtime"
+	"slices"
 	"strconv"
 	"strings"
 	"testing"
@@ -211,7 +212,7 @@
 }
 
 func TestSimple(t *testing.T) {
-	ctx, _ := testJava(t, `
+	bp := `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -222,31 +223,157 @@
 		java_library {
 			name: "bar",
 			srcs: ["b.java"],
+			static_libs: ["quz"],
 		}
 
 		java_library {
 			name: "baz",
 			srcs: ["c.java"],
+			static_libs: ["quz"],
 		}
-	`)
 
-	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
+		java_library {
+			name: "quz",
+			srcs: ["d.java"],
+		}`
 
-	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
-		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+	frameworkTurbineCombinedJars := []string{
+		"out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
 	}
 
-	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
-	barTurbine := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
-	bazTurbine := filepath.Join("out", "soong", ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar")
+	frameworkTurbineJars := []string{
+		"out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
+	}
 
-	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barTurbine)
+	testCases := []struct {
+		name string
 
-	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazTurbine)
+		preparer android.FixturePreparer
 
-	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
-		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
+		fooJavacInputs          []string
+		fooJavacClasspath       []string
+		fooCombinedInputs       []string
+		fooHeaderCombinedInputs []string
+
+		barJavacInputs          []string
+		barJavacClasspath       []string
+		barCombinedInputs       []string
+		barHeaderCombinedInputs []string
+	}{
+		{
+			name:           "normal",
+			preparer:       android.NullFixturePreparer,
+			fooJavacInputs: []string{"a.java"},
+			fooJavacClasspath: slices.Concat(
+				frameworkTurbineCombinedJars,
+				[]string{
+					"out/soong/.intermediates/bar/android_common/turbine-combined/bar.jar",
+					"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+				},
+			),
+			fooCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/javac/foo.jar",
+				"out/soong/.intermediates/baz/android_common/combined/baz.jar",
+			},
+
+			fooHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+				"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
+			},
+
+			barJavacInputs: []string{"b.java"},
+			barJavacClasspath: slices.Concat(
+				frameworkTurbineCombinedJars,
+				[]string{
+					"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
+				},
+			),
+			barCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/javac/bar.jar",
+				"out/soong/.intermediates/quz/android_common/javac/quz.jar",
+			},
+			barHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+				"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
+			},
+		},
+		{
+			name:           "transitive classpath",
+			preparer:       PrepareForTestWithTransitiveClasspathEnabled,
+			fooJavacInputs: []string{"a.java"},
+			fooJavacClasspath: slices.Concat(
+				frameworkTurbineJars,
+				[]string{
+					"out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+					"out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+					"out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+				},
+			),
+			fooCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/javac/foo.jar",
+				"out/soong/.intermediates/baz/android_common/javac/baz.jar",
+				"out/soong/.intermediates/quz/android_common/javac/quz.jar",
+			},
+
+			fooHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+				"out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+				"out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+			},
+
+			barJavacInputs: []string{"b.java"},
+			barJavacClasspath: slices.Concat(
+				frameworkTurbineJars,
+				[]string{"out/soong/.intermediates/quz/android_common/turbine/quz.jar"},
+			),
+			barCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/javac/bar.jar",
+				"out/soong/.intermediates/quz/android_common/javac/quz.jar",
+			},
+			barHeaderCombinedInputs: []string{
+				"out/soong/.intermediates/bar/android_common/turbine/bar.jar",
+				"out/soong/.intermediates/quz/android_common/turbine/quz.jar",
+			},
+		},
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			result := android.GroupFixturePreparers(
+				PrepareForTestWithJavaDefaultModules,
+				tt.preparer,
+			).RunTestWithBp(t, bp)
+			foo := result.ModuleForTests("foo", "android_common")
+
+			fooJavac := foo.Rule("javac")
+			android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs)
+
+			fooJavacClasspath := fooJavac.Args["classpath"]
+			android.AssertStringPathsRelativeToTopEquals(t, "foo javac classpath", result.Config, tt.fooJavacClasspath,
+				strings.Split(strings.TrimPrefix(fooJavacClasspath, "-classpath "), ":"))
+
+			fooCombinedJar := foo.Output("combined/foo.jar")
+			android.AssertPathsRelativeToTopEquals(t, "foo combined inputs", tt.fooCombinedInputs, fooCombinedJar.Inputs)
+
+			fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar")
+			android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs)
+
+			bar := result.ModuleForTests("bar", "android_common")
+			barJavac := bar.Rule("javac")
+			android.AssertPathsRelativeToTopEquals(t, "bar javac inputs", tt.barJavacInputs, barJavac.Inputs)
+
+			barJavacClasspath := barJavac.Args["classpath"]
+			android.AssertStringPathsRelativeToTopEquals(t, "bar javac classpath", result.Config, tt.barJavacClasspath,
+				strings.Split(strings.TrimPrefix(barJavacClasspath, "-classpath "), ":"))
+
+			barCombinedJar := bar.Output("combined/bar.jar")
+			android.AssertPathsRelativeToTopEquals(t, "bar combined inputs", tt.barCombinedInputs, barCombinedJar.Inputs)
+
+			barCombinedHeaderJar := bar.Output("turbine-combined/bar.jar")
+			android.AssertPathsRelativeToTopEquals(t, "bar header combined inputs", tt.barHeaderCombinedInputs, barCombinedHeaderJar.Inputs)
+		})
 	}
 }
 
@@ -590,7 +717,7 @@
 	barModule := ctx.ModuleForTests("bar", "android_common")
 	barJar := barModule.Output("combined/bar.jar").Output
 	bazModule := ctx.ModuleForTests("baz", "android_common")
-	bazJar := bazModule.Rule("combineJar").Output
+	bazJar := bazModule.Output("combined/baz.jar").Output
 	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").
 		Output("combined/sdklib.stubs.jar").Output
 
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 844e974..f6e7fca 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -56,6 +56,13 @@
 		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine-combined/kotlin-annotations.jar",
 	}
 
+	kotlinStdlibTurbineJars := []string{
+		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine/kotlin-stdlib.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine/kotlin-stdlib-jdk7.jar",
+		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine/kotlin-stdlib-jdk8.jar",
+		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine/kotlin-annotations.jar",
+	}
+
 	kotlinStdlibJavacJars := []string{
 		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/javac/kotlin-stdlib.jar",
 		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/javac/kotlin-stdlib-jdk7.jar",
@@ -68,11 +75,21 @@
 		"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine-combined/core-lambda-stubs.jar",
 	}
 
+	bootclasspathTurbineJars := []string{
+		"out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine/stable.core.platform.api.stubs.jar",
+		"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine/core-lambda-stubs.jar",
+	}
+
 	frameworkTurbineCombinedJars := []string{
 		"out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
 		"out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
 	}
 
+	frameworkTurbineJars := []string{
+		"out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
+	}
+
 	testCases := []struct {
 		name string
 
@@ -150,6 +167,69 @@
 				kotlinStdlibTurbineCombinedJars,
 			),
 		},
+		{
+			name:             "transitive classpath",
+			preparer:         PrepareForTestWithTransitiveClasspathEnabled,
+			fooKotlincInputs: []string{"a.java", "b.kt"},
+			fooJavacInputs:   []string{"a.java"},
+			fooKotlincClasspath: slices.Concat(
+				bootclasspathTurbineJars,
+				frameworkTurbineJars,
+				[]string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
+				kotlinStdlibTurbineJars,
+			),
+			fooJavacClasspath: slices.Concat(
+				[]string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"},
+				frameworkTurbineJars,
+				[]string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
+				kotlinStdlibTurbineJars,
+			),
+			fooCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/foo/android_common/kotlin/foo.jar",
+					"out/soong/.intermediates/foo/android_common/javac/foo.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
+				},
+				kotlinStdlibJavacJars,
+			),
+			fooHeaderCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+				},
+				kotlinStdlibTurbineJars,
+			),
+
+			barKotlincInputs: []string{"b.kt"},
+			barKotlincClasspath: slices.Concat(
+				bootclasspathTurbineJars,
+				frameworkTurbineJars,
+				[]string{
+					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
+					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+				},
+				kotlinStdlibTurbineJars,
+				[]string{"out/soong/.intermediates/baz/android_common/turbine/baz.jar"},
+			),
+			barCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/bar/android_common/kotlin/bar.jar",
+					"out/soong/.intermediates/baz/android_common/javac/baz.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
+				},
+				kotlinStdlibJavacJars,
+			),
+			barHeaderCombinedInputs: slices.Concat(
+				[]string{
+					"out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar",
+					"out/soong/.intermediates/baz/android_common/turbine/baz.jar",
+					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
+				},
+				kotlinStdlibTurbineJars,
+			),
+		},
 	}
 
 	for _, tt := range testCases {
diff --git a/java/robolectric.go b/java/robolectric.go
index 26f4b71..374fc5f 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -16,9 +16,6 @@
 
 import (
 	"fmt"
-	"io"
-	"strconv"
-	"strings"
 
 	"android/soong/android"
 	"android/soong/java/config"
@@ -88,16 +85,6 @@
 	robolectricProperties robolectricProperties
 	testProperties        testProperties
 
-	libs  []string
-	tests []string
-
-	manifest    android.Path
-	resourceApk android.Path
-
-	combinedJar android.WritablePath
-
-	roboSrcJar android.Path
-
 	testConfig android.Path
 	data       android.Paths
 
@@ -121,12 +108,12 @@
 	}
 
 	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
-		ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
+		ctx.AddVariationDependencies(nil, staticLibTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
 	} else if !proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) {
 		if proptools.Bool(r.robolectricProperties.Upstream) {
-			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream")
+			ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib+"_upstream")
 		} else {
-			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
+			ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib)
 		}
 	}
 
@@ -134,10 +121,10 @@
 		ctx.AddVariationDependencies(nil, roboRuntimeOnlyTag, robolectricCurrentLib+"_upstream")
 	} else {
 		// opting out from strict mode, robolectric_non_strict_mode_permission lib should be added
-		ctx.AddVariationDependencies(nil, libTag, "robolectric_non_strict_mode_permission")
+		ctx.AddVariationDependencies(nil, staticLibTag, "robolectric_non_strict_mode_permission")
 	}
 
-	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, robolectricDefaultLibs...)
 
 	ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
 
@@ -163,9 +150,6 @@
 	})
 	r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data)
 
-	roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
-		Join(ctx, "com/android/tools/test_config.properties")
-
 	var ok bool
 	var instrumentedApp *AndroidApp
 
@@ -181,90 +165,58 @@
 		panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
 	}
 
+	var resourceApk android.Path
+	var manifest android.Path
 	if instrumentedApp != nil {
-		r.manifest = instrumentedApp.mergedManifestFile
-		r.resourceApk = instrumentedApp.outputFile
-
-		generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
-		r.extraResources = android.Paths{roboTestConfig}
-	}
-
-	r.Library.GenerateAndroidBuildActions(ctx)
-
-	roboSrcJar := android.PathForModuleGen(ctx, "robolectric", ctx.ModuleName()+".srcjar")
-
-	if instrumentedApp != nil {
-		r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
-		r.roboSrcJar = roboSrcJar
+		manifest = instrumentedApp.mergedManifestFile
+		resourceApk = instrumentedApp.outputFile
 	}
 
 	roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
 	generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar)
 
-	combinedJarJars := android.Paths{
-		// roboTestConfigJar comes first so that its com/android/tools/test_config.properties
-		// overrides the one from r.extraResources.  The r.extraResources one can be removed
-		// once the Make test runner is removed.
-		roboTestConfigJar,
-		r.outputFile,
-	}
+	extraCombinedJars := android.Paths{roboTestConfigJar}
 
-	if instrumentedApp != nil {
-		combinedJarJars = append(combinedJarJars, instrumentedApp.implementationAndResourcesJar)
-	}
-
-	handleLibDeps := func(dep android.Module, runtimeOnly bool) {
-		if !runtimeOnly {
-			r.libs = append(r.libs, ctx.OtherModuleName(dep))
-		}
+	handleLibDeps := func(dep android.Module) {
 		if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
 			if m, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
-				combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...)
+				extraCombinedJars = append(extraCombinedJars, m.ImplementationAndResourcesJars...)
 			}
 		}
 	}
 
 	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
-		handleLibDeps(dep, false)
+		handleLibDeps(dep)
 	}
 	for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) {
-		handleLibDeps(dep, false)
+		handleLibDeps(dep)
 	}
 	// handle the runtimeOnly tag for strict_mode
 	for _, dep := range ctx.GetDirectDepsWithTag(roboRuntimeOnlyTag) {
-		handleLibDeps(dep, true)
+		handleLibDeps(dep)
 	}
 
-	r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base())
-	TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{},
-		false, nil, nil)
-
-	// TODO: this could all be removed if tradefed was used as the test runner, it will find everything
-	// annotated as a test and run it.
-	for _, src := range r.uniqueSrcFiles {
-		s := src.Rel()
-		if !strings.HasSuffix(s, "Test.java") && !strings.HasSuffix(s, "Test.kt") {
-			continue
-		} else if strings.HasSuffix(s, "/BaseRobolectricTest.java") {
-			continue
-		} else {
-			s = strings.TrimPrefix(s, "src/")
-		}
-		r.tests = append(r.tests, s)
+	if instrumentedApp != nil {
+		extraCombinedJars = append(extraCombinedJars, instrumentedApp.implementationAndResourcesJar)
 	}
 
+	r.stem = proptools.StringDefault(r.overridableProperties.Stem, ctx.ModuleName())
+	r.classLoaderContexts = r.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+	r.dexpreopter.disableDexpreopt()
+	r.compile(ctx, nil, nil, nil, extraCombinedJars)
+
 	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
 	var installDeps android.InstallPaths
 
-	if r.manifest != nil {
-		r.data = append(r.data, r.manifest)
-		installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
+	if manifest != nil {
+		r.data = append(r.data, manifest)
+		installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", manifest)
 		installDeps = append(installDeps, installedManifest)
 	}
 
-	if r.resourceApk != nil {
-		r.data = append(r.data, r.resourceApk)
-		installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
+	if resourceApk != nil {
+		r.data = append(r.data, resourceApk)
+		installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", resourceApk)
 		installDeps = append(installDeps, installedResourceApk)
 	}
 
@@ -287,29 +239,10 @@
 		installDeps = append(installDeps, installJni)
 	}
 
-	r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
+	r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
 	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
-func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
-	instrumentedApp *AndroidApp) {
-	rule := android.NewRuleBuilder(pctx, ctx)
-
-	manifest := instrumentedApp.mergedManifestFile
-	resourceApk := instrumentedApp.outputFile
-
-	rule.Command().Text("rm -f").Output(outputFile)
-	rule.Command().
-		Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&").
-		Textf(`echo "android_resource_apk=%s" >>`, resourceApk.String()).Output(outputFile).
-		// Make it depend on the files to which it points so the test file's timestamp is updated whenever the
-		// contents change
-		Implicit(manifest).
-		Implicit(resourceApk)
-
-	rule.Build("generate_test_config", "generate test_config.properties")
-}
-
 func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) {
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -332,22 +265,6 @@
 	rule.Build("generate_test_config_samedir", "generate test_config.properties")
 }
 
-func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
-	instrumentedApp *AndroidApp) {
-
-	srcJarArgs := android.CopyOf(instrumentedApp.srcJarArgs)
-	srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
-
-	for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
-		if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
-			srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...)
-			srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...)
-		}
-	}
-
-	TransformResourcesToJar(ctx, outputFile, srcJarArgs, srcJarDeps)
-}
-
 func (r *robolectricTest) AndroidMkEntries() []android.AndroidMkEntries {
 	entriesList := r.Library.AndroidMkEntries()
 	entries := &entriesList[0]
@@ -359,61 +276,11 @@
 				entries.SetPath("LOCAL_FULL_TEST_CONFIG", r.testConfig)
 			}
 		})
-
-	entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
-		func(w io.Writer, name, prefix, moduleDir string) {
-			if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 {
-				numShards := int(*s)
-				shardSize := (len(r.tests) + numShards - 1) / numShards
-				shards := android.ShardStrings(r.tests, shardSize)
-				for i, shard := range shards {
-					r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard)
-				}
-
-				// TODO: add rules to dist the outputs of the individual tests, or combine them together?
-				fmt.Fprintln(w, "")
-				fmt.Fprintln(w, ".PHONY:", "Run"+name)
-				fmt.Fprintln(w, "Run"+name, ": \\")
-				for i := range shards {
-					fmt.Fprintln(w, "   ", "Run"+name+strconv.Itoa(i), "\\")
-				}
-				fmt.Fprintln(w, "")
-			} else {
-				r.writeTestRunner(w, name, "Run"+name, r.tests)
-			}
-		},
-	}
-
 	return entriesList
 }
 
-func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, tests []string) {
-	fmt.Fprintln(w, "")
-	fmt.Fprintln(w, "include $(CLEAR_VARS)", " # java.robolectricTest")
-	fmt.Fprintln(w, "LOCAL_MODULE :=", name)
-	android.AndroidMkEmitAssignList(w, "LOCAL_JAVA_LIBRARIES", []string{module}, r.libs)
-	fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
-	if r.roboSrcJar != nil {
-		fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
-	}
-	android.AndroidMkEmitAssignList(w, "LOCAL_ROBOTEST_FILES", tests)
-	if t := r.robolectricProperties.Test_options.Timeout; t != nil {
-		fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
-	}
-	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
-		fmt.Fprintf(w, "-include prebuilts/misc/common/robolectric/%s/run_robotests.mk\n", v)
-	} else {
-		fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
-	}
-}
-
 // An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
-// instead of on a device.  It also generates a rule with the name of the module prefixed with "Run" that can be
-// used to run the tests.  Running the tests with build rule will eventually be deprecated and replaced with atest.
-//
-// The test runner considers any file listed in srcs whose name ends with Test.java to be a test class, unless
-// it is named BaseRobolectricTest.java.  The path to the each source file must exactly match the package
-// name, or match the package name when the prefix "src/" is removed.
+// instead of on a device.
 func RobolectricTestFactory() android.Module {
 	module := &robolectricTest{}
 
diff --git a/java/rro.go b/java/rro.go
index 0fc6e1c..8bb9be2 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -17,7 +17,11 @@
 // This file contains the module implementations for runtime_resource_overlay and
 // override_runtime_resource_overlay.
 
-import "android/soong/android"
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
+)
 
 func init() {
 	RegisterRuntimeResourceOverlayBuildComponents(android.InitRegistrationContext)
@@ -71,7 +75,7 @@
 	Min_sdk_version *string
 
 	// list of android_library modules whose resources are extracted and linked against statically
-	Static_libs []string
+	Static_libs proptools.Configurable[[]string]
 
 	// list of android_app modules whose resources are extracted and linked against
 	Resource_libs []string
@@ -120,7 +124,7 @@
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
 
-	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs.GetOrDefault(ctx, nil)...)
 	ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
 
 	for _, aconfig_declaration := range r.aaptProperties.Flags_packages {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 25317c5..b7aa4e5 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1595,6 +1595,11 @@
 			module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile
 		}
 
+		if installFilesInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, android.InstallFilesProvider); ok {
+			if installFilesInfo.CheckbuildTarget != nil {
+				ctx.CheckbuildFile(installFilesInfo.CheckbuildTarget)
+			}
+		}
 		android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: module.implLibraryModule.uniqueSrcFiles.Strings()})
 	}
 
@@ -1739,11 +1744,13 @@
 func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
 	visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
 
+	staticLibs := module.properties.Static_libs.Clone()
+	staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs)
 	props := struct {
 		Name           *string
 		Visibility     []string
 		Libs           []string
-		Static_libs    []string
+		Static_libs    proptools.Configurable[[]string]
 		Apex_available []string
 		Stem           *string
 	}{
@@ -1752,7 +1759,7 @@
 
 		Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...),
 
-		Static_libs: append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...),
+		Static_libs: staticLibs,
 		// Pass the apex_available settings down so that the impl library can be statically
 		// embedded within a library that is added to an APEX. Needed for updatable-media.
 		Apex_available: module.ApexAvailable(),
@@ -1858,7 +1865,7 @@
 		Sdk_version                      *string
 		Api_surface                      *string
 		System_modules                   *string
-		Libs                             []string
+		Libs                             proptools.Configurable[[]string]
 		Output_javadoc_comments          *bool
 		Arg_files                        []string
 		Args                             *string
@@ -1902,10 +1909,11 @@
 	props.Installable = proptools.BoolPtr(false)
 	// A droiddoc module has only one Libs property and doesn't distinguish between
 	// shared libs and static libs. So we need to add both of these libs to Libs property.
-	props.Libs = module.properties.Libs
-	props.Libs = append(props.Libs, module.properties.Static_libs...)
-	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
-	props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
+	props.Libs = proptools.NewConfigurable[[]string](nil, nil)
+	props.Libs.AppendSimpleValue(module.properties.Libs)
+	props.Libs.Append(module.properties.Static_libs)
+	props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
+	props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
 	props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
 	props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
 	props.Java_version = module.properties.Java_version
@@ -2019,7 +2027,7 @@
 		Name              *string
 		Visibility        []string
 		Api_contributions []string
-		Libs              []string
+		Libs              proptools.Configurable[[]string]
 		Static_libs       []string
 		System_modules    *string
 		Enable_validation *bool
@@ -2051,11 +2059,12 @@
 	props.Api_contributions = apiContributions
 
 	// Ensure that stub-annotations is added to the classpath before any other libs
-	props.Libs = []string{"stub-annotations"}
-	props.Libs = append(props.Libs, module.properties.Libs...)
-	props.Libs = append(props.Libs, module.properties.Static_libs...)
-	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
-	props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
+	props.Libs = proptools.NewConfigurable[[]string](nil, nil)
+	props.Libs.AppendSimpleValue([]string{"stub-annotations"})
+	props.Libs.AppendSimpleValue(module.properties.Libs)
+	props.Libs.Append(module.properties.Static_libs)
+	props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs)
+	props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs)
 	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
 
 	props.System_modules = module.deviceProperties.System_modules
@@ -2099,6 +2108,7 @@
 		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
 		props.Dist.Tag = proptools.StringPtr(".jar")
 	}
+	props.Is_stubs_module = proptools.BoolPtr(true)
 
 	return props
 }
@@ -2364,7 +2374,7 @@
 
 	// Add the impl_only_libs and impl_only_static_libs *after* we're done using them in submodules.
 	module.properties.Libs = append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...)
-	module.properties.Static_libs = append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...)
+	module.properties.Static_libs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs)
 }
 
 func (module *SdkLibrary) InitSdkLibraryProperties() {
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 485776b..bb63315 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -907,7 +907,7 @@
 		fooModule := result.ModuleForTests("foo"+scope, "android_common")
 		javac := fooModule.Rule("javac")
 
-		sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
+		sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Output("combined/sdklib.stubs" + scope + ".jar").Output
 		android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String())
 	}
 
@@ -1528,7 +1528,8 @@
 
 	// The foo.stubs.source should depend on bar-lib
 	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
-	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+	eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
 }
 
 func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) {
@@ -1554,7 +1555,8 @@
 
 	// The foo.stubs.source should depend on bar-lib
 	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
-	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+	eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
+	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
 }
 
 func TestJavaSdkLibrary_ApiLibrary(t *testing.T) {
@@ -1705,18 +1707,15 @@
 	exportableSourceStubsLibraryModuleName := apiScopePublic.exportableSourceStubsLibraryModuleName("foo")
 
 	// Check modules generation
-	topLevelModule := result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
+	result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
 	result.ModuleForTests(exportableSourceStubsLibraryModuleName, "android_common")
 
 	// Check static lib dependency
 	android.AssertBoolEquals(t, "exportable top level stubs library module depends on the"+
 		"exportable source stubs library module", true,
-		CheckModuleHasDependency(t, result.TestContext, exportableStubsLibraryModuleName,
-			"android_common", exportableSourceStubsLibraryModuleName),
+		CheckModuleHasDependencyWithTag(t, result.TestContext, exportableStubsLibraryModuleName,
+			"android_common", staticLibTag, exportableSourceStubsLibraryModuleName),
 	)
-	android.AssertArrayString(t, "exportable source stub library is a static lib of the"+
-		"top level exportable stubs library", []string{exportableSourceStubsLibraryModuleName},
-		topLevelModule.Module().(*Library).properties.Static_libs)
 }
 
 // For java libraries depending on java_sdk_library(_import) via libs, assert that
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 2dac27a..9bfe6a2 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -391,15 +391,19 @@
 	t.Parallel()
 	t.Run("basic", func(t *testing.T) {
 		t.Parallel()
-		testClasspathTestCases(t, classpathTestcases, false)
+		testClasspathTestCases(t, classpathTestcases, false, false)
 	})
 
 	t.Run("Always_use_prebuilt_sdks=true", func(t *testing.T) {
-		testClasspathTestCases(t, classpathTestcases, true)
+		testClasspathTestCases(t, classpathTestcases, true, false)
+	})
+
+	t.Run("UseTransitiveJarsInClasspath", func(t *testing.T) {
+		testClasspathTestCases(t, classpathTestcases, false, true)
 	})
 }
 
-func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks bool) {
+func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks, useTransitiveJarsInClasspath bool) {
 	for _, testcase := range classpathTestcases {
 		if testcase.forAlwaysUsePrebuiltSdks != nil && *testcase.forAlwaysUsePrebuiltSdks != alwaysUsePrebuiltSdks {
 			continue
@@ -437,7 +441,14 @@
 			convertModulesToPaths := func(cp []string) []string {
 				ret := make([]string, len(cp))
 				for i, e := range cp {
-					ret[i] = defaultModuleToPath(e)
+					switch {
+					case e == `""`, strings.HasSuffix(e, ".jar"):
+						ret[i] = e
+					case useTransitiveJarsInClasspath:
+						ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine", e+".jar")
+					default:
+						ret[i] = filepath.Join("out", "soong", ".intermediates", defaultJavaDir, e, "android_common", "turbine-combined", e+".jar")
+					}
 				}
 				return ret
 			}
@@ -531,6 +542,9 @@
 					variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
 				})
 			}
+			if useTransitiveJarsInClasspath {
+				preparer = PrepareForTestWithTransitiveClasspathEnabled
+			}
 
 			fixtureFactory := android.GroupFixturePreparers(
 				prepareForJavaTest,
diff --git a/java/system_modules.go b/java/system_modules.go
index f89bf9e..d9430b2 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -127,6 +127,9 @@
 
 	OutputDir     android.Path
 	OutputDirDeps android.Paths
+
+	// depset of header jars for this module and all transitive static dependencies
+	TransitiveStaticLibsHeaderJars *android.DepSet[android.Path]
 }
 
 var SystemModulesProvider = blueprint.NewProvider[*SystemModulesProviderInfo]()
@@ -149,18 +152,23 @@
 func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	var jars android.Paths
 
+	var transitiveStaticLibsHeaderJars []*android.DepSet[android.Path]
 	ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
 		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			jars = append(jars, dep.HeaderJars...)
+			if dep.TransitiveStaticLibsHeaderJars != nil {
+				transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars)
+			}
 		}
 	})
 
 	system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars)
 
 	android.SetProvider(ctx, SystemModulesProvider, &SystemModulesProviderInfo{
-		HeaderJars:    jars,
-		OutputDir:     system.outputDir,
-		OutputDirDeps: system.outputDeps,
+		HeaderJars:                     jars,
+		OutputDir:                      system.outputDir,
+		OutputDirDeps:                  system.outputDeps,
+		TransitiveStaticLibsHeaderJars: android.NewDepSet(android.PREORDER, nil, transitiveStaticLibsHeaderJars),
 	})
 }
 
diff --git a/java/testing.go b/java/testing.go
index 0e85022..0c79e9f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -184,6 +184,10 @@
 			host_supported: true,
 			srcs: ["Test.java"],
 			sdk_version: "current",
+			apex_available: [
+				"//apex_available:anyapex",
+				"//apex_available:platform",
+			],
 		}
 	`)),
 )
@@ -408,7 +412,6 @@
 		"core.current.stubs",
 		"legacy.core.platform.api.stubs",
 		"stable.core.platform.api.stubs",
-
 		"android_stubs_current_exportable",
 		"android_system_stubs_current_exportable",
 		"android_test_stubs_current_exportable",
@@ -416,13 +419,11 @@
 		"android_system_server_stubs_current_exportable",
 		"core.current.stubs.exportable",
 		"legacy.core.platform.api.stubs.exportable",
-
 		"kotlin-stdlib",
 		"kotlin-stdlib-jdk7",
 		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
 		"stub-annotations",
-
 		"aconfig-annotations-lib",
 		"unsupportedappusage",
 	}
@@ -435,6 +436,7 @@
 				sdk_version: "none",
 				system_modules: "stable-core-platform-api-stubs-system-modules",
 				compile_dex: true,
+				is_stubs_module: true,
 			}
 		`, extra)
 	}
@@ -579,6 +581,7 @@
 				name: "%[1]s-lib",
 				sdk_version: "none",
 				system_modules: "none",
+				srcs: ["a.java"],
 			}
 		`, extra)
 	}
@@ -630,6 +633,18 @@
 	return false
 }
 
+// CheckModuleHasDependency returns true if the module depends on the expected dependency.
+func CheckModuleHasDependencyWithTag(t *testing.T, ctx *android.TestContext, name, variant string, desiredTag blueprint.DependencyTag, expected string) bool {
+	module := ctx.ModuleForTests(name, variant).Module()
+	found := false
+	ctx.VisitDirectDepsWithTags(module, func(m blueprint.Module, tag blueprint.DependencyTag) {
+		if tag == desiredTag && m.Name() == expected {
+			found = true
+		}
+	})
+	return found
+}
+
 // CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
 // the platform-bootclasspath module.
 func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
@@ -778,3 +793,5 @@
 		config.installDir = installDir
 	})
 }
+
+var PrepareForTestWithTransitiveClasspathEnabled = android.PrepareForTestWithBuildFlag("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH", "true")
diff --git a/python/python.go b/python/python.go
index 8726f02..01ac86c 100644
--- a/python/python.go
+++ b/python/python.go
@@ -264,10 +264,9 @@
 			variants = append(variants, pyVersion3)
 		}
 		if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
-			if !ctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
-				ctx.ModuleName() != "py2-cmd" &&
+			if ctx.ModuleName() != "py2-cmd" &&
 				ctx.ModuleName() != "py2-stdlib" {
-				ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
+				ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3.")
 			}
 			variants = append(variants, pyVersion2)
 		}
diff --git a/rust/rust.go b/rust/rust.go
index 5a973c4..240c221 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -947,6 +947,7 @@
 			sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator)
 			mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs())
 		}
+		ctx.CheckbuildFile(mod.sourceProvider.Srcs()...)
 		android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
 	}
 
@@ -957,15 +958,13 @@
 			return
 		}
 		mod.outputFile = android.OptionalPathForPath(buildOutput.outputFile)
+		ctx.CheckbuildFile(buildOutput.outputFile)
 		if buildOutput.kytheFile != nil {
 			mod.kytheFiles = append(mod.kytheFiles, buildOutput.kytheFile)
 		}
 		bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), android.OptionalPathForPath(mod.compiler.unstrippedOutputFilePath()))
 
 		mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps)
-		if mod.docTimestampFile.Valid() {
-			ctx.CheckbuildFile(mod.docTimestampFile.Path())
-		}
 
 		apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
 		if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) && !mod.ProcMacro() {
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index bb88cce..1d2fc64 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -3,7 +3,52 @@
 
 ###################################################
 # core-libart.jar & core-oj.jar
-java(\..*)?
+java\.awt\.font
+java\.beans
+java\.io
+java\.lang
+java\.lang\.annotation
+java\.lang\.constant
+java\.lang\.invoke
+java\.lang\.ref
+java\.lang\.reflect
+java\.lang\.runtime
+java\.math
+java\.net
+java\.nio
+java\.nio\.file
+java\.nio\.file\.spi
+java\.nio\.file\.attribute
+java\.nio\.channels
+java\.nio\.channels\.spi
+java\.nio\.charset
+java\.nio\.charset\.spi
+java\.security
+java\.security\.acl
+java\.security\.cert
+java\.security\.interfaces
+java\.security\.spec
+java\.sql
+java\.text
+java\.text\.spi
+java\.time
+java\.time\.chrono
+java\.time\.format
+java\.time\.temporal
+java\.time\.zone
+java\.util
+java\.util\.concurrent
+java\.util\.concurrent\.atomic
+java\.util\.concurrent\.locks
+java\.util\.function
+java\.util\.jar
+java\.util\.logging
+java\.util\.prefs
+java\.util\.random
+java\.util\.regex
+java\.util\.spi
+java\.util\.stream
+java\.util\.zip
 # TODO: Remove javax.annotation.processing if possible, see http://b/132338110:
 javax\.annotation\.processing
 javax\.crypto
@@ -27,7 +72,20 @@
 javax\.xml\.transform\.stream
 javax\.xml\.validation
 javax\.xml\.xpath
-jdk\..*
+jdk\.internal
+jdk\.internal\.access
+jdk\.internal\.event
+jdk\.internal\.math
+jdk\.internal\.misc
+jdk\.internal\.ref
+jdk\.internal\.reflect
+jdk\.internal\.util
+jdk\.internal\.util\.jar
+jdk\.internal\.util\.random
+jdk\.internal\.vm
+jdk\.internal\.vm\.annotation
+jdk\.net
+jdk\.random
 org\.w3c\.dom
 org\.w3c\.dom\.ls
 org\.w3c\.dom\.traversal
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 7ee548f..8b994eb 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -338,6 +338,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "2",
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -348,6 +349,7 @@
 				public: {enabled: true},
 				min_sdk_version: "2",
 				permitted_packages: ["myothersdklibrary"],
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -357,6 +359,7 @@
 				compile_dex: true,
 				public: {enabled: true},
 				min_sdk_version: "2",
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -624,6 +627,7 @@
 				min_sdk_version: "2",
 				permitted_packages: ["myothersdklibrary"],
 				compile_dex: true,
+				sdk_version: "current",
 			}
 		`),
 
@@ -655,6 +659,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "2",
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -877,6 +882,7 @@
 				public: {enabled: true},
 				permitted_packages: ["mysdklibrary"],
 				min_sdk_version: "current",
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -895,6 +901,7 @@
 					package_prefixes: ["newlibrary.all.mine"],
 					single_packages: ["newlibrary.mine"],
 				},
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -1080,6 +1087,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "S",
+				sdk_version: "current",
 			}
 
 			java_sdk_library {
@@ -1090,6 +1098,7 @@
 				public: {enabled: true},
 				min_sdk_version: "Tiramisu",
 				permitted_packages: ["mynewsdklibrary"],
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -1287,6 +1296,7 @@
 				shared_library: false,
 				public: {enabled: true},
 				min_sdk_version: "Tiramisu",
+				sdk_version: "current",
 			}
 			java_sdk_library {
 				name: "mynewsdklibrary",
@@ -1296,6 +1306,7 @@
 				public: {enabled: true},
 				min_sdk_version: "Tiramisu",
 				permitted_packages: ["mynewsdklibrary"],
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 5b644fd..2fb3a3f 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -211,6 +211,11 @@
 		OutputFile: s.snapshotFile,
 		DistFiles:  android.MakeDefaultDistFiles(s.snapshotFile.Path(), s.infoFile.Path()),
 		Include:    "$(BUILD_PHONY_PACKAGE)",
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.SetBool("LOCAL_DONT_CHECK_MODULE", true)
+			},
+		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
 			func(w io.Writer, name, prefix, moduleDir string) {
 				// Allow the sdk to be built by simply passing its name on the command line.
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 057b370..416dce6 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -131,11 +131,7 @@
 java_import {
     name: "myjavalib",
     prefer: false,
-    visibility: [
-        "//other/foo",
-        "//package",
-        "//prebuilts/mysdk",
-    ],
+    visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
@@ -151,11 +147,7 @@
 java_import {
     name: "mydefaultedjavalib",
     prefer: false,
-    visibility: [
-        "//other/bar",
-        "//package",
-        "//prebuilts/mysdk",
-    ],
+    visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/mydefaultedjavalib.jar"],
 }
@@ -163,10 +155,7 @@
 java_import {
     name: "myprivatejavalib",
     prefer: false,
-    visibility: [
-        "//package",
-        "//prebuilts/mysdk",
-    ],
+    visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/myprivatejavalib.jar"],
 }
@@ -185,28 +174,6 @@
 `)
 }
 
-func TestPrebuiltVisibilityProperty_AddPrivate(t *testing.T) {
-	testSdkError(t, `prebuilt_visibility: "//visibility:private" does not widen the visibility`, `
-		sdk {
-			name: "mysdk",
-			prebuilt_visibility: [
-				"//visibility:private",
-			],
-			java_header_libs: [
-				"myjavalib",
-			],
-		}
-
-		java_library {
-			name: "myjavalib",
-			// Uses package default visibility
-			srcs: ["Test.java"],
-			system_modules: "none",
-			sdk_version: "none",
-		}
-`)
-}
-
 func TestSdkInstall(t *testing.T) {
 	sdk := `
 		sdk {
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index c1c4ed6..fd6c4e7 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -80,6 +80,7 @@
 				dex_preopt: {
 					profile: "art-profile",
 				},
+				sdk_version: "current",
 			}
 		`),
 	).RunTest(t)
@@ -110,12 +111,14 @@
 			apex_available: ["myapex"],
 			srcs: ["Test.java"],
 			min_sdk_version: "33", // Tiramisu
+			sdk_version: "current",
 		}
 		java_sdk_library {
 			name: "mysdklibrary-future",
 			apex_available: ["myapex"],
 			srcs: ["Test.java"],
 			min_sdk_version: "34", // UpsideDownCake
+			sdk_version: "current",
 		}
 		sdk {
 			name: "mysdk",
@@ -199,6 +202,7 @@
 			apex_available: ["myapex"],
 			srcs: ["Test.java"],
 			min_sdk_version: "34", // UpsideDownCake
+			sdk_version: "current",
 		}
 		sdk {
 			name: "mysdk",
diff --git a/sdk/update.go b/sdk/update.go
index a4b1967..93bb861 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -563,11 +563,11 @@
 	}
 	builder.infoContents = string(output)
 	android.WriteFileRuleVerbatim(ctx, info, builder.infoContents)
-	installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
+	installedInfo := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
 	s.infoFile = android.OptionalPathForPath(installedInfo)
 
 	// Install the zip, making sure that the info file has been installed as well.
-	installedZip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
+	installedZip := ctx.InstallFileWithoutCheckbuild(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
 	s.snapshotFile = android.OptionalPathForPath(installedZip)
 }
 
@@ -1109,20 +1109,24 @@
 		// same package so can be marked as private.
 		m.AddProperty("visibility", []string{"//visibility:private"})
 	} else {
-		// Extract visibility information from a member variant. All variants have the same
-		// visibility so it doesn't matter which one is used.
-		visibilityRules := android.EffectiveVisibilityRules(s.ctx, variant)
-
-		// Add any additional visibility rules needed for the prebuilts to reference each other.
-		err := visibilityRules.Widen(s.sdk.properties.Prebuilt_visibility)
-		if err != nil {
-			s.ctx.PropertyErrorf("prebuilt_visibility", "%s", err)
-		}
-
-		visibility := visibilityRules.Strings()
-		if len(visibility) != 0 {
-			m.AddProperty("visibility", visibility)
-		}
+		// Change the visibility of the module SDK prebuilts to public.
+		// This includes
+		// 1. Stub libraries of `sdk` modules
+		// 2. Binaries and libraries of `module_exports` modules
+		//
+		// This is a workaround to improve maintainlibility of the module SDK.
+		// Since module sdks are generated from release branches and dropped to development
+		// branches, there might be a visibility skew between the sources and prebuilts
+		// of a specific module.
+		// To reconcile this potential skew, change the visibility to public.
+		//
+		// This means dependencies can bypass visibility restrictions when prebuilts are used, so we rely
+		// on source builds in CI to check them.
+		//
+		// TODO (b/361303067): This special case for category (2) can be removed if existing usages
+		// of host/test prebuilts of modules like conscrypt,tzdata,i18n are switched to source builds.
+		// It will also require ART switching to full manifests.
+		m.AddProperty("visibility", []string{"//visibility:public"})
 	}
 
 	// Where available copy apex_available properties from the member.
diff --git a/ui/build/build.go b/ui/build/build.go
index 49ac791..28c3284 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -80,7 +80,7 @@
 		if username, ok = config.environ.Get("BUILD_USERNAME"); !ok {
 			ctx.Fatalln("Missing BUILD_USERNAME")
 		}
-		buildNumber = fmt.Sprintf("eng.%.6s.00000000.000000", username)
+		buildNumber = fmt.Sprintf("eng.%.6s", username)
 		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
 	}
 	// Write the build number to a file so it can be read back in
diff --git a/ui/build/config.go b/ui/build/config.go
index 6432348..08e1957 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -41,6 +41,7 @@
 const (
 	envConfigDir = "vendor/google/tools/soong_config"
 	jsonSuffix   = "json"
+	abfsSrcDir   = "/src"
 )
 
 var (
@@ -214,6 +215,10 @@
 		sandboxConfig:         &SandboxConfig{},
 		ninjaWeightListSource: DEFAULT,
 	}
+	wd, err := os.Getwd()
+	if err != nil {
+		ctx.Fatalln("Failed to get working directory:", err)
+	}
 
 	// Skip soong tests by default on Linux
 	if runtime.GOOS == "linux" {
@@ -245,17 +250,13 @@
 
 	// Make sure OUT_DIR is set appropriately
 	if outDir, ok := ret.environ.Get("OUT_DIR"); ok {
-		ret.environ.Set("OUT_DIR", filepath.Clean(outDir))
+		ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, filepath.Clean(outDir)))
 	} else {
 		outDir := "out"
 		if baseDir, ok := ret.environ.Get("OUT_DIR_COMMON_BASE"); ok {
-			if wd, err := os.Getwd(); err != nil {
-				ctx.Fatalln("Failed to get working directory:", err)
-			} else {
-				outDir = filepath.Join(baseDir, filepath.Base(wd))
-			}
+			outDir = filepath.Join(baseDir, filepath.Base(wd))
 		}
-		ret.environ.Set("OUT_DIR", outDir)
+		ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, outDir))
 	}
 
 	// loadEnvConfig needs to know what the OUT_DIR is, so it should
@@ -361,12 +362,12 @@
 	ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1")
 
 	tmpDir := absPath(ctx, ret.TempDir())
-	ret.environ.Set("TMPDIR", tmpDir)
+	ret.environ.Set("TMPDIR", ret.sandboxPath(wd, tmpDir))
 
 	// Always set ASAN_SYMBOLIZER_PATH so that ASAN-based tools can symbolize any crashes
 	symbolizerPath := filepath.Join("prebuilts/clang/host", ret.HostPrebuiltTag(),
 		"llvm-binutils-stable/llvm-symbolizer")
-	ret.environ.Set("ASAN_SYMBOLIZER_PATH", absPath(ctx, symbolizerPath))
+	ret.environ.Set("ASAN_SYMBOLIZER_PATH", ret.sandboxPath(wd, absPath(ctx, symbolizerPath)))
 
 	// Precondition: the current directory is the top of the source tree
 	checkTopDir(ctx)
@@ -426,9 +427,9 @@
 	}
 
 	ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
-	ret.environ.Set("JAVA_HOME", absJavaHome)
-	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
-	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
+	ret.environ.Set("JAVA_HOME", ret.sandboxPath(wd, absJavaHome))
+	ret.environ.Set("ANDROID_JAVA_HOME", ret.sandboxPath(wd, javaHome))
+	ret.environ.Set("ANDROID_JAVA8_HOME", ret.sandboxPath(wd, java8Home))
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
@@ -444,7 +445,7 @@
 		ret.buildDateTime = strconv.FormatInt(time.Now().Unix(), 10)
 	}
 
-	ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
+	ret.environ.Set("BUILD_DATETIME_FILE", ret.sandboxPath(wd, buildDateTimeFile))
 
 	if _, ok := ret.environ.Get("BUILD_USERNAME"); !ok {
 		username := "unknown"
@@ -455,6 +456,7 @@
 		}
 		ret.environ.Set("BUILD_USERNAME", username)
 	}
+	ret.environ.Set("PWD", ret.sandboxPath(wd, wd))
 
 	if ret.UseRBE() {
 		for k, v := range getRBEVars(ctx, Config{ret}) {
@@ -1296,6 +1298,19 @@
 	return err == nil
 }
 
+func (c *configImpl) sandboxPath(base, in string) string {
+	if !c.UseABFS() {
+		return in
+	}
+
+	rel, err := filepath.Rel(base, in)
+	if err != nil {
+		return in
+	}
+
+	return filepath.Join(abfsSrcDir, rel)
+}
+
 func (c *configImpl) UseRBE() bool {
 	// These alternate modes of running Soong do not use RBE / reclient.
 	if c.Queryview() || c.JsonModuleGraph() {
@@ -1722,6 +1737,11 @@
 }
 
 func (c *configImpl) SkipMetricsUpload() bool {
+	// b/362625275 - Metrics upload sometimes prevents abfs unmount
+	if c.UseABFS() {
+		return true
+	}
+
 	return c.skipMetricsUpload
 }
 
diff --git a/ui/build/path.go b/ui/build/path.go
index 51ebff1..cc1d7e9 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -57,6 +57,22 @@
 	return ret
 }
 
+func updatePathForSandbox(config Config) {
+	wd, err := os.Getwd()
+	if err != nil {
+		return
+	}
+
+	var newPath []string
+	if path, ok := config.Environment().Get("PATH"); ok && path != "" {
+		entries := strings.Split(path, string(filepath.ListSeparator))
+		for _, ent := range entries {
+			newPath = append(newPath, config.sandboxPath(wd, ent))
+		}
+	}
+	config.Environment().Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
+}
+
 // SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other
 // places that does not need the full logging capabilities of path_interposer,
 // wants the minimal performance overhead, and still get the benefits of $PATH
@@ -109,18 +125,10 @@
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
-	if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
-		py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
-		if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
-			myPath = py2Path + string(os.PathListSeparator) + myPath
-		}
-	} else if value != "" {
-		ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
-	}
-
 	// Set $PATH to be the directories containing the host tool symlinks, and
 	// the prebuilts directory for the current host OS.
 	config.Environment().Set("PATH", myPath)
+	updatePathForSandbox(config)
 	config.pathReplaced = true
 }
 
@@ -253,17 +261,9 @@
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
-	if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
-		py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
-		if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
-			myPath = py2Path + string(os.PathListSeparator) + myPath
-		}
-	} else if value != "" {
-		ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
-	}
-
 	// Replace the $PATH variable with the path_interposer symlinks, and
 	// checked-in prebuilts.
 	config.Environment().Set("PATH", myPath)
+	updatePathForSandbox(config)
 	config.pathReplaced = true
 }
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index d9ca854..95b71a7 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -50,7 +50,6 @@
 
 const (
 	nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
-	abfsSrcDir = "/src"
 )
 
 var sandboxConfig struct {
@@ -148,20 +147,42 @@
 	return sandboxConfig.working
 }
 
-func (c *Cmd) srcDirArg() string {
-	if !c.config.UseABFS() {
-		return sandboxConfig.srcDir
+// Assumes input path is absolute, clean, and if applicable, an evaluated
+// symlink. If path is not a subdirectory of src dir or relative path
+// cannot be determined, return the input untouched.
+func (c *Cmd) relFromSrcDir(path string) string {
+	if !strings.HasPrefix(path, sandboxConfig.srcDir) {
+		return path
 	}
 
-	return sandboxConfig.srcDir + ":" + abfsSrcDir
+	rel, err := filepath.Rel(sandboxConfig.srcDir, path)
+	if err != nil {
+		return path
+	}
+
+	return rel
+}
+
+func (c *Cmd) dirArg(path string) string {
+	if !c.config.UseABFS() {
+		return path
+	}
+
+	rel := c.relFromSrcDir(path)
+
+	return path + ":" + filepath.Join(abfsSrcDir, rel)
+}
+
+func (c *Cmd) srcDirArg() string {
+	return c.dirArg(sandboxConfig.srcDir)
 }
 
 func (c *Cmd) outDirArg() string {
-	if !c.config.UseABFS() {
-		return sandboxConfig.outDir
-	}
+	return c.dirArg(sandboxConfig.outDir)
+}
 
-	return sandboxConfig.outDir + ":" + filepath.Join(abfsSrcDir, sandboxConfig.outDir)
+func (c *Cmd) distDirArg() string {
+	return c.dirArg(sandboxConfig.distDir)
 }
 
 // When configured to use ABFS, we need to allow the creation of the /src
@@ -187,8 +208,17 @@
 	return args
 }
 
+func (c *Cmd) workDir() string {
+	if !c.config.UseABFS() {
+		wd, _ := os.Getwd()
+		return wd
+	}
+
+	return abfsSrcDir
+}
+
 func (c *Cmd) wrapSandbox() {
-	wd, _ := os.Getwd()
+	wd := c.workDir()
 
 	var sandboxArgs []string
 	sandboxArgs = append(sandboxArgs,
@@ -226,7 +256,7 @@
 	)
 
 	sandboxArgs = append(sandboxArgs,
-		c.readMountArgs()...
+		c.readMountArgs()...,
 	)
 
 	sandboxArgs = append(sandboxArgs,
@@ -264,7 +294,7 @@
 
 	if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
 		//Mount dist dir as read-write if it already exists
-		sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
+		sandboxArgs = append(sandboxArgs, "-B", c.distDirArg())
 	}
 
 	if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a9c2cc7..b94ffa5 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -244,7 +244,6 @@
 	globfiles := bootstrap.GlobFileListFiles(bootstrap.GlobDirectory(config.SoongOutDir(), globPathName))
 
 	return bootstrap.PrimaryBuilderInvocation{
-		Inputs:      []string{"Android.bp"},
 		Implicits:   globfiles,
 		Outputs:     []string{pb.output},
 		Args:        allArgs,