Merge "Revert "Enable -Wfortify-source"" 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/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 96e8133..16a34b7 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -41,6 +41,7 @@
         "build_prop.go",
         "compliance_metadata.go",
         "config.go",
+        "container_violations.go",
         "container.go",
         "test_config.go",
         "configurable_properties.go",
@@ -58,6 +59,7 @@
         "gen_notice.go",
         "hooks.go",
         "image.go",
+        "init.go",
         "license.go",
         "license_kind.go",
         "license_metadata.go",
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index f0675dd..6bfbf37 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -136,7 +136,7 @@
 			AconfigFiles: mergedAconfigFiles,
 			ModeInfos:    mergedModeInfos,
 		})
-		ctx.Module().base().aconfigFilePaths = getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)
+		ctx.setAconfigPaths(getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles))
 	}
 }
 
diff --git a/android/androidmk.go b/android/androidmk.go
index f6f4889..fb51531 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -157,6 +157,7 @@
 }
 
 type AndroidMkEntriesContext interface {
+	OtherModuleProviderContext
 	Config() Config
 }
 
@@ -354,14 +355,15 @@
 		availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
 	}
 
+	info := OtherModuleProviderOrDefault(a.entryContext, mod, InstallFilesProvider)
 	// If the distFiles created by GenerateTaggedDistFiles contains paths for the
 	// DefaultDistTag then that takes priority so delete any existing paths.
-	if _, ok := amod.distFiles[DefaultDistTag]; ok {
+	if _, ok := info.DistFiles[DefaultDistTag]; ok {
 		delete(availableTaggedDists, DefaultDistTag)
 	}
 
 	// Finally, merge the distFiles created by GenerateTaggedDistFiles.
-	availableTaggedDists = availableTaggedDists.merge(amod.distFiles)
+	availableTaggedDists = availableTaggedDists.merge(info.DistFiles)
 
 	if len(availableTaggedDists) == 0 {
 		// Nothing dist-able for this module.
@@ -372,7 +374,7 @@
 	distContributions := &distContributions{}
 
 	if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) {
-		distContributions.licenseMetadataFile = amod.licenseMetadataFile
+		distContributions.licenseMetadataFile = info.LicenseMetadataFile
 	}
 
 	// Iterate over this module's dist structs, merged from the dist and dists properties.
@@ -552,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)...)
 	}
@@ -590,10 +600,10 @@
 		}
 
 		if !base.InVendorRamdisk() {
-			a.AddPaths("LOCAL_FULL_INIT_RC", base.initRcPaths)
+			a.AddPaths("LOCAL_FULL_INIT_RC", info.InitRcPaths)
 		}
-		if len(base.vintfFragmentsPaths) > 0 {
-			a.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", base.vintfFragmentsPaths)
+		if len(info.VintfFragmentsPaths) > 0 {
+			a.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", info.VintfFragmentsPaths)
 		}
 		a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary))
 		if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) {
@@ -910,7 +920,6 @@
 		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/androidmk_test.go b/android/androidmk_test.go
index 72b8654..c37eeab 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -46,7 +46,6 @@
 
 func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 
-	m.base().licenseMetadataFile = PathForOutput(ctx, "meta_lic")
 	var defaultDistPaths Paths
 
 	// If the dist_output_file: true then create an output file that is stored in
@@ -276,7 +275,8 @@
 		)
 	}
 	for idx, line := range androidMkLines {
-		expectedLine := strings.ReplaceAll(expectedAndroidMkLines[idx], "meta_lic", module.base().licenseMetadataFile.String())
+		expectedLine := strings.ReplaceAll(expectedAndroidMkLines[idx], "meta_lic",
+			OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).LicenseMetadataFile.String())
 		if line != expectedLine {
 			t.Errorf(
 				"Expected AndroidMk line to be '%s', got '%s'",
diff --git a/android/apex.go b/android/apex.go
index 028be57..29b2a9f 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"slices"
 	"sort"
 	"strconv"
@@ -145,6 +146,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 {
@@ -475,13 +487,6 @@
 	AvailableToAnyApex  = "//apex_available:anyapex"
 )
 
-var (
-	AvailableToRecognziedWildcards = []string{
-		AvailableToPlatform,
-		AvailableToAnyApex,
-	}
-)
-
 // CheckAvailableForApex provides the default algorithm for checking the apex availability. When the
 // availability is empty, it defaults to ["//apex_available:platform"] which means "available to the
 // platform but not available to any APEX". When the list is not empty, `what` is matched against
@@ -707,7 +712,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/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/build_prop.go b/android/build_prop.go
index 13d59f9..ede93ed 100644
--- a/android/build_prop.go
+++ b/android/build_prop.go
@@ -63,6 +63,8 @@
 		return ctx.Config().SystemExtPropFiles(ctx)
 	} else if partition == "product" {
 		return ctx.Config().ProductPropFiles(ctx)
+	} else if partition == "odm" {
+		return ctx.Config().OdmPropFiles(ctx)
 	}
 	return nil
 }
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index 4c92f71..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))
@@ -189,8 +212,8 @@
 		installed = append(installed, ctx.installFiles...)
 		installed = append(installed, ctx.katiInstalls.InstallPaths()...)
 		installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
-		installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
-		installed = append(installed, m.katiVintfInstalls.InstallPaths()...)
+		installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...)
+		installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...)
 		complianceMetadataInfo.SetListValue(ComplianceMetadataProp.INSTALLED_FILES, FirstUniqueStrings(installed.Strings()))
 	}
 	ctx.setProvider(ComplianceMetadataProvider, complianceMetadataInfo)
diff --git a/android/config.go b/android/config.go
index d6d76a4..cf3499f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -173,6 +173,13 @@
 	return c.IsEnvTrue("DISABLE_VERIFY_OVERLAPS") || c.ReleaseDisableVerifyOverlaps() || !c.ReleaseDefaultModuleBuildFromSource()
 }
 
+func (c Config) CoverageSuffix() string {
+	if v := c.IsEnvTrue("EMMA_INSTRUMENT"); v {
+		return "coverage."
+	}
+	return ""
+}
+
 // MaxPageSizeSupported returns the max page size supported by the device. This
 // value will define the ELF segment alignment for binaries (executables and
 // shared libraries).
@@ -1483,11 +1490,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
 		}
@@ -2050,22 +2052,10 @@
 	return PathsForSource(ctx, c.productVariables.ProductPropFiles)
 }
 
+func (c *config) OdmPropFiles(ctx PathContext) Paths {
+	return PathsForSource(ctx, c.productVariables.OdmPropFiles)
+}
+
 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 10aff4d..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"
 )
@@ -89,10 +91,18 @@
 	"framework-annotations-lib",
 	"unsupportedappusage",
 
+	// TODO(b/363016634): Remove from the allowlist when the module is converted
+	// to java_sdk_library and the java_aconfig_library modules depend on the stub.
+	"aconfig_storage_reader_java",
+
 	// framework-res provides core resources essential for building apps and system UI.
 	// This module is implicitly added as a dependency for java modules even when the
 	// dependency specifies sdk_version.
 	"framework-res",
+
+	// jacocoagent is implicitly added as a dependency in coverage builds, and is not installed
+	// on the device.
+	"jacocoagent",
 }
 
 // Returns true when the dependency is globally allowlisted for inter-container dependency
@@ -219,7 +229,6 @@
 // ----------------------------------------------------------------------------
 
 type InstallableModule interface {
-	ContainersInfo() ContainersInfo
 	StaticDependencyTags() []blueprint.DependencyTag
 	DynamicDependencyTags() []blueprint.DependencyTag
 }
@@ -391,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
 
@@ -413,7 +456,7 @@
 
 func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
 	if ctx.Module() == module {
-		return module.ContainersInfo(), true
+		return ctx.getContainersInfo(), true
 	}
 
 	return OtherModuleProvider(ctx, module, ContainersInfoProvider)
@@ -428,7 +471,36 @@
 
 	if _, ok := ctx.Module().(InstallableModule); ok {
 		containersInfo := generateContainerInfo(ctx)
-		ctx.Module().base().containersInfo = containersInfo
+		ctx.setContainersInfo(containersInfo)
 		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
new file mode 100644
index 0000000..e67533d
--- /dev/null
+++ b/android/container_violations.go
@@ -0,0 +1,1042 @@
+// 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
+
+var ContainerDependencyViolationAllowlist = map[string][]string{
+	"android.car-module.impl": {
+		"modules-utils-preconditions", // apex [com.android.car.framework] -> 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]
+	},
+
+	"AppInstalledOnMultipleUsers": {
+		"framework", // cts -> unstable
+	},
+
+	"art-aconfig-flags-java-lib": {
+		"framework-api-annotations-lib", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> system
+	},
+
+	"Bluetooth": {
+		"app-compat-annotations",         // apex [com.android.btservices] -> system
+		"framework-bluetooth-pre-jarjar", // apex [com.android.btservices] -> system
+	},
+
+	"bluetooth-nano-protos": {
+		"libprotobuf-java-nano", // apex [com.android.btservices] -> apex [com.android.wifi, test_com.android.wifi]
+	},
+
+	"bluetooth.change-ids": {
+		"app-compat-annotations", // apex [com.android.btservices] -> system
+	},
+
+	"CarServiceUpdatable": {
+		"modules-utils-os",                    // apex [com.android.car.framework] -> apex [com.android.permission, test_com.android.permission]
+		"modules-utils-preconditions",         // apex [com.android.car.framework] -> 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]
+		"modules-utils-shell-command-handler", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.art, com.android.art.debug, com.android.art.testing, com.android.btservices, com.android.configinfrastructure, com.android.mediaprovider, com.android.nfcservices, com.android.permission, com.android.scheduling, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.mediaprovider, test_com.android.permission, test_com.android.wifi, test_imgdiag_com.android.art, test_jitzygote_com.android.art]
+	},
+
+	"connectivity-net-module-utils-bpf": {
+		"net-utils-device-common-struct-base", // apex [com.android.tethering] -> system
+	},
+
+	"conscrypt-aconfig-flags-lib": {
+		"aconfig-annotations-lib-sdk-none", // apex [com.android.conscrypt, test_com.android.conscrypt] -> system
+	},
+
+	"cronet_aml_base_base_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+		"jsr305", // apex [com.android.tethering] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+	},
+
+	"cronet_aml_build_android_build_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_base_feature_overrides_java_proto": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_cronet_api_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_cronet_impl_common_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_cronet_impl_native_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+		"jsr305", // apex [com.android.tethering] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+	},
+
+	"cronet_aml_components_cronet_android_cronet_jni_registration_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_cronet_shared_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_cronet_stats_log_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_cronet_urlconnection_impl_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_flags_java_proto": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_components_cronet_android_request_context_config_java_proto": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_net_android_net_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+		"jsr305", // apex [com.android.tethering] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+	},
+
+	"cronet_aml_net_android_net_thread_stats_uid_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_third_party_jni_zero_jni_zero_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"cronet_aml_url_url_java": {
+		"framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system
+	},
+
+	"CtsAdservicesHostTestApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAdServicesNotInAllowListEndToEndTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAdServicesPermissionsAppOptOutEndToEndTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAdServicesPermissionsNoPermEndToEndTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAdServicesPermissionsValidEndToEndTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAlarmManagerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAndroidAppTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAppExitTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAppFgsStartTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAppFgsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAppOpsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAppSearchTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAppTestStubsApp2": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsAudioHostTestApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsBackgroundActivityAppAllowCrossUidFlagDefault": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsBatterySavingTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsBluetoothTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsBootDisplayModeApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsBroadcastTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsBRSTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCompanionDeviceManagerCoreTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCompanionDeviceManagerMultiProcessTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCompanionDeviceManagerUiAutomationTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsContentSuggestionsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsContentTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCredentialManagerBackupRestoreApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCrossProfileEnabledApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCrossProfileEnabledNoPermsApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCrossProfileNotEnabledApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsCrossProfileUserEnabledApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDeviceAndProfileOwnerApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDeviceAndProfileOwnerApp23": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDeviceAndProfileOwnerApp25": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDeviceAndProfileOwnerApp30": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDeviceLockTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDeviceOwnerApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDevicePolicySimTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDevicePolicyTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDreamsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsDrmTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsEphemeralTestsEphemeralApp1": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsFgsBootCompletedTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsFgsBootCompletedTestCasesApi35": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsFgsStartTestHelperApi34": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsFgsStartTestHelperCurrent": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsFileDescriptorTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsHostsideCompatChangeTestsApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsHostsideNetworkPolicyTestsApp2": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsIdentityTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsIkeTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsInstalledLoadingProgressDeviceTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsInstantAppTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsIntentSenderApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsJobSchedulerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsKeystoreTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsLegacyNotification27TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsLibcoreTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsLibcoreWycheproofConscryptTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsListeningPortsTest": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsLocationCoarseTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsLocationFineTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsLocationNoneTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsLocationPrivilegedTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsManagedProfileApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaAudioTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaBetterTogetherTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaCodecTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaDecoderTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaDrmFrameworkTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaEncoderTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaExtractorTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaMiscTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaMuxerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaPerformanceClassTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaPlayerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaProjectionSDK33TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaProjectionSDK34TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaProjectionTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaProviderTranscodeTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaRecorderTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaRouterHostSideTestBluetoothPermissionsApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaRouterHostSideTestMediaRoutingControlApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaRouterHostSideTestModifyAudioRoutingApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMediaV2TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMimeMapTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsModifyQuietModeEnabledApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsMusicRecognitionTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNativeMediaAAudioTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNetTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNetTestCasesLegacyApi22": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNetTestCasesMaxTargetSdk30": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNetTestCasesMaxTargetSdk31": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNetTestCasesMaxTargetSdk33": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNetTestCasesUpdateStatsPermission": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsNfcTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsOnDevicePersonalizationTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsPackageInstallerApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsPackageManagerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsPackageSchemeTestsWithoutVisibility": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsPackageSchemeTestsWithVisibility": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsPermissionsSyncTestApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsPreservedSettingsApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsProtoTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsProviderTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsProxyMediaRouterTestHelperApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsRebootReadinessTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsResourcesLoaderTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsResourcesTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSandboxedAdIdManagerTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSandboxedAppSetIdManagerTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSandboxedFledgeManagerTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSandboxedMeasurementManagerTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSandboxedTopicsManagerTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSdkExtensionsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSdkSandboxInprocessTests": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSecureElementTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSecurityTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSelinuxEphemeralTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSelinuxTargetSdk25TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSelinuxTargetSdk27TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSelinuxTargetSdk28TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSelinuxTargetSdk29TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSelinuxTargetSdk30TestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSelinuxTargetSdkCurrentTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSettingsDeviceOwnerApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSharedUserMigrationTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsShortFgsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSimRestrictedApisTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSliceTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSpeechTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsStatsSecurityApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSuspendAppsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsSystemUiTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsTareTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsTelephonyTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsTetheringTest": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsThreadNetworkTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsUsageStatsTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsUsbManagerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsUserRestrictionTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsUtilTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsUwbTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVcnTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVideoCodecTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVideoTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsViewReceiveContentTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVirtualDevicesAppLaunchTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVirtualDevicesAudioTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVirtualDevicesCameraTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVirtualDevicesSensorTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsVirtualDevicesTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWearableSensingServiceTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWebViewCompatChangeApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWidgetTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWidgetTestCases29": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWifiNonUpdatableTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWifiTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWindowManagerExternalApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsWindowManagerTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"CtsZipValidateApp": {
+		"framework", // cts -> unstable
+	},
+
+	"CVE-2021-0965": {
+		"framework", // cts -> unstable
+	},
+
+	"device_config_reboot_flags_java_lib": {
+		"ext",       // apex [com.android.configinfrastructure] -> system
+		"framework", // apex [com.android.configinfrastructure] -> system
+	},
+
+	"devicelockcontroller-lib": {
+		"modules-utils-expresslog", // apex [com.android.devicelock] -> apex [com.android.btservices, com.android.car.framework]
+	},
+
+	"FederatedCompute": {
+		"auto_value_annotations", // apex [com.android.ondevicepersonalization] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"framework-adservices.impl": {
+		"adservices_flags_lib", // apex [com.android.adservices, com.android.extservices] -> system
+	},
+
+	"framework-bluetooth.impl": {
+		"app-compat-annotations", // apex [com.android.btservices] -> system
+	},
+
+	"framework-connectivity-t.impl": {
+		"app-compat-annotations",            // apex [com.android.tethering] -> system
+		"framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+	},
+
+	"framework-connectivity.impl": {
+		"app-compat-annotations", // apex [com.android.tethering] -> system
+	},
+
+	"framework-ondevicepersonalization.impl": {
+		"ondevicepersonalization_flags_lib", // apex [com.android.ondevicepersonalization] -> system
+	},
+
+	"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]
+	},
+
+	"framework-permission-s.impl": {
+		"app-compat-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"framework-wifi.impl": {
+		"aconfig_storage_reader_java", // apex [com.android.wifi, test_com.android.wifi] -> system
+		"app-compat-annotations",      // apex [com.android.wifi, test_com.android.wifi] -> system
+	},
+
+	"grpc-java-core-internal": {
+		"gson",             // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> apex [com.android.virt]
+		"perfmark-api-lib", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> system
+	},
+
+	"httpclient_impl": {
+		"httpclient_api", // apex [com.android.tethering] -> system
+	},
+
+	"IncrementalTestAppValidator": {
+		"framework", // cts -> unstable
+	},
+
+	"libcore-aconfig-flags-lib": {
+		"framework-api-annotations-lib", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> system
+	},
+
+	"loadlibrarytest_product_app": {
+		"libnativeloader_vendor_shared_lib", // product -> vendor
+	},
+
+	"loadlibrarytest_testlib": {
+		"libnativeloader_vendor_shared_lib", // system -> vendor
+	},
+
+	"MctsMediaDrmFrameworkTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MctsMediaTranscodingTestCases": {
+		"framework", // cts -> unstable
+	},
+
+	"MediaProvider": {
+		"app-compat-annotations", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+	},
+
+	"mediaprovider_flags_java_lib": {
+		"ext",       // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+		"framework", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system
+	},
+
+	"MockSatelliteGatewayServiceApp": {
+		"framework", // cts -> unstable
+	},
+
+	"MockSatelliteServiceApp": {
+		"framework", // cts -> unstable
+	},
+
+	"net-utils-device-common-netlink": {
+		"net-utils-device-common-struct-base", // apex [com.android.tethering] -> system
+	},
+
+	"net-utils-device-common-struct": {
+		"net-utils-device-common-struct-base", // apex [com.android.tethering] -> system
+	},
+
+	"NfcNciApex": {
+		"android.permission.flags-aconfig-java", // apex [com.android.nfcservices] -> apex [com.android.permission, test_com.android.permission]
+	},
+
+	"okhttp-norepackage": {
+		"okhttp-android-util-log", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> system
+	},
+
+	"ondevicepersonalization-plugin-lib": {
+		"auto_value_annotations", // apex [com.android.ondevicepersonalization] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"opencensus-java-api": {
+		"auto_value_annotations", // apex [com.android.devicelock] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"PermissionController-lib": {
+		"safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"PlatformProperties": {
+		"sysprop-library-stub-platform", // apex [com.android.btservices, com.android.nfcservices, com.android.tethering, com.android.virt, com.android.wifi, test_com.android.wifi] -> system
+	},
+
+	"safety-center-config": {
+		"safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"safety-center-internal-data": {
+		"safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"safety-center-pending-intents": {
+		"safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"safety-center-persistence": {
+		"safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"safety-center-resources-lib": {
+		"safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"SdkSandboxManagerDisabledTests": {
+		"framework", // cts -> unstable
+	},
+
+	"SdkSandboxManagerTests": {
+		"framework", // cts -> unstable
+	},
+
+	"service-art.impl": {
+		"auto_value_annotations", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"service-bluetooth-pre-jarjar": {
+		"framework-bluetooth-pre-jarjar", // apex [com.android.btservices] -> system
+		"service-bluetooth.change-ids",   // apex [com.android.btservices] -> system
+	},
+
+	"service-connectivity": {
+		"libprotobuf-java-nano", // apex [com.android.tethering] -> apex [com.android.wifi, test_com.android.wifi]
+	},
+
+	"service-connectivity-pre-jarjar": {
+		"framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+	},
+
+	"service-connectivity-protos": {
+		"libprotobuf-java-nano", // apex [com.android.tethering] -> apex [com.android.wifi, test_com.android.wifi]
+	},
+
+	"service-connectivity-tiramisu-pre-jarjar": {
+		"framework-connectivity-pre-jarjar",   // apex [com.android.tethering] -> system
+		"framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system
+	},
+
+	"service-entitlement": {
+		"auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"service-entitlement-api": {
+		"auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"service-entitlement-data": {
+		"auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"service-entitlement-impl": {
+		"auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"service-healthfitness.impl": {
+		"modules-utils-preconditions", // apex [com.android.healthfitness] -> 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]
+	},
+
+	"service-networksecurity-pre-jarjar": {
+		"framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system
+	},
+
+	"service-permission.impl": {
+		"jsr305",                    // apex [com.android.permission, test_com.android.permission] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+		"safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system
+	},
+
+	"service-remoteauth-pre-jarjar": {
+		"framework-connectivity-pre-jarjar",   // apex [com.android.tethering] -> system
+		"framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system
+	},
+
+	"service-thread-pre-jarjar": {
+		"framework-connectivity-pre-jarjar",   // apex [com.android.tethering] -> system
+		"framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system
+	},
+
+	"service-uwb-pre-jarjar": {
+		"framework-uwb-pre-jarjar", // apex [com.android.uwb] -> system
+	},
+
+	"service-wifi": {
+		"auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+	},
+
+	"TelephonyDeviceTest": {
+		"framework", // cts -> unstable
+	},
+
+	"tensorflowlite_java": {
+		"android-support-annotations", // apex [com.android.adservices, com.android.extservices, com.android.ondevicepersonalization] -> system
+	},
+
+	"TestExternalImsServiceApp": {
+		"framework", // cts -> unstable
+	},
+
+	"TestSmsRetrieverApp": {
+		"framework", // cts -> unstable
+	},
+
+	"TetheringApiCurrentLib": {
+		"connectivity-internal-api-util", // apex [com.android.tethering] -> system
+	},
+
+	"TetheringNext": {
+		"connectivity-internal-api-util", // apex [com.android.tethering] -> system
+	},
+
+	"tetheringstatsprotos": {
+		"ext",       // apex [com.android.tethering] -> system
+		"framework", // apex [com.android.tethering] -> system
+	},
+
+	"uwb_aconfig_flags_lib": {
+		"ext",       // apex [com.android.uwb] -> system
+		"framework", // apex [com.android.uwb] -> system
+	},
+
+	"uwb_androidx_backend": {
+		"android-support-annotations", // apex [com.android.tethering] -> system
+	},
+
+	"wifi-service-pre-jarjar": {
+		"app-compat-annotations",    // apex [com.android.wifi, test_com.android.wifi] -> system
+		"auto_value_annotations",    // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus]
+		"framework-wifi-pre-jarjar", // apex [com.android.wifi, test_com.android.wifi] -> system
+		"jsr305",                    // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider]
+	},
+}
diff --git a/android/defaults.go b/android/defaults.go
index c0a2fc6..0d51d9d 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -28,7 +28,7 @@
 var DefaultsDepTag defaultsDependencyTag
 
 type defaultsProperties struct {
-	Defaults proptools.Configurable[[]string]
+	Defaults []string
 }
 
 type DefaultableModuleBase struct {
@@ -278,13 +278,13 @@
 
 func defaultsDepsMutator(ctx BottomUpMutatorContext) {
 	if defaultable, ok := ctx.Module().(Defaultable); ok {
-		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults.GetOrDefault(ctx, nil)...)
+		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
 	}
 }
 
 func defaultsMutator(ctx TopDownMutatorContext) {
 	if defaultable, ok := ctx.Module().(Defaultable); ok {
-		defaults := defaultable.defaults().Defaults.GetOrDefault(ctx, nil)
+		defaults := defaultable.defaults().Defaults
 		if len(defaults) > 0 {
 			var defaultsList []Defaults
 			seen := make(map[Defaults]bool)
@@ -295,7 +295,7 @@
 						if !seen[defaults] {
 							seen[defaults] = true
 							defaultsList = append(defaultsList, defaults)
-							return len(defaults.defaults().Defaults.GetOrDefault(ctx, nil)) > 0
+							return len(defaults.defaults().Defaults) > 0
 						}
 					} else {
 						ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
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/license_metadata.go b/android/license_metadata.go
index cd69749..0ac975f 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -152,7 +152,7 @@
 
 	// Install map
 	args = append(args,
-		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(ctx.licenseInstallMap), "-m "))
 
 	// Built files
 	if len(outputFiles) > 0 {
diff --git a/android/makevars.go b/android/makevars.go
index 810eb38..8305d8e 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -281,8 +281,8 @@
 		if m.ExportedToMake() {
 			info := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider)
 			katiInstalls = append(katiInstalls, info.KatiInstalls...)
-			katiInitRcInstalls = append(katiInitRcInstalls, m.base().katiInitRcInstalls...)
-			katiVintfManifestInstalls = append(katiVintfManifestInstalls, m.base().katiVintfInstalls...)
+			katiInitRcInstalls = append(katiInitRcInstalls, info.KatiInitRcInstalls...)
+			katiVintfManifestInstalls = append(katiVintfManifestInstalls, info.KatiVintfInstalls...)
 			katiSymlinks = append(katiSymlinks, info.KatiSymlinks...)
 		}
 	})
diff --git a/android/module.go b/android/module.go
index e74af83..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"
@@ -87,8 +90,6 @@
 	ReplacedByPrebuilt()
 	IsReplacedByPrebuilt() bool
 	ExportedToMake() bool
-	InitRc() Paths
-	VintfFragments() Paths
 	EffectiveLicenseKinds() []string
 	EffectiveLicenseFiles() Paths
 
@@ -113,14 +114,7 @@
 	TargetRequiredModuleNames() []string
 	VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string
 
-	// TransitivePackagingSpecs returns the PackagingSpecs for this module and any transitive
-	// dependencies with dependency tags for which IsInstallDepNeeded() returns true.
-	TransitivePackagingSpecs() []PackagingSpec
-
 	ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator
-
-	// Get the information about the containers this module belongs to.
-	ContainersInfo() ContainersInfo
 }
 
 // Qualified id for a module
@@ -501,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 {
@@ -835,16 +833,7 @@
 	// The primary licenses property, may be nil, records license metadata for the module.
 	primaryLicensesProperty applicableLicensesProperty
 
-	noAddressSanitizer   bool
-	installFilesDepSet   *DepSet[InstallPath]
-	packagingSpecsDepSet *DepSet[PackagingSpec]
-	// katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
-	// allowed to have duplicates across modules and variants.
-	katiInitRcInstalls katiInstalls
-	katiVintfInstalls  katiInstalls
-
-	// The files to copy to the dist as explicitly specified in the .bp file.
-	distFiles TaggedDistFiles
+	noAddressSanitizer bool
 
 	hooks hooks
 
@@ -854,34 +843,6 @@
 	buildParams []BuildParams
 	ruleParams  map[blueprint.Rule]blueprint.RuleParams
 	variables   map[string]string
-
-	initRcPaths         Paths
-	vintfFragmentsPaths Paths
-
-	installedInitRcPaths         InstallPaths
-	installedVintfFragmentsPaths InstallPaths
-
-	// Merged Aconfig files for all transitive deps.
-	aconfigFilePaths Paths
-
-	// set of dependency module:location mappings used to populate the license metadata for
-	// apex containers.
-	licenseInstallMap []string
-
-	// The path to the generated license metadata file for the module.
-	licenseMetadataFile WritablePath
-
-	// moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will
-	// be included in the final module-info.json produced by Make.
-	moduleInfoJSON *ModuleInfoJSON
-
-	// complianceMetadataInfo is for different module types to dump metadata.
-	// See android.ModuleContext interface.
-	complianceMetadataInfo *ComplianceMetadataInfo
-
-	// containersInfo stores the information about the containers and the information of the
-	// apexes the module belongs to.
-	containersInfo ContainersInfo
 }
 
 func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1454,12 +1415,13 @@
 		if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
 			// Installation is still handled by Make, so anything hidden from Make is not
 			// installable.
+			info := OtherModuleProviderOrDefault(ctx, dep, InstallFilesProvider)
 			if !dep.IsHideFromMake() && !dep.IsSkipInstall() {
-				installDeps = append(installDeps, dep.base().installFilesDepSet)
+				installDeps = append(installDeps, info.TransitiveInstallFiles)
 			}
 			// Add packaging deps even when the dependency is not installed so that uninstallable
 			// modules can still be packaged.  Often the package will be installed instead.
-			packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
+			packagingSpecs = append(packagingSpecs, info.TransitivePackagingSpecs)
 		}
 	})
 
@@ -1477,10 +1439,6 @@
 	return IsInstallDepNeededTag(tag)
 }
 
-func (m *ModuleBase) TransitivePackagingSpecs() []PackagingSpec {
-	return m.packagingSpecsDepSet.ToList()
-}
-
 func (m *ModuleBase) NoAddressSanitizer() bool {
 	return m.noAddressSanitizer
 }
@@ -1594,44 +1552,43 @@
 	return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil)
 }
 
-func (m *ModuleBase) InitRc() Paths {
-	return append(Paths{}, m.initRcPaths...)
-}
+func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) {
+	namespacePrefix := ctx.Namespace().id
+	if namespacePrefix != "" {
+		namespacePrefix = namespacePrefix + "-"
+	}
 
-func (m *ModuleBase) VintfFragments() Paths {
-	return append(Paths{}, m.vintfFragmentsPaths...)
-}
+	if !ctx.uncheckedModule {
+		name := namespacePrefix + ctx.ModuleName() + "-" + ctx.ModuleSubDir() + "-checkbuild"
+		ctx.Phony(name, ctx.checkbuildFiles...)
+		ctx.checkbuildTarget = PathForPhony(ctx, name)
+	}
 
-func (m *ModuleBase) CompileMultilib() *string {
-	return m.base().commonProperties.Compile_multilib
-}
-
-// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
-// apex container for use when generation the license metadata file.
-func (m *ModuleBase) SetLicenseInstallMap(installMap []string) {
-	m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
 }
 
 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)
 		}
 	})
 
@@ -1652,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 {
@@ -1773,17 +1729,36 @@
 }
 
 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
-	KatiSymlinks katiInstalls
-	TestData     []DataPath
+	KatiInstalls             katiInstalls
+	KatiSymlinks             katiInstalls
+	TestData                 []DataPath
+	TransitivePackagingSpecs *DepSet[PackagingSpec]
+	LicenseMetadataFile      WritablePath
+
+	// The following fields are private before, make it private again once we have
+	// better solution.
+	TransitiveInstallFiles *DepSet[InstallPath]
+	// katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
+	// allowed to have duplicates across modules and variants.
+	KatiInitRcInstalls           katiInstalls
+	KatiVintfInstalls            katiInstalls
+	InitRcPaths                  Paths
+	VintfFragmentsPaths          Paths
+	InstalledInitRcPaths         InstallPaths
+	InstalledVintfFragmentsPaths InstallPaths
+
+	// The files to copy to the dist as explicitly specified in the .bp file.
+	DistFiles TaggedDistFiles
 }
 
-var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]()
+var InstallFilesProvider = blueprint.NewProvider[InstallFilesInfo]()
 
 type FinalModuleBuildTargetsInfo struct {
 	// Used by buildTargetSingleton to create checkbuild and per-directory build targets
@@ -1793,7 +1768,7 @@
 	BlueprintDir     string
 }
 
-var InstallFilesProvider = blueprint.NewProvider[InstallFilesInfo]()
+var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]()
 
 func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
 	ctx := &moduleContext{
@@ -1805,14 +1780,17 @@
 	}
 
 	setContainerInfo(ctx)
+	if ctx.Config().Getenv("DISABLE_CONTAINER_CHECK") != "true" {
+		checkContainerViolations(ctx)
+	}
 
-	m.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
+	ctx.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
 
 	dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx)
-	// set m.installFilesDepSet to only the transitive dependencies to be used as the dependencies
+	// set the TransitiveInstallFiles to only the transitive dependencies to be used as the dependencies
 	// of installed files of this module.  It will be replaced by a depset including the installed
 	// files of this module at the end for use by modules that depend on this one.
-	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, nil, dependencyInstallFiles)
+	ctx.TransitiveInstallFiles = NewDepSet[InstallPath](TOPOLOGICAL, nil, dependencyInstallFiles)
 
 	// Temporarily continue to call blueprintCtx.GetMissingDependencies() to maintain the previous behavior of never
 	// reporting missing dependency errors in Blueprint when AllowMissingDependencies == true.
@@ -1856,6 +1834,8 @@
 		checkDistProperties(ctx, fmt.Sprintf("dists[%d]", i), &m.distProperties.Dists[i])
 	}
 
+	var installFiles InstallFilesInfo
+
 	if m.Enabled(ctx) {
 		// ensure all direct android.Module deps are enabled
 		ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
@@ -1873,30 +1853,36 @@
 			// so only a single rule is created for each init.rc or vintf fragment file.
 
 			if !m.InVendorRamdisk() {
-				m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+				ctx.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
 				rcDir := PathForModuleInstall(ctx, "etc", "init")
-				for _, src := range m.initRcPaths {
+				for _, src := range ctx.initRcPaths {
 					installedInitRc := rcDir.Join(ctx, src.Base())
-					m.katiInitRcInstalls = append(m.katiInitRcInstalls, katiInstall{
+					ctx.katiInitRcInstalls = append(ctx.katiInitRcInstalls, katiInstall{
 						from: src,
 						to:   installedInitRc,
 					})
 					ctx.PackageFile(rcDir, src.Base(), src)
-					m.installedInitRcPaths = append(m.installedInitRcPaths, installedInitRc)
+					ctx.installedInitRcPaths = append(ctx.installedInitRcPaths, installedInitRc)
 				}
+				installFiles.InitRcPaths = ctx.initRcPaths
+				installFiles.KatiInitRcInstalls = ctx.katiInitRcInstalls
+				installFiles.InstalledInitRcPaths = ctx.installedInitRcPaths
 			}
 
-			m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil))
+			ctx.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil))
 			vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
-			for _, src := range m.vintfFragmentsPaths {
+			for _, src := range ctx.vintfFragmentsPaths {
 				installedVintfFragment := vintfDir.Join(ctx, src.Base())
-				m.katiVintfInstalls = append(m.katiVintfInstalls, katiInstall{
+				ctx.katiVintfInstalls = append(ctx.katiVintfInstalls, katiInstall{
 					from: src,
 					to:   installedVintfFragment,
 				})
 				ctx.PackageFile(vintfDir, src.Base(), src)
-				m.installedVintfFragmentsPaths = append(m.installedVintfFragmentsPaths, installedVintfFragment)
+				ctx.installedVintfFragmentsPaths = append(ctx.installedVintfFragmentsPaths, installedVintfFragment)
 			}
+			installFiles.VintfFragmentsPaths = ctx.vintfFragmentsPaths
+			installFiles.KatiVintfInstalls = ctx.katiVintfInstalls
+			installFiles.InstalledVintfFragmentsPaths = ctx.installedVintfFragmentsPaths
 		}
 
 		licensesPropertyFlattener(ctx)
@@ -1918,73 +1904,38 @@
 			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 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
 		// as GenerateTaggedDistFiles() calls OutputFiles(tag) and so relies on the
 		// output paths being set which must be done before or during
 		// GenerateAndroidBuildActions.
-		m.distFiles = m.GenerateTaggedDistFiles(ctx)
+		installFiles.DistFiles = m.GenerateTaggedDistFiles(ctx)
 		if ctx.Failed() {
 			return
 		}
 
-		SetProvider(ctx, InstallFilesProvider, InstallFilesInfo{
-			InstallFiles:    ctx.installFiles,
-			CheckbuildFiles: ctx.checkbuildFiles,
-			PackagingSpecs:  ctx.packagingSpecs,
-			KatiInstalls:    ctx.katiInstalls,
-			KatiSymlinks:    ctx.katiSymlinks,
-			TestData:        ctx.testData,
-		})
+		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
+		installFiles.TestData = ctx.testData
 	} else if ctx.Config().AllowMissingDependencies() {
 		// If the module is not enabled it will not create any build rules, nothing will call
 		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -2000,17 +1951,19 @@
 		}
 	}
 
-	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles)
-	m.packagingSpecsDepSet = NewDepSet[PackagingSpec](TOPOLOGICAL, ctx.packagingSpecs, dependencyPackagingSpecs)
+	ctx.TransitiveInstallFiles = NewDepSet[InstallPath](TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles)
+	installFiles.TransitiveInstallFiles = ctx.TransitiveInstallFiles
+	installFiles.TransitivePackagingSpecs = NewDepSet[PackagingSpec](TOPOLOGICAL, ctx.packagingSpecs, dependencyPackagingSpecs)
 
-	buildLicenseMetadata(ctx, m.licenseMetadataFile)
+	SetProvider(ctx, InstallFilesProvider, installFiles)
+	buildLicenseMetadata(ctx, ctx.licenseMetadataFile)
 
-	if m.moduleInfoJSON != nil {
+	if ctx.moduleInfoJSON != nil {
 		var installed InstallPaths
 		installed = append(installed, ctx.katiInstalls.InstallPaths()...)
 		installed = append(installed, ctx.katiSymlinks.InstallPaths()...)
-		installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
-		installed = append(installed, m.katiVintfInstalls.InstallPaths()...)
+		installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...)
+		installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...)
 		installedStrings := installed.Strings()
 
 		var targetRequired, hostRequired []string
@@ -2025,28 +1978,28 @@
 			data = append(data, d.ToRelativeInstallPath())
 		}
 
-		if m.moduleInfoJSON.Uninstallable {
+		if ctx.moduleInfoJSON.Uninstallable {
 			installedStrings = nil
-			if len(m.moduleInfoJSON.CompatibilitySuites) == 1 && m.moduleInfoJSON.CompatibilitySuites[0] == "null-suite" {
-				m.moduleInfoJSON.CompatibilitySuites = nil
-				m.moduleInfoJSON.TestConfig = nil
-				m.moduleInfoJSON.AutoTestConfig = nil
+			if len(ctx.moduleInfoJSON.CompatibilitySuites) == 1 && ctx.moduleInfoJSON.CompatibilitySuites[0] == "null-suite" {
+				ctx.moduleInfoJSON.CompatibilitySuites = nil
+				ctx.moduleInfoJSON.TestConfig = nil
+				ctx.moduleInfoJSON.AutoTestConfig = nil
 				data = nil
 			}
 		}
 
-		m.moduleInfoJSON.core = CoreModuleInfoJSON{
-			RegisterName:       m.moduleInfoRegisterName(ctx, m.moduleInfoJSON.SubName),
+		ctx.moduleInfoJSON.core = CoreModuleInfoJSON{
+			RegisterName:       m.moduleInfoRegisterName(ctx, ctx.moduleInfoJSON.SubName),
 			Path:               []string{ctx.ModuleDir()},
 			Installed:          installedStrings,
-			ModuleName:         m.BaseModuleName() + m.moduleInfoJSON.SubName,
+			ModuleName:         m.BaseModuleName() + ctx.moduleInfoJSON.SubName,
 			SupportedVariants:  []string{m.moduleInfoVariant(ctx)},
 			TargetDependencies: targetRequired,
 			HostDependencies:   hostRequired,
 			Data:               data,
-			Required:           m.RequiredModuleNames(ctx),
+			Required:           append(m.RequiredModuleNames(ctx), m.VintfFragmentModuleNames(ctx)...),
 		}
-		SetProvider(ctx, ModuleInfoJSONProvider, m.moduleInfoJSON)
+		SetProvider(ctx, ModuleInfoJSONProvider, ctx.moduleInfoJSON)
 	}
 
 	m.buildParams = ctx.buildParams
@@ -2109,10 +2062,6 @@
 	return variant
 }
 
-func (m *ModuleBase) ContainersInfo() ContainersInfo {
-	return m.containersInfo
-}
-
 // Check the supplied dist structure to make sure that it is valid.
 //
 // property - the base property, e.g. dist or dists[1], which is combined with the
@@ -2151,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
@@ -2745,7 +2744,7 @@
 
 // Collect information for opening IDE project files in java/jdeps.go.
 type IDEInfo interface {
-	IDEInfo(ideInfo *IdeInfo)
+	IDEInfo(ctx BaseModuleContext, ideInfo *IdeInfo)
 	BaseModuleName() string
 }
 
@@ -2757,7 +2756,9 @@
 	IDECustomizedModuleName() string
 }
 
+// Collect information for opening IDE project files in java/jdeps.go.
 type IdeInfo struct {
+	BaseModuleName    string   `json:"-"`
 	Deps              []string `json:"dependencies,omitempty"`
 	Srcs              []string `json:"srcs,omitempty"`
 	Aidl_include_dirs []string `json:"aidl_include_dirs,omitempty"`
@@ -2771,6 +2772,31 @@
 	Libs              []string `json:"libs,omitempty"`
 }
 
+// Merge merges two IdeInfos and produces a new one, leaving the origional unchanged
+func (i IdeInfo) Merge(other IdeInfo) IdeInfo {
+	return IdeInfo{
+		Deps:              mergeStringLists(i.Deps, other.Deps),
+		Srcs:              mergeStringLists(i.Srcs, other.Srcs),
+		Aidl_include_dirs: mergeStringLists(i.Aidl_include_dirs, other.Aidl_include_dirs),
+		Jarjar_rules:      mergeStringLists(i.Jarjar_rules, other.Jarjar_rules),
+		Jars:              mergeStringLists(i.Jars, other.Jars),
+		Classes:           mergeStringLists(i.Classes, other.Classes),
+		Installed_paths:   mergeStringLists(i.Installed_paths, other.Installed_paths),
+		SrcJars:           mergeStringLists(i.SrcJars, other.SrcJars),
+		Paths:             mergeStringLists(i.Paths, other.Paths),
+		Static_libs:       mergeStringLists(i.Static_libs, other.Static_libs),
+		Libs:              mergeStringLists(i.Libs, other.Libs),
+	}
+}
+
+// mergeStringLists appends the two string lists together and returns a new string list,
+// leaving the originals unchanged. Duplicate strings will be deduplicated.
+func mergeStringLists(a, b []string) []string {
+	return FirstUniqueStrings(Concat(a, b))
+}
+
+var IdeInfoProviderKey = blueprint.NewProvider[IdeInfo]()
+
 func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents string) []error {
 	bpctx := ctx.blueprintBaseModuleContext()
 	return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents)
diff --git a/android/module_context.go b/android/module_context.go
index e9fbb8c..3889e40 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -107,68 +107,79 @@
 	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
 	// with the given additional dependencies.  The file is marked executable after copying.
 	//
-	// 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.
+	// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
+	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
+	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
+	// dependency tags for which IsInstallDepNeeded returns true.
 	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
 
 	// InstallFile creates a rule to copy srcPath to name in the installPath directory,
 	// with the given additional dependencies.
 	//
+	// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
+	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
+	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
+	// 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.
-	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
+	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.
 	//
-	// 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.
+	// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
+	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
+	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
+	// dependency tags for which IsInstallDepNeeded returns true.
 	InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...InstallPath) InstallPath
 
 	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
 	// directory.
 	//
-	// The installed symlink 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.
+	// The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
+	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
+	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
+	// dependency tags for which IsInstallDepNeeded returns true.
 	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
 
 	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
 	// in the installPath directory.
 	//
-	// The installed symlink 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.
+	// The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
+	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
+	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
+	// dependency tags for which IsInstallDepNeeded returns true.
 	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
 
 	// InstallTestData creates rules to install test data (e.g. data files used during a test) into
 	// the installPath directory.
 	//
-	// The installed files will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed files 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.
+	// The installed files can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
+	// for the installed files can be accessed by InstallFilesInfo.PackagingSpecs on this module
+	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
+	// dependency tags for which IsInstallDepNeeded returns true.
 	InstallTestData(installPath InstallPath, data []DataPath) InstallPaths
 
 	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
 	// the rule to copy the file.  This is useful to define how a module would be packaged
 	// without installing it into the global installation directories.
 	//
-	// The created PackagingSpec for the 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.
+	// The created PackagingSpec can be accessed by InstallFilesInfo.PackagingSpecs on this module
+	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
+	// 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
@@ -218,26 +229,55 @@
 
 	GetOutputFiles() OutputFilesInfo
 
+	// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
+	// apex container for use when generation the license metadata file.
+	SetLicenseInstallMap(installMap []string)
+
 	// ComplianceMetadataInfo returns a ComplianceMetadataInfo instance for different module types to dump metadata,
 	// which usually happens in GenerateAndroidBuildActions() of a module type.
 	// See android.ModuleBase.complianceMetadataInfo
 	ComplianceMetadataInfo() *ComplianceMetadataInfo
+
+	// Get the information about the containers this module belongs to.
+	getContainersInfo() ContainersInfo
+	setContainersInfo(info ContainersInfo)
+
+	setAconfigPaths(paths Paths)
 }
 
 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
 
+	TransitiveInstallFiles *DepSet[InstallPath]
+
+	// set of dependency module:location mappings used to populate the license metadata for
+	// apex containers.
+	licenseInstallMap []string
+
+	// The path to the generated license metadata file for the module.
+	licenseMetadataFile WritablePath
+
 	katiInstalls katiInstalls
 	katiSymlinks katiInstalls
+	// katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
+	// allowed to have duplicates across modules and variants.
+	katiInitRcInstalls           katiInstalls
+	katiVintfInstalls            katiInstalls
+	initRcPaths                  Paths
+	vintfFragmentsPaths          Paths
+	installedInitRcPaths         InstallPaths
+	installedVintfFragmentsPaths InstallPaths
 
 	testData []DataPath
 
@@ -245,6 +285,21 @@
 	buildParams []BuildParams
 	ruleParams  map[blueprint.Rule]blueprint.RuleParams
 	variables   map[string]string
+
+	// moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will
+	// be included in the final module-info.json produced by Make.
+	moduleInfoJSON *ModuleInfoJSON
+
+	// containersInfo stores the information about the containers and the information of the
+	// apexes the module belongs to.
+	containersInfo ContainersInfo
+
+	// Merged Aconfig files for all transitive deps.
+	aconfigFilePaths Paths
+
+	// complianceMetadataInfo is for different module types to dump metadata.
+	// See android.ModuleContext interface.
+	complianceMetadataInfo *ComplianceMetadataInfo
 }
 
 var _ ModuleContext = &moduleContext{}
@@ -470,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,
 	})
@@ -492,11 +552,16 @@
 }
 
 func (m *moduleContext) getAconfigPaths() *Paths {
-	return &m.module.base().aconfigFilePaths
+	return &m.aconfigFilePaths
+}
+
+func (m *moduleContext) setAconfigPaths(paths Paths) {
+	m.aconfigFilePaths = paths
 }
 
 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,
@@ -507,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 {
@@ -521,9 +588,9 @@
 	}
 
 	if m.requiresFullInstall() {
-		deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...)
-		deps = append(deps, m.module.base().installedInitRcPaths...)
-		deps = append(deps, m.module.base().installedVintfFragmentsPaths...)
+		deps = append(deps, InstallPaths(m.TransitiveInstallFiles.ToList())...)
+		deps = append(deps, m.installedInitRcPaths...)
+		deps = append(deps, m.installedVintfFragmentsPaths...)
 
 		var implicitDeps, orderOnlyDeps Paths
 
@@ -580,7 +647,9 @@
 
 	m.packageFile(fullInstallPath, srcPath, executable)
 
-	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+	if checkbuild {
+		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+	}
 
 	return fullInstallPath
 }
@@ -621,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,
@@ -633,6 +702,8 @@
 		skipInstall:      m.skipInstall(),
 		aconfigPaths:     m.getAconfigPaths(),
 		archType:         m.target.Arch.ArchType,
+		overrides:        &overrides,
+		owner:            m.ModuleName(),
 	})
 
 	return fullInstallPath
@@ -668,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,
@@ -677,6 +749,8 @@
 		skipInstall:      m.skipInstall(),
 		aconfigPaths:     m.getAconfigPaths(),
 		archType:         m.target.Arch.ArchType,
+		overrides:        &overrides,
+		owner:            m.ModuleName(),
 	})
 
 	return fullInstallPath
@@ -688,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 {
@@ -704,15 +784,15 @@
 }
 
 func (m *moduleContext) LicenseMetadataFile() Path {
-	return m.module.base().licenseMetadataFile
+	return m.licenseMetadataFile
 }
 
 func (m *moduleContext) ModuleInfoJSON() *ModuleInfoJSON {
-	if moduleInfoJSON := m.module.base().moduleInfoJSON; moduleInfoJSON != nil {
+	if moduleInfoJSON := m.moduleInfoJSON; moduleInfoJSON != nil {
 		return moduleInfoJSON
 	}
 	moduleInfoJSON := &ModuleInfoJSON{}
-	m.module.base().moduleInfoJSON = moduleInfoJSON
+	m.moduleInfoJSON = moduleInfoJSON
 	return moduleInfoJSON
 }
 
@@ -738,13 +818,15 @@
 	return m.outputFiles
 }
 
+func (m *moduleContext) SetLicenseInstallMap(installMap []string) {
+	m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
+}
+
 func (m *moduleContext) ComplianceMetadataInfo() *ComplianceMetadataInfo {
-	if complianceMetadataInfo := m.module.base().complianceMetadataInfo; complianceMetadataInfo != nil {
-		return complianceMetadataInfo
+	if m.complianceMetadataInfo == nil {
+		m.complianceMetadataInfo = NewComplianceMetadataInfo()
 	}
-	complianceMetadataInfo := NewComplianceMetadataInfo()
-	m.module.base().complianceMetadataInfo = complianceMetadataInfo
-	return complianceMetadataInfo
+	return m.complianceMetadataInfo
 }
 
 // Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
@@ -784,3 +866,11 @@
 func (m *moduleContext) TargetRequiredModuleNames() []string {
 	return m.module.TargetRequiredModuleNames()
 }
+
+func (m *moduleContext) getContainersInfo() ContainersInfo {
+	return m.containersInfo
+}
+
+func (m *moduleContext) setContainersInfo(info ContainersInfo) {
+	m.containersInfo = info
+}
diff --git a/android/module_test.go b/android/module_test.go
index 92041ec..d64e3a5 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -722,6 +722,7 @@
 				propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"},
 				propInfo{Name: "B", Type: "bool", Value: "true"},
 				propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}},
+				propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}},
 				propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
 				propInfo{Name: "Name", Type: "string", Value: "foo"},
 				propInfo{Name: "Nested.E", Type: "string", Value: "nested e"},
diff --git a/android/neverallow.go b/android/neverallow.go
index 0f363e7..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 {
@@ -287,7 +305,7 @@
 			continue
 		}
 
-		if !n.appliesToProperties(properties) {
+		if !n.appliesToProperties(ctx, properties) {
 			continue
 		}
 
@@ -604,9 +622,9 @@
 	return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
 }
 
-func (r *rule) appliesToProperties(properties []interface{}) bool {
-	includeProps := hasAllProperties(properties, r.props)
-	excludeProps := hasAnyProperty(properties, r.unlessProps)
+func (r *rule) appliesToProperties(ctx BottomUpMutatorContext, properties []interface{}) bool {
+	includeProps := hasAllProperties(ctx, properties, r.props)
+	excludeProps := hasAnyProperty(ctx, properties, r.unlessProps)
 	return includeProps && !excludeProps
 }
 
@@ -644,25 +662,25 @@
 	return names
 }
 
-func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
+func hasAnyProperty(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool {
 	for _, v := range props {
-		if hasProperty(properties, v) {
+		if hasProperty(ctx, properties, v) {
 			return true
 		}
 	}
 	return false
 }
 
-func hasAllProperties(properties []interface{}, props []ruleProperty) bool {
+func hasAllProperties(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool {
 	for _, v := range props {
-		if !hasProperty(properties, v) {
+		if !hasProperty(ctx, properties, v) {
 			return false
 		}
 	}
 	return true
 }
 
-func hasProperty(properties []interface{}, prop ruleProperty) bool {
+func hasProperty(ctx BottomUpMutatorContext, properties []interface{}, prop ruleProperty) bool {
 	for _, propertyStruct := range properties {
 		propertiesValue := reflect.ValueOf(propertyStruct).Elem()
 		for _, v := range prop.fields {
@@ -679,14 +697,14 @@
 			return prop.matcher.Test(value)
 		}
 
-		if matchValue(propertiesValue, check) {
+		if matchValue(ctx, propertiesValue, check) {
 			return true
 		}
 	}
 	return false
 }
 
-func matchValue(value reflect.Value, check func(string) bool) bool {
+func matchValue(ctx BottomUpMutatorContext, value reflect.Value, check func(string) bool) bool {
 	if !value.IsValid() {
 		return false
 	}
@@ -698,19 +716,26 @@
 		value = value.Elem()
 	}
 
-	switch value.Kind() {
-	case reflect.String:
-		return check(value.String())
-	case reflect.Bool:
-		return check(strconv.FormatBool(value.Bool()))
-	case reflect.Int:
-		return check(strconv.FormatInt(value.Int(), 10))
-	case reflect.Slice:
-		slice, ok := value.Interface().([]string)
-		if !ok {
-			panic("Can only handle slice of string")
+	switch v := value.Interface().(type) {
+	case string:
+		return check(v)
+	case bool:
+		return check(strconv.FormatBool(v))
+	case int:
+		return check(strconv.FormatInt((int64)(v), 10))
+	case []string:
+		for _, v := range v {
+			if check(v) {
+				return true
+			}
 		}
-		for _, v := range slice {
+		return false
+	case proptools.Configurable[string]:
+		return check(v.GetOrDefault(ctx, ""))
+	case proptools.Configurable[bool]:
+		return check(strconv.FormatBool(v.GetOrDefault(ctx, false)))
+	case proptools.Configurable[[]string]:
+		for _, v := range v.GetOrDefault(ctx, nil) {
 			if check(v) {
 				return true
 			}
diff --git a/android/notices.go b/android/notices.go
index b9c1682..3c41d92 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -36,10 +36,22 @@
 	return SortedUniqueStrings(dirs)
 }
 
-func modulesLicenseMetadata(ctx BuilderContext, modules ...Module) Paths {
+type BuilderAndOtherModuleProviderContext interface {
+	BuilderContext
+	OtherModuleProviderContext
+}
+
+func modulesLicenseMetadata(ctx OtherModuleProviderContext, modules ...Module) Paths {
 	result := make(Paths, 0, len(modules))
+	mctx, isMctx := ctx.(ModuleContext)
 	for _, module := range modules {
-		if mf := module.base().licenseMetadataFile; mf != nil {
+		var mf Path
+		if isMctx && mctx.Module() == module {
+			mf = mctx.LicenseMetadataFile()
+		} else {
+			mf = OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).LicenseMetadataFile
+		}
+		if mf != nil {
 			result = append(result, mf)
 		}
 	}
@@ -48,7 +60,7 @@
 
 // buildNoticeOutputFromLicenseMetadata writes out a notice file.
 func buildNoticeOutputFromLicenseMetadata(
-	ctx BuilderContext, tool, ruleName string, outputFile WritablePath,
+	ctx BuilderAndOtherModuleProviderContext, tool, ruleName string, outputFile WritablePath,
 	libraryName string, stripPrefix []string, modules ...Module) {
 	depsFile := outputFile.ReplaceExtension(ctx, strings.TrimPrefix(outputFile.Ext()+".d", "."))
 	rule := NewRuleBuilder(pctx, ctx)
@@ -84,7 +96,7 @@
 // on the license metadata files for the input `modules` defaulting to the
 // current context module if none given.
 func BuildNoticeTextOutputFromLicenseMetadata(
-	ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+	ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
 	stripPrefix []string, modules ...Module) {
 	buildNoticeOutputFromLicenseMetadata(ctx, "textnotice", "text_notice_"+ruleName,
 		outputFile, libraryName, stripPrefix, modules...)
@@ -94,7 +106,7 @@
 // on the license metadata files for the input `modules` defaulting to the
 // current context module if none given.
 func BuildNoticeHtmlOutputFromLicenseMetadata(
-	ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+	ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
 	stripPrefix []string, modules ...Module) {
 	buildNoticeOutputFromLicenseMetadata(ctx, "htmlnotice", "html_notice_"+ruleName,
 		outputFile, libraryName, stripPrefix, modules...)
@@ -104,7 +116,7 @@
 // on the license metadata files for the input `modules` defaulting to the
 // current context module if none given.
 func BuildNoticeXmlOutputFromLicenseMetadata(
-	ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+	ctx BuilderAndOtherModuleProviderContext, outputFile WritablePath, ruleName, libraryName string,
 	stripPrefix []string, modules ...Module) {
 	buildNoticeOutputFromLicenseMetadata(ctx, "xmlnotice", "xml_notice_"+ruleName,
 		outputFile, libraryName, stripPrefix, modules...)
diff --git a/android/packaging.go b/android/packaging.go
index c247ed2..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) {
@@ -346,7 +388,8 @@
 		if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
 			return
 		}
-		for _, ps := range child.TransitivePackagingSpecs() {
+		for _, ps := range OtherModuleProviderOrDefault(
+			ctx, child, InstallFilesProvider).TransitivePackagingSpecs.ToList() {
 			if !filterArch(ps) {
 				continue
 			}
@@ -356,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/product_config.go b/android/product_config.go
index 20b29a7..04180bf 100644
--- a/android/product_config.go
+++ b/android/product_config.go
@@ -37,8 +37,10 @@
 	if targetProduct != "" {
 		targetProduct += "."
 	}
-	soongVariablesPath := PathForOutput(ctx, "soong."+targetProduct+"variables")
-	extraVariablesPath := PathForOutput(ctx, "soong."+targetProduct+"extra.variables")
+
+	coverageSuffix := ctx.Config().CoverageSuffix()
+	soongVariablesPath := PathForOutput(ctx, "soong."+targetProduct+coverageSuffix+"variables")
+	extraVariablesPath := PathForOutput(ctx, "soong."+targetProduct+coverageSuffix+"extra.variables")
 
 	rule := NewRuleBuilder(pctx, ctx)
 	rule.Command().BuiltTool("merge_json").
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 464aca4..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,6 +582,44 @@
 				})
 			}
 
+			// 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/variable.go b/android/variable.go
index c8744ed..14f1756 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -512,13 +512,9 @@
 	SystemPropFiles    []string `json:",omitempty"`
 	SystemExtPropFiles []string `json:",omitempty"`
 	ProductPropFiles   []string `json:",omitempty"`
+	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 ec71c18..6421c8e 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)
@@ -699,6 +704,8 @@
 	// If not-nil and an APEX is a member of an SDK then dependencies of that APEX with this tag will
 	// also be added as exported members of that SDK.
 	memberType android.SdkMemberType
+
+	installable bool
 }
 
 func (d *dependencyTag) SdkMemberType(_ android.Module) android.SdkMemberType {
@@ -717,18 +724,23 @@
 	return !d.sourceOnly
 }
 
+func (d *dependencyTag) InstallDepNeeded() bool {
+	return d.installable
+}
+
 var _ android.ReplaceSourceWithPrebuilt = &dependencyTag{}
 var _ android.SdkMemberDependencyTag = &dependencyTag{}
 
 var (
-	androidAppTag   = &dependencyTag{name: "androidApp", payload: true}
-	bpfTag          = &dependencyTag{name: "bpf", payload: true}
-	certificateTag  = &dependencyTag{name: "certificate"}
-	dclaTag         = &dependencyTag{name: "dcla"}
-	executableTag   = &dependencyTag{name: "executable", payload: true}
-	fsTag           = &dependencyTag{name: "filesystem", payload: true}
-	bcpfTag         = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType}
-	sscpfTag        = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true, memberType: java.SystemServerClasspathFragmentSdkMemberType}
+	androidAppTag  = &dependencyTag{name: "androidApp", payload: true}
+	bpfTag         = &dependencyTag{name: "bpf", payload: true}
+	certificateTag = &dependencyTag{name: "certificate"}
+	dclaTag        = &dependencyTag{name: "dcla"}
+	executableTag  = &dependencyTag{name: "executable", payload: true}
+	fsTag          = &dependencyTag{name: "filesystem", payload: true}
+	bcpfTag        = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType}
+	// The dexpreopt artifacts of apex system server jars are installed onto system image.
+	sscpfTag        = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true, memberType: java.SystemServerClasspathFragmentSdkMemberType, installable: true}
 	compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true, memberType: java.CompatConfigSdkMemberType}
 	javaLibTag      = &dependencyTag{name: "javaLib", payload: true}
 	jniLibTag       = &dependencyTag{name: "jniLib", payload: true}
@@ -1686,12 +1698,10 @@
 	if sdkLib, ok := module.(*java.SdkLibrary); ok {
 		for _, install := range sdkLib.BuiltInstalledForApex() {
 			af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
-			install.PackageFile(ctx)
 		}
 	} else if dexpreopter, ok := module.(java.DexpreopterInterface); ok {
 		for _, install := range dexpreopter.DexpreoptBuiltInstalledForApex() {
 			af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
-			install.PackageFile(ctx)
 		}
 	}
 	return af
@@ -1932,8 +1942,6 @@
 
 	// visitor skips these from this list of module names
 	unwantedTransitiveDeps []string
-
-	aconfigFiles []android.Path
 }
 
 func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
@@ -2000,7 +2008,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
@@ -2012,7 +2019,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)
@@ -2021,11 +2027,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",
@@ -2065,7 +2069,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))
@@ -2074,14 +2077,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() {
@@ -2095,7 +2095,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)
 			}
@@ -2127,7 +2126,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)
 			}
@@ -2142,7 +2140,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)
@@ -2222,13 +2219,15 @@
 			}
 
 			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) {
+				return false
+			}
+
 			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) {
@@ -2244,10 +2243,13 @@
 		}
 	} else if rust.IsDylibDepTag(depTag) {
 		if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
+			if !android.IsDepInSameApex(ctx, am, am) {
+				return false
+			}
+
 			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) {
@@ -2266,7 +2268,6 @@
 				return false
 			}
 			vctx.filesInfo = append(vctx.filesInfo, af)
-			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		default:
 			ctx.PropertyErrorf("bootclasspath_fragments",
@@ -2281,7 +2282,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",
@@ -2299,19 +2299,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 {
@@ -2393,13 +2380,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)
@@ -2860,7 +2850,7 @@
 }
 
 // Collect information for opening IDE project files in java/jdeps.go.
-func (a *apexBundle) IDEInfo(dpInfo *android.IdeInfo) {
+func (a *apexBundle) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.Java_libs...)
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.Bootclasspath_fragments...)
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.ResolvedSystemserverclasspathFragments...)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 6b9944d..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) {
@@ -906,7 +915,7 @@
 		cc_library {
 			name: "mylib",
 			srcs: ["mylib.cpp"],
-			shared_libs: ["mylib2", "mylib3"],
+			shared_libs: ["mylib2", "mylib3", "my_prebuilt_platform_lib", "my_prebuilt_platform_stub_only_lib"],
 			system_shared_libs: [],
 			stl: "none",
 			apex_available: [ "myapex" ],
@@ -919,6 +928,7 @@
 			system_shared_libs: [],
 			stl: "none",
 			stubs: {
+				symbol_file: "mylib2.map.txt",
 				versions: ["1", "2", "3"],
 			},
 		}
@@ -930,6 +940,7 @@
 			system_shared_libs: [],
 			stl: "none",
 			stubs: {
+				symbol_file: "mylib3.map.txt",
 				versions: ["10", "11", "12"],
 			},
 			apex_available: [ "myapex" ],
@@ -943,6 +954,24 @@
 			apex_available: [ "myapex" ],
 		}
 
+		cc_prebuilt_library_shared {
+			name: "my_prebuilt_platform_lib",
+			stubs: {
+				symbol_file: "my_prebuilt_platform_lib.map.txt",
+				versions: ["1", "2", "3"],
+			},
+			srcs: ["foo.so"],
+		}
+
+		// Similar to my_prebuilt_platform_lib, but this library only provides stubs, i.e. srcs is empty
+		cc_prebuilt_library_shared {
+			name: "my_prebuilt_platform_stub_only_lib",
+			stubs: {
+				symbol_file: "my_prebuilt_platform_stub_only_lib.map.txt",
+				versions: ["1", "2", "3"],
+			}
+		}
+
 		rust_binary {
 			name: "foo.rust",
 			srcs: ["foo.rs"],
@@ -1022,6 +1051,20 @@
 
 	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so")
+
+	// Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib
+	ensureContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_lib.so")
+	// ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib
+	ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_lib.so")
+	// Ensure that genstub for platform-provided lib is invoked with --systemapi
+	ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
+
+	// Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib
+	ensureContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_stub_only_lib.so")
+	// ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib
+	ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_stub_only_lib.so")
+	// Ensure that genstub for platform-provided lib is invoked with --systemapi
+	ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_stub_only_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
 }
 
 func TestApexShouldNotEmbedStubVariant(t *testing.T) {
@@ -1156,6 +1199,7 @@
 			system_shared_libs: [],
 			stl: "none",
 			stubs: {
+				symbol_file: "mylib2.map.txt",
 				versions: ["28", "29", "30", "current"],
 			},
 			min_sdk_version: "28",
@@ -1168,6 +1212,7 @@
 			system_shared_libs: [],
 			stl: "none",
 			stubs: {
+				symbol_file: "mylib3.map.txt",
 				versions: ["28", "29", "30", "current"],
 			},
 			apex_available: [ "myapex" ],
@@ -4893,6 +4938,7 @@
 		java_import {
 			name: "libfoo",
 			jars: ["libfoo.jar"],
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -4933,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: {
@@ -4949,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 {
@@ -4960,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",
 		}
 	`
 
@@ -4974,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) {
@@ -5004,6 +5084,7 @@
 
 		java_library {
 			name: "libfoo",
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5130,6 +5211,7 @@
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5284,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 {
@@ -5381,6 +5465,7 @@
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -5388,6 +5473,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5478,6 +5564,7 @@
 			name: "libfoo",
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -5486,6 +5573,7 @@
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
 			installable: true,
+			sdk_version: "core_current",
 		}
 
 		java_sdk_library_import {
@@ -5504,6 +5592,7 @@
 			apex_available: ["myapex"],
 			permitted_packages: ["bar"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 	`
 
@@ -6098,6 +6187,7 @@
 			name: "TesterHelpAppFoo",
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: [ "myapex" ],
+			sdk_version: "test_current",
 		}
 
 	`)
@@ -7700,7 +7790,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
-			libs: ["myotherjar"],
+			static_libs: ["myotherjar"],
 			apex_available: [
 				"myapex",
 				"myapex.updatable",
@@ -8361,6 +8451,7 @@
 			apex_available: [
 				"myapex",
 			],
+			sdk_version: "current",
 		}
 
 		systemserverclasspath_fragment {
@@ -9403,6 +9494,7 @@
 			srcs: ["mybootclasspathlib.java"],
 			apex_available: ["myapex"],
 			compile_dex: true,
+			sdk_version: "current",
 		}
 
 		systemserverclasspath_fragment {
@@ -9718,6 +9810,7 @@
 				unsafe_ignore_missing_latest_api: true,
 				min_sdk_version: "31",
 				static_libs: ["util"],
+				sdk_version: "core_current",
 			}
 
 			java_library {
@@ -9726,6 +9819,7 @@
 				apex_available: ["myapex"],
 				min_sdk_version: "31",
 				static_libs: ["another_util"],
+				sdk_version: "core_current",
 			}
 
 			java_library {
@@ -9733,6 +9827,7 @@
                 srcs: ["a.java"],
 				min_sdk_version: "31",
 				apex_available: ["myapex"],
+				sdk_version: "core_current",
 			}
 		`)
 	})
@@ -9788,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",
@@ -9819,6 +9914,8 @@
 					apex_available: ["myapex"],
 					compile_dex: true,
 					unsafe_ignore_missing_latest_api: true,
+					sdk_version: "current",
+					min_sdk_version: "30",
 				}
 		`)
 	})
@@ -10071,6 +10168,9 @@
 			key: "myapex.key",
 			bootclasspath_fragments: ["mybootclasspathfragment"],
 			min_sdk_version: "29",
+			java_libs: [
+				"jacocoagent",
+			],
 		}
 		apex_key {
 			name: "myapex.key",
@@ -10700,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",
@@ -10835,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",
@@ -11003,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",
@@ -11940,7 +12040,7 @@
 		).RunTest(t)
 
 		ldRule := result.ModuleForTests("installedlib", "android_arm64_armv8-a_shared").Rule("ld")
-		android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared/libfoo.so")
+		android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared_current/libfoo.so")
 
 		installRules := result.InstallMakeRulesForTesting(t)
 
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 25131ee..7cad337 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 {
@@ -922,6 +924,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1093,6 +1096,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
@@ -1245,6 +1249,7 @@
 			],
 			srcs: ["b.java"],
 			compile_dex: true,
+			sdk_version: "core_current",
 		}
 
 		java_library {
diff --git a/apex/builder.go b/apex/builder.go
index bfe1692..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
@@ -595,7 +655,7 @@
 	if len(installMapSet) > 0 {
 		var installs []string
 		installs = append(installs, android.SortedKeys(installMapSet)...)
-		a.SetLicenseInstallMap(installs)
+		ctx.SetLicenseInstallMap(installs)
 	}
 
 	////////////////////////////////////////////////////////////////////////////////////////////
@@ -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/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index 95db37d..d8ee4ba 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -409,3 +409,106 @@
 		android.AssertStringListContains(t, tc.desc, inputs, tc.expectedProfile)
 	}
 }
+
+// Check that dexpreopt works with Google mainline prebuilts even in workspaces where source is missing
+func TestDexpreoptWithMainlinePrebuiltNoSource(t *testing.T) {
+	bp := `
+		// Platform.
+
+		platform_bootclasspath {
+			name: "platform-bootclasspath",
+			fragments: [
+				{
+					apex: "com.android.art",
+					module: "art-bootclasspath-fragment",
+				},
+			],
+		}
+
+		// Source AOSP ART apex
+		java_library {
+			name: "core-oj",
+			srcs: ["core-oj.java"],
+			installable: true,
+			apex_available: [
+				"com.android.art",
+			],
+		}
+
+		bootclasspath_fragment {
+			name: "art-bootclasspath-fragment",
+			image_name: "art",
+			contents: ["core-oj"],
+			apex_available: [
+				"com.android.art",
+			],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
+		apex_key {
+			name: "com.android.art.key",
+			public_key: "com.android.art.avbpubkey",
+			private_key: "com.android.art.pem",
+		}
+
+		apex {
+			name: "com.android.art",
+			key: "com.android.art.key",
+			bootclasspath_fragments: ["art-bootclasspath-fragment"],
+			updatable: false,
+		}
+
+
+		// Prebuilt Google ART APEX.
+
+		java_import {
+			name: "core-oj",
+			jars: ["core-oj.jar"],
+			apex_available: [
+				"com.android.art",
+			],
+		}
+
+		prebuilt_bootclasspath_fragment {
+			name: "art-bootclasspath-fragment",
+			image_name: "art",
+			contents: ["core-oj"],
+			hidden_api: {
+				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+				metadata: "my-bootclasspath-fragment/metadata.csv",
+				index: "my-bootclasspath-fragment/index.csv",
+				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+				all_flags: "my-bootclasspath-fragment/all-flags.csv",
+			},
+			apex_available: [
+				"com.android.art",
+			],
+		}
+
+		prebuilt_apex {
+			name: "com.google.android.art",
+			apex_name: "com.android.art",
+			src: "com.android.art-arm.apex",
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
+		}
+
+		apex_contributions {
+			name: "art.prebuilt.contributions",
+			api_domain: "com.android.art",
+			contents: ["prebuilt_com.google.android.art"],
+		}
+	`
+	res := android.GroupFixturePreparers(
+		java.PrepareForTestWithDexpreopt,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureConfigureBootJars("com.android.art:core-oj"),
+		PrepareForTestWithApexBuildComponents,
+		prepareForTestWithArtApex,
+		android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "art.prebuilt.contributions"),
+	).RunTestWithBp(t, bp)
+	if !java.CheckModuleHasDependency(t, res.TestContext, "dex_bootjars", "android_common", "prebuilt_com.google.android.art") {
+		t.Errorf("Expected dexpreopt to use prebuilt apex")
+	}
+}
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 920fc0c..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
@@ -791,6 +792,128 @@
 		`)
 }
 
+// Skip bcp_fragment content validation of source apexes if prebuilts are active.
+func TestNonBootJarInPrebuilts(t *testing.T) {
+	testCases := []struct {
+		description               string
+		selectedApexContributions string
+		expectedError             string
+	}{
+		{
+			description:               "source is active",
+			selectedApexContributions: "",
+			expectedError:             "in contents must also be declared in PRODUCT_APEX_BOOT_JARS",
+		},
+		{
+			description:               "prebuilts are active",
+			selectedApexContributions: "myapex.prebuilt.contributions",
+			expectedError:             "", // skip content validation of source bcp fragment
+		},
+	}
+	bp := `
+// Source
+apex {
+	name: "myapex",
+	key: "myapex.key",
+	bootclasspath_fragments: ["apex-fragment"],
+	updatable: false,
+	min_sdk_version: "29",
+}
+
+override_apex {
+	name: "myapex.override", // overrides the min_sdk_version, thereby creating different variants of its transitive deps
+	base: "myapex",
+	min_sdk_version: "34",
+}
+
+apex_key {
+	name: "myapex.key",
+	public_key: "testkey.avbpubkey",
+	private_key: "testkey.pem",
+}
+
+java_library {
+	name: "foo",
+	srcs: ["b.java"],
+	installable: true,
+	apex_available: ["myapex"],
+	permitted_packages: ["foo"],
+	min_sdk_version: "29",
+}
+
+java_library {
+	name: "bar",
+	srcs: ["b.java"],
+	installable: true,
+	apex_available: ["myapex"],
+	permitted_packages: ["bar"],
+	min_sdk_version: "29",
+}
+
+bootclasspath_fragment {
+	name: "apex-fragment",
+	contents: ["foo", "bar"],
+	apex_available:[ "myapex" ],
+	hidden_api: {
+		split_packages: ["*"],
+	},
+}
+
+platform_bootclasspath {
+	name: "myplatform-bootclasspath",
+	fragments: [{
+			apex: "myapex",
+			module:"apex-fragment",
+	}],
+}
+
+// prebuilts
+prebuilt_apex {
+	name: "myapex",
+		apex_name: "myapex",
+		src: "myapex.apex",
+		exported_bootclasspath_fragments: ["apex-fragment"],
+	}
+
+	prebuilt_bootclasspath_fragment {
+		name: "apex-fragment",
+		contents: ["foo"],
+		hidden_api: {
+			annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+			metadata: "my-bootclasspath-fragment/metadata.csv",
+			index: "my-bootclasspath-fragment/index.csv",
+			stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+			all_flags: "my-bootclasspath-fragment/all-flags.csv",
+		},
+	}
+	java_import {
+		name: "foo",
+		jars: ["foo.jar"],
+	}
+
+apex_contributions {
+	name: "myapex.prebuilt.contributions",
+	api_domain: "myapex",
+	contents: ["prebuilt_myapex"],
+}
+`
+
+	for _, tc := range testCases {
+		fixture := android.GroupFixturePreparers(
+			prepareForTestWithPlatformBootclasspath,
+			PrepareForTestWithApexBuildComponents,
+			prepareForTestWithMyapex,
+			java.FixtureConfigureApexBootJars("myapex:foo"),
+			android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", tc.selectedApexContributions),
+		)
+		if tc.expectedError != "" {
+			fixture = fixture.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError))
+		}
+		fixture.RunTestWithBp(t, bp)
+	}
+
+}
+
 // Source and prebuilt apex provide different set of boot jars
 func TestNonBootJarMissingInPrebuiltFragment(t *testing.T) {
 	bp := `
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9dc8a63..f1a134e 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -195,7 +195,6 @@
 	// If this apex contains a system server jar, then the dexpreopt artifacts should be added as required
 	for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
 		p.requiredModuleNames = append(p.requiredModuleNames, install.FullModuleName())
-		install.PackageFile(ctx)
 	}
 }
 
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/bin/aninja b/bin/aninja
index 5acb968..5cb5a55 100755
--- a/bin/aninja
+++ b/bin/aninja
@@ -34,5 +34,5 @@
 esac
 
 cd $(gettop)
-prebuilts/build-tools/${host_arch}/bin/ninja -f out/combined-${TARGET_PRODUCT}.ninja "$@"
+prebuilts/build-tools/${host_arch}/bin/ninja -f $(getoutdir)/combined-${TARGET_PRODUCT}.ninja "$@"
 
diff --git a/cc/cc.go b/cc/cc.go
index 947dc1a..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)
@@ -3042,7 +3048,7 @@
 		}
 
 		if dep.Target().Os != ctx.Os() {
-			ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
+			ctx.ModuleErrorf("OS mismatch between %q (%s) and %q (%s)", ctx.ModuleName(), ctx.Os().Name, depName, dep.Target().Os.Name)
 			return
 		}
 		if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 79e386f..93630db 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -927,7 +927,7 @@
 
 	cc_prebuilt_library_shared {
 		name: "libllndkprebuilt",
-		stubs: { versions: ["1", "2"] },
+		stubs: { versions: ["1", "2"] , symbol_file: "libllndkprebuilt.map.txt" },
 		llndk: {
 			symbol_file: "libllndkprebuilt.map.txt",
 		},
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/config/global.go b/cc/config/global.go
index 0e8fff6..c838357 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -287,8 +287,7 @@
 		"-Wno-error=deprecated-builtins", // http://b/241601211
 		"-Wno-error=deprecated",          // in external/googletest/googletest
 		// New warnings to be fixed after clang-r475365
-		"-Wno-error=single-bit-bitfield-constant-conversion", // http://b/243965903
-		"-Wno-error=enum-constexpr-conversion",               // http://b/243964282
+		"-Wno-error=enum-constexpr-conversion", // http://b/243964282
 		// New warnings to be fixed after clang-r522817
 		"-Wno-error=invalid-offsetof",
 		"-Wno-error=thread-safety-reference-return",
diff --git a/cc/library.go b/cc/library.go
index 6017848..65a923a 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -594,43 +594,7 @@
 		return objs
 	}
 	if library.buildStubs() {
-		symbolFile := String(library.Properties.Stubs.Symbol_file)
-		if symbolFile != "" && !strings.HasSuffix(symbolFile, ".map.txt") {
-			ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile)
-			return Objects{}
-		}
-		library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
-		// b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
-		// systemapi, respectively. The former is for symbols defined in platform libraries
-		// and the latter is for symbols defined in APEXes.
-		// A single library can contain either # apex or # systemapi, but not both.
-		// The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
-		// However, having this distinction helps guard accidental
-		// promotion or demotion of API and also helps the API review process b/191371676
-		var flag string
-		if ctx.Module().(android.ApexModule).NotInPlatform() {
-			flag = "--apex"
-		} else {
-			flag = "--systemapi"
-		}
-		// b/184712170, unless the lib is an NDK library, exclude all public symbols from
-		// the stub so that it is mandated that all symbols are explicitly marked with
-		// either apex or systemapi.
-		if !ctx.Module().(*Module).IsNdk(ctx.Config()) {
-			flag = flag + " --no-ndk"
-		}
-		nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
-			android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
-		objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
-		library.versionScriptPath = android.OptionalPathForPath(
-			nativeAbiResult.versionScript)
-
-		// Parse symbol file to get API list for coverage
-		if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
-			library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
-		}
-
-		return objs
+		return library.compileModuleLibApiStubs(ctx, flags, deps)
 	}
 
 	srcs := library.baseCompiler.Properties.Srcs.GetOrDefault(ctx, nil)
@@ -681,6 +645,61 @@
 	return objs
 }
 
+// Compile stubs for the API surface between platform and apex
+// This method will be used by source and prebuilt cc module types.
+func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+	// TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk.
+	if library.Properties.Stubs.Symbol_file == nil {
+		return Objects{}
+	}
+	symbolFile := String(library.Properties.Stubs.Symbol_file)
+	library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
+	// b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
+	// systemapi, respectively. The former is for symbols defined in platform libraries
+	// and the latter is for symbols defined in APEXes.
+	// A single library can contain either # apex or # systemapi, but not both.
+	// The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
+	// However, having this distinction helps guard accidental
+	// promotion or demotion of API and also helps the API review process b/191371676
+	var flag string
+	if ctx.Module().(android.ApexModule).NotInPlatform() {
+		flag = "--apex"
+	} else {
+		flag = "--systemapi"
+	}
+	// b/184712170, unless the lib is an NDK library, exclude all public symbols from
+	// the stub so that it is mandated that all symbols are explicitly marked with
+	// either apex or systemapi.
+	if !ctx.Module().(*Module).IsNdk(ctx.Config()) &&
+		// the symbol files of libclang libs are autogenerated and do not contain systemapi tags
+		// TODO (spandandas): Update mapfile.py to include #systemapi tag on all symbols
+		!strings.Contains(ctx.ModuleName(), "libclang_rt") {
+		flag = flag + " --no-ndk"
+	}
+	// TODO(b/361303067): Remove this special case if bionic/ projects are added to ART development branches.
+	if isBionic(ctx.baseModuleName()) {
+		// set the flags explicitly for bionic libs.
+		// this is necessary for development in minimal branches which does not contain bionic/*.
+		// In such minimal branches, e.g. on the prebuilt libc stubs
+		// 1. IsNdk will return false (since the ndk_library definition for libc does not exist)
+		// 2. NotInPlatform will return true (since the source com.android.runtime does not exist)
+		flag = "--apex"
+	}
+	nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
+		android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
+	objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
+
+	library.versionScriptPath = android.OptionalPathForPath(
+		nativeAbiResult.versionScript)
+
+	// Parse symbol file to get API list for coverage
+	if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
+		library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
+	}
+
+	return objs
+}
+
 type libraryInterface interface {
 	versionedInterface
 
@@ -1182,12 +1201,17 @@
 	return unstrippedOutputFile
 }
 
-func addStubDependencyProviders(ctx ModuleContext) {
+// Visits the stub variants of the library and returns a struct containing the stub .so paths
+func addStubDependencyProviders(ctx ModuleContext) []SharedStubLibrary {
+	stubsInfo := []SharedStubLibrary{}
 	stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
 	if len(stubs) > 0 {
-		var stubsInfo []SharedStubLibrary
 		for _, stub := range stubs {
-			stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+			stubInfo, ok := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+			// TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk.
+			if !ok {
+				continue
+			}
 			flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
 			stubsInfo = append(stubsInfo, SharedStubLibrary{
 				Version:           moduleLibraryInterface(stub).stubsVersion(),
@@ -1195,11 +1219,14 @@
 				FlagExporterInfo:  flagInfo,
 			})
 		}
-		android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
-			SharedStubLibraries: stubsInfo,
-			IsLLNDK:             ctx.IsLlndk(),
-		})
+		if len(stubsInfo) > 0 {
+			android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+				SharedStubLibraries: stubsInfo,
+				IsLLNDK:             ctx.IsLlndk(),
+			})
+		}
 	}
+	return stubsInfo
 }
 
 func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
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/prebuilt.go b/cc/prebuilt.go
index fb151d8..299fb51 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"strings"
 
 	"github.com/google/blueprint/proptools"
 
@@ -95,10 +96,6 @@
 	return p.libraryDecorator.linkerDeps(ctx, deps)
 }
 
-func (p *prebuiltLibraryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
-	return flags
-}
-
 func (p *prebuiltLibraryLinker) linkerProps() []interface{} {
 	return p.libraryDecorator.linkerProps()
 }
@@ -117,6 +114,30 @@
 
 	// TODO(ccross): verify shared library dependencies
 	srcs := p.prebuiltSrcs(ctx)
+	stubInfo := addStubDependencyProviders(ctx)
+
+	// Stub variants will create a stub .so file from stub .c files
+	if p.buildStubs() && objs.objFiles != nil {
+		// TODO (b/275273834): Make objs.objFiles == nil a hard error when the symbol files have been added to module sdk.
+
+		// The map.txt files of libclang_rt.* contain version information, but the checked in .so files do not.
+		// e.g. libclang_rt.* libs impl
+		// $ nm -D prebuilts/../libclang_rt.hwasan-aarch64-android.so
+		// __hwasan_init
+
+		// stubs generated from .map.txt
+		// $ nm -D out/soong/.intermediates/../<stubs>/libclang_rt.hwasan-aarch64-android.so
+		// __hwasan_init@@LIBCLANG_RT_ASAN
+
+		// Special-case libclang_rt.* libs to account for this discrepancy.
+		// TODO (spandandas): Remove this special case https://r.android.com/3236596 has been submitted, and a new set of map.txt
+		// files of libclang_rt.* libs have been generated.
+		if strings.Contains(ctx.ModuleName(), "libclang_rt.") {
+			p.versionScriptPath = android.OptionalPathForPath(nil)
+		}
+		return p.linkShared(ctx, flags, deps, objs)
+	}
+
 	if len(srcs) > 0 {
 		if len(srcs) > 1 {
 			ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
@@ -203,6 +224,16 @@
 
 			return outputFile
 		}
+	} else if p.shared() && len(stubInfo) > 0 {
+		// This is a prebuilt which does not have any implementation (nil `srcs`), but provides APIs.
+		// Provide the latest (i.e. `current`) stubs to reverse dependencies.
+		latestStub := stubInfo[len(stubInfo)-1].SharedLibraryInfo.SharedLibrary
+		android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
+			SharedLibrary: latestStub,
+			Target:        ctx.Target(),
+		})
+
+		return latestStub
 	}
 
 	if p.header() {
@@ -257,11 +288,11 @@
 
 func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) {
 	module, library := NewLibrary(hod)
-	module.compiler = nil
 
 	prebuilt := &prebuiltLibraryLinker{
 		libraryDecorator: library,
 	}
+	module.compiler = prebuilt
 	module.linker = prebuilt
 	module.library = prebuilt
 
@@ -280,6 +311,13 @@
 	return module, library
 }
 
+func (p *prebuiltLibraryLinker) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+	if p.buildStubs() && p.stubsVersion() != "" {
+		return p.compileModuleLibApiStubs(ctx, flags, deps)
+	}
+	return Objects{}
+}
+
 // cc_prebuilt_library installs a precompiled shared library that are
 // listed in the srcs property in the device's directory.
 func PrebuiltLibraryFactory() android.Module {
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index e69a930..f3931a4 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -27,6 +27,7 @@
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
 	"strconv"
 	"strings"
 	"time"
@@ -51,6 +52,8 @@
 	sandboxDirPlaceholder = "__SBOX_SANDBOX_DIR__"
 )
 
+var envVarNameRegex = regexp.MustCompile("^[a-zA-Z0-9_-]+$")
+
 func init() {
 	flag.StringVar(&sandboxesRoot, "sandbox-path", "",
 		"root of temp directory to put the sandbox into")
@@ -238,6 +241,51 @@
 	return &manifest, nil
 }
 
+func createEnv(command *sbox_proto.Command) ([]string, error) {
+	env := []string{}
+	if command.DontInheritEnv == nil || !*command.DontInheritEnv {
+		env = os.Environ()
+	}
+	for _, envVar := range command.Env {
+		if envVar.Name == nil || !envVarNameRegex.MatchString(*envVar.Name) {
+			name := "nil"
+			if envVar.Name != nil {
+				name = *envVar.Name
+			}
+			return nil, fmt.Errorf("Invalid environment variable name: %q", name)
+		}
+		if envVar.State == nil {
+			return nil, fmt.Errorf("Must set state")
+		}
+		switch state := envVar.State.(type) {
+		case *sbox_proto.EnvironmentVariable_Value:
+			env = append(env, *envVar.Name+"="+state.Value)
+		case *sbox_proto.EnvironmentVariable_Unset:
+			if !state.Unset {
+				return nil, fmt.Errorf("Can't have unset set to false")
+			}
+			prefix := *envVar.Name + "="
+			for i := 0; i < len(env); i++ {
+				if strings.HasPrefix(env[i], prefix) {
+					env = append(env[:i], env[i+1:]...)
+					i--
+				}
+			}
+		case *sbox_proto.EnvironmentVariable_Inherit:
+			if !state.Inherit {
+				return nil, fmt.Errorf("Can't have inherit set to false")
+			}
+			val, ok := os.LookupEnv(*envVar.Name)
+			if ok {
+				env = append(env, *envVar.Name+"="+val)
+			}
+		default:
+			return nil, fmt.Errorf("Unhandled state type")
+		}
+	}
+	return env, nil
+}
+
 // runCommand runs a single command from a manifest.  If the command references the
 // __SBOX_DEPFILE__ placeholder it returns the name of the depfile that was used.
 func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) (depFile string, err error) {
@@ -313,6 +361,12 @@
 			return "", fmt.Errorf("Failed to update PATH: %w", err)
 		}
 	}
+
+	cmd.Env, err = createEnv(command)
+	if err != nil {
+		return "", err
+	}
+
 	err = cmd.Run()
 
 	if err != nil {
diff --git a/cmd/sbox/sbox_proto/sbox.pb.go b/cmd/sbox/sbox_proto/sbox.pb.go
index 7c84f2c..271039c 100644
--- a/cmd/sbox/sbox_proto/sbox.pb.go
+++ b/cmd/sbox/sbox_proto/sbox.pb.go
@@ -14,8 +14,8 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.26.0
-// 	protoc        v3.9.1
+// 	protoc-gen-go v1.33.0
+// 	protoc        v3.21.12
 // source: sbox.proto
 
 package sbox_proto
@@ -116,6 +116,13 @@
 	// A list of files that will be copied before the sandboxed command, and whose contents should be
 	// copied as if they were listed in copy_before.
 	RspFiles []*RspFile `protobuf:"bytes,6,rep,name=rsp_files,json=rspFiles" json:"rsp_files,omitempty"`
+	// The environment variables that will be set or unset while running the command.
+	// Also see dont_inherit_env.
+	Env []*EnvironmentVariable `protobuf:"bytes,7,rep,name=env" json:"env,omitempty"`
+	// By default, all environment variables are inherited from the calling process, but may be
+	// replaced or unset by env. If dont_inherit_env is set, no environment variables will be
+	// inherited, and instead only the variables in env will be defined.
+	DontInheritEnv *bool `protobuf:"varint,8,opt,name=dont_inherit_env,json=dontInheritEnv" json:"dont_inherit_env,omitempty"`
 }
 
 func (x *Command) Reset() {
@@ -192,6 +199,129 @@
 	return nil
 }
 
+func (x *Command) GetEnv() []*EnvironmentVariable {
+	if x != nil {
+		return x.Env
+	}
+	return nil
+}
+
+func (x *Command) GetDontInheritEnv() bool {
+	if x != nil && x.DontInheritEnv != nil {
+		return *x.DontInheritEnv
+	}
+	return false
+}
+
+type EnvironmentVariable struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of the environment variable
+	Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
+	// Types that are assignable to State:
+	//
+	//	*EnvironmentVariable_Value
+	//	*EnvironmentVariable_Unset
+	//	*EnvironmentVariable_Inherit
+	State isEnvironmentVariable_State `protobuf_oneof:"state"`
+}
+
+func (x *EnvironmentVariable) Reset() {
+	*x = EnvironmentVariable{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_sbox_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *EnvironmentVariable) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EnvironmentVariable) ProtoMessage() {}
+
+func (x *EnvironmentVariable) ProtoReflect() protoreflect.Message {
+	mi := &file_sbox_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use EnvironmentVariable.ProtoReflect.Descriptor instead.
+func (*EnvironmentVariable) Descriptor() ([]byte, []int) {
+	return file_sbox_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *EnvironmentVariable) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (m *EnvironmentVariable) GetState() isEnvironmentVariable_State {
+	if m != nil {
+		return m.State
+	}
+	return nil
+}
+
+func (x *EnvironmentVariable) GetValue() string {
+	if x, ok := x.GetState().(*EnvironmentVariable_Value); ok {
+		return x.Value
+	}
+	return ""
+}
+
+func (x *EnvironmentVariable) GetUnset() bool {
+	if x, ok := x.GetState().(*EnvironmentVariable_Unset); ok {
+		return x.Unset
+	}
+	return false
+}
+
+func (x *EnvironmentVariable) GetInherit() bool {
+	if x, ok := x.GetState().(*EnvironmentVariable_Inherit); ok {
+		return x.Inherit
+	}
+	return false
+}
+
+type isEnvironmentVariable_State interface {
+	isEnvironmentVariable_State()
+}
+
+type EnvironmentVariable_Value struct {
+	// The value to set the environment variable to.
+	Value string `protobuf:"bytes,2,opt,name=value,oneof"`
+}
+
+type EnvironmentVariable_Unset struct {
+	// This environment variable should be unset in the command.
+	Unset bool `protobuf:"varint,3,opt,name=unset,oneof"`
+}
+
+type EnvironmentVariable_Inherit struct {
+	// This environment variable should be inherited from the parent process.
+	// Can be combined with dont_inherit_env to only inherit certain environment
+	// variables.
+	Inherit bool `protobuf:"varint,4,opt,name=inherit,oneof"`
+}
+
+func (*EnvironmentVariable_Value) isEnvironmentVariable_State() {}
+
+func (*EnvironmentVariable_Unset) isEnvironmentVariable_State() {}
+
+func (*EnvironmentVariable_Inherit) isEnvironmentVariable_State() {}
+
 // Copy describes a from-to pair of files to copy.  The paths may be relative, the root that they
 // are relative to is specific to the context the Copy is used in and will be different for
 // from and to.
@@ -209,7 +339,7 @@
 func (x *Copy) Reset() {
 	*x = Copy{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_sbox_proto_msgTypes[2]
+		mi := &file_sbox_proto_msgTypes[3]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -222,7 +352,7 @@
 func (*Copy) ProtoMessage() {}
 
 func (x *Copy) ProtoReflect() protoreflect.Message {
-	mi := &file_sbox_proto_msgTypes[2]
+	mi := &file_sbox_proto_msgTypes[3]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -235,7 +365,7 @@
 
 // Deprecated: Use Copy.ProtoReflect.Descriptor instead.
 func (*Copy) Descriptor() ([]byte, []int) {
-	return file_sbox_proto_rawDescGZIP(), []int{2}
+	return file_sbox_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *Copy) GetFrom() string {
@@ -274,7 +404,7 @@
 func (x *RspFile) Reset() {
 	*x = RspFile{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_sbox_proto_msgTypes[3]
+		mi := &file_sbox_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -287,7 +417,7 @@
 func (*RspFile) ProtoMessage() {}
 
 func (x *RspFile) ProtoReflect() protoreflect.Message {
-	mi := &file_sbox_proto_msgTypes[3]
+	mi := &file_sbox_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -300,7 +430,7 @@
 
 // Deprecated: Use RspFile.ProtoReflect.Descriptor instead.
 func (*RspFile) Descriptor() ([]byte, []int) {
-	return file_sbox_proto_rawDescGZIP(), []int{3}
+	return file_sbox_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *RspFile) GetFile() string {
@@ -330,7 +460,7 @@
 func (x *PathMapping) Reset() {
 	*x = PathMapping{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_sbox_proto_msgTypes[4]
+		mi := &file_sbox_proto_msgTypes[5]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -343,7 +473,7 @@
 func (*PathMapping) ProtoMessage() {}
 
 func (x *PathMapping) ProtoReflect() protoreflect.Message {
-	mi := &file_sbox_proto_msgTypes[4]
+	mi := &file_sbox_proto_msgTypes[5]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -356,7 +486,7 @@
 
 // Deprecated: Use PathMapping.ProtoReflect.Descriptor instead.
 func (*PathMapping) Descriptor() ([]byte, []int) {
-	return file_sbox_proto_rawDescGZIP(), []int{4}
+	return file_sbox_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *PathMapping) GetFrom() string {
@@ -383,7 +513,7 @@
 	0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6f, 0x75, 0x74,
 	0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
 	0x09, 0x52, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x44, 0x65, 0x70, 0x66, 0x69, 0x6c, 0x65,
-	0x22, 0xdc, 0x01, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x0b,
+	0x22, 0xb3, 0x02, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x0b,
 	0x63, 0x6f, 0x70, 0x79, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28,
 	0x0b, 0x32, 0x0a, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x52, 0x0a, 0x63,
 	0x6f, 0x70, 0x79, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x64,
@@ -396,23 +526,37 @@
 	0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x48,
 	0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x09, 0x72, 0x73, 0x70, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73,
 	0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x52, 0x73,
-	0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22,
-	0x4a, 0x0a, 0x04, 0x43, 0x6f, 0x70, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18,
-	0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74,
-	0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x65,
-	0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
-	0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x55, 0x0a, 0x07, 0x52,
-	0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01,
-	0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x61,
-	0x74, 0x68, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x11, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70,
-	0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
-	0x67, 0x73, 0x22, 0x31, 0x0a, 0x0b, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
-	0x67, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52,
-	0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28,
-	0x09, 0x52, 0x02, 0x74, 0x6f, 0x42, 0x23, 0x5a, 0x21, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
-	0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x2f,
-	0x73, 0x62, 0x6f, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12,
+	0x2b, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73,
+	0x62, 0x6f, 0x78, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56,
+	0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x28, 0x0a, 0x10,
+	0x64, 0x6f, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x65, 0x6e, 0x76,
+	0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x6f, 0x6e, 0x74, 0x49, 0x6e, 0x68, 0x65,
+	0x72, 0x69, 0x74, 0x45, 0x6e, 0x76, 0x22, 0x7e, 0x0a, 0x13, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f,
+	0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x12, 0x16, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x75, 0x6e, 0x73,
+	0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x05, 0x75, 0x6e, 0x73, 0x65,
+	0x74, 0x12, 0x1a, 0x0a, 0x07, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x42, 0x07, 0x0a,
+	0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x4a, 0x0a, 0x04, 0x43, 0x6f, 0x70, 0x79, 0x12, 0x12,
+	0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72,
+	0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02,
+	0x74, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62,
+	0x6c, 0x65, 0x22, 0x55, 0x0a, 0x07, 0x52, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a,
+	0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c,
+	0x65, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e,
+	0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e,
+	0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x70, 0x61, 0x74,
+	0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x31, 0x0a, 0x0b, 0x50, 0x61, 0x74,
+	0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d,
+	0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02,
+	0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x42, 0x23, 0x5a, 0x21,
+	0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6d,
+	0x64, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f,
 }
 
 var (
@@ -427,25 +571,27 @@
 	return file_sbox_proto_rawDescData
 }
 
-var file_sbox_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_sbox_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
 var file_sbox_proto_goTypes = []interface{}{
-	(*Manifest)(nil),    // 0: sbox.Manifest
-	(*Command)(nil),     // 1: sbox.Command
-	(*Copy)(nil),        // 2: sbox.Copy
-	(*RspFile)(nil),     // 3: sbox.RspFile
-	(*PathMapping)(nil), // 4: sbox.PathMapping
+	(*Manifest)(nil),            // 0: sbox.Manifest
+	(*Command)(nil),             // 1: sbox.Command
+	(*EnvironmentVariable)(nil), // 2: sbox.EnvironmentVariable
+	(*Copy)(nil),                // 3: sbox.Copy
+	(*RspFile)(nil),             // 4: sbox.RspFile
+	(*PathMapping)(nil),         // 5: sbox.PathMapping
 }
 var file_sbox_proto_depIdxs = []int32{
 	1, // 0: sbox.Manifest.commands:type_name -> sbox.Command
-	2, // 1: sbox.Command.copy_before:type_name -> sbox.Copy
-	2, // 2: sbox.Command.copy_after:type_name -> sbox.Copy
-	3, // 3: sbox.Command.rsp_files:type_name -> sbox.RspFile
-	4, // 4: sbox.RspFile.path_mappings:type_name -> sbox.PathMapping
-	5, // [5:5] is the sub-list for method output_type
-	5, // [5:5] is the sub-list for method input_type
-	5, // [5:5] is the sub-list for extension type_name
-	5, // [5:5] is the sub-list for extension extendee
-	0, // [0:5] is the sub-list for field type_name
+	3, // 1: sbox.Command.copy_before:type_name -> sbox.Copy
+	3, // 2: sbox.Command.copy_after:type_name -> sbox.Copy
+	4, // 3: sbox.Command.rsp_files:type_name -> sbox.RspFile
+	2, // 4: sbox.Command.env:type_name -> sbox.EnvironmentVariable
+	5, // 5: sbox.RspFile.path_mappings:type_name -> sbox.PathMapping
+	6, // [6:6] is the sub-list for method output_type
+	6, // [6:6] is the sub-list for method input_type
+	6, // [6:6] is the sub-list for extension type_name
+	6, // [6:6] is the sub-list for extension extendee
+	0, // [0:6] is the sub-list for field type_name
 }
 
 func init() { file_sbox_proto_init() }
@@ -479,7 +625,7 @@
 			}
 		}
 		file_sbox_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Copy); i {
+			switch v := v.(*EnvironmentVariable); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -491,7 +637,7 @@
 			}
 		}
 		file_sbox_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*RspFile); i {
+			switch v := v.(*Copy); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -503,6 +649,18 @@
 			}
 		}
 		file_sbox_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RspFile); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_sbox_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*PathMapping); i {
 			case 0:
 				return &v.state
@@ -515,13 +673,18 @@
 			}
 		}
 	}
+	file_sbox_proto_msgTypes[2].OneofWrappers = []interface{}{
+		(*EnvironmentVariable_Value)(nil),
+		(*EnvironmentVariable_Unset)(nil),
+		(*EnvironmentVariable_Inherit)(nil),
+	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_sbox_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   5,
+			NumMessages:   6,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/cmd/sbox/sbox_proto/sbox.proto b/cmd/sbox/sbox_proto/sbox.proto
index 2f0dcf0..1158554 100644
--- a/cmd/sbox/sbox_proto/sbox.proto
+++ b/cmd/sbox/sbox_proto/sbox.proto
@@ -51,6 +51,30 @@
   // A list of files that will be copied before the sandboxed command, and whose contents should be
   // copied as if they were listed in copy_before.
   repeated RspFile rsp_files = 6;
+
+  // The environment variables that will be set or unset while running the command.
+  // Also see dont_inherit_env.
+  repeated EnvironmentVariable env = 7;
+
+  // By default, all environment variables are inherited from the calling process, but may be
+  // replaced or unset by env. If dont_inherit_env is set, no environment variables will be
+  // inherited, and instead only the variables in env will be defined.
+  optional bool dont_inherit_env = 8;
+}
+
+message EnvironmentVariable {
+  // The name of the environment variable
+  required string name = 1;
+  oneof state {
+    // The value to set the environment variable to.
+    string value = 2;
+    // This environment variable should be unset in the command.
+    bool unset = 3;
+    // This environment variable should be inherited from the parent process.
+    // Can be combined with dont_inherit_env to only inherit certain environment
+    // variables.
+    bool inherit = 4;
+  }
 }
 
 // Copy describes a from-to pair of files to copy.  The paths may be relative, the root that they
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index e483fe4..988a57b 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -146,9 +146,16 @@
 				partitionNames[pName] = true
 			}
 			// Get size of the partition by reading the -size.txt file
-			pSize := fmt.Sprintf("$(cat %s)", sparseImageSizes[pName])
+			var pSize string
+			if size, hasSize := sparseImageSizes[pName]; hasSize {
+				pSize = fmt.Sprintf("$(cat %s)", size)
+			} else {
+				pSize = "0"
+			}
 			cmd.FlagWithArg("--partition=", fmt.Sprintf("%s:readonly:%s:%s", pName, pSize, gName))
-			cmd.FlagWithInput("--image="+pName+"=", sparseImages[pName])
+			if image, hasImage := sparseImages[pName]; hasImage {
+				cmd.FlagWithInput("--image="+pName+"=", image)
+			}
 		}
 	}
 
@@ -192,6 +199,9 @@
 // Add a rule that converts the filesystem for the given partition to the given rule builder. The
 // path to the sparse file and the text file having the size of the partition are returned.
 func sparseFilesystem(ctx android.ModuleContext, p partitionProperties, builder *android.RuleBuilder) (sparseImg android.OutputPath, sizeTxt android.OutputPath) {
+	if p.Filesystem == nil {
+		return
+	}
 	img := android.PathForModuleSrc(ctx, proptools.String(p.Filesystem))
 	name := proptools.String(p.Name)
 	sparseImg = android.PathForModuleOut(ctx, name+".img").OutputPath
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 7c71b77..4f1b320 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -17,7 +17,6 @@
 var (
 	SandboxingDenyModuleList = []string{
 		// go/keep-sorted start
-		"aidl_camera_build_version",
 		"com.google.pixel.camera.hal.manifest",
 		// go/keep-sorted end
 	}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 9195643..fd72d3c 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -243,13 +243,35 @@
 	}
 }
 
+var buildNumberAllowlistKey = android.NewOnceKey("genruleBuildNumberAllowlistKey")
+
 // This allowlist should be kept to the bare minimum, it's
 // intended for things that existed before the build number
 // was tightly controlled. Prefer using libbuildversion
 // via the use_version_lib property of cc modules.
-var genrule_build_number_allowlist = map[string]bool{
-	"build/soong/tests:gen":                   true,
-	"tools/tradefederation/core:tradefed_zip": true,
+// This is a function instead of a global map so that
+// soong plugins cannot add entries to the allowlist
+func isModuleInBuildNumberAllowlist(ctx android.ModuleContext) bool {
+	allowlist := ctx.Config().Once(buildNumberAllowlistKey, func() interface{} {
+		// Define the allowlist as a list and then copy it into a map so that
+		// gofmt doesn't change unnecessary lines trying to align the values of the map.
+		allowlist := []string{
+			// go/keep-sorted start
+			"build/soong/tests:gen",
+			"hardware/google/camera/common/hal/aidl_service:aidl_camera_build_version",
+			"tools/tradefederation/core:tradefed_zip",
+			"vendor/google/services/LyricCameraHAL/src/apex:com.google.pixel.camera.hal.manifest",
+			// go/keep-sorted end
+		}
+		allowlistMap := make(map[string]bool, len(allowlist))
+		for _, a := range allowlist {
+			allowlistMap[a] = true
+		}
+		return allowlistMap
+	}).(map[string]bool)
+
+	_, ok := allowlist[ctx.ModuleDir()+":"+ctx.ModuleName()]
+	return ok
 }
 
 // generateCommonBuildActions contains build action generation logic
@@ -320,7 +342,8 @@
 						ctx.ModuleErrorf("host tool %q missing output file", tool)
 						return
 					}
-					if specs := t.TransitivePackagingSpecs(); specs != nil {
+					if specs := android.OtherModuleProviderOrDefault(
+						ctx, t, android.InstallFilesProvider).TransitivePackagingSpecs.ToList(); specs != nil {
 						// If the HostToolProvider has PackgingSpecs, which are definitions of the
 						// required relative locations of the tool and its dependencies, use those
 						// instead.  They will be copied to those relative locations in the sbox
@@ -546,7 +569,7 @@
 		cmd.ImplicitTools(tools)
 		cmd.ImplicitPackagedTools(packagedTools)
 		if proptools.Bool(g.properties.Uses_order_only_build_number_file) {
-			if _, ok := genrule_build_number_allowlist[ctx.ModuleDir()+":"+ctx.ModuleName()]; !ok {
+			if !isModuleInBuildNumberAllowlist(ctx) {
 				ctx.ModuleErrorf("Only allowlisted modules may use uses_order_only_build_number_file: true")
 			}
 			cmd.OrderOnly(ctx.Config().BuildNumberFile(ctx))
@@ -624,7 +647,7 @@
 }
 
 // Collect information for opening IDE project files in java/jdeps.go.
-func (g *Module) IDEInfo(dpInfo *android.IdeInfo) {
+func (g *Module) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	dpInfo.Srcs = append(dpInfo.Srcs, g.Srcs().Strings()...)
 	for _, src := range g.properties.ResolvedSrcs {
 		if strings.HasPrefix(src, ":") {
diff --git a/java/aar.go b/java/aar.go
index e6ad502..42866f8 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -403,6 +403,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 +538,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 ") {
@@ -887,7 +890,6 @@
 	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{}
@@ -914,12 +916,12 @@
 	setOutputFiles(ctx, a.Library.Module)
 }
 
-func (a *AndroidLibrary) IDEInfo(dpInfo *android.IdeInfo) {
-	a.Library.IDEInfo(dpInfo)
-	a.aapt.IDEInfo(dpInfo)
+func (a *AndroidLibrary) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+	a.Library.IDEInfo(ctx, dpInfo)
+	a.aapt.IDEInfo(ctx, dpInfo)
 }
 
-func (a *aapt) IDEInfo(dpInfo *android.IdeInfo) {
+func (a *aapt) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	if a.rJar != nil {
 		dpInfo.Jars = append(dpInfo.Jars, a.rJar.String())
 	}
@@ -991,7 +993,7 @@
 	// Functionality common to Module and Import.
 	embeddableInModuleAndImport
 
-	providesTransitiveHeaderJars
+	providesTransitiveHeaderJarsForR8
 
 	properties AARImportProperties
 
@@ -1252,10 +1254,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,7 +1290,7 @@
 	android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n"))
 	a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
 
-	a.collectTransitiveHeaderJars(ctx)
+	a.collectTransitiveHeaderJarsForR8(ctx)
 
 	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 
@@ -1350,14 +1354,17 @@
 		a.headerJarFile = classpathFile
 	}
 
+	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),
+		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
 	})
 
@@ -1451,6 +1458,6 @@
 	return module
 }
 
-func (a *AARImport) IDEInfo(dpInfo *android.IdeInfo) {
+func (a *AARImport) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	dpInfo.Jars = append(dpInfo.Jars, a.headerJarFile.String(), a.rJar.String())
 }
diff --git a/java/app.go b/java/app.go
index 1ebf658..d5c220d 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1009,6 +1009,8 @@
 		ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
 	}
 
+	ctx.CheckbuildFile(a.outputFile)
+
 	a.buildAppDependencyInfo(ctx)
 
 	providePrebuiltInfo(ctx,
@@ -1243,9 +1245,9 @@
 
 var _ cc.Coverage = (*AndroidApp)(nil)
 
-func (a *AndroidApp) IDEInfo(dpInfo *android.IdeInfo) {
-	a.Library.IDEInfo(dpInfo)
-	a.aapt.IDEInfo(dpInfo)
+func (a *AndroidApp) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+	a.Library.IDEInfo(ctx, dpInfo)
+	a.aapt.IDEInfo(ctx, dpInfo)
 }
 
 func (a *AndroidApp) productCharacteristicsRROPackageName() string {
@@ -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 9101457..75b552f 100644
--- a/java/base.go
+++ b/java/base.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"encoding/gob"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -233,6 +234,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
@@ -593,6 +598,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 +744,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 +776,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))
 }
@@ -1265,10 +1285,12 @@
 		}
 		j.headerJarFile = combinedHeaderJarFile
 
+		ctx.CheckbuildFile(j.headerJarFile)
+
 		android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{
 			HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
-			TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
-			TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+			TransitiveLibsHeaderJarsForR8:       j.transitiveLibsHeaderJarsForR8,
+			TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
 			AidlIncludeDirs:                     j.exportAidlIncludeDirs,
 			ExportedPlugins:                     j.exportedPluginJars,
 			ExportedPluginClasses:               j.exportedPluginClasses,
@@ -1591,6 +1613,18 @@
 		outputFile = ravenizerOutput
 	}
 
+	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
+	}
+
 	// Check package restrictions if necessary.
 	if len(j.properties.Permitted_packages) > 0 {
 		// Time stamp file created by the package check rule.
@@ -1733,6 +1767,8 @@
 			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.
@@ -1776,13 +1812,14 @@
 
 	j.collectTransitiveSrcFiles(ctx, srcFiles)
 
-	ctx.CheckbuildFile(outputFile)
+	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,
+		TransitiveLibsHeaderJarsForR8:       j.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
 		ImplementationAndResourcesJars:      android.PathsIfNonNil(j.implementationAndResourcesJar),
 		ImplementationJars:                  android.PathsIfNonNil(j.implementationJarFile),
 		ResourceJars:                        android.PathsIfNonNil(j.resourceJar),
@@ -1944,6 +1981,8 @@
 	TransformJarsToJar(ctx, combinedHeaderJarOutputPath, "for turbine", jars, android.OptionalPath{},
 		false, nil, []string{"META-INF/TRANSITIVE"})
 
+	ctx.CheckbuildFile(combinedHeaderJarOutputPath)
+
 	return headerJar, combinedHeaderJarOutputPath
 }
 
@@ -1960,22 +1999,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 +2033,16 @@
 				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 {
@@ -2049,7 +2084,7 @@
 }
 
 // Collect information for opening IDE project files in java/jdeps.go.
-func (j *Module) IDEInfo(dpInfo *android.IdeInfo) {
+func (j *Module) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	// jarjar rules will repackage the sources. To prevent misleading results, IdeInfo should contain the
 	// repackaged jar instead of the input sources.
 	if j.expandJarjarRules != nil {
@@ -2273,7 +2308,7 @@
 
 	sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())
 
-	j.collectTransitiveHeaderJars(ctx)
+	j.collectTransitiveHeaderJarsForR8(ctx)
 	ctx.VisitDirectDeps(func(module android.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -2485,6 +2520,8 @@
 
 func init() {
 	android.SetJarJarPrefixHandler(mergeJarJarPrefixes)
+
+	gob.Register(BaseJarJarProviderData{})
 }
 
 // BaseJarJarProviderData contains information that will propagate across dependencies regardless of
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bce507a..bef3b58 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -836,7 +836,7 @@
 }
 
 // Collect information for opening IDE project files in java/jdeps.go.
-func (b *BootclasspathFragmentModule) IDEInfo(dpInfo *android.IdeInfo) {
+func (b *BootclasspathFragmentModule) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	dpInfo.Deps = append(dpInfo.Deps, b.properties.Contents...)
 }
 
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/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 63b69d0..7cc06fc 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -192,7 +192,7 @@
 // implement the following interface for IDE completion.
 var _ android.IDEInfo = (*DeviceHostConverter)(nil)
 
-func (d *DeviceHostConverter) IDEInfo(ideInfo *android.IdeInfo) {
+func (d *DeviceHostConverter) IDEInfo(ctx android.BaseModuleContext, ideInfo *android.IdeInfo) {
 	ideInfo.Deps = append(ideInfo.Deps, d.properties.Libs...)
 	ideInfo.Libs = append(ideInfo.Libs, d.properties.Libs...)
 }
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 a38642a..1c63e3f 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -88,18 +88,11 @@
 				entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
 				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
 				entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
-				// Unset LOCAL_SOONG_INSTALLED_MODULE so that this does not default to the primary .apex file
-				// Without this, installation of the dexpreopt artifacts get skipped
-				entries.SetString("LOCAL_SOONG_INSTALLED_MODULE", "")
 			},
 		},
 	}
 }
 
-func (install dexpreopterInstall) PackageFile(ctx android.ModuleContext) android.PackagingSpec {
-	return ctx.PackageFile(install.installDirOnDevice, install.installFileOnDevice, install.outputPathOnHost)
-}
-
 type Dexpreopter struct {
 	dexpreopter
 }
@@ -217,15 +210,19 @@
 		}
 	})
 	// Find the apex variant for this module
-	_, apexVariantsWithoutTestApexes, _ := android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+	var apexVariantsWithoutTestApexes []string
+	if apexInfo.BaseApexName != "" {
+		// This is a transitive dependency of an override_apex
+		apexVariantsWithoutTestApexes = []string{apexInfo.BaseApexName}
+	} else {
+		_, apexVariantsWithoutTestApexes, _ = android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+	}
 	disableSource := false
 	// find the selected apexes
 	for _, apexVariant := range apexVariantsWithoutTestApexes {
-		for _, selected := range psi.GetSelectedModulesForApiDomain(apexVariant) {
-			// If the apex_contribution for this api domain contains a prebuilt apex, disable the source variant
-			if strings.HasPrefix(selected, "prebuilt_com.google.android") {
-				disableSource = true
-			}
+		if len(psi.GetSelectedModulesForApiDomain(apexVariant)) > 0 {
+			// If the apex_contribution for this api domain is non-empty, disable the source variant
+			disableSource = true
 		}
 	}
 	return disableSource
@@ -492,6 +489,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
@@ -583,16 +581,20 @@
 				// Preopting of boot classpath jars in the ART APEX are handled in
 				// java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
 				// The installs will be handled by Make as sub-modules of the java library.
-				d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
+				di := dexpreopterInstall{
 					name:                arch + "-" + installBase,
 					moduleName:          libName,
 					outputPathOnHost:    install.From,
 					installDirOnDevice:  installPath,
 					installFileOnDevice: installBase,
-				})
+				}
+				ctx.InstallFile(di.installDirOnDevice, di.installFileOnDevice, di.outputPathOnHost)
+				d.builtInstalledForApex = append(d.builtInstalledForApex, di)
+
 			}
 		} 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_bootjars.go b/java/dexpreopt_bootjars.go
index a81ab83..a2e4734 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -558,6 +558,10 @@
 			apexVariationOfSelected := append(ctx.Target().Variations(), blueprint.Variation{Mutator: "apex", Variation: apex})
 			if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, selected) {
 				ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, selected)
+			} else if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, android.RemoveOptionalPrebuiltPrefix(selected)) {
+				// The prebuilt might have been renamed by prebuilt_rename mutator if the source module does not exist.
+				// Remove the prebuilt_ prefix.
+				ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, android.RemoveOptionalPrebuiltPrefix(selected))
 			}
 		}
 	}
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/droidstubs.go b/java/droidstubs.go
index d622903..6bcdf85 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -970,6 +970,15 @@
 		d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt")
 		cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO:  Change to ":api-lint"
 
+		// If UnflaggedApi issues have not already been configured then make sure that existing
+		// UnflaggedApi issues are reported as warnings but issues in new/changed code are treated as
+		// errors by the Build Warnings Aye Aye Analyzer in Gerrit.
+		// Once existing issues have been fixed this will be changed to error.
+		// TODO(b/362771529): Switch to --error
+		if !strings.Contains(cmd.String(), " UnflaggedApi ") {
+			cmd.Flag("--error-when-new UnflaggedApi")
+		}
+
 		// TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
 		if d.Name() != "android.car-system-stubs-docs" &&
 			d.Name() != "android.car-stubs-docs" {
diff --git a/java/java.go b/java/java.go
index 46344c8..8cc1085 100644
--- a/java/java.go
+++ b/java/java.go
@@ -259,10 +259,10 @@
 	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
-	TransitiveStaticLibsHeaderJars *android.DepSet[android.Path]
+	TransitiveStaticLibsHeaderJarsForR8 *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.
@@ -2404,15 +2404,15 @@
 	return al.SdkVersion(ctx).ApiLevel
 }
 
-func (al *ApiLibrary) IDEInfo(i *android.IdeInfo) {
-	i.Deps = append(i.Deps, al.ideDeps()...)
+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.SrcJars = append(i.SrcJars, al.stubsSrcJar.String())
 }
 
 // deps of java_api_library for module_bp_java_deps.json
-func (al *ApiLibrary) ideDeps() []string {
+func (al *ApiLibrary) ideDeps(ctx android.BaseModuleContext) []string {
 	ret := []string{}
 	ret = append(ret, al.properties.Libs...)
 	ret = append(ret, al.properties.Static_libs...)
@@ -2634,7 +2634,7 @@
 
 	var flags javaBuilderFlags
 
-	j.collectTransitiveHeaderJars(ctx)
+	j.collectTransitiveHeaderJarsForR8(ctx)
 	var staticJars android.Paths
 	var staticResourceJars android.Paths
 	var staticHeaderJars android.Paths
@@ -2735,6 +2735,8 @@
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
 
+	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 +2803,7 @@
 			if ctx.Failed() {
 				return
 			}
+			ctx.CheckbuildFile(dexOutputFile)
 
 			// Initialize the hiddenapi structure.
 			j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex)
@@ -2814,14 +2817,14 @@
 	}
 
 	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),
+		TransitiveLibsHeaderJarsForR8:       j.transitiveLibsHeaderJarsForR8,
+		TransitiveStaticLibsHeaderJarsForR8: j.transitiveStaticLibsHeaderJarsForR8,
+		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
 	})
 
@@ -2933,7 +2936,7 @@
 
 // Collect information for opening IDE project files in java/jdeps.go.
 
-func (j *Import) IDEInfo(dpInfo *android.IdeInfo) {
+func (j *Import) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	dpInfo.Jars = append(dpInfo.Jars, j.combinedHeaderFile.String())
 }
 
diff --git a/java/jdeps.go b/java/jdeps.go
index e856b37..c2ce503 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -57,27 +57,19 @@
 			return
 		}
 
-		ideInfoProvider, ok := module.(android.IDEInfo)
+		ideInfoProvider, ok := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
 		if !ok {
 			return
 		}
-		name := ideInfoProvider.BaseModuleName()
+		name := ideInfoProvider.BaseModuleName
 		ideModuleNameProvider, ok := module.(android.IDECustomizedModuleName)
 		if ok {
 			name = ideModuleNameProvider.IDECustomizedModuleName()
 		}
 
 		dpInfo := moduleInfos[name]
-		ideInfoProvider.IDEInfo(&dpInfo)
-		dpInfo.Deps = android.FirstUniqueStrings(dpInfo.Deps)
-		dpInfo.Srcs = android.FirstUniqueStrings(dpInfo.Srcs)
-		dpInfo.Aidl_include_dirs = android.FirstUniqueStrings(dpInfo.Aidl_include_dirs)
-		dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
-		dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
-		dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
+		dpInfo = dpInfo.Merge(ideInfoProvider)
 		dpInfo.Paths = []string{ctx.ModuleDir(module)}
-		dpInfo.Static_libs = android.FirstUniqueStrings(dpInfo.Static_libs)
-		dpInfo.Libs = android.FirstUniqueStrings(dpInfo.Libs)
 		moduleInfos[name] = dpInfo
 
 		mkProvider, ok := module.(android.AndroidMkDataProvider)
diff --git a/java/jdeps_test.go b/java/jdeps_test.go
index ff54da9..d282f19 100644
--- a/java/jdeps_test.go
+++ b/java/jdeps_test.go
@@ -32,9 +32,7 @@
 		}
 	`)
 	module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
-	dpInfo := &android.IdeInfo{}
-
-	module.IDEInfo(dpInfo)
+	dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
 
 	for _, expected := range []string{"Foo", "Bar"} {
 		if !android.InList(expected, dpInfo.Deps) {
@@ -54,9 +52,7 @@
 		}
 	`)
 	module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
-	dpInfo := &android.IdeInfo{}
-
-	module.IDEInfo(dpInfo)
+	dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
 
 	for _, expected := range []string{"Foo", "Bar"} {
 		if !android.InList(expected, dpInfo.Deps) {
@@ -66,26 +62,36 @@
 }
 
 func TestCollectJavaLibraryPropertiesAddScrs(t *testing.T) {
-	expected := []string{"Foo", "Bar"}
-	module := LibraryFactory().(*Library)
-	module.expandIDEInfoCompiledSrcs = append(module.expandIDEInfoCompiledSrcs, expected...)
-	dpInfo := &android.IdeInfo{}
+	ctx, _ := testJava(t,
+		`
+		java_library {
+			name: "javalib",
+			srcs: ["Foo.java", "Bar.java"],
+		}
+	`)
+	module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
+	dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
 
-	module.IDEInfo(dpInfo)
-
+	expected := []string{"Foo.java", "Bar.java"}
 	if !reflect.DeepEqual(dpInfo.Srcs, expected) {
 		t.Errorf("Library.IDEInfo() Srcs = %v, want %v", dpInfo.Srcs, expected)
 	}
 }
 
 func TestCollectJavaLibraryPropertiesAddAidlIncludeDirs(t *testing.T) {
+	ctx, _ := testJava(t,
+		`
+		java_library {
+			name: "javalib",
+			aidl: {
+				include_dirs: ["Foo", "Bar"],
+			},
+		}
+	`)
+	module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
+	dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
+
 	expected := []string{"Foo", "Bar"}
-	module := LibraryFactory().(*Library)
-	module.deviceProperties.Aidl.Include_dirs = append(module.deviceProperties.Aidl.Include_dirs, expected...)
-	dpInfo := &android.IdeInfo{}
-
-	module.IDEInfo(dpInfo)
-
 	if !reflect.DeepEqual(dpInfo.Aidl_include_dirs, expected) {
 		t.Errorf("Library.IDEInfo() Aidl_include_dirs = %v, want %v", dpInfo.Aidl_include_dirs, expected)
 	}
@@ -101,9 +107,8 @@
 		}
 	`)
 	module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
-	dpInfo := &android.IdeInfo{}
+	dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
 
-	module.IDEInfo(dpInfo)
 	android.AssertBoolEquals(t, "IdeInfo.Srcs of repackaged library should be empty", true, len(dpInfo.Srcs) == 0)
 	android.AssertStringEquals(t, "IdeInfo.Jar_rules of repackaged library should not be empty", "jarjar_rules.txt", dpInfo.Jarjar_rules[0])
 	if !android.SubstringInList(dpInfo.Jars, "soong/.intermediates/javalib/android_common/jarjar/turbine/javalib.jar") {
@@ -125,8 +130,7 @@
 		}
 	`)
 	module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
-	dpInfo := &android.IdeInfo{}
+	dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey)
 
-	module.IDEInfo(dpInfo)
 	android.AssertStringListContains(t, "IdeInfo.Deps should contain versioned sdk module", dpInfo.Deps, "sdk_public_29_android")
 }
diff --git a/java/sdk.go b/java/sdk.go
index dd198ac..4537f19 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -308,10 +308,12 @@
 
 			rule.Command().
 				Text("rm -f").Output(aidl)
+
 			rule.Command().
 				BuiltTool("sdkparcelables").
 				Input(jar).
-				Output(aidl)
+				Output(aidl).
+				Flag("--guarantee_stable")
 
 			aidls = append(aidls, aidl)
 		}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 2fe629f..98b65dd 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()})
 	}
 
@@ -2099,6 +2104,7 @@
 		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
 		props.Dist.Tag = proptools.StringPtr(".jar")
 	}
+	props.Is_stubs_module = proptools.BoolPtr(true)
 
 	return props
 }
@@ -3599,8 +3605,8 @@
 }
 
 // TODO(b/358613520): This can be removed when modules are no longer allowed to depend on the top-level library.
-func (s *SdkLibrary) IDEInfo(dpInfo *android.IdeInfo) {
-	s.Library.IDEInfo(dpInfo)
+func (s *SdkLibrary) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
+	s.Library.IDEInfo(ctx, dpInfo)
 	if s.implLibraryModule != nil {
 		dpInfo.Deps = append(dpInfo.Deps, s.implLibraryModule.Name())
 	} else {
diff --git a/java/system_modules.go b/java/system_modules.go
index 5b00079..f89bf9e 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -307,7 +307,7 @@
 // implement the following interface for IDE completion.
 var _ android.IDEInfo = (*SystemModules)(nil)
 
-func (s *SystemModules) IDEInfo(ideInfo *android.IdeInfo) {
+func (s *SystemModules) IDEInfo(ctx android.BaseModuleContext, ideInfo *android.IdeInfo) {
 	ideInfo.Deps = append(ideInfo.Deps, s.properties.Libs...)
 	ideInfo.Libs = append(ideInfo.Libs, s.properties.Libs...)
 }
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index bad2cf1..924abd4 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -216,6 +216,11 @@
 	return tag == systemServerClasspathFragmentContentDepTag
 }
 
+// The dexpreopt artifacts of apex system server jars are installed onto system image.
+func (s systemServerClasspathFragmentContentDependencyTag) InstallDepNeeded() bool {
+	return true
+}
+
 func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
 	module := ctx.Module()
 	_, isSourceModule := module.(*SystemServerClasspathModule)
@@ -234,7 +239,7 @@
 }
 
 // Collect information for opening IDE project files in java/jdeps.go.
-func (s *SystemServerClasspathModule) IDEInfo(dpInfo *android.IdeInfo) {
+func (s *SystemServerClasspathModule) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
 	dpInfo.Deps = append(dpInfo.Deps, s.properties.Contents...)
 	dpInfo.Deps = append(dpInfo.Deps, s.properties.Standalone_contents...)
 }
diff --git a/java/testing.go b/java/testing.go
index 0e85022..03dcee6 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)
 	}
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 533ec62..05b99fd 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -98,6 +98,7 @@
 	builder.Command().
 		BuiltTool("conv_linker_config").
 		Flag("proto").
+		Flag("--force").
 		FlagWithInput("-s ", input).
 		FlagWithOutput("-o ", interimOutput)
 
diff --git a/rust/config/global.go b/rust/config/global.go
index 0c5eb85..990a643 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var (
 	pctx = android.NewPackageContext("android/soong/rust/config")
 
-	RustDefaultVersion = "1.79.0"
+	RustDefaultVersion = "1.80.1"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/rust/library.go b/rust/library.go
index 50d5a72..7db8f36 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -70,6 +70,10 @@
 
 	// Whether this library is part of the Rust toolchain sysroot.
 	Sysroot *bool
+
+	// Exclude this rust_ffi target from being included in APEXes.
+	// TODO(b/362509506): remove this once stubs are properly supported by rust_ffi targets.
+	Apex_exclude *bool
 }
 
 type LibraryMutatedProperties struct {
@@ -122,6 +126,7 @@
 	shared() bool
 	sysroot() bool
 	source() bool
+	apexExclude() bool
 
 	// Returns true if the build options for the module have selected a particular build type
 	buildRlib() bool
@@ -186,6 +191,10 @@
 	return library.MutatedProperties.VariantIsSource
 }
 
+func (library *libraryDecorator) apexExclude() bool {
+	return Bool(library.Properties.Apex_exclude)
+}
+
 func (library *libraryDecorator) buildRlib() bool {
 	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
 }
diff --git a/rust/rust.go b/rust/rust.go
index 3402adc..240c221 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -294,6 +294,15 @@
 	return mod.StaticallyLinked()
 }
 
+func (mod *Module) ApexExclude() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.apexExclude()
+		}
+	}
+	return false
+}
+
 func (mod *Module) Object() bool {
 	// Rust has no modules which produce only object files.
 	return false
@@ -938,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()})
 	}
 
@@ -948,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() {
@@ -1863,6 +1871,10 @@
 		return false
 	}
 
+	if rustDep, ok := dep.(*Module); ok && rustDep.ApexExclude() {
+		return false
+	}
+
 	return true
 }
 
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..9379f36 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,22 @@
 		// 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 is safe for (1) since these are stub libraries.
+		// This is ok for (2) since these are host and test exports and are intended for
+		// ART development.
+		// TODO (b/361303067): This can be removed if ART uses full manifests.
+		m.AddProperty("visibility", []string{"//visibility:public"})
 	}
 
 	// Where available copy apex_available properties from the member.
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index bbac2db..2bad5a8 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -33,6 +33,7 @@
 	"kernel/tests/",
 	"libcore/",
 	"libnativehelper/",
+	"packages/",
 	"pdk/",
 	"prebuilts/",
 	"sdk/",
diff --git a/ui/build/config.go b/ui/build/config.go
index 64ac1a0..711f325 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
@@ -350,6 +351,9 @@
 
 		// Use config.useN2 instead.
 		"SOONG_USE_N2",
+
+		// Leaks usernames into environment.
+		"HOME",
 	)
 
 	if ret.UseGoma() || ret.ForceUseGoma() {
@@ -361,12 +365,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 +430,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 +448,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 +459,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}) {
@@ -1041,7 +1046,7 @@
 
 func (c *configImpl) UsedEnvFile(tag string) string {
 	if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
-		return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+"."+tag)
+		return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+c.CoverageSuffix()+"."+tag)
 	}
 	return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag)
 }
@@ -1149,6 +1154,13 @@
 	return "", fmt.Errorf("TARGET_PRODUCT is not defined")
 }
 
+func (c *configImpl) CoverageSuffix() string {
+	if v := c.environ.IsEnvTrue("EMMA_INSTRUMENT"); v {
+		return ".coverage"
+	}
+	return ""
+}
+
 func (c *configImpl) TargetDevice() string {
 	return c.targetDevice
 }
@@ -1289,6 +1301,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() {
@@ -1520,7 +1545,7 @@
 	if err != nil {
 		return filepath.Join(c.SoongOutDir(), "soong.variables")
 	} else {
-		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
+		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+c.CoverageSuffix()+".variables")
 	}
 }
 
@@ -1529,7 +1554,7 @@
 	if err != nil {
 		return filepath.Join(c.SoongOutDir(), "soong.extra.variables")
 	} else {
-		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".extra.variables")
+		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+c.CoverageSuffix()+".extra.variables")
 	}
 }
 
@@ -1538,7 +1563,7 @@
 	if err != nil {
 		return filepath.Join(c.SoongOutDir(), "build.ninja")
 	} else {
-		return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
+		return filepath.Join(c.SoongOutDir(), "build."+targetProduct+c.CoverageSuffix()+".ninja")
 	}
 }
 
@@ -1550,11 +1575,11 @@
 }
 
 func (c *configImpl) SoongAndroidMk() string {
-	return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+".mk")
+	return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+c.CoverageSuffix()+".mk")
 }
 
 func (c *configImpl) SoongMakeVarsMk() string {
-	return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
+	return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+c.CoverageSuffix()+".mk")
 }
 
 func (c *configImpl) SoongBuildMetrics() string {
@@ -1715,6 +1740,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/kati.go b/ui/build/kati.go
index a0efd2c..5743ff7 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -41,7 +41,7 @@
 // arguments.
 func genKatiSuffix(ctx Context, config Config) {
 	// Construct the base suffix.
-	katiSuffix := "-" + config.TargetProduct()
+	katiSuffix := "-" + config.TargetProduct() + config.CoverageSuffix()
 
 	// Append kati arguments to the suffix.
 	if args := config.KatiArgs(); len(args) > 0 {
diff --git a/ui/build/path.go b/ui/build/path.go
index 51ebff1..075bf2e 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
@@ -121,6 +137,7 @@
 	// 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
 }
 
@@ -265,5 +282,6 @@
 	// 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() {