Merge "Revert "Add install_symlink_host Soong module type"" into main
diff --git a/Android.bp b/Android.bp
index 535246e..ab8e4a0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3,6 +3,7 @@
     default_visibility: [
         "//build/soong:__subpackages__",
     ],
+    default_team: "trendy_team_build",
 }
 
 subdirs = [
@@ -116,6 +117,11 @@
     visibility: ["//visibility:public"],
 }
 
+art_boot_images {
+    name: "art_boot_images",
+    visibility: ["//art:__subpackages__"],
+}
+
 // Pseudo-test that's run on checkbuilds to ensure that get_clang_version can
 // parse cc/config/global.go.
 genrule {
@@ -136,9 +142,13 @@
     visibility: ["//visibility:public"],
 }
 
+// TODO(b/365670526): remove the cuttlefish visibility once it is fully removed
 product_config {
     name: "product_config",
-    visibility: ["//device/google/cuttlefish/system_image"],
+    visibility: [
+        "//build/make/target/product/generic",
+        "//device/google/cuttlefish/system_image",
+    ],
 }
 
 build_prop {
@@ -147,6 +157,7 @@
     product_config: ":product_config",
     // Currently, only microdroid and cf system image can refer to system-build.prop
     visibility: [
+        "//build/make/target/product/generic",
         "//device/google/cuttlefish/system_image",
         "//packages/modules/Virtualization/build/microdroid",
     ],
diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go
index 98d288f..ed0b3ed 100644
--- a/aconfig/codegen/init.go
+++ b/aconfig/codegen/init.go
@@ -32,6 +32,7 @@
 				`    --mode ${mode}` +
 				`    --cache ${in}` +
 				`    --out ${out}.tmp` +
+				`    --allow-instrumentation ${debug}` +
 				` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
 				` && rm -rf ${out}.tmp`,
 			CommandDeps: []string{
@@ -39,7 +40,7 @@
 				"$soong_zip",
 			},
 			Restat: true,
-		}, "mode")
+		}, "mode", "debug")
 
 	// For cc_aconfig_library: Generate C++ library
 	cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index 673ac2a..ebca413 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -20,6 +20,7 @@
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
+	"strconv"
 )
 
 type declarationsTagType struct {
@@ -71,6 +72,7 @@
 		module.AddSharedLibrary("aconfig-annotations-lib")
 		// TODO(b/303773055): Remove the annotation after access issue is resolved.
 		module.AddSharedLibrary("unsupportedappusage")
+		module.AddSharedLibrary("aconfig_storage_reader_java")
 	}
 }
 
@@ -102,7 +104,8 @@
 		Output:      srcJarPath,
 		Description: "aconfig.srcjar",
 		Args: map[string]string{
-			"mode": mode,
+			"mode":  mode,
+			"debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
 		},
 	})
 
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index d2a9622..b902f8b 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -107,7 +107,7 @@
 	mergedAconfigFiles := make(map[string]Paths)
 	mergedModeInfos := make(map[string]ModeInfo)
 
-	ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
+	ctx.VisitDirectDeps(func(module Module) {
 		if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
 			maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
 		}
diff --git a/android/apex.go b/android/apex.go
index 114fe29..79ab13c 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -989,8 +989,8 @@
 // Function called while walking an APEX's payload dependencies.
 //
 // Return true if the `to` module should be visited, false otherwise.
-type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
-type WalkPayloadDepsFunc func(ctx ModuleContext, do PayloadDepsCallback)
+type PayloadDepsCallback func(ctx BaseModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
+type WalkPayloadDepsFunc func(ctx BaseModuleContext, do PayloadDepsCallback)
 
 // ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
 type ModuleWithMinSdkVersionCheck interface {
@@ -1017,7 +1017,7 @@
 		return
 	}
 
-	walk(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
+	walk(ctx, func(ctx BaseModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
 		if externalDep {
 			// external deps are outside the payload boundary, which is "stable"
 			// interface. We don't have to check min_sdk_version for external
diff --git a/android/arch.go b/android/arch.go
index 942727a..d9ecb50 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -138,6 +138,13 @@
 	return a.Name
 }
 
+func (a ArchType) Bitness() string {
+	if a.Multilib == "lib32" {
+		return "32"
+	}
+	return "64"
+}
+
 const COMMON_VARIANT = "common"
 
 var (
diff --git a/android/arch_list.go b/android/arch_list.go
index 9501c87..389f194 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -29,6 +29,7 @@
 		"armv9-2a",
 	},
 	X86: {
+		"alderlake",
 		"amberlake",
 		"atom",
 		"broadwell",
@@ -53,6 +54,7 @@
 		"x86_64",
 	},
 	X86_64: {
+		"alderlake",
 		"amberlake",
 		"broadwell",
 		"goldmont",
@@ -110,9 +112,6 @@
 }
 
 var archFeatures = map[ArchType][]string{
-	Arm: {
-		"neon",
-	},
 	Arm64: {
 		"dotprod",
 	},
@@ -142,17 +141,6 @@
 }
 
 var androidArchFeatureMap = map[ArchType]map[string][]string{
-	Arm: {
-		"armv7-a-neon": {
-			"neon",
-		},
-		"armv8-a": {
-			"neon",
-		},
-		"armv8-2a": {
-			"neon",
-		},
-	},
 	Arm64: {
 		"armv8-2a-dotprod": {
 			"dotprod",
@@ -165,6 +153,16 @@
 		},
 	},
 	X86: {
+		"alderlake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
 		"amberlake": {
 			"ssse3",
 			"sse4",
@@ -341,6 +339,16 @@
 			"sse4_2",
 			"popcnt",
 		},
+		"alderlake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
 		"amberlake": {
 			"ssse3",
 			"sse4",
diff --git a/android/base_module_context.go b/android/base_module_context.go
index bb81377..c7d7573 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -113,31 +113,22 @@
 	// the first DependencyTag.
 	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
 
-	// VisitDirectDepsBlueprint calls visit for each direct dependency.  If there are multiple
+	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the
+	// dependencies are disabled.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
+	VisitDirectDeps(visit func(Module))
+
+	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
 	// direct dependencies on the same module visit will be called multiple times on that module
 	// and OtherModuleDependencyTag will return a different tag for each.
 	//
 	// The Module passed to the visit function should not be retained outside of the visit
 	// function, it may be invalidated by future mutators.
-	VisitDirectDepsBlueprint(visit func(blueprint.Module))
-
-	// VisitDirectDepsIgnoreBlueprint calls visit for each direct dependency.  If there are multiple
-	// direct dependencies on the same module visit will be called multiple times on that module
-	// and OtherModuleDependencyTag will return a different tag for each.  It silently ignores any
-	// dependencies that are not an android.Module.
-	//
-	// The Module passed to the visit function should not be retained outside of the visit
-	// function, it may be invalidated by future mutators.
-	VisitDirectDepsIgnoreBlueprint(visit func(Module))
-
-	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
-	// direct dependencies on the same module visit will be called multiple times on that module
-	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the
-	// dependencies are not an android.Module.
-	//
-	// The Module passed to the visit function should not be retained outside of the visit
-	// function, it may be invalidated by future mutators.
-	VisitDirectDeps(visit func(Module))
+	VisitDirectDepsAllowDisabled(visit func(Module))
 
 	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
 
@@ -164,17 +155,6 @@
 	// invalidated by future mutators.
 	WalkDeps(visit func(child, parent Module) bool)
 
-	// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
-	// tree in top down order.  visit may be called multiple times for the same (child, parent)
-	// pair if there are multiple direct dependencies between the child and parent with different
-	// tags.  OtherModuleDependencyTag will return the tag for the currently visited
-	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down
-	// to child.
-	//
-	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
-	// invalidated by future mutators.
-	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
-
 	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
 	// and returns a top-down dependency path from a start module to current child module.
 	GetWalkPath() []Module
@@ -220,10 +200,6 @@
 	// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
 	// can be used to evaluate the final value of Configurable properties.
 	EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue
-
-	// HasMutatorFinished returns true if the given mutator has finished running.
-	// It will panic if given an invalid mutator name.
-	HasMutatorFinished(mutatorName string) bool
 }
 
 type baseModuleContext struct {
@@ -274,10 +250,6 @@
 	b.bp.SetProvider(provider, value)
 }
 
-func (b *baseModuleContext) HasMutatorFinished(mutatorName string) bool {
-	return b.bp.HasMutatorFinished(mutatorName)
-}
-
 func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
 	return b.bp.GetDirectDepWithTag(name, tag)
 }
@@ -319,7 +291,7 @@
 	return true
 }
 
-func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool, ignoreBlueprint bool) Module {
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
 	aModule, _ := module.(Module)
 
 	if !strict {
@@ -327,10 +299,7 @@
 	}
 
 	if aModule == nil {
-		if !ignoreBlueprint {
-			b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag)
-		}
-		return nil
+		panic(fmt.Errorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag))
 	}
 
 	if !aModule.Enabled(b) {
@@ -353,15 +322,8 @@
 
 func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep {
 	var deps []dep
-	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil {
-			if aModule.base().BaseModuleName() == name {
-				returnedTag := b.bp.OtherModuleDependencyTag(aModule)
-				if tag == nil || returnedTag == tag {
-					deps = append(deps, dep{aModule, returnedTag})
-				}
-			}
-		} else if b.bp.OtherModuleName(module) == name {
+	b.VisitDirectDeps(func(module Module) {
+		if module.base().BaseModuleName() == name {
 			returnedTag := b.bp.OtherModuleDependencyTag(module)
 			if tag == nil || returnedTag == tag {
 				deps = append(deps, dep{module, returnedTag})
@@ -404,11 +366,9 @@
 
 func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
 	var deps []Module
-	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil {
-			if b.bp.OtherModuleDependencyTag(aModule) == tag {
-				deps = append(deps, aModule)
-			}
+	b.VisitDirectDeps(func(module Module) {
+		if b.bp.OtherModuleDependencyTag(module) == tag {
+			deps = append(deps, module)
 		}
 	})
 	return deps
@@ -421,30 +381,24 @@
 	return b.getDirectDepFirstTag(name)
 }
 
-func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
-	b.bp.VisitDirectDeps(visit)
-}
-
 func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
-	b.visitDirectDeps(visit, false)
-}
-
-func (b *baseModuleContext) VisitDirectDepsIgnoreBlueprint(visit func(Module)) {
-	b.visitDirectDeps(visit, true)
-}
-
-func (b *baseModuleContext) visitDirectDeps(visit func(Module), ignoreBlueprint bool) {
 	b.bp.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, ignoreBlueprint); aModule != nil {
+		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 			visit(aModule)
 		}
 	})
 }
 
+func (b *baseModuleContext) VisitDirectDepsAllowDisabled(visit func(Module)) {
+	b.bp.VisitDirectDeps(func(module blueprint.Module) {
+		visit(module.(Module))
+	})
+}
+
 func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
 	b.bp.VisitDirectDeps(func(module blueprint.Module) {
 		if b.bp.OtherModuleDependencyTag(module) == tag {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 				visit(aModule)
 			}
 		}
@@ -455,7 +409,7 @@
 	b.bp.VisitDirectDepsIf(
 		// pred
 		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 				return pred(aModule)
 			} else {
 				return false
@@ -469,7 +423,7 @@
 
 func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
 	b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 			visit(aModule)
 		}
 	})
@@ -479,7 +433,7 @@
 	b.bp.VisitDepsDepthFirstIf(
 		// pred
 		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 				return pred(aModule)
 			} else {
 				return false
@@ -491,10 +445,6 @@
 		})
 }
 
-func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
-	b.bp.WalkDeps(visit)
-}
-
 func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
 	b.walkPath = []Module{b.Module()}
 	b.tagPath = []blueprint.DependencyTag{}
diff --git a/android/config.go b/android/config.go
index 00fc823..9f92fff 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1252,7 +1252,7 @@
 }
 
 func (c *config) LibartImgHostBaseAddress() string {
-	return "0x60000000"
+	return "0x70000000"
 }
 
 func (c *config) LibartImgDeviceBaseAddress() string {
@@ -1278,6 +1278,7 @@
 	}
 	return false
 }
+
 func (c *config) EnforceRROExcludedOverlay(path string) bool {
 	excluded := c.productVariables.EnforceRROExcludedOverlays
 	if len(excluded) > 0 {
@@ -1286,6 +1287,11 @@
 	return false
 }
 
+func (c *config) EnforceRROGlobally() bool {
+	enforceList := c.productVariables.EnforceRROTargets
+	return InList("*", enforceList)
+}
+
 func (c *config) ExportedNamespaces() []string {
 	return append([]string(nil), c.productVariables.NamespacesToExport...)
 }
@@ -1691,14 +1697,6 @@
 	return Bool(c.productVariables.EnforceProductPartitionInterface)
 }
 
-func (c *config) EnforceInterPartitionJavaSdkLibrary() bool {
-	return Bool(c.productVariables.EnforceInterPartitionJavaSdkLibrary)
-}
-
-func (c *config) InterPartitionJavaLibraryAllowList() []string {
-	return c.productVariables.InterPartitionJavaLibraryAllowList
-}
-
 func (c *config) ProductHiddenAPIStubs() []string {
 	return c.productVariables.ProductHiddenAPIStubs
 }
diff --git a/android/container.go b/android/container.go
index c048d6c..2a3777b 100644
--- a/android/container.go
+++ b/android/container.go
@@ -479,7 +479,7 @@
 func checkContainerViolations(ctx ModuleContext) {
 	if _, ok := ctx.Module().(InstallableModule); ok {
 		containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
-		ctx.VisitDirectDepsIgnoreBlueprint(func(dep Module) {
+		ctx.VisitDirectDeps(func(dep Module) {
 			if !dep.Enabled(ctx) {
 				return
 			}
diff --git a/android/early_module_context.go b/android/early_module_context.go
index 23f4c90..11de771 100644
--- a/android/early_module_context.go
+++ b/android/early_module_context.go
@@ -93,6 +93,10 @@
 	// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
 	// default SimpleNameInterface if Context.SetNameInterface was not called.
 	Namespace() *Namespace
+
+	// HasMutatorFinished returns true if the given mutator has finished running.
+	// It will panic if given an invalid mutator name.
+	HasMutatorFinished(mutatorName string) bool
 }
 
 // Deprecated: use EarlyModuleContext instead
@@ -175,3 +179,7 @@
 func (e *earlyModuleContext) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) {
 	e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args...)
 }
+
+func (e *earlyModuleContext) HasMutatorFinished(mutatorName string) bool {
+	return e.EarlyModuleContext.HasMutatorFinished(mutatorName)
+}
diff --git a/android/hooks.go b/android/hooks.go
index 2ad3b5f..bd2fa5e 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -95,10 +95,17 @@
 
 type createModuleContext interface {
 	Module() Module
+	HasMutatorFinished(mutatorName string) bool
 	createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module
 }
 
 func createModule(ctx createModuleContext, factory ModuleFactory, ext string, props ...interface{}) Module {
+	if ctx.HasMutatorFinished("defaults") {
+		// Creating modules late is oftentimes problematic, because they don't have earlier
+		// mutators run on them. Prevent making modules after the defaults mutator has run.
+		panic("Cannot create a module after the defaults mutator has finished")
+	}
+
 	inherited := []interface{}{&ctx.Module().base().commonProperties}
 
 	var typeName string
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 0ac975f..f925638 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -63,11 +63,7 @@
 	var allDepOutputFiles Paths
 	var allDepMetadataDepSets []*DepSet[Path]
 
-	ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
-		dep, _ := bpdep.(Module)
-		if dep == nil {
-			return
-		}
+	ctx.VisitDirectDeps(func(dep Module) {
 		if !dep.Enabled(ctx) {
 			return
 		}
diff --git a/android/module.go b/android/module.go
index d6c129a..1866d7a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1861,10 +1861,8 @@
 
 	if m.Enabled(ctx) {
 		// ensure all direct android.Module deps are enabled
-		ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
-			if m, ok := bm.(Module); ok {
-				ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps, false)
-			}
+		ctx.VisitDirectDeps(func(m Module) {
+			ctx.validateAndroidModule(m, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps)
 		})
 
 		if m.Device() {
diff --git a/android/mutator.go b/android/mutator.go
index 9404945..434e3ba 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -26,7 +26,7 @@
 //   run Pre-deps mutators
 //   run depsMutator
 //   run PostDeps mutators
-//   run FinalDeps mutators (CreateVariations disallowed in this phase)
+//   run FinalDeps mutators (TransitionMutators disallowed in this phase)
 //   continue on to GenerateAndroidBuildActions
 
 // collateGloballyRegisteredMutators constructs the list of mutators that have been registered
@@ -231,36 +231,6 @@
 	// module's dependency list.
 	AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
 
-	// CreateVariations splits  a module into multiple variants, one for each name in the variationNames
-	// parameter.  It returns a list of new modules in the same order as the variationNames
-	// list.
-	//
-	// If any of the dependencies of the module being operated on were already split
-	// by calling CreateVariations with the same name, the dependency will automatically
-	// be updated to point the matching variant.
-	//
-	// If a module is split, and then a module depending on the first module is not split
-	// when the Mutator is later called on it, the dependency of the depending module will
-	// automatically be updated to point to the first variant.
-	CreateVariations(...string) []Module
-
-	// CreateLocationVariations splits a module into multiple variants, one for each name in the variantNames
-	// parameter.  It returns a list of new modules in the same order as the variantNames
-	// list.
-	//
-	// Local variations do not affect automatic dependency resolution - dependencies added
-	// to the split module via deps or DynamicDependerModule must exactly match a variant
-	// that contains all the non-local variations.
-	CreateLocalVariations(...string) []Module
-
-	// SetDependencyVariation sets all dangling dependencies on the current module to point to the variation
-	// with given name. This function ignores the default variation set by SetDefaultDependencyVariation.
-	SetDependencyVariation(string)
-
-	// SetDefaultDependencyVariation sets the default variation when a dangling reference is detected
-	// during the subsequent calls on Create*Variations* functions. To reset, set it to nil.
-	SetDefaultDependencyVariation(*string)
-
 	// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
 	// argument to select which variant of the dependency to use.  It returns a slice of modules for
 	// each dependency (some entries may be nil).  A variant of the dependency must exist that matches
@@ -287,12 +257,6 @@
 	// be ordered correctly for all future mutator passes.
 	AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []blueprint.Module
 
-	// AddInterVariantDependency adds a dependency between two variants of the same module.  Variants are always
-	// ordered in the same orderas they were listed in CreateVariations, and AddInterVariantDependency does not change
-	// that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps,
-	// WalkDeps, etc.
-	AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
-
 	// ReplaceDependencies finds all the variants of the module with the specified name, then
 	// replaces all dependencies onto those variants with the current variant of this module.
 	// Replacements don't take effect until after the mutator pass is finished.
@@ -303,30 +267,6 @@
 	// as long as the supplied predicate returns true.
 	// Replacements don't take effect until after the mutator pass is finished.
 	ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate)
-
-	// AliasVariation takes a variationName that was passed to CreateVariations for this module,
-	// and creates an alias from the current variant (before the mutator has run) to the new
-	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
-	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
-	// be used to add dependencies on the newly created variant using the variant map from
-	// before CreateVariations was run.
-	AliasVariation(variationName string)
-
-	// CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this
-	// module, and creates an alias from a new fromVariationName variant the toVariationName
-	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
-	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
-	// be used to add dependencies on the toVariationName variant using the fromVariationName
-	// variant.
-	CreateAliasVariation(fromVariationName, toVariationName string)
-
-	// SetVariationProvider sets the value for a provider for the given newly created variant of
-	// the current module, i.e. one of the Modules returned by CreateVariations..  It panics if
-	// not called during the appropriate mutator or GenerateBuildActions pass for the provider,
-	// if the value is not of the appropriate type, or if the module is not a newly created
-	// variant of the current module.  The value should not be modified after being passed to
-	// SetVariationProvider.
-	SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{})
 }
 
 // An outgoingTransitionContextImpl and incomingTransitionContextImpl is created for every dependency of every module
@@ -763,51 +703,6 @@
 	}
 	b.bp.AddReverseDependency(module, tag, name)
 }
-
-func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []Module {
-	if b.finalPhase {
-		panic("CreateVariations not allowed in FinalDepsMutators")
-	}
-
-	modules := b.bp.CreateVariations(variations...)
-
-	aModules := make([]Module, len(modules))
-	for i := range variations {
-		aModules[i] = modules[i].(Module)
-		base := aModules[i].base()
-		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
-		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
-	}
-
-	return aModules
-}
-
-func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []Module {
-	if b.finalPhase {
-		panic("CreateLocalVariations not allowed in FinalDepsMutators")
-	}
-
-	modules := b.bp.CreateLocalVariations(variations...)
-
-	aModules := make([]Module, len(modules))
-	for i := range variations {
-		aModules[i] = modules[i].(Module)
-		base := aModules[i].base()
-		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
-		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
-	}
-
-	return aModules
-}
-
-func (b *bottomUpMutatorContext) SetDependencyVariation(variation string) {
-	b.bp.SetDependencyVariation(variation)
-}
-
-func (b *bottomUpMutatorContext) SetDefaultDependencyVariation(variation *string) {
-	b.bp.SetDefaultDependencyVariation(variation)
-}
-
 func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag,
 	names ...string) []blueprint.Module {
 	if b.baseModuleContext.checkedMissingDeps() {
@@ -825,10 +720,6 @@
 	return b.bp.AddFarVariationDependencies(variations, tag, names...)
 }
 
-func (b *bottomUpMutatorContext) AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module) {
-	b.bp.AddInterVariantDependency(tag, from, to)
-}
-
 func (b *bottomUpMutatorContext) ReplaceDependencies(name string) {
 	if b.baseModuleContext.checkedMissingDeps() {
 		panic("Adding deps not allowed after checking for missing deps")
@@ -842,15 +733,3 @@
 	}
 	b.bp.ReplaceDependenciesIf(name, predicate)
 }
-
-func (b *bottomUpMutatorContext) AliasVariation(variationName string) {
-	b.bp.AliasVariation(variationName)
-}
-
-func (b *bottomUpMutatorContext) CreateAliasVariation(fromVariationName, toVariationName string) {
-	b.bp.CreateAliasVariation(fromVariationName, toVariationName)
-}
-
-func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{}) {
-	b.bp.SetVariationProvider(module, provider, value)
-}
diff --git a/android/mutator_test.go b/android/mutator_test.go
index b3ef00f..5d4074a 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -287,7 +287,7 @@
 	AssertDeepEquals(t, "final", finalWant, finalGot)
 }
 
-func TestNoCreateVariationsInFinalDeps(t *testing.T) {
+func TestTransitionMutatorInFinalDeps(t *testing.T) {
 	GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
diff --git a/android/paths.go b/android/paths.go
index 0d94f03..1c8258e 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -92,7 +92,7 @@
 type ModuleWithDepsPathContext interface {
 	EarlyModulePathContext
 	OtherModuleProviderContext
-	VisitDirectDepsBlueprint(visit func(blueprint.Module))
+	VisitDirectDeps(visit func(Module))
 	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
 	HasMutatorFinished(mutatorName string) bool
 }
@@ -598,7 +598,7 @@
 	// create the tag here as was supplied to create the tag when the dependency was added so that
 	// this finds the matching dependency module.
 	expectedTag := sourceOrOutputDepTag(moduleName, tag)
-	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+	ctx.VisitDirectDeps(func(module Module) {
 		depTag := ctx.OtherModuleDependencyTag(module)
 		if depTag == expectedTag {
 			found = module
diff --git a/android/prebuilt.go b/android/prebuilt.go
index fd5a6ea..4f04d05 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -359,8 +359,8 @@
 //
 // This function is for use on dependencies after PrebuiltPostDepsMutator has
 // run - any dependency that is registered before that will already reference
-// the right module. This function is only safe to call after all mutators that
-// may call CreateVariations, e.g. in GenerateAndroidBuildActions.
+// the right module. This function is only safe to call after all TransitionMutators
+// have run, e.g. in GenerateAndroidBuildActions.
 func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module {
 	if !module.IsReplacedByPrebuilt() {
 		return module
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 18bbcab..56de9cd 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -38,6 +38,9 @@
 const sboxToolsSubDir = "tools"
 const sboxOutDir = sboxSandboxBaseDir + "/" + sboxOutSubDir
 
+const nsjailToolsSubDir = "tools"
+const nsjailOutDir = "out"
+
 // RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
 // graph.
 type RuleBuilder struct {
@@ -59,6 +62,9 @@
 	sboxManifestPath WritablePath
 	missingDeps      []string
 	args             map[string]string
+	nsjail           bool
+	nsjailBasePath   WritablePath
+	nsjailImplicits  Paths
 }
 
 // NewRuleBuilder returns a newly created RuleBuilder.
@@ -165,12 +171,43 @@
 	if len(r.commands) > 0 {
 		panic("Sbox() may not be called after Command()")
 	}
+	if r.nsjail {
+		panic("Sbox() may not be called after Nsjail()")
+	}
 	r.sbox = true
 	r.outDir = outputDir
 	r.sboxManifestPath = manifestPath
 	return r
 }
 
+// Nsjail marks the rule as needing to be wrapped by nsjail. The outputDir should point to the
+// output directory that nsjail will mount to out/. It should not be written to by any other rule.
+// baseDir should point to a location where nsjail will mount to /nsjail_build_sandbox, which will
+// be the working directory of the command.
+func (r *RuleBuilder) Nsjail(outputDir WritablePath, baseDir WritablePath) *RuleBuilder {
+	if len(r.commands) > 0 {
+		panic("Nsjail() may not be called after Command()")
+	}
+	if r.sbox {
+		panic("Nsjail() may not be called after Sbox()")
+	}
+	r.nsjail = true
+	r.outDir = outputDir
+	r.nsjailBasePath = baseDir
+	return r
+}
+
+// NsjailImplicits adds implicit inputs that are not directly mounted. This is useful when
+// the rule mounts directories, as files within those directories can be globbed and
+// tracked as dependencies with NsjailImplicits().
+func (r *RuleBuilder) NsjailImplicits(inputs Paths) *RuleBuilder {
+	if !r.nsjail {
+		panic("NsjailImplicits() must be called after Nsjail()")
+	}
+	r.nsjailImplicits = append(r.nsjailImplicits, inputs...)
+	return r
+}
+
 // SandboxTools enables tool sandboxing for the rule by copying any referenced tools into the
 // sandbox.
 func (r *RuleBuilder) SandboxTools() *RuleBuilder {
@@ -514,7 +551,73 @@
 
 	commandString := strings.Join(commands, " && ")
 
-	if r.sbox {
+	if !r.sbox {
+		// If not using sbox the rule will run the command directly, put the hash of the
+		// list of input files in a comment at the end of the command line to ensure ninja
+		// reruns the rule when the list of input files changes.
+		commandString += " # hash of input list: " + hashSrcFiles(inputs)
+	}
+
+	if r.nsjail {
+		var nsjailCmd strings.Builder
+		nsjailPath := r.ctx.Config().PrebuiltBuildTool(r.ctx, "nsjail")
+		nsjailCmd.WriteString("mkdir -p ")
+		nsjailCmd.WriteString(r.nsjailBasePath.String())
+		nsjailCmd.WriteString(" && ")
+		nsjailCmd.WriteString(nsjailPath.String())
+		nsjailCmd.WriteRune(' ')
+		nsjailCmd.WriteString("-B $PWD/")
+		nsjailCmd.WriteString(r.nsjailBasePath.String())
+		nsjailCmd.WriteString(":nsjail_build_sandbox")
+
+		// out is mounted to $(genDir).
+		nsjailCmd.WriteString(" -B $PWD/")
+		nsjailCmd.WriteString(r.outDir.String())
+		nsjailCmd.WriteString(":nsjail_build_sandbox/out")
+
+		for _, input := range inputs {
+			nsjailCmd.WriteString(" -R $PWD/")
+			nsjailCmd.WriteString(input.String())
+			nsjailCmd.WriteString(":nsjail_build_sandbox/")
+			nsjailCmd.WriteString(r.nsjailPathForInputRel(input))
+		}
+		for _, tool := range tools {
+			nsjailCmd.WriteString(" -R $PWD/")
+			nsjailCmd.WriteString(tool.String())
+			nsjailCmd.WriteString(":nsjail_build_sandbox/")
+			nsjailCmd.WriteString(nsjailPathForToolRel(r.ctx, tool))
+		}
+		inputs = append(inputs, tools...)
+		for _, c := range r.commands {
+			for _, tool := range c.packagedTools {
+				nsjailCmd.WriteString(" -R $PWD/")
+				nsjailCmd.WriteString(tool.srcPath.String())
+				nsjailCmd.WriteString(":nsjail_build_sandbox/")
+				nsjailCmd.WriteString(nsjailPathForPackagedToolRel(tool))
+				inputs = append(inputs, tool.srcPath)
+			}
+		}
+
+		// These five directories are necessary to run native host tools like /bin/bash and py3-cmd.
+		nsjailCmd.WriteString(" -R /bin")
+		nsjailCmd.WriteString(" -R /lib")
+		nsjailCmd.WriteString(" -R /lib64")
+		nsjailCmd.WriteString(" -R /dev")
+		nsjailCmd.WriteString(" -R /usr")
+
+		nsjailCmd.WriteString(" -m none:/tmp:tmpfs:size=1073741824") // 1GB, should be enough
+		nsjailCmd.WriteString(" -D nsjail_build_sandbox")
+		nsjailCmd.WriteString(" --disable_rlimits")
+		nsjailCmd.WriteString(" -q")
+		nsjailCmd.WriteString(" -- ")
+		nsjailCmd.WriteString("/bin/bash -c ")
+		nsjailCmd.WriteString(proptools.ShellEscape(commandString))
+
+		commandString = nsjailCmd.String()
+
+		inputs = append(inputs, nsjailPath)
+		inputs = append(inputs, r.nsjailImplicits...)
+	} else if r.sbox {
 		// If running the command inside sbox, write the rule data out to an sbox
 		// manifest.textproto.
 		manifest := sbox_proto.Manifest{}
@@ -734,11 +837,6 @@
 			rewrapperCommand := r.rbeParams.NoVarTemplate(r.ctx.Config().RBEWrapper())
 			commandString = rewrapperCommand + " bash -c '" + strings.ReplaceAll(commandString, `'`, `'\''`) + "'"
 		}
-	} else {
-		// If not using sbox the rule will run the command directly, put the hash of the
-		// list of input files in a comment at the end of the command line to ensure ninja
-		// reruns the rule when the list of input files changes.
-		commandString += " # hash of input list: " + hashSrcFiles(inputs)
 	}
 
 	// Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
@@ -869,6 +967,8 @@
 			rel = filepath.Join(sboxSandboxBaseDir, rel)
 		}
 		return rel
+	} else if c.rule.nsjail {
+		return c.rule.nsjailPathForInputRel(path)
 	}
 	return path.String()
 }
@@ -894,6 +994,10 @@
 		// Errors will be handled in RuleBuilder.Build where we have a context to report them
 		rel, _, _ := maybeRelErr(c.rule.outDir.String(), path.String())
 		return filepath.Join(sboxOutDir, rel)
+	} else if c.rule.nsjail {
+		// Errors will be handled in RuleBuilder.Build where we have a context to report them
+		rel, _, _ := maybeRelErr(c.rule.outDir.String(), path.String())
+		return filepath.Join(nsjailOutDir, rel)
 	}
 	return path.String()
 }
@@ -945,15 +1049,49 @@
 	return filepath.Join(sboxToolsSubDir, "out", spec.relPathInPackage)
 }
 
+func nsjailPathForToolRel(ctx BuilderContext, path Path) string {
+	// Errors will be handled in RuleBuilder.Build where we have a context to report them
+	toolDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "")
+	relOutSoong, isRelOutSoong, _ := maybeRelErr(toolDir.String(), path.String())
+	if isRelOutSoong {
+		// The tool is in the Soong output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
+		return filepath.Join(nsjailToolsSubDir, "out", relOutSoong)
+	}
+	// The tool is in the source directory, it will be copied to __SBOX_OUT_DIR__/tools/src
+	return filepath.Join(nsjailToolsSubDir, "src", path.String())
+}
+
+func (r *RuleBuilder) nsjailPathForInputRel(path Path) string {
+	rel, isRelSboxOut, _ := maybeRelErr(r.outDir.String(), path.String())
+	if isRelSboxOut {
+		return filepath.Join(nsjailOutDir, rel)
+	}
+	return path.String()
+}
+
+func (r *RuleBuilder) nsjailPathsForInputsRel(paths Paths) []string {
+	ret := make([]string, len(paths))
+	for i, path := range paths {
+		ret[i] = r.nsjailPathForInputRel(path)
+	}
+	return ret
+}
+
+func nsjailPathForPackagedToolRel(spec PackagingSpec) string {
+	return filepath.Join(nsjailToolsSubDir, "out", spec.relPathInPackage)
+}
+
 // PathForPackagedTool takes a PackageSpec for a tool and returns the corresponding path for the
 // tool after copying it into the sandbox.  This can be used  on the RuleBuilder command line to
 // reference the tool.
 func (c *RuleBuilderCommand) PathForPackagedTool(spec PackagingSpec) string {
-	if !c.rule.sboxTools {
-		panic("PathForPackagedTool() requires SandboxTools()")
+	if c.rule.sboxTools {
+		return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
+	} else if c.rule.nsjail {
+		return nsjailPathForPackagedToolRel(spec)
+	} else {
+		panic("PathForPackagedTool() requires SandboxTools() or Nsjail()")
 	}
-
-	return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
 }
 
 // PathForTool takes a path to a tool, which may be an output file or a source file, and returns
@@ -962,6 +1100,8 @@
 func (c *RuleBuilderCommand) PathForTool(path Path) string {
 	if c.rule.sbox && c.rule.sboxTools {
 		return filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path))
+	} else if c.rule.nsjail {
+		return nsjailPathForToolRel(c.rule.ctx, path)
 	}
 	return path.String()
 }
@@ -976,6 +1116,12 @@
 			ret = append(ret, filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path)))
 		}
 		return ret
+	} else if c.rule.nsjail {
+		var ret []string
+		for _, path := range paths {
+			ret = append(ret, nsjailPathForToolRel(c.rule.ctx, path))
+		}
+		return ret
 	}
 	return paths.Strings()
 }
@@ -983,20 +1129,22 @@
 // PackagedTool adds the specified tool path to the command line.  It can only be used with tool
 // sandboxing enabled by SandboxTools(), and will copy the tool into the sandbox.
 func (c *RuleBuilderCommand) PackagedTool(spec PackagingSpec) *RuleBuilderCommand {
-	if !c.rule.sboxTools {
-		panic("PackagedTool() requires SandboxTools()")
-	}
-
 	c.packagedTools = append(c.packagedTools, spec)
-	c.Text(sboxPathForPackagedToolRel(spec))
+	if c.rule.sboxTools {
+		c.Text(sboxPathForPackagedToolRel(spec))
+	} else if c.rule.nsjail {
+		c.Text(nsjailPathForPackagedToolRel(spec))
+	} else {
+		panic("PackagedTool() requires SandboxTools() or Nsjail()")
+	}
 	return c
 }
 
 // ImplicitPackagedTool copies the specified tool into the sandbox without modifying the command
 // line.  It can only be used with tool sandboxing enabled by SandboxTools().
 func (c *RuleBuilderCommand) ImplicitPackagedTool(spec PackagingSpec) *RuleBuilderCommand {
-	if !c.rule.sboxTools {
-		panic("ImplicitPackagedTool() requires SandboxTools()")
+	if !c.rule.sboxTools && !c.rule.nsjail {
+		panic("ImplicitPackagedTool() requires SandboxTools() or Nsjail()")
 	}
 
 	c.packagedTools = append(c.packagedTools, spec)
@@ -1006,8 +1154,8 @@
 // ImplicitPackagedTools copies the specified tools into the sandbox without modifying the command
 // line.  It can only be used with tool sandboxing enabled by SandboxTools().
 func (c *RuleBuilderCommand) ImplicitPackagedTools(specs []PackagingSpec) *RuleBuilderCommand {
-	if !c.rule.sboxTools {
-		panic("ImplicitPackagedTools() requires SandboxTools()")
+	if !c.rule.sboxTools && !c.rule.nsjail {
+		panic("ImplicitPackagedTools() requires SandboxTools() or Nsjail()")
 	}
 
 	c.packagedTools = append(c.packagedTools, specs...)
diff --git a/android/variable.go b/android/variable.go
index e0d512d..7041f49 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -428,9 +428,6 @@
 
 	EnforceProductPartitionInterface *bool `json:",omitempty"`
 
-	EnforceInterPartitionJavaSdkLibrary *bool    `json:",omitempty"`
-	InterPartitionJavaLibraryAllowList  []string `json:",omitempty"`
-
 	BoardUsesRecoveryAsBoot *bool `json:",omitempty"`
 
 	BoardKernelBinaries                []string `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 0caf37c..5f4d823 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -68,8 +68,6 @@
 	ctx.Transition("apex", &apexTransitionMutator{})
 	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
 	ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel()
-	// Register after apex_info mutator so that it can use ApexVariationName
-	ctx.TopDown("apex_strict_updatability_lint", apexStrictUpdatibilityLintMutator).Parallel()
 }
 
 type apexBundleProperties struct {
@@ -583,7 +581,7 @@
 	dataPaths                 []android.DataPath // becomes LOCAL_TEST_DATA
 
 	jacocoReportClassesFile android.Path     // only for javalibs and apps
-	lintDepSets             java.LintDepSets // only for javalibs and apps
+	lintInfo                *java.LintInfo   // only for javalibs and apps
 	certificate             java.Certificate // only for apps
 	overriddenPackageName   string           // only for apps
 
@@ -1115,34 +1113,6 @@
 	enforceAppUpdatability(mctx)
 }
 
-// apexStrictUpdatibilityLintMutator propagates strict_updatability_linting to transitive deps of a mainline module
-// This check is enforced for updatable modules
-func apexStrictUpdatibilityLintMutator(mctx android.TopDownMutatorContext) {
-	if !mctx.Module().Enabled(mctx) {
-		return
-	}
-	if apex, ok := mctx.Module().(*apexBundle); ok && apex.checkStrictUpdatabilityLinting(mctx) {
-		mctx.WalkDeps(func(child, parent android.Module) bool {
-			// b/208656169 Do not propagate strict updatability linting to libcore/
-			// These libs are available on the classpath during compilation
-			// These libs are transitive deps of the sdk. See java/sdk.go:decodeSdkDep
-			// Only skip libraries defined in libcore root, not subdirectories
-			if mctx.OtherModuleDir(child) == "libcore" {
-				// Do not traverse transitive deps of libcore/ libs
-				return false
-			}
-			if android.InList(child.Name(), skipLintJavalibAllowlist) {
-				return false
-			}
-			if lintable, ok := child.(java.LintDepSetsIntf); ok {
-				lintable.SetStrictUpdatabilityLinting(true)
-			}
-			// visit transitive deps
-			return true
-		})
-	}
-}
-
 // enforceAppUpdatability propagates updatable=true to apps of updatable apexes
 func enforceAppUpdatability(mctx android.TopDownMutatorContext) {
 	if !mctx.Module().Enabled(mctx) {
@@ -1203,20 +1173,9 @@
 		"test_jitzygote_com.android.art",
 		// go/keep-sorted end
 	}
-
-	// TODO: b/215736885 Remove this list
-	skipLintJavalibAllowlist = []string{
-		"conscrypt.module.platform.api.stubs",
-		"conscrypt.module.public.api.stubs",
-		"conscrypt.module.public.api.stubs.system",
-		"conscrypt.module.public.api.stubs.module_lib",
-		"framework-media.stubs",
-		"framework-media.stubs.system",
-		"framework-media.stubs.module_lib",
-	}
 )
 
-func (a *apexBundle) checkStrictUpdatabilityLinting(mctx android.TopDownMutatorContext) bool {
+func (a *apexBundle) checkStrictUpdatabilityLinting(mctx android.ModuleContext) bool {
 	// The allowlist contains the base apex name, so use that instead of the ApexVariationName
 	return a.Updatable() && !android.InList(mctx.ModuleName(), skipStrictUpdatabilityLintAllowlist)
 }
@@ -1662,7 +1621,6 @@
 	BaseModuleName() string
 	DexJarBuildPath(ctx android.ModuleErrorfContext) java.OptionalDexJarPath
 	JacocoReportClassesFile() android.Path
-	LintDepSets() java.LintDepSets
 	Stem() string
 }
 
@@ -1682,7 +1640,9 @@
 	dirInApex := "javalib"
 	af := newApexFile(ctx, dexImplementationJar, module.BaseModuleName(), dirInApex, javaSharedLib, module)
 	af.jacocoReportClassesFile = module.JacocoReportClassesFile()
-	af.lintDepSets = module.LintDepSets()
+	if lintInfo, ok := android.OtherModuleProvider(ctx, module, java.LintProvider); ok {
+		af.lintInfo = lintInfo
+	}
 	af.customStem = module.Stem() + ".jar"
 	// TODO: b/338641779 - Remove special casing of sdkLibrary once bcpf and sscpf depends
 	// on the implementation library
@@ -1720,7 +1680,6 @@
 	JacocoReportClassesFile() android.Path
 	Certificate() java.Certificate
 	BaseModuleName() string
-	LintDepSets() java.LintDepSets
 	PrivAppAllowlist() android.OptionalPath
 }
 
@@ -1756,7 +1715,9 @@
 
 	af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp)
 	af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
-	af.lintDepSets = aapp.LintDepSets()
+	if lintInfo, ok := android.OtherModuleProvider(ctx, aapp, java.LintProvider); ok {
+		af.lintInfo = lintInfo
+	}
 	af.certificate = aapp.Certificate()
 
 	if app, ok := aapp.(interface {
@@ -1807,7 +1768,7 @@
 // visited module, the `do` callback is executed. Returning true in the callback continues the visit
 // to the child modules. Returning false makes the visit to continue in the sibling or the parent
 // modules. This is used in check* functions below.
-func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
+func (a *apexBundle) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) {
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		am, ok := child.(android.ApexModule)
 		if !ok || !am.CanHaveApexVariants() {
@@ -1974,12 +1935,12 @@
 	})
 }
 
-func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent blueprint.Module) bool {
+func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent android.Module) bool {
 	depTag := ctx.OtherModuleDependencyTag(child)
 	if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
 		return false
 	}
-	if mod, ok := child.(android.Module); ok && !mod.Enabled(ctx) {
+	if !child.Enabled(ctx) {
 		return false
 	}
 	depName := ctx.OtherModuleName(child)
@@ -2323,7 +2284,7 @@
 		checkDuplicate:         a.shouldCheckDuplicate(ctx),
 		unwantedTransitiveDeps: a.properties.Unwanted_transitive_deps,
 	}
-	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
+	ctx.WalkDeps(func(child, parent android.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
 	vctx.normalizeFileInfo(ctx)
 	if a.privateKeyFile == nil {
 		if ctx.Config().AllowMissingDependencies() {
@@ -2653,7 +2614,7 @@
 
 	abInfo, _ := android.ModuleProvider(ctx, android.ApexBundleInfoProvider)
 
-	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if ccm, ok := to.(*cc.Module); ok {
 			apexName := ctx.ModuleName()
 			fromName := ctx.OtherModuleName(from)
@@ -2724,7 +2685,7 @@
 func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) {
 	// Visit direct deps only. As long as we guarantee top-level deps are using stable SDKs,
 	// java's checkLinkType guarantees correct usage for transitive deps
-	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+	ctx.VisitDirectDeps(func(module android.Module) {
 		tag := ctx.OtherModuleDependencyTag(module)
 		switch tag {
 		case javaLibTag, androidAppTag:
@@ -2765,7 +2726,7 @@
 		return
 	}
 
-	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		// As soon as the dependency graph crosses the APEX boundary, don't go further.
 		if externalDep {
 			return false
@@ -2817,7 +2778,7 @@
 
 // checkStaticExecutable ensures that executables in an APEX are not static.
 func (a *apexBundle) checkStaticExecutables(ctx android.ModuleContext) {
-	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+	ctx.VisitDirectDeps(func(module android.Module) {
 		if ctx.OtherModuleDependencyTag(module) != executableTag {
 			return
 		}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ad0bb17..7465f40 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5429,11 +5429,11 @@
 			apex_available: ["myapex"],
 			shared_library: false,
 			permitted_packages: ["bar"],
+			prefer: true,
 		}
 
 		java_sdk_library {
 			name: "libbar",
-			enabled: false,
 			srcs: ["foo/bar/MyClass.java"],
 			unsafe_ignore_missing_latest_api: true,
 			apex_available: ["myapex"],
@@ -9693,120 +9693,84 @@
 	}
 
 	testCases := []struct {
-		testCaseName              string
-		apexUpdatable             bool
-		javaStrictUpdtabilityLint bool
-		lintFileExists            bool
-		disallowedFlagExpected    bool
+		testCaseName                    string
+		apexUpdatable                   bool
+		javaStrictUpdtabilityLint       bool
+		lintFileExists                  bool
+		disallowedFlagExpectedOnApex    bool
+		disallowedFlagExpectedOnJavalib bool
 	}{
 		{
-			testCaseName:              "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
-			apexUpdatable:             true,
-			javaStrictUpdtabilityLint: true,
-			lintFileExists:            false,
-			disallowedFlagExpected:    false,
+			testCaseName:                    "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
+			apexUpdatable:                   true,
+			javaStrictUpdtabilityLint:       true,
+			lintFileExists:                  false,
+			disallowedFlagExpectedOnApex:    false,
+			disallowedFlagExpectedOnJavalib: false,
 		},
 		{
-			testCaseName:              "non-updatable apex respects strict_updatability of javalib",
-			apexUpdatable:             false,
-			javaStrictUpdtabilityLint: false,
-			lintFileExists:            true,
-			disallowedFlagExpected:    false,
+			testCaseName:                    "non-updatable apex respects strict_updatability of javalib",
+			apexUpdatable:                   false,
+			javaStrictUpdtabilityLint:       false,
+			lintFileExists:                  true,
+			disallowedFlagExpectedOnApex:    false,
+			disallowedFlagExpectedOnJavalib: false,
 		},
 		{
-			testCaseName:              "non-updatable apex respects strict updatability of javalib",
-			apexUpdatable:             false,
-			javaStrictUpdtabilityLint: true,
-			lintFileExists:            true,
-			disallowedFlagExpected:    true,
+			testCaseName:                    "non-updatable apex respects strict updatability of javalib",
+			apexUpdatable:                   false,
+			javaStrictUpdtabilityLint:       true,
+			lintFileExists:                  true,
+			disallowedFlagExpectedOnApex:    false,
+			disallowedFlagExpectedOnJavalib: true,
 		},
 		{
-			testCaseName:              "updatable apex sets strict updatability of javalib to true",
-			apexUpdatable:             true,
-			javaStrictUpdtabilityLint: false, // will be set to true by mutator
-			lintFileExists:            true,
-			disallowedFlagExpected:    true,
+			testCaseName:                    "updatable apex checks strict updatability of javalib",
+			apexUpdatable:                   true,
+			javaStrictUpdtabilityLint:       false,
+			lintFileExists:                  true,
+			disallowedFlagExpectedOnApex:    true,
+			disallowedFlagExpectedOnJavalib: false,
 		},
 	}
 
 	for _, testCase := range testCases {
-		fixtures := []android.FixturePreparer{}
-		baselineProperty := ""
-		if testCase.lintFileExists {
-			fixtures = append(fixtures, fs.AddToFixture())
-			baselineProperty = "baseline_filename: \"lint-baseline.xml\""
-		}
-		bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint, baselineProperty)
-
-		result := testApex(t, bp, fixtures...)
-		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
-		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
-
-		if disallowedFlagActual != testCase.disallowedFlagExpected {
-			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
-		}
-	}
-}
-
-func TestUpdatabilityLintSkipLibcore(t *testing.T) {
-	bp := `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			java_libs: ["myjavalib"],
-			updatable: true,
-			min_sdk_version: "29",
-		}
-		apex_key {
-			name: "myapex.key",
-		}
-		java_library {
-			name: "myjavalib",
-			srcs: ["MyClass.java"],
-			apex_available: [ "myapex" ],
-			sdk_version: "current",
-			min_sdk_version: "29",
-			lint: {
-				baseline_filename: "lint-baseline.xml",
+		t.Run(testCase.testCaseName, func(t *testing.T) {
+			fixtures := []android.FixturePreparer{}
+			baselineProperty := ""
+			if testCase.lintFileExists {
+				fixtures = append(fixtures, fs.AddToFixture())
+				baselineProperty = "baseline_filename: \"lint-baseline.xml\""
 			}
-		}
-		`
+			bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint, baselineProperty)
 
-	testCases := []struct {
-		testCaseName           string
-		moduleDirectory        string
-		disallowedFlagExpected bool
-	}{
-		{
-			testCaseName:           "lintable module defined outside libcore",
-			moduleDirectory:        "",
-			disallowedFlagExpected: true,
-		},
-		{
-			testCaseName:           "lintable module defined in libcore root directory",
-			moduleDirectory:        "libcore/",
-			disallowedFlagExpected: false,
-		},
-		{
-			testCaseName:           "lintable module defined in libcore child directory",
-			moduleDirectory:        "libcore/childdir/",
-			disallowedFlagExpected: true,
-		},
-	}
+			result := testApex(t, bp, fixtures...)
 
-	for _, testCase := range testCases {
-		lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
-		bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
-		result := testApex(t, "", lintFileCreator, bpFileCreator)
-		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
-		cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
-		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
+			checkModule := func(m android.TestingBuildParams, name string, expectStrictUpdatability bool) {
+				if expectStrictUpdatability {
+					if m.Rule == nil {
+						t.Errorf("expected strict updatability check rule on %s", name)
+					} else {
+						android.AssertStringDoesContain(t, fmt.Sprintf("strict updatability check rule for %s", name),
+							m.RuleParams.Command, "--disallowed_issues NewApi")
+						android.AssertStringListContains(t, fmt.Sprintf("strict updatability check baselines for %s", name),
+							m.Inputs.Strings(), "lint-baseline.xml")
+					}
+				} else {
+					if m.Rule != nil {
+						t.Errorf("expected no strict updatability check rule on %s", name)
+					}
+				}
+			}
 
-		if disallowedFlagActual != testCase.disallowedFlagExpected {
-			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
-		}
+			myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+			apex := result.ModuleForTests("myapex", "android_common_myapex")
+			apexStrictUpdatabilityCheck := apex.MaybeOutput("lint_strict_updatability_check.stamp")
+			javalibStrictUpdatabilityCheck := myjavalib.MaybeOutput("lint_strict_updatability_check.stamp")
+
+			checkModule(apexStrictUpdatabilityCheck, "myapex", testCase.disallowedFlagExpectedOnApex)
+			checkModule(javalibStrictUpdatabilityCheck, "myjavalib", testCase.disallowedFlagExpectedOnJavalib)
+		})
 	}
 }
 
@@ -9848,11 +9812,12 @@
 	}
 
 	result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
-	myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
-		t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
-	}
+	apex := result.ModuleForTests("myapex", "android_common_myapex")
+	apexStrictUpdatabilityCheck := apex.Output("lint_strict_updatability_check.stamp")
+	android.AssertStringDoesContain(t, "strict updatability check rule for myapex",
+		apexStrictUpdatabilityCheck.RuleParams.Command, "--disallowed_issues NewApi")
+	android.AssertStringListContains(t, "strict updatability check baselines for myapex",
+		apexStrictUpdatabilityCheck.Inputs.Strings(), "lint-baseline.xml")
 }
 
 func TestApexLintBcpFragmentSdkLibDeps(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index 19ec1bd..bf3ba9f 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -1092,7 +1092,7 @@
 	}
 
 	depInfos := android.DepNameToDepInfoMap{}
-	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if from.Name() == to.Name() {
 			// This can happen for cc.reuseObjTag. We are not interested in tracking this.
 			// As soon as the dependency graph crosses the APEX boundary, don't go further.
@@ -1159,10 +1159,23 @@
 func (a *apexBundle) buildLintReports(ctx android.ModuleContext) {
 	depSetsBuilder := java.NewLintDepSetBuilder()
 	for _, fi := range a.filesInfo {
-		depSetsBuilder.Transitive(fi.lintDepSets)
+		if fi.lintInfo != nil {
+			depSetsBuilder.Transitive(fi.lintInfo)
+		}
 	}
 
-	a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
+	depSets := depSetsBuilder.Build()
+	var validations android.Paths
+
+	if a.checkStrictUpdatabilityLinting(ctx) {
+		baselines := depSets.Baseline.ToList()
+		if len(baselines) > 0 {
+			outputFile := java.VerifyStrictUpdatabilityChecks(ctx, baselines)
+			validations = append(validations, outputFile)
+		}
+	}
+
+	a.lintReports = java.BuildModuleLintReportZips(ctx, depSets, validations)
 }
 
 func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 9c2d899..f4da31e 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -409,6 +409,9 @@
 		// The fragments.
 		`com.android.art:art-bootclasspath-fragment`,
 		`myapex:my-bootclasspath-fragment`,
+
+		// Impl lib of sdk_library for transitive srcjar generation
+		`platform:foo.impl`,
 	})
 }
 
@@ -565,6 +568,9 @@
 		// The fragments.
 		"myapex:mybootclasspath-fragment",
 		"myapex:prebuilt_mybootclasspath-fragment",
+
+		// Impl lib of sdk_library for transitive srcjar generation
+		"platform:foo.impl",
 	})
 }
 
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 2c9a536..3a65614 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -100,9 +100,7 @@
 	// Copy of archFeatures from android/arch_list.go because the bazel
 	// package can't access the android package
 	archFeatures := map[string][]string{
-		"arm": {
-			"neon",
-		},
+		"arm": {},
 		"arm64": {
 			"dotprod",
 		},
diff --git a/cc/cc.go b/cc/cc.go
index 96795d3..a8ff474 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -137,7 +137,7 @@
 
 	// LLNDK headers for the ABI checker to check LLNDK implementation library.
 	// An LLNDK implementation is the core variant. LLNDK header libs are reexported by the vendor variant.
-	// The core variant cannot depend on the vendor variant because of the order of CreateVariations.
+	// The core variant cannot depend on the vendor variant because of the order of imageTransitionMutator.Split().
 	// Instead, the LLNDK implementation depends on the LLNDK header libs.
 	LlndkHeaderLibs []string
 }
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 5aa2a7e..e7ac038 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -40,6 +40,9 @@
 			"-march=x86-64",
 		},
 
+		"alderlake": []string{
+			"-march=alderlake",
+		},
 		"broadwell": []string{
 			"-march=broadwell",
 		},
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 4b0041c..a92881d 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -42,6 +42,9 @@
 		"x86_64": []string{
 			"-march=prescott",
 		},
+		"alderlake": []string{
+			"-march=alderlake",
+		},
 		"atom": []string{
 			"-march=atom",
 		},
diff --git a/compliance/Android.bp b/compliance/Android.bp
index 08736b4..80f5685 100644
--- a/compliance/Android.bp
+++ b/compliance/Android.bp
@@ -34,6 +34,7 @@
     name: "notice_xml_system",
     partition_name: "system",
     visibility: [
+        "//build/make/target/product/generic",
         "//device/google/cuttlefish/system_image",
     ],
 }
diff --git a/filesystem/aconfig_files.go b/filesystem/aconfig_files.go
index 5c047bc..8af2ffa 100644
--- a/filesystem/aconfig_files.go
+++ b/filesystem/aconfig_files.go
@@ -79,6 +79,7 @@
 	generatePartitionAconfigStorageFile("package_map", "package.map")
 	generatePartitionAconfigStorageFile("flag_map", "flag.map")
 	generatePartitionAconfigStorageFile("flag_val", "flag.val")
+	generatePartitionAconfigStorageFile("flag_info", "flag.info")
 
 	android.WriteExecutableFileRuleVerbatim(ctx, aconfigFlagsBuilderPath, sb.String())
 }
diff --git a/genrule/Android.bp b/genrule/Android.bp
index f4197e6..49df480 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -25,3 +25,53 @@
     // Used by plugins
     visibility: ["//visibility:public"],
 }
+
+genrule {
+    name: "nsjail_genrule_test_input",
+    cmd: "echo nsjail_genrule_test_input > $(out)",
+    out: ["nsjail_genrule_test_input.txt"],
+}
+
+// Pseudo-test that's run on checkbuilds to verify consistent directory
+// structure for genrules using sbox or nsjail.
+genrule_defaults {
+    name: "nsjail_genrule_test_gen_defaults",
+    // verify both relative paths and its contents
+    cmd: "(echo $(out) $(genDir) && sha256sum " +
+        "$(location get_clang_version) " +
+        "$(location py3-cmd) " +
+        "$(location genrule.go) " +
+        "$(location :nsjail_genrule_test_input) " +
+        "$(locations *.go)) | sed 's@\\./@@g' > $(out)",
+    tools: [
+        "get_clang_version", // random tool
+        "py3-cmd", // random prebuilt tool
+    ],
+    tool_files: ["genrule.go"], // random local file
+    srcs: [
+        ":nsjail_genrule_test_input", // random OutputFileProducer
+        "*.go", // random glob
+    ],
+    out: ["nsjail_genrule_test.txt"],
+}
+
+genrule {
+    name: "nsjail_genrule_test_gen_without_nsjail",
+    defaults: ["nsjail_genrule_test_gen_defaults"],
+}
+
+genrule {
+    name: "nsjail_genrule_test_gen_with_nsjail",
+    defaults: ["nsjail_genrule_test_gen_defaults"],
+    use_nsjail: true,
+}
+
+genrule {
+    name: "nsjail_genrule_test",
+    srcs: [
+        ":nsjail_genrule_test_gen_without_nsjail",
+        ":nsjail_genrule_test_gen_with_nsjail",
+    ],
+    cmd: "diff $(in) > $(out)",
+    out: ["nsjail_genrule_test"],
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index a48038b..e5222a4 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -21,6 +21,7 @@
 import (
 	"fmt"
 	"io"
+	"path/filepath"
 	"strconv"
 	"strings"
 
@@ -210,6 +211,9 @@
 	// For gensrsc sharding.
 	shard  int
 	shards int
+
+	// For nsjail tasks
+	useNsjail bool
 }
 
 func (g *Module) GeneratedSourceFiles() android.Paths {
@@ -313,16 +317,14 @@
 	if len(g.properties.Tools) > 0 {
 		seenTools := make(map[string]bool)
 
-		ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		ctx.VisitDirectDepsAllowDisabled(func(module android.Module) {
 			switch tag := ctx.OtherModuleDependencyTag(module).(type) {
 			case hostToolDependencyTag:
 				tool := ctx.OtherModuleName(module)
-				if m, ok := module.(android.Module); ok {
-					// Necessary to retrieve any prebuilt replacement for the tool, since
-					// toolDepsMutator runs too late for the prebuilt mutators to have
-					// replaced the dependency.
-					module = android.PrebuiltGetPreferred(ctx, m)
-				}
+				// Necessary to retrieve any prebuilt replacement for the tool, since
+				// toolDepsMutator runs too late for the prebuilt mutators to have
+				// replaced the dependency.
+				module = android.PrebuiltGetPreferred(ctx, module)
 
 				switch t := module.(type) {
 				case android.HostToolProvider:
@@ -454,21 +456,26 @@
 
 		// Pick a unique path outside the task.genDir for the sbox manifest textproto,
 		// a unique rule name, and the user-visible description.
-		manifestName := "genrule.sbox.textproto"
+		var rule *android.RuleBuilder
 		desc := "generate"
 		name := "generator"
-		if task.shards > 0 {
-			manifestName = "genrule_" + strconv.Itoa(task.shard) + ".sbox.textproto"
-			desc += " " + strconv.Itoa(task.shard)
-			name += strconv.Itoa(task.shard)
-		} else if len(task.out) == 1 {
-			desc += " " + task.out[0].Base()
+		if task.useNsjail {
+			rule = android.NewRuleBuilder(pctx, ctx).Nsjail(task.genDir, android.PathForModuleOut(ctx, "nsjail_build_sandbox"))
+		} else {
+			manifestName := "genrule.sbox.textproto"
+			if task.shards > 0 {
+				manifestName = "genrule_" + strconv.Itoa(task.shard) + ".sbox.textproto"
+				desc += " " + strconv.Itoa(task.shard)
+				name += strconv.Itoa(task.shard)
+			} else if len(task.out) == 1 {
+				desc += " " + task.out[0].Base()
+			}
+
+			manifestPath := android.PathForModuleOut(ctx, manifestName)
+
+			// Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
+			rule = getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath))
 		}
-
-		manifestPath := android.PathForModuleOut(ctx, manifestName)
-
-		// Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
-		rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath))
 		if Bool(g.properties.Write_if_changed) {
 			rule.Restat()
 		}
@@ -569,6 +576,15 @@
 			cmd.OrderOnly(ctx.Config().BuildNumberFile(ctx))
 		}
 
+		if task.useNsjail {
+			for _, input := range task.in {
+				// can fail if input is a file.
+				if paths, err := ctx.GlobWithDeps(filepath.Join(input.String(), "**/*"), nil); err == nil {
+					rule.NsjailImplicits(android.PathsForSource(ctx, paths))
+				}
+			}
+		}
+
 		// Create the rule to run the genrule command inside sbox.
 		rule.Build(name, desc)
 
@@ -832,15 +848,18 @@
 	properties := &genRuleProperties{}
 
 	taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask {
+		useNsjail := Bool(properties.Use_nsjail)
+
 		outs := make(android.WritablePaths, len(properties.Out))
 		for i, out := range properties.Out {
 			outs[i] = android.PathForModuleGen(ctx, out)
 		}
 		return []generateTask{{
-			in:     srcFiles,
-			out:    outs,
-			genDir: android.PathForModuleGen(ctx),
-			cmd:    rawCommand,
+			in:        srcFiles,
+			out:       outs,
+			genDir:    android.PathForModuleGen(ctx),
+			cmd:       rawCommand,
+			useNsjail: useNsjail,
 		}}
 	}
 
@@ -855,6 +874,8 @@
 }
 
 type genRuleProperties struct {
+	Use_nsjail *bool
+
 	// names of the output files that will be generated
 	Out []string `android:"arch_variant"`
 }
diff --git a/java/Android.bp b/java/Android.bp
index a930dd4..1101d7a 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -72,7 +72,6 @@
         "rro.go",
         "sdk.go",
         "sdk_library.go",
-        "sdk_library_external.go",
         "sdk_library_internal.go",
         "support_libraries.go",
         "system_modules.go",
diff --git a/java/aar.go b/java/aar.go
index b5e24c4..7d73b03 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -45,7 +45,7 @@
 	ctx.RegisterModuleType("android_library_import", AARImportFactory)
 	ctx.RegisterModuleType("android_library", AndroidLibraryFactory)
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator)
+		ctx.Transition("propagate_rro_enforcement", &propagateRROEnforcementTransitionMutator{})
 	})
 }
 
@@ -151,15 +151,67 @@
 	path   android.Path
 }
 
-// Propagate RRO enforcement flag to static lib dependencies transitively.
-func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) {
+// Propagate RRO enforcement flag to static lib dependencies transitively.  If EnforceRROGlobally is set then
+// all modules will use the "" variant.  If specific modules have RRO enforced, then modules (usually apps) with
+// RRO enabled will use the "" variation for themselves, but use the "rro" variant of direct and transitive static
+// android_library dependencies.
+type propagateRROEnforcementTransitionMutator struct{}
+
+func (p propagateRROEnforcementTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+	// Never split modules, apps with or without RRO enabled use the "" variant, static android_library dependencies
+	// will use create the "rro" variant from incoming tranisitons.
+	return []string{""}
+}
+
+func (p propagateRROEnforcementTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	// Non-static dependencies are not involved in RRO and always use the empty variant.
+	if ctx.DepTag() != staticLibTag {
+		return ""
+	}
+
 	m := ctx.Module()
-	if d, ok := m.(AndroidLibraryDependency); ok && d.IsRROEnforced(ctx) {
-		ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
-			if a, ok := d.(AndroidLibraryDependency); ok {
-				a.SetRROEnforcedForDependent(true)
-			}
-		})
+	if _, ok := m.(AndroidLibraryDependency); ok {
+		// If RRO is enforced globally don't bother using "rro" variants, the empty variant will have RRO enabled.
+		if ctx.Config().EnforceRROGlobally() {
+			return ""
+		}
+
+		// If RRO is enabled for this module use the "rro" variants of static dependencies.  IncomingTransition will
+		// rewrite this back to "" if the dependency is not an android_library.
+		if ctx.Config().EnforceRROForModule(ctx.Module().Name()) {
+			return "rro"
+		}
+	}
+
+	return sourceVariation
+}
+
+func (p propagateRROEnforcementTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	// Propagate the "rro" variant to android_library modules, but use the empty variant for everything else.
+	if incomingVariation == "rro" {
+		m := ctx.Module()
+		if _, ok := m.(AndroidLibraryDependency); ok {
+			return "rro"
+		}
+		return ""
+	}
+
+	return ""
+}
+
+func (p propagateRROEnforcementTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	m := ctx.Module()
+	if d, ok := m.(AndroidLibraryDependency); ok {
+		if variation == "rro" {
+			// This is the "rro" variant of a module that has both variants, mark this one as RRO enabled and
+			// hide it from make to avoid collisions with the non-RRO empty variant.
+			d.SetRROEnforcedForDependent(true)
+			m.HideFromMake()
+		} else if ctx.Config().EnforceRROGlobally() {
+			// RRO is enabled globally, mark it enabled for this module, but there is only one variant so no
+			// need to hide it from make.
+			d.SetRROEnforcedForDependent(true)
+		}
 	}
 }
 
diff --git a/java/androidmk.go b/java/androidmk.go
index a1bc904..0539d25 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -415,7 +415,7 @@
 				} else {
 					var names []string
 					for _, jniLib := range app.jniLibs {
-						names = append(names, jniLib.name)
+						names = append(names, jniLib.name+":"+jniLib.target.Arch.ArchType.Bitness())
 					}
 					entries.AddStrings("LOCAL_REQUIRED_MODULES", names...)
 				}
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 243a279..1d98b18 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -286,7 +286,7 @@
 	}{
 		{
 			name:     "app",
-			expected: []string{"libjni"},
+			expected: []string{"libjni:64"},
 		},
 		{
 			name:     "app_embedded",
diff --git a/java/app.go b/java/app.go
index 4ac42a7..b77793b 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1135,7 +1135,7 @@
 	return jniLibs, prebuiltJniPackages
 }
 
-func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
+func (a *AndroidApp) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) {
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		isExternal := !a.DepIsInSameApex(ctx, child)
 		if am, ok := child.(android.ApexModule); ok {
@@ -1153,7 +1153,7 @@
 	}
 
 	depsInfo := android.DepNameToDepInfoMap{}
-	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+	a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		depName := to.Name()
 
 		// Skip dependencies that are only available to APEXes; they are developed with updatability
@@ -1417,7 +1417,8 @@
 	}
 
 	testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
-		a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs)
+		a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites,
+		a.testProperties.Auto_gen_config, configs, a.testProperties.Test_options.Test_runner_options)
 	a.testConfig = a.FixTestConfig(ctx, testConfig)
 	a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs)
 	a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -1781,16 +1782,15 @@
 			}
 		}
 
-		// Skip java_sdk_library dependencies that provide stubs, but not an implementation.
-		// This will be restricted to optional_uses_libs
-		if sdklib, ok := m.(SdkLibraryDependency); ok {
-			if tag == usesLibOptTag && sdklib.DexJarBuildPath(ctx).PathOrNil() == nil {
-				u.shouldDisableDexpreopt = true
-				return
-			}
-		}
-
 		if lib, ok := m.(UsesLibraryDependency); ok {
+			if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok {
+				// Skip java_sdk_library dependencies that provide stubs, but not an implementation.
+				// This will be restricted to optional_uses_libs
+				if tag == usesLibOptTag && lib.DexJarBuildPath(ctx).PathOrNil() == nil {
+					u.shouldDisableDexpreopt = true
+					return
+				}
+			}
 			libName := dep
 			if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil {
 				libName = *ulib.ProvidesUsesLib()
diff --git a/java/app_import.go b/java/app_import.go
index 045a89a..a54cf2f 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -533,10 +533,6 @@
 	return android.SdkSpecPrivate.ApiLevel
 }
 
-func (a *AndroidAppImport) LintDepSets() LintDepSets {
-	return LintDepSets{}
-}
-
 var _ android.ApexModule = (*AndroidAppImport)(nil)
 
 // Implements android.ApexModule
diff --git a/java/app_test.go b/java/app_test.go
index d7f5f0c..2a2611d 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1419,26 +1419,31 @@
 }
 
 func TestAndroidResourceOverlays(t *testing.T) {
+	type moduleAndVariant struct {
+		module  string
+		variant string
+	}
+
 	testCases := []struct {
 		name                       string
 		enforceRROTargets          []string
 		enforceRROExcludedOverlays []string
-		resourceFiles              map[string][]string
-		overlayFiles               map[string][]string
-		rroDirs                    map[string][]string
+		resourceFiles              map[moduleAndVariant][]string
+		overlayFiles               map[moduleAndVariant][]string
+		rroDirs                    map[moduleAndVariant][]string
 	}{
 		{
 			name:                       "no RRO",
 			enforceRROTargets:          nil,
 			enforceRROExcludedOverlays: nil,
-			resourceFiles: map[string][]string{
-				"foo":  nil,
-				"bar":  {"bar/res/res/values/strings.xml"},
-				"lib":  nil,
-				"lib2": {"lib2/res/res/values/strings.xml"},
+			resourceFiles: map[moduleAndVariant][]string{
+				{"foo", "android_common"}:  nil,
+				{"bar", "android_common"}:  {"bar/res/res/values/strings.xml"},
+				{"lib", "android_common"}:  nil,
+				{"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"},
 			},
-			overlayFiles: map[string][]string{
-				"foo": {
+			overlayFiles: map[moduleAndVariant][]string{
+				{"foo", "android_common"}: {
 					"out/soong/.intermediates/lib2/android_common/package-res.apk",
 					"out/soong/.intermediates/lib/android_common/package-res.apk",
 					"out/soong/.intermediates/lib3/android_common/package-res.apk",
@@ -1447,57 +1452,65 @@
 					"device/vendor/blah/overlay/foo/res/values/strings.xml",
 					"product/vendor/blah/overlay/foo/res/values/strings.xml",
 				},
-				"bar": {
+				{"bar", "android_common"}: {
 					"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
 					"device/vendor/blah/overlay/bar/res/values/strings.xml",
 				},
-				"lib": {
+				{"lib", "android_common"}: {
 					"out/soong/.intermediates/lib2/android_common/package-res.apk",
 					"lib/res/res/values/strings.xml",
 					"device/vendor/blah/overlay/lib/res/values/strings.xml",
 				},
 			},
-			rroDirs: map[string][]string{
-				"foo": nil,
-				"bar": nil,
+			rroDirs: map[moduleAndVariant][]string{
+				{"foo", "android_common"}: nil,
+				{"bar", "android_common"}: nil,
 			},
 		},
 		{
 			name:                       "enforce RRO on foo",
 			enforceRROTargets:          []string{"foo"},
 			enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
-			resourceFiles: map[string][]string{
-				"foo":  nil,
-				"bar":  {"bar/res/res/values/strings.xml"},
-				"lib":  nil,
-				"lib2": {"lib2/res/res/values/strings.xml"},
+			resourceFiles: map[moduleAndVariant][]string{
+				{"foo", "android_common"}:      nil,
+				{"bar", "android_common"}:      {"bar/res/res/values/strings.xml"},
+				{"lib", "android_common"}:      nil,
+				{"lib", "android_common_rro"}:  nil,
+				{"lib2", "android_common"}:     {"lib2/res/res/values/strings.xml"},
+				{"lib2", "android_common_rro"}: {"lib2/res/res/values/strings.xml"},
 			},
-			overlayFiles: map[string][]string{
-				"foo": {
-					"out/soong/.intermediates/lib2/android_common/package-res.apk",
-					"out/soong/.intermediates/lib/android_common/package-res.apk",
-					"out/soong/.intermediates/lib3/android_common/package-res.apk",
+			overlayFiles: map[moduleAndVariant][]string{
+				{"foo", "android_common"}: {
+					"out/soong/.intermediates/lib2/android_common_rro/package-res.apk",
+					"out/soong/.intermediates/lib/android_common_rro/package-res.apk",
+					"out/soong/.intermediates/lib3/android_common_rro/package-res.apk",
 					"foo/res/res/values/strings.xml",
 					"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
 				},
-				"bar": {
+				{"bar", "android_common"}: {
 					"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
 					"device/vendor/blah/overlay/bar/res/values/strings.xml",
 				},
-				"lib": {
+				{"lib", "android_common"}: {
 					"out/soong/.intermediates/lib2/android_common/package-res.apk",
 					"lib/res/res/values/strings.xml",
+					"device/vendor/blah/overlay/lib/res/values/strings.xml",
+				},
+				{"lib", "android_common_rro"}: {
+					"out/soong/.intermediates/lib2/android_common_rro/package-res.apk",
+					"lib/res/res/values/strings.xml",
 				},
 			},
 
-			rroDirs: map[string][]string{
-				"foo": {
+			rroDirs: map[moduleAndVariant][]string{
+				{"foo", "android_common"}: {
 					"device:device/vendor/blah/overlay/foo/res",
 					"product:product/vendor/blah/overlay/foo/res",
 					"device:device/vendor/blah/overlay/lib/res",
 				},
-				"bar": nil,
-				"lib": {"device:device/vendor/blah/overlay/lib/res"},
+				{"bar", "android_common"}:     nil,
+				{"lib", "android_common"}:     nil,
+				{"lib", "android_common_rro"}: {"device:device/vendor/blah/overlay/lib/res"},
 			},
 		},
 		{
@@ -1508,35 +1521,35 @@
 				"device/vendor/blah/static_overlay/foo",
 				"device/vendor/blah/static_overlay/bar/res",
 			},
-			resourceFiles: map[string][]string{
-				"foo":  nil,
-				"bar":  {"bar/res/res/values/strings.xml"},
-				"lib":  nil,
-				"lib2": {"lib2/res/res/values/strings.xml"},
+			resourceFiles: map[moduleAndVariant][]string{
+				{"foo", "android_common"}:  nil,
+				{"bar", "android_common"}:  {"bar/res/res/values/strings.xml"},
+				{"lib", "android_common"}:  nil,
+				{"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"},
 			},
-			overlayFiles: map[string][]string{
-				"foo": {
+			overlayFiles: map[moduleAndVariant][]string{
+				{"foo", "android_common"}: {
 					"out/soong/.intermediates/lib2/android_common/package-res.apk",
 					"out/soong/.intermediates/lib/android_common/package-res.apk",
 					"out/soong/.intermediates/lib3/android_common/package-res.apk",
 					"foo/res/res/values/strings.xml",
 					"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
 				},
-				"bar": {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
-				"lib": {
+				{"bar", "android_common"}: {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
+				{"lib", "android_common"}: {
 					"out/soong/.intermediates/lib2/android_common/package-res.apk",
 					"lib/res/res/values/strings.xml",
 				},
 			},
-			rroDirs: map[string][]string{
-				"foo": {
+			rroDirs: map[moduleAndVariant][]string{
+				{"foo", "android_common"}: {
 					"device:device/vendor/blah/overlay/foo/res",
 					"product:product/vendor/blah/overlay/foo/res",
 					// Lib dep comes after the direct deps
 					"device:device/vendor/blah/overlay/lib/res",
 				},
-				"bar": {"device:device/vendor/blah/overlay/bar/res"},
-				"lib": {"device:device/vendor/blah/overlay/lib/res"},
+				{"bar", "android_common"}: {"device:device/vendor/blah/overlay/bar/res"},
+				{"lib", "android_common"}: {"device:device/vendor/blah/overlay/lib/res"},
 			},
 		},
 	}
@@ -1621,19 +1634,19 @@
 				for _, o := range list {
 					res := module.MaybeOutput(o)
 					if res.Rule != nil {
-						// If the overlay is compiled as part of this module (i.e. a .arsc.flat file),
+						// If the overlay is compiled as part of this moduleAndVariant (i.e. a .arsc.flat file),
 						// verify the inputs to the .arsc.flat rule.
 						files = append(files, res.Inputs.Strings()...)
 					} else {
-						// Otherwise, verify the full path to the output of the other module
+						// Otherwise, verify the full path to the output of the other moduleAndVariant
 						files = append(files, o)
 					}
 				}
 				return files
 			}
 
-			getResources := func(moduleName string) (resourceFiles, overlayFiles, rroDirs []string) {
-				module := result.ModuleForTests(moduleName, "android_common")
+			getResources := func(moduleName, variantName string) (resourceFiles, overlayFiles, rroDirs []string) {
+				module := result.ModuleForTests(moduleName, variantName)
 				resourceList := module.MaybeOutput("aapt2/res.list")
 				if resourceList.Rule != nil {
 					resourceFiles = resourceListToFiles(module, android.PathsRelativeToTop(resourceList.Inputs))
@@ -1658,21 +1671,33 @@
 				return resourceFiles, overlayFiles, rroDirs
 			}
 
-			modules := []string{"foo", "bar", "lib", "lib2"}
-			for _, module := range modules {
-				resourceFiles, overlayFiles, rroDirs := getResources(module)
+			modules := []moduleAndVariant{
+				{"foo", "android_common"},
+				{"foo", "android_common_rro"},
+				{"bar", "android_common"},
+				{"bar", "android_common_rro"},
+				{"lib", "android_common"},
+				{"lib", "android_common_rro"},
+				{"lib2", "android_common"},
+				{"lib2", "android_common_rro"},
+			}
+			for _, moduleAndVariant := range modules {
+				if _, exists := testCase.resourceFiles[moduleAndVariant]; !exists {
+					continue
+				}
+				resourceFiles, overlayFiles, rroDirs := getResources(moduleAndVariant.module, moduleAndVariant.variant)
 
-				if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[module]) {
+				if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[moduleAndVariant]) {
 					t.Errorf("expected %s resource files:\n  %#v\n got:\n  %#v",
-						module, testCase.resourceFiles[module], resourceFiles)
+						moduleAndVariant, testCase.resourceFiles[moduleAndVariant], resourceFiles)
 				}
-				if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[module]) {
+				if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[moduleAndVariant]) {
 					t.Errorf("expected %s overlay files:\n  %#v\n got:\n  %#v",
-						module, testCase.overlayFiles[module], overlayFiles)
+						moduleAndVariant, testCase.overlayFiles[moduleAndVariant], overlayFiles)
 				}
-				if !reflect.DeepEqual(rroDirs, testCase.rroDirs[module]) {
+				if !reflect.DeepEqual(rroDirs, testCase.rroDirs[moduleAndVariant]) {
 					t.Errorf("expected %s rroDirs:  %#v\n got:\n  %#v",
-						module, testCase.rroDirs[module], rroDirs)
+						moduleAndVariant, testCase.rroDirs[moduleAndVariant], rroDirs)
 				}
 			}
 		})
diff --git a/java/base.go b/java/base.go
index b64eb5b..7c26cc3 100644
--- a/java/base.go
+++ b/java/base.go
@@ -708,9 +708,6 @@
 		ctx.SetOutputFiles(android.Paths{m.dexer.proguardDictionary.Path()}, ".proguard_map")
 	}
 	ctx.SetOutputFiles(m.properties.Generated_srcjars, ".generated_srcjars")
-	if m.linter.outputs.xml != nil {
-		ctx.SetOutputFiles(android.Paths{m.linter.outputs.xml}, ".lint")
-	}
 }
 
 func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
@@ -854,33 +851,6 @@
 	// Add dependency on libraries that provide additional hidden api annotations.
 	ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
 
-	if ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
-		// Require java_sdk_library at inter-partition java dependency to ensure stable
-		// interface between partitions. If inter-partition java_library dependency is detected,
-		// raise build error because java_library doesn't have a stable interface.
-		//
-		// Inputs:
-		//    PRODUCT_ENFORCE_INTER_PARTITION_JAVA_SDK_LIBRARY
-		//      if true, enable enforcement
-		//    PRODUCT_INTER_PARTITION_JAVA_LIBRARY_ALLOWLIST
-		//      exception list of java_library names to allow inter-partition dependency
-		for idx := range j.properties.Libs {
-			if libDeps[idx] == nil {
-				continue
-			}
-
-			if javaDep, ok := libDeps[idx].(javaSdkLibraryEnforceContext); ok {
-				// java_sdk_library is always allowed at inter-partition dependency.
-				// So, skip check.
-				if _, ok := javaDep.(*SdkLibrary); ok {
-					continue
-				}
-
-				j.checkPartitionsForJavaDependency(ctx, "libs", javaDep)
-			}
-		}
-	}
-
 	// For library dependencies that are component libraries (like stubs), add the implementation
 	// as a dependency (dexpreopt needs to be against the implementation library, not stubs).
 	for _, dep := range libDeps {
@@ -1736,8 +1706,12 @@
 		return
 	}
 
+	completeStaticLibsImplementationJarsToCombine := completeStaticLibsImplementationJars
+
 	if j.shouldInstrument(ctx) {
-		outputFile = j.instrument(ctx, flags, outputFile, jarName, specs)
+		instrumentedOutputFile := j.instrument(ctx, flags, outputFile, jarName, specs)
+		completeStaticLibsImplementationJarsToCombine = android.NewDepSet(android.PREORDER, android.Paths{instrumentedOutputFile}, nil)
+		outputFile = instrumentedOutputFile
 	}
 
 	// merge implementation jar with resources if necessary
@@ -1745,7 +1719,7 @@
 	if ctx.Config().UseTransitiveJarsInClasspath() {
 		resourceJars := completeStaticLibsResourceJars.ToList()
 		if len(resourceJars) > 0 {
-			implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJars.ToList()...)
+			implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJarsToCombine.ToList()...)
 			implementationAndResourcesJarsToCombine = append(implementationAndResourcesJarsToCombine, extraDepCombinedJars...)
 		}
 	} else {
@@ -2414,10 +2388,9 @@
 			return
 		}
 
-		if _, ok := module.(SdkLibraryDependency); ok {
+		if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
 			switch tag {
 			case sdkLibTag, libTag, staticLibTag:
-				sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider)
 				generatingLibsString := android.PrettyConcat(
 					getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
 				ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
@@ -2726,7 +2699,7 @@
 	module := ctx.Module()
 	moduleName := module.Name()
 
-	ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) {
+	ctx.VisitDirectDeps(func(m android.Module) {
 		tag := ctx.OtherModuleDependencyTag(m)
 		// This logic mirrors that in (*Module).collectDeps above.  There are several places
 		// where we explicitly return RenameUseExclude, even though it is the default, to
@@ -2749,7 +2722,7 @@
 			if IsJniDepTag(tag) || tag == certificateTag || tag == proguardRaiseTag {
 				return RenameUseExclude, "tags"
 			}
-			if _, ok := m.(SdkLibraryDependency); ok {
+			if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok {
 				switch tag {
 				case sdkLibTag, libTag:
 					return RenameUseExclude, "sdklibdep" // matches collectDeps()
diff --git a/java/dex.go b/java/dex.go
index e0e642c..faf51a3 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -220,14 +220,28 @@
 		deps = append(deps, f)
 	}
 
+	var requestReleaseMode bool
+	requestReleaseMode, flags = android.RemoveFromList("--release", flags)
+
 	if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
 		flags = append(flags, "--debug")
+		requestReleaseMode = false
 	}
 
 	if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
 		flags = append(flags,
 			"--debug",
 			"--verbose")
+		requestReleaseMode = false
+	}
+
+	// Don't strip out debug information for eng builds, unless the target
+	// explicitly provided the `--release` build flag. This allows certain
+	// test targets to remain optimized as part of eng test_suites builds.
+	if requestReleaseMode {
+		flags = append(flags, "--release")
+	} else if ctx.Config().Eng() {
+		flags = append(flags, "--debug")
 	}
 
 	// Supplying the platform build flag disables various features like API modeling and desugaring.
@@ -384,11 +398,6 @@
 	// TODO(ccross): if this is an instrumentation test of an obfuscated app, use the
 	// dictionary of the app and move the app from libraryjars to injars.
 
-	// Don't strip out debug information for eng builds.
-	if ctx.Config().Eng() {
-		r8Flags = append(r8Flags, "--debug")
-	}
-
 	// TODO(b/180878971): missing classes should be added to the relevant builds.
 	// TODO(b/229727645): do not use true as default for Android platform builds.
 	if proptools.BoolDefault(opt.Ignore_warnings, true) {
diff --git a/java/dex_test.go b/java/dex_test.go
index 4862d06..8bc28e6 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -713,3 +713,97 @@
 	}
 }`)
 }
+
+func TestDebugReleaseFlags(t *testing.T) {
+	bp := `
+		android_app {
+			name: "app",
+			srcs: ["foo.java"],
+			platform_apis: true,
+			dxflags: ["%s"]
+		}
+	`
+
+	testcases := []struct {
+		name          string
+		envVar        string
+		isEng         bool
+		dxFlags       string
+		expectedFlags string
+	}{
+		{
+			name:          "app_no_optimize_dx",
+			envVar:        "NO_OPTIMIZE_DX",
+			expectedFlags: "--debug",
+		},
+		{
+			name:    "app_release_no_optimize_dx",
+			envVar:  "NO_OPTIMIZE_DX",
+			dxFlags: "--release",
+			// Global env vars override explicit dxflags.
+			expectedFlags: "--debug",
+		},
+		{
+			name:          "app_generate_dex_debug",
+			envVar:        "GENERATE_DEX_DEBUG",
+			expectedFlags: "--debug",
+		},
+		{
+			name:    "app_release_generate_dex_debug",
+			envVar:  "GENERATE_DEX_DEBUG",
+			dxFlags: "--release",
+			// Global env vars override explicit dxflags.
+			expectedFlags: "--debug",
+		},
+		{
+			name:          "app_eng",
+			isEng:         true,
+			expectedFlags: "--debug",
+		},
+		{
+			name:    "app_release_eng",
+			isEng:   true,
+			dxFlags: "--release",
+			// Eng mode does *not* override explicit dxflags.
+			expectedFlags: "--release",
+		},
+	}
+
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			fixturePreparer := PrepareForTestWithJavaDefaultModules
+			fixturePreparer = android.GroupFixturePreparers(
+				fixturePreparer,
+				android.FixtureModifyProductVariables(
+					func(variables android.FixtureProductVariables) {
+						variables.Eng = proptools.BoolPtr(tc.isEng)
+					},
+				),
+			)
+			if tc.envVar != "" {
+				fixturePreparer = android.GroupFixturePreparers(
+					fixturePreparer,
+					android.FixtureMergeEnv(map[string]string{
+						tc.envVar: "true",
+					}),
+				)
+			}
+			result := fixturePreparer.RunTestWithBp(t, fmt.Sprintf(bp, tc.dxFlags))
+
+			appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+			android.AssertStringDoesContain(t, "expected flag in R8 flags",
+				appR8.Args["r8Flags"], tc.expectedFlags)
+
+			var unexpectedFlags string
+			if tc.expectedFlags == "--debug" {
+				unexpectedFlags = "--release"
+			} else if tc.expectedFlags == "--release" {
+				unexpectedFlags = "--debug"
+			}
+			if unexpectedFlags != "" {
+				android.AssertStringDoesNotContain(t, "unexpected flag in R8 flags",
+					appR8.Args["r8Flags"], unexpectedFlags)
+			}
+		})
+	}
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index a2e4734..7a77b15 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -463,6 +463,7 @@
 
 func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
 	ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
+	ctx.RegisterModuleType("art_boot_images", artBootImagesFactory)
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator).Parallel()
 	})
@@ -601,6 +602,7 @@
 	d.defaultBootImage = defaultBootImageConfig(ctx)
 	d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1)
 	var profileInstalls android.RuleBuilderInstalls
+	var artBootImageHostInstalls android.RuleBuilderInstalls
 	for _, name := range getImageNames() {
 		config := imageConfigs[name]
 		if config != d.defaultBootImage {
@@ -616,6 +618,18 @@
 			d.bootFrameworkProfile = bootProfile
 			profileInstalls = append(profileInstalls, installs...)
 		}
+		// Gather the install files of the host variant of the ART boot image.
+		// These installed files will be used in ART tests.
+		if config.name == "art" {
+			for _, variant := range config.variants {
+				if variant.target.Os != ctx.Config().BuildOS {
+					// not a host variant
+					continue
+				}
+				artBootImageHostInstalls = append(artBootImageHostInstalls, variant.installs...)
+				artBootImageHostInstalls = append(artBootImageHostInstalls, variant.vdexInstalls...)
+			}
+		}
 	}
 	if len(profileInstalls) > 0 {
 		android.SetProvider(ctx, profileInstallInfoProvider, profileInstallInfo{
@@ -626,6 +640,15 @@
 			installFile(ctx, install)
 		}
 	}
+	// Set a provider containing the install files of the host variant of the ART boot image.
+	// The actual install rules will be created by `art_boot_images`
+	android.SetProvider(
+		ctx,
+		artBootImageHostInfoProvider,
+		artBootImageHostInfo{
+			installs: artBootImageHostInstalls,
+		},
+	)
 }
 
 // GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
@@ -968,6 +991,14 @@
 	}
 }
 
+var artBootImageHostInfoProvider = blueprint.NewProvider[artBootImageHostInfo]()
+
+// artBootImageHostInfo contains the install locations of the host variant of ART boot image
+// this contains both the primary and secondary arch locations
+type artBootImageHostInfo struct {
+	installs android.RuleBuilderInstalls
+}
+
 // Generate boot image build rules for a specific target.
 func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) bootImageVariantOutputs {
 
@@ -1344,18 +1375,7 @@
 	}
 
 	image := d.defaultBootImage
-	if image != nil {
-		if profileInstallInfo, ok := android.OtherModuleProvider(ctx, d, profileInstallInfoProvider); ok {
-			ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", profileInstallInfo.profileInstalls.String())
-			if profileInstallInfo.profileLicenseMetadataFile.Valid() {
-				ctx.Strict("DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA", profileInstallInfo.profileLicenseMetadataFile.String())
-			}
-		}
-
-		if SkipDexpreoptBootJars(ctx) {
-			return
-		}
-
+	if image != nil && !SkipDexpreoptBootJars(ctx) {
 		global := dexpreopt.GetGlobalConfig(ctx)
 		dexPaths, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
 		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " "))
@@ -1396,3 +1416,70 @@
 		OutputFile: android.OptionalPathForPath(d.bootFrameworkProfile),
 	}}
 }
+
+// artBootImages is a thin wrapper around `dex_bootjars`.
+// it creates the installation rules for the host variant of the ART boot image.
+type artBootImages struct {
+	android.ModuleBase
+
+	// A non-empty file that will be written as `LOCAL_SOONG_INSTALLED_MODULE` in out/soong/Android-*.mk
+	outputFile android.OptionalPath
+}
+
+func artBootImagesFactory() android.Module {
+	m := &artBootImages{}
+	android.InitAndroidMultiTargetsArchModule(m, android.HostSupported, android.MultilibCommon)
+	return m
+}
+
+func (dbj *artBootImages) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Create a dependency on `dex_bootjars` to access the intermediate locations of host art boot image.
+	ctx.AddDependency(ctx.Module(), dexpreoptBootJarDepTag, "dex_bootjars")
+}
+
+func (d *artBootImages) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(m android.Module) {
+		hostInstallsInfo, ok := android.OtherModuleProvider(ctx, m, artBootImageHostInfoProvider)
+		if !ok {
+			ctx.ModuleErrorf("Could not find information about the host variant of ART boot image")
+		}
+		installs := d.installFile(ctx, hostInstallsInfo.installs)
+		if len(installs) > 0 {
+			d.outputFile = android.OptionalPathForPath(installs[0])
+			// Create a phony target that can ART run-tests can depend on.
+			ctx.Phony(d.Name(), installs...)
+		} else {
+			// this might be true e.g. when building with `WITH_DEXPREOPT=false`
+			// create an empty file so that the `art_boot_images` is known to the packaging system.
+			d.outputFile = android.OptionalPathForPath(android.PathForModuleOut(ctx, "undefined_art_boot_images"))
+		}
+	})
+}
+
+// Creates an installation rule for host variant of ART boot image files.
+// Returns the list of install locations (out/host/linux-x86/...)
+func (d *artBootImages) installFile(ctx android.ModuleContext, ruleBuilderInstalls android.RuleBuilderInstalls) android.Paths {
+	var ret android.Paths
+	for _, ruleBuilderInstall := range ruleBuilderInstalls {
+		installDir := android.PathForModuleInstall(
+			ctx,
+			strings.TrimPrefix(filepath.Dir(ruleBuilderInstall.To), "/"),
+		)
+		filename := filepath.Base(ruleBuilderInstall.To)
+		ctx.InstallFile(
+			installDir,
+			filename,
+			ruleBuilderInstall.From,
+		)
+		ret = append(ret, installDir.Join(ctx, filename))
+	}
+	return ret
+}
+
+// Set `OutputFile` expclitly so that this module does not get elided when generating out/soong/Android-*.mk
+func (d *artBootImages) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{{
+		Class:      "ETC",
+		OutputFile: d.outputFile,
+	}}
+}
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 37c54b9..33c682b 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -1335,8 +1335,6 @@
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art
 DEXPREOPT_IMAGE_NAMES=art boot mainline
-DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof:/system/etc/boot-image.prof out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof
-DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-extra1.oat:/apex/art_boot_images/javalib/arm/boot-extra1.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat:/apex/art_boot_images/javalib/arm64/boot-extra1.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat:/apex/art_boot_images/javalib/x86/boot-extra1.oat
diff --git a/java/droiddoc.go b/java/droiddoc.go
index a7e92d9..2980d91 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -373,8 +373,7 @@
 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 			}
 		case libTag, sdkLibTag:
-			if _, ok := module.(SdkLibraryDependency); ok {
-				sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider)
+			if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
 				generatingLibsString := android.PrettyConcat(
 					getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
 				ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 4144de8..3650058 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -298,13 +298,12 @@
 // available, or reports an error.
 func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
 	var dexJar OptionalDexJarPath
-	if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
+	if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
 		if ctx.Config().ReleaseHiddenApiExportableStubs() {
-			dexJar = sdkLibrary.SdkApiExportableStubDexJar(ctx, kind)
+			dexJar = sdkLibrary.ExportableStubDexJarPaths[kind]
 		} else {
-			dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
+			dexJar = sdkLibrary.EverythingStubDexJarPaths[kind]
 		}
-
 	} else if j, ok := module.(UsesLibraryDependency); ok {
 		dexJar = j.DexJarBuildPath(ctx)
 	} else {
@@ -853,15 +852,15 @@
 			i.StubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
 		}
 
-		if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
-			removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
+		if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
+			removedTxtFile := sdkLibrary.RemovedTxtFiles[sdkKind]
 			i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
 		}
 	}
 
 	// If the contents includes any java_sdk_library modules then add them to the stubs.
 	for _, module := range contents {
-		if _, ok := module.(SdkLibraryDependency); ok {
+		if _, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
 			// Add information for every possible API scope needed by hidden API.
 			for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
 				addFromModule(ctx, module, apiScope)
diff --git a/java/java.go b/java/java.go
index 91c4d6d..92dcc63 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2612,17 +2612,6 @@
 	return nil
 }
 
-func (j *Import) LintDepSets() LintDepSets {
-	return LintDepSets{}
-}
-
-func (j *Import) getStrictUpdatabilityLinting() bool {
-	return false
-}
-
-func (j *Import) setStrictUpdatabilityLinting(bool) {
-}
-
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs.GetOrDefault(ctx, nil)...)
@@ -2700,7 +2689,7 @@
 					transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars)
 				}
 			}
-		} else if _, ok := module.(SdkLibraryDependency); ok {
+		} else if _, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
 			switch tag {
 			case libTag, sdkLibTag:
 				sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider)
@@ -3098,21 +3087,10 @@
 	return nil
 }
 
-func (a *DexImport) LintDepSets() LintDepSets {
-	return LintDepSets{}
-}
-
 func (j *DexImport) IsInstallable() bool {
 	return true
 }
 
-func (j *DexImport) getStrictUpdatabilityLinting() bool {
-	return false
-}
-
-func (j *DexImport) setStrictUpdatabilityLinting(bool) {
-}
-
 func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(j.properties.Jars) != 1 {
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
@@ -3315,7 +3293,7 @@
 	depName := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(depModule))
 
 	var sdkLib *string
-	if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() {
+	if lib, ok := android.OtherModuleProvider(ctx, depModule, SdkLibraryInfoProvider); ok && lib.SharedLibrary {
 		// A shared SDK library. This should be added as a top-level CLC element.
 		sdkLib = &depName
 	} else if lib, ok := depModule.(SdkLibraryComponentDependency); ok && lib.OptionalSdkLibraryImplementation() != nil {
diff --git a/java/java_test.go b/java/java_test.go
index e0fd0f2..641bf40 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -3065,6 +3065,43 @@
 		"baz.jar", bazOutputPaths[0].Rel())
 }
 
+func TestCoverage(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+		prepareForTestWithFrameworkJacocoInstrumentation,
+		PrepareForTestWithTransitiveClasspathEnabled,
+	).RunTestWithBp(t, `
+		android_app {
+			name: "foo",
+			srcs: ["foo.java"],
+			static_libs: ["android.car"],
+			platform_apis: true,
+		}
+
+		// A library in InstrumentFrameworkModules
+		java_library {
+			name: "android.car",
+			srcs: ["android.car.java"],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+	androidCar := result.ModuleForTests("android.car", "android_common")
+
+	fooJacoco := foo.Rule("jacoco")
+	fooCombine := foo.Description("for javac")
+
+	androidCarJacoco := androidCar.Rule("jacoco")
+	androidCarJavac := androidCar.Rule("javac")
+
+	android.AssertStringEquals(t, "foo instrumentation rule inputs", fooJacoco.Input.String(), fooCombine.Output.String())
+	android.AssertStringEquals(t, "android.car instrumentation rule inputs", androidCarJacoco.Input.String(), androidCarJavac.Output.String())
+
+	// The input to instrumentation for the `foo` app contains the non-instrumented android.car classes.
+	android.AssertStringListContains(t, "foo combined inputs", fooCombine.Inputs.Strings(), androidCarJavac.Output.String())
+	android.AssertStringListDoesNotContain(t, "foo combined inputs", fooCombine.Inputs.Strings(), androidCarJacoco.Output.String())
+}
+
 func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTestOnly []string, expectedTopLevel []string) {
 	t.Helper()
 	actualTrueModules := []string{}
diff --git a/java/lint.go b/java/lint.go
index 6782adc..2cbefc3 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -19,6 +19,7 @@
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -90,7 +91,6 @@
 	compileSdkKind          android.SdkKind
 	javaLanguageLevel       string
 	kotlinLanguageLevel     string
-	outputs                 lintOutputs
 	properties              LintProperties
 	extraMainlineLintErrors []string
 	compile_data            android.Paths
@@ -100,68 +100,55 @@
 	buildModuleReportZip bool
 }
 
-type lintOutputs struct {
-	html              android.Path
-	text              android.Path
-	xml               android.Path
-	referenceBaseline android.Path
-
-	depSets LintDepSets
-}
-
-type lintOutputsIntf interface {
-	lintOutputs() *lintOutputs
-}
-
-type LintDepSetsIntf interface {
-	LintDepSets() LintDepSets
-
-	// Methods used to propagate strict_updatability_linting values.
-	GetStrictUpdatabilityLinting() bool
-	SetStrictUpdatabilityLinting(bool)
-}
-
 type LintDepSets struct {
-	HTML, Text, XML *android.DepSet[android.Path]
+	HTML, Text, XML, Baseline *android.DepSet[android.Path]
 }
 
 type LintDepSetsBuilder struct {
-	HTML, Text, XML *android.DepSetBuilder[android.Path]
+	HTML, Text, XML, Baseline *android.DepSetBuilder[android.Path]
 }
 
 func NewLintDepSetBuilder() LintDepSetsBuilder {
 	return LintDepSetsBuilder{
-		HTML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
-		Text: android.NewDepSetBuilder[android.Path](android.POSTORDER),
-		XML:  android.NewDepSetBuilder[android.Path](android.POSTORDER),
+		HTML:     android.NewDepSetBuilder[android.Path](android.POSTORDER),
+		Text:     android.NewDepSetBuilder[android.Path](android.POSTORDER),
+		XML:      android.NewDepSetBuilder[android.Path](android.POSTORDER),
+		Baseline: android.NewDepSetBuilder[android.Path](android.POSTORDER),
 	}
 }
 
-func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
+func (l LintDepSetsBuilder) Direct(html, text, xml android.Path, baseline android.OptionalPath) LintDepSetsBuilder {
 	l.HTML.Direct(html)
 	l.Text.Direct(text)
 	l.XML.Direct(xml)
+	if baseline.Valid() {
+		l.Baseline.Direct(baseline.Path())
+	}
 	return l
 }
 
-func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
-	if depSets.HTML != nil {
-		l.HTML.Transitive(depSets.HTML)
+func (l LintDepSetsBuilder) Transitive(info *LintInfo) LintDepSetsBuilder {
+	if info.TransitiveHTML != nil {
+		l.HTML.Transitive(info.TransitiveHTML)
 	}
-	if depSets.Text != nil {
-		l.Text.Transitive(depSets.Text)
+	if info.TransitiveText != nil {
+		l.Text.Transitive(info.TransitiveText)
 	}
-	if depSets.XML != nil {
-		l.XML.Transitive(depSets.XML)
+	if info.TransitiveXML != nil {
+		l.XML.Transitive(info.TransitiveXML)
+	}
+	if info.TransitiveBaseline != nil {
+		l.Baseline.Transitive(info.TransitiveBaseline)
 	}
 	return l
 }
 
 func (l LintDepSetsBuilder) Build() LintDepSets {
 	return LintDepSets{
-		HTML: l.HTML.Build(),
-		Text: l.Text.Build(),
-		XML:  l.XML.Build(),
+		HTML:     l.HTML.Build(),
+		Text:     l.Text.Build(),
+		XML:      l.XML.Build(),
+		Baseline: l.Baseline.Build(),
 	}
 }
 
@@ -209,24 +196,18 @@
 	},
 }
 
-func (l *linter) LintDepSets() LintDepSets {
-	return l.outputs.depSets
-}
+var LintProvider = blueprint.NewProvider[*LintInfo]()
 
-func (l *linter) GetStrictUpdatabilityLinting() bool {
-	return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
-}
+type LintInfo struct {
+	HTML              android.Path
+	Text              android.Path
+	XML               android.Path
+	ReferenceBaseline android.Path
 
-func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
-	l.properties.Lint.Strict_updatability_linting = &strictLinting
-}
-
-var _ LintDepSetsIntf = (*linter)(nil)
-
-var _ lintOutputsIntf = (*linter)(nil)
-
-func (l *linter) lintOutputs() *lintOutputs {
-	return &l.outputs
+	TransitiveHTML     *android.DepSet[android.Path]
+	TransitiveText     *android.DepSet[android.Path]
+	TransitiveXML      *android.DepSet[android.Path]
+	TransitiveBaseline *android.DepSet[android.Path]
 }
 
 func (l *linter) enabled() bool {
@@ -262,7 +243,9 @@
 	return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
 }
 
-func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
+func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path,
+	baselines android.Paths) lintPaths {
+
 	projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
 	// Lint looks for a lint.xml file next to the project.xml file, give it one.
 	configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
@@ -325,12 +308,10 @@
 	cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
 	cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
 
-	if l.GetStrictUpdatabilityLinting() {
+	if Bool(l.properties.Lint.Strict_updatability_linting) && len(baselines) > 0 {
 		// Verify the module does not baseline issues that endanger safe updatability.
-		if l.properties.Lint.Baseline_filename != nil {
-			cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
-			cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
-		}
+		strictUpdatabilityChecksOutputFile := VerifyStrictUpdatabilityChecks(ctx, baselines)
+		cmd.Validation(strictUpdatabilityChecksOutputFile)
 	}
 
 	return lintPaths{
@@ -342,6 +323,22 @@
 
 }
 
+func VerifyStrictUpdatabilityChecks(ctx android.ModuleContext, baselines android.Paths) android.Path {
+	rule := android.NewRuleBuilder(pctx, ctx)
+	baselineRspFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check_baselines.rsp")
+	outputFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check.stamp")
+	rule.Command().Text("rm -f").Output(outputFile)
+	rule.Command().
+		BuiltTool("lint_strict_updatability_checks").
+		FlagWithArg("--name ", ctx.ModuleName()).
+		FlagWithRspFileInputList("--baselines ", baselineRspFile, baselines).
+		FlagForEachArg("--disallowed_issues ", updatabilityChecks)
+	rule.Command().Text("touch").Output(outputFile)
+	rule.Build("lint_strict_updatability_checks", "lint strict updatability checks")
+
+	return outputFile
+}
+
 // generateManifest adds a command to the rule to write a simple manifest that contains the
 // minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
 func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
@@ -411,6 +408,26 @@
 	l.extraLintCheckJars = append(l.extraLintCheckJars, android.PathForSource(ctx,
 		"prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar"))
 
+	var baseline android.OptionalPath
+	if l.properties.Lint.Baseline_filename != nil {
+		baseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
+	}
+
+	html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
+	text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
+	xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
+	referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
+
+	depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml, baseline)
+
+	ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
+		if info, ok := android.OtherModuleProvider(ctx, dep, LintProvider); ok {
+			depSetsBuilder.Transitive(info)
+		}
+	})
+
+	depSets := depSetsBuilder.Build()
+
 	rule := android.NewRuleBuilder(pctx, ctx).
 		Sbox(android.PathForModuleOut(ctx, "lint"),
 			android.PathForModuleOut(ctx, "lint.sbox.textproto")).
@@ -437,20 +454,9 @@
 	srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
 	rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList).Implicits(l.compile_data)
 
-	lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
+	baselines := depSets.Baseline.ToList()
 
-	html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
-	text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
-	xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
-	referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
-
-	depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
-
-	ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
-		if depLint, ok := dep.(LintDepSetsIntf); ok {
-			depSetsBuilder.Transitive(depLint.LintDepSets())
-		}
-	})
+	lintPaths := l.writeLintProjectXML(ctx, rule, srcsList, baselines)
 
 	rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
 	rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
@@ -505,8 +511,8 @@
 		cmd.FlagWithArg("--check ", checkOnly)
 	}
 
-	if l.properties.Lint.Baseline_filename != nil {
-		cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
+	if baseline.Valid() {
+		cmd.FlagWithInput("--baseline ", baseline.Path())
 	}
 
 	cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
@@ -530,25 +536,30 @@
 
 	rule.Build("lint", "lint")
 
-	l.outputs = lintOutputs{
-		html:              html,
-		text:              text,
-		xml:               xml,
-		referenceBaseline: referenceBaseline,
+	android.SetProvider(ctx, LintProvider, &LintInfo{
+		HTML:              html,
+		Text:              text,
+		XML:               xml,
+		ReferenceBaseline: referenceBaseline,
 
-		depSets: depSetsBuilder.Build(),
-	}
+		TransitiveHTML:     depSets.HTML,
+		TransitiveText:     depSets.Text,
+		TransitiveXML:      depSets.XML,
+		TransitiveBaseline: depSets.Baseline,
+	})
 
 	if l.buildModuleReportZip {
-		l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
+		l.reports = BuildModuleLintReportZips(ctx, depSets, nil)
 	}
 
 	// Create a per-module phony target to run the lint check.
 	phonyName := ctx.ModuleName() + "-lint"
 	ctx.Phony(phonyName, xml)
+
+	ctx.SetOutputFiles(android.Paths{xml}, ".lint")
 }
 
-func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
+func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets, validations android.Paths) android.Paths {
 	htmlList := android.SortedUniquePaths(depSets.HTML.ToList())
 	textList := android.SortedUniquePaths(depSets.Text.ToList())
 	xmlList := android.SortedUniquePaths(depSets.XML.ToList())
@@ -558,13 +569,13 @@
 	}
 
 	htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
-	lintZip(ctx, htmlList, htmlZip)
+	lintZip(ctx, htmlList, htmlZip, validations)
 
 	textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
-	lintZip(ctx, textList, textZip)
+	lintZip(ctx, textList, textZip, validations)
 
 	xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
-	lintZip(ctx, xmlList, xmlZip)
+	lintZip(ctx, xmlList, xmlZip, validations)
 
 	return android.Paths{htmlZip, textZip, xmlZip}
 }
@@ -642,7 +653,7 @@
 		return
 	}
 
-	var outputs []*lintOutputs
+	var outputs []*LintInfo
 	var dirs []string
 	ctx.VisitAllModules(func(m android.Module) {
 		if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
@@ -658,14 +669,14 @@
 			}
 		}
 
-		if l, ok := m.(lintOutputsIntf); ok {
-			outputs = append(outputs, l.lintOutputs())
+		if lintInfo, ok := android.OtherModuleProvider(ctx, m, LintProvider); ok {
+			outputs = append(outputs, lintInfo)
 		}
 	})
 
 	dirs = android.SortedUniqueStrings(dirs)
 
-	zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
+	zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) {
 		var paths android.Paths
 
 		for _, output := range outputs {
@@ -674,20 +685,20 @@
 			}
 		}
 
-		lintZip(ctx, paths, outputPath)
+		lintZip(ctx, paths, outputPath, nil)
 	}
 
 	l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
-	zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
+	zip(l.htmlZip, func(l *LintInfo) android.Path { return l.HTML })
 
 	l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
-	zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
+	zip(l.textZip, func(l *LintInfo) android.Path { return l.Text })
 
 	l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
-	zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
+	zip(l.xmlZip, func(l *LintInfo) android.Path { return l.XML })
 
 	l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip")
-	zip(l.referenceBaselineZip, func(l *lintOutputs) android.Path { return l.referenceBaseline })
+	zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline })
 
 	ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
 }
@@ -703,17 +714,9 @@
 func init() {
 	android.RegisterParallelSingletonType("lint",
 		func() android.Singleton { return &lintSingleton{} })
-
-	registerLintBuildComponents(android.InitRegistrationContext)
 }
 
-func registerLintBuildComponents(ctx android.RegistrationContext) {
-	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
-	})
-}
-
-func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
+func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath, validations android.Paths) {
 	paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
 
 	sort.Slice(paths, func(i, j int) bool {
@@ -725,19 +728,8 @@
 	rule.Command().BuiltTool("soong_zip").
 		FlagWithOutput("-o ", outputPath).
 		FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
-		FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
+		FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths).
+		Validations(validations)
 
 	rule.Build(outputPath.Base(), outputPath.Base())
 }
-
-// Enforce the strict updatability linting to all applicable transitive dependencies.
-func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
-	m := ctx.Module()
-	if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
-		ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
-			if a, ok := d.(LintDepSetsIntf); ok {
-				a.SetStrictUpdatabilityLinting(true)
-			}
-		})
-	}
-}
diff --git a/java/lint_test.go b/java/lint_test.go
index b51753f..afe3914 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -164,7 +164,7 @@
 			sdk_version: "current",
 			lint: {
 				strict_updatability_linting: true,
-				baseline_filename: "lint-baseline.xml",
+				baseline_filename: "foo_lint_baseline.xml",
 			},
 		}
 
@@ -176,7 +176,7 @@
 			min_sdk_version: "29",
 			sdk_version: "current",
 			lint: {
-				baseline_filename: "lint-baseline.xml",
+				baseline_filename: "bar_lint_baseline.xml",
 			}
 		}
 	`
@@ -188,18 +188,13 @@
 		RunTestWithBp(t, bp)
 
 	foo := result.ModuleForTests("foo", "android_common")
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, foo.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command,
-		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
+	strictUpdatabilityCheck := foo.Output("lint_strict_updatability_check.stamp")
+	if !strings.Contains(strictUpdatabilityCheck.RuleParams.Command,
+		"--disallowed_issues NewApi") {
 		t.Error("did not restrict baselining NewApi")
 	}
-
-	bar := result.ModuleForTests("bar", "android_common")
-	sboxProto = android.RuleBuilderSboxProtoForTests(t, result.TestContext, bar.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command,
-		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
-		t.Error("did not restrict baselining NewApi")
-	}
+	android.AssertStringListContains(t, "strict updatability check baseline inputs", strictUpdatabilityCheck.Inputs.Strings(), "foo_lint_baseline.xml")
+	android.AssertStringListContains(t, "strict updatability check baseline inputs", strictUpdatabilityCheck.Inputs.Strings(), "bar_lint_baseline.xml")
 }
 
 func TestJavaLintDatabaseSelectionFull(t *testing.T) {
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index d794e51..5bb7754 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -33,6 +33,7 @@
 	platformBootclasspathArtBootJarDepTag  = bootclasspathDependencyTag{name: "art-boot-jar"}
 	platformBootclasspathBootJarDepTag     = bootclasspathDependencyTag{name: "platform-boot-jar"}
 	platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"}
+	platformBootclasspathImplLibDepTag     = dependencyTag{name: "impl-lib-tag"}
 )
 
 type platformBootclasspathModule struct {
@@ -111,12 +112,18 @@
 	// Add dependencies on all the ART jars.
 	global := dexpreopt.GetGlobalConfig(ctx)
 	addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art")
+
+	var bootImageModuleNames []string
+
 	// TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
 	addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag)
+	bootImageModuleNames = append(bootImageModuleNames, global.ArtApexJars.CopyOfJars()...)
 
 	// Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable
 	// APEXes.
-	addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag)
+	platformJars := b.platformJars(ctx)
+	addDependenciesOntoBootImageModules(ctx, platformJars, platformBootclasspathBootJarDepTag)
+	bootImageModuleNames = append(bootImageModuleNames, platformJars.CopyOfJars()...)
 
 	// Add dependencies on all the updatable jars, except the ART jars.
 	apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
@@ -127,9 +134,17 @@
 	addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...)
 	// TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
 	addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
+	bootImageModuleNames = append(bootImageModuleNames, apexJars.CopyOfJars()...)
 
 	// Add dependencies on all the fragments.
 	b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
+
+	for _, bootImageModuleName := range bootImageModuleNames {
+		implLibName := implLibraryModuleName(bootImageModuleName)
+		if ctx.OtherModuleExists(implLibName) {
+			ctx.AddFarVariationDependencies(nil, platformBootclasspathImplLibDepTag, implLibName)
+		}
+	}
 }
 
 func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) {
@@ -166,8 +181,15 @@
 	allModules = append(allModules, apexModules...)
 	b.configuredModules = allModules
 
+	// Do not add implLibModule to allModules as the impl lib is only used to collect the
+	// transitive source files
+	var implLibModule []android.Module
+	ctx.VisitDirectDepsWithTag(implLibraryTag, func(m android.Module) {
+		implLibModule = append(implLibModule, m)
+	})
+
 	var transitiveSrcFiles android.Paths
-	for _, module := range allModules {
+	for _, module := range append(allModules, implLibModule...) {
 		if depInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			if depInfo.TransitiveSrcFiles != nil {
 				transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...)
diff --git a/java/rro_test.go b/java/rro_test.go
index 742c839..4d79130 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -282,7 +282,7 @@
 			enforceRROTargets: []string{"foo"},
 			rroDirs: map[string][]string{
 				"foo": {"product/vendor/blah/overlay/lib2/res"},
-				"bar": {"product/vendor/blah/overlay/lib2/res"},
+				"bar": nil,
 			},
 		},
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index c2b1c4f..f308772 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -922,7 +922,7 @@
 	c.initSdkLibraryComponent(module)
 }
 
-func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool {
+func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied() bool {
 	namePtr := proptools.StringPtr(c.module.RootLibraryName())
 	c.sdkLibraryComponentProperties.SdkLibraryName = namePtr
 
@@ -944,12 +944,32 @@
 	return c.sharedLibrary()
 }
 
-func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) {
+func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) SdkLibraryInfo {
 	c.doctagPaths = android.PathsForModuleSrc(ctx, c.commonSdkLibraryProperties.Doctag_files)
-}
 
-func (c *commonToSdkLibraryAndImport) getImplLibraryModule() *Library {
-	return c.implLibraryModule
+	everythingStubPaths := make(map[android.SdkKind]OptionalDexJarPath)
+	exportableStubPaths := make(map[android.SdkKind]OptionalDexJarPath)
+	removedApiFilePaths := make(map[android.SdkKind]android.OptionalPath)
+	for kind := android.SdkNone; kind <= android.SdkPrivate; kind += 1 {
+		everythingStubPath := makeUnsetDexJarPath()
+		exportableStubPath := makeUnsetDexJarPath()
+		removedApiFilePath := android.OptionalPath{}
+		if scopePath := c.findClosestScopePath(sdkKindToApiScope(kind)); scopePath != nil {
+			everythingStubPath = scopePath.stubsDexJarPath
+			exportableStubPath = scopePath.exportableStubsDexJarPath
+			removedApiFilePath = scopePath.removedApiFilePath
+		}
+		everythingStubPaths[kind] = everythingStubPath
+		exportableStubPaths[kind] = exportableStubPath
+		removedApiFilePaths[kind] = removedApiFilePath
+	}
+
+	return SdkLibraryInfo{
+		EverythingStubDexJarPaths: everythingStubPaths,
+		ExportableStubDexJarPaths: exportableStubPaths,
+		RemovedTxtFiles:           removedApiFilePaths,
+		SharedLibrary:             c.sharedLibrary(),
+	}
 }
 
 // The component names for different outputs of the java_sdk_library.
@@ -1023,29 +1043,6 @@
 	return nil
 }
 
-// selectScopePaths returns the *scopePaths appropriate for the specific kind.
-//
-// If the module does not support the specific kind then it will return the *scopePaths for the
-// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then
-// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not.
-func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths {
-	apiScope := sdkKindToApiScope(kind)
-
-	paths := c.findClosestScopePath(apiScope)
-	if paths == nil {
-		var scopes []string
-		for _, s := range AllApiScopes {
-			if c.findScopePaths(s) != nil {
-				scopes = append(scopes, s.name)
-			}
-		}
-		ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.RootLibraryName(), scopes)
-		return nil
-	}
-
-	return paths
-}
-
 // sdkKindToApiScope maps from android.SdkKind to apiScope.
 func sdkKindToApiScope(kind android.SdkKind) *apiScope {
 	var apiScope *apiScope
@@ -1064,37 +1061,6 @@
 	return apiScope
 }
 
-// to satisfy SdkLibraryDependency interface
-func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath {
-	paths := c.selectScopePaths(ctx, kind)
-	if paths == nil {
-		return makeUnsetDexJarPath()
-	}
-
-	return paths.stubsDexJarPath
-}
-
-// to satisfy SdkLibraryDependency interface
-func (c *commonToSdkLibraryAndImport) SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath {
-	paths := c.selectScopePaths(ctx, kind)
-	if paths == nil {
-		return makeUnsetDexJarPath()
-	}
-
-	return paths.exportableStubsDexJarPath
-}
-
-// to satisfy SdkLibraryDependency interface
-func (c *commonToSdkLibraryAndImport) SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath {
-	apiScope := sdkKindToApiScope(kind)
-	paths := c.findScopePaths(apiScope)
-	if paths == nil {
-		return android.OptionalPath{}
-	}
-
-	return paths.removedApiFilePath
-}
-
 func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
 	componentProps := &struct {
 		SdkLibraryName              *string
@@ -1185,36 +1151,25 @@
 var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
 var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
 
-// Provides access to sdk_version related files, e.g. header and implementation jars.
-type SdkLibraryDependency interface {
-	SdkLibraryComponentDependency
-
-	// SdkApiStubDexJar returns the dex jar for the stubs for the prebuilt
-	// java_sdk_library_import module. It is needed by the hiddenapi processing tool which
-	// processes dex files.
-	SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
-
-	// SdkApiExportableStubDexJar returns the exportable dex jar for the stubs for
-	// java_sdk_library module. It is needed by the hiddenapi processing tool which processes
-	// dex files.
-	SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
-
-	// SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind.
-	SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath
-
-	// sharedLibrary returns true if this can be used as a shared library.
-	sharedLibrary() bool
-
-	// getImplLibraryModule returns the pointer to the implementation library submodule of this
-	// sdk library.
-	getImplLibraryModule() *Library
-}
-
 type SdkLibraryInfo struct {
 	// GeneratingLibs is the names of the library modules that this sdk library
 	// generates. Note that this only includes the name of the modules that other modules can
 	// depend on, and is not a holistic list of generated modules.
 	GeneratingLibs []string
+
+	// Map of sdk kind to the dex jar for the "everything" stubs.
+	// It is needed by the hiddenapi processing tool which processes dex files.
+	EverythingStubDexJarPaths map[android.SdkKind]OptionalDexJarPath
+
+	// Map of sdk kind to the dex jar for the "exportable" stubs.
+	// It is needed by the hiddenapi processing tool which processes dex files.
+	ExportableStubDexJarPaths map[android.SdkKind]OptionalDexJarPath
+
+	// Map of sdk kind to the optional path to the removed.txt file.
+	RemovedTxtFiles map[android.SdkKind]android.OptionalPath
+
+	// Whether if this can be used as a shared library.
+	SharedLibrary bool
 }
 
 var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]()
@@ -1248,12 +1203,13 @@
 	builtInstalledForApex []dexpreopterInstall
 }
 
-var _ SdkLibraryDependency = (*SdkLibrary)(nil)
-
 func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool {
 	return module.sdkLibraryProperties.Generate_system_and_test_apis
 }
 
+var _ UsesLibraryDependency = (*SdkLibrary)(nil)
+
+// To satisfy the UsesLibraryDependency interface
 func (module *SdkLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	if module.implLibraryModule != nil {
 		return module.implLibraryModule.DexJarBuildPath(ctx)
@@ -1261,6 +1217,7 @@
 	return makeUnsetDexJarPath()
 }
 
+// To satisfy the UsesLibraryDependency interface
 func (module *SdkLibrary) DexJarInstallPath() android.Path {
 	if module.implLibraryModule != nil {
 		return module.implLibraryModule.DexJarInstallPath()
@@ -1323,7 +1280,7 @@
 }
 
 func CheckMinSdkVersion(ctx android.ModuleContext, module *Library) {
-	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.ModuleContext, do android.PayloadDepsCallback) {
+	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.BaseModuleContext, do android.PayloadDepsCallback) {
 		ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 			isExternal := !module.depIsInSameApex(ctx, child)
 			if am, ok := child.(android.ApexModule); ok {
@@ -1448,8 +1405,6 @@
 		module.HideFromMake()
 	}
 
-	module.generateCommonBuildActions(ctx)
-
 	module.stem = proptools.StringDefault(module.overridableProperties.Stem, ctx.ModuleName())
 
 	module.provideHiddenAPIPropertyInfo(ctx)
@@ -1482,11 +1437,11 @@
 			if dep, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok {
 				module.implLibraryHeaderJars = append(module.implLibraryHeaderJars, dep.HeaderJars...)
 				module.implLibraryModule = to.(*Library)
-				android.SetProvider(ctx, JavaInfoProvider, dep)
 			}
 		}
 	})
 
+	sdkLibInfo := module.generateCommonBuildActions(ctx)
 	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		module.hideApexVariantFromMake = true
@@ -1515,7 +1470,10 @@
 		module.dexer.proguardDictionary = module.implLibraryModule.dexer.proguardDictionary
 		module.dexer.proguardUsageZip = module.implLibraryModule.dexer.proguardUsageZip
 		module.linter.reports = module.implLibraryModule.linter.reports
-		module.linter.outputs.depSets = module.implLibraryModule.LintDepSets()
+
+		if lintInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, LintProvider); ok {
+			android.SetProvider(ctx, LintProvider, lintInfo)
+		}
 
 		if !module.Host() {
 			module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile
@@ -1570,9 +1528,8 @@
 		setOutputFiles(ctx, module.implLibraryModule.Module)
 	}
 
-	android.SetProvider(ctx, SdkLibraryInfoProvider, SdkLibraryInfo{
-		GeneratingLibs: generatingLibs,
-	})
+	sdkLibInfo.GeneratingLibs = generatingLibs
+	android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo)
 }
 
 func (module *SdkLibrary) BuiltInstalledForApex() []dexpreopterInstall {
@@ -1883,7 +1840,7 @@
 			module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false)
 		}
 
-		if module.initCommonAfterDefaultsApplied(ctx) {
+		if module.initCommonAfterDefaultsApplied() {
 			module.CreateInternalModules(ctx)
 		}
 	})
@@ -1962,8 +1919,6 @@
 	installFile android.Path
 }
 
-var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
-
 // The type of a structure that contains a field of type sdkLibraryScopeProperties
 // for each apiscope in allApiScopes, e.g. something like:
 //
@@ -2019,7 +1974,7 @@
 	InitJavaModule(module, android.HostAndDeviceSupported)
 
 	module.SetDefaultableHook(func(mctx android.DefaultableHookContext) {
-		if module.initCommonAfterDefaultsApplied(mctx) {
+		if module.initCommonAfterDefaultsApplied() {
 			module.createInternalModules(mctx)
 		}
 	})
@@ -2140,8 +2095,6 @@
 var _ hiddenAPIModule = (*SdkLibraryImport)(nil)
 
 func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	module.generateCommonBuildActions(ctx)
-
 	// Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework
 	module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar")
 
@@ -2171,6 +2124,7 @@
 			}
 		}
 	})
+	sdkLibInfo := module.generateCommonBuildActions(ctx)
 
 	// Populate the scope paths with information from the properties.
 	for apiScope, scopeProperties := range module.scopeProperties {
@@ -2212,11 +2166,12 @@
 		setOutputFiles(ctx, module.implLibraryModule.Module)
 	}
 
-	android.SetProvider(ctx, SdkLibraryInfoProvider, SdkLibraryInfo{
-		GeneratingLibs: generatingLibs,
-	})
+	sdkLibInfo.GeneratingLibs = generatingLibs
+	android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo)
 }
 
+var _ UsesLibraryDependency = (*SdkLibraryImport)(nil)
+
 // to satisfy UsesLibraryDependency interface
 func (module *SdkLibraryImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	// The dex implementation jar extracted from the .apex file should be used in preference to the
@@ -2254,29 +2209,6 @@
 }
 
 // to satisfy apex.javaDependency interface
-func (module *SdkLibraryImport) LintDepSets() LintDepSets {
-	if module.implLibraryModule == nil {
-		return LintDepSets{}
-	} else {
-		return module.implLibraryModule.LintDepSets()
-	}
-}
-
-func (module *SdkLibraryImport) GetStrictUpdatabilityLinting() bool {
-	if module.implLibraryModule == nil {
-		return false
-	} else {
-		return module.implLibraryModule.GetStrictUpdatabilityLinting()
-	}
-}
-
-func (module *SdkLibraryImport) SetStrictUpdatabilityLinting(strictLinting bool) {
-	if module.implLibraryModule != nil {
-		module.implLibraryModule.SetStrictUpdatabilityLinting(strictLinting)
-	}
-}
-
-// to satisfy apex.javaDependency interface
 func (module *SdkLibraryImport) Stem() string {
 	return module.BaseModuleName()
 }
@@ -2462,7 +2394,7 @@
 	s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk
 	s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk
 
-	implLibrary := sdk.getImplLibraryModule()
+	implLibrary := sdk.implLibraryModule
 	if implLibrary != nil && implLibrary.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided {
 		s.DexPreoptProfileGuided = proptools.BoolPtr(true)
 	}
diff --git a/java/sdk_library_external.go b/java/sdk_library_external.go
deleted file mode 100644
index 4f83981..0000000
--- a/java/sdk_library_external.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2020 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 java
-
-import (
-	"android/soong/android"
-)
-
-type partitionGroup int
-
-// Representation of partition group for checking inter-partition library dependencies.
-// Between system and system_ext, there are no restrictions of dependencies,
-// so we can treat these partitions as the same in terms of inter-partition dependency.
-// Same policy is applied between vendor and odm partiton.
-const (
-	partitionGroupNone partitionGroup = iota
-	// group for system, and system_ext partition
-	partitionGroupSystem
-	// group for vendor and odm partition
-	partitionGroupVendor
-	// product partition
-	partitionGroupProduct
-)
-
-func (g partitionGroup) String() string {
-	switch g {
-	case partitionGroupSystem:
-		return "system"
-	case partitionGroupVendor:
-		return "vendor"
-	case partitionGroupProduct:
-		return "product"
-	}
-
-	return ""
-}
-
-// Get partition group of java module that can be used at inter-partition dependency check.
-// We currently have three groups
-//
-//	(system, system_ext) => system partition group
-//	(vendor, odm) => vendor partition group
-//	(product) => product partition group
-func (j *Module) partitionGroup(ctx android.EarlyModuleContext) partitionGroup {
-	// system and system_ext partition can be treated as the same in terms of inter-partition dependency.
-	if j.Platform() || j.SystemExtSpecific() {
-		return partitionGroupSystem
-	}
-
-	// vendor and odm partition can be treated as the same in terms of inter-partition dependency.
-	if j.SocSpecific() || j.DeviceSpecific() {
-		return partitionGroupVendor
-	}
-
-	// product partition is independent.
-	if j.ProductSpecific() {
-		return partitionGroupProduct
-	}
-
-	panic("Cannot determine partition type")
-}
-
-func (j *Module) allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool {
-	return inList(j.Name(), ctx.Config().InterPartitionJavaLibraryAllowList())
-}
-
-func (j *Module) syspropWithPublicStubs() bool {
-	return j.deviceProperties.SyspropPublicStub != ""
-}
-
-type javaSdkLibraryEnforceContext interface {
-	Name() string
-	allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool
-	partitionGroup(ctx android.EarlyModuleContext) partitionGroup
-	syspropWithPublicStubs() bool
-}
-
-var _ javaSdkLibraryEnforceContext = (*Module)(nil)
-
-func (j *Module) checkPartitionsForJavaDependency(ctx android.EarlyModuleContext, propName string, dep javaSdkLibraryEnforceContext) {
-	if dep.allowListedInterPartitionJavaLibrary(ctx) {
-		return
-	}
-
-	if dep.syspropWithPublicStubs() {
-		return
-	}
-
-	// If product interface is not enforced, skip check between system and product partition.
-	// But still need to check between product and vendor partition because product interface flag
-	// just represents enforcement between product and system, and vendor interface enforcement
-	// that is enforced here by precondition is representing enforcement between vendor and other partitions.
-	if !ctx.Config().EnforceProductPartitionInterface() {
-		productToSystem := j.partitionGroup(ctx) == partitionGroupProduct && dep.partitionGroup(ctx) == partitionGroupSystem
-		systemToProduct := j.partitionGroup(ctx) == partitionGroupSystem && dep.partitionGroup(ctx) == partitionGroupProduct
-
-		if productToSystem || systemToProduct {
-			return
-		}
-	}
-
-	// If module and dependency library is inter-partition
-	if j.partitionGroup(ctx) != dep.partitionGroup(ctx) {
-		errorFormat := "dependency on java_library (%q) is not allowed across the partitions (%s -> %s), use java_sdk_library instead"
-		ctx.PropertyErrorf(propName, errorFormat, dep.Name(), j.partitionGroup(ctx), dep.partitionGroup(ctx))
-	}
-}
diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go
index 6f24902..ca088cf 100644
--- a/java/sdk_library_internal.go
+++ b/java/sdk_library_internal.go
@@ -33,9 +33,13 @@
 	implLibSuffix    = ".impl"
 )
 
+func implLibraryModuleName(sdkLibName string) string {
+	return sdkLibName + implLibSuffix
+}
+
 // Module name of the runtime implementation library
 func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
-	return c.module.RootLibraryName() + implLibSuffix
+	return implLibraryModuleName(c.module.RootLibraryName())
 }
 
 // Module name of the XML file for the lib
diff --git a/java/testing.go b/java/testing.go
index 0c79e9f..d5a19e9 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -388,7 +388,6 @@
 	RegisterStubsBuildComponents(ctx)
 	RegisterSystemModulesBuildComponents(ctx)
 	registerSystemserverClasspathBuildComponents(ctx)
-	registerLintBuildComponents(ctx)
 	android.RegisterApexContributionsBuildComponents(ctx)
 }
 
@@ -424,7 +423,9 @@
 		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
 		"stub-annotations",
+
 		"aconfig-annotations-lib",
+		"aconfig_storage_reader_java",
 		"unsupportedappusage",
 	}
 
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
index fee1923..3c484d8 100644
--- a/rust/config/x86_64_device.go
+++ b/rust/config/x86_64_device.go
@@ -29,6 +29,7 @@
 
 	x86_64ArchVariantRustFlags = map[string][]string{
 		"":                            []string{},
+		"alderlake":                   []string{"-C target-cpu=alderlake"},
 		"broadwell":                   []string{"-C target-cpu=broadwell"},
 		"goldmont":                    []string{"-C target-cpu=goldmont"},
 		"goldmont-plus":               []string{"-C target-cpu=goldmont-plus"},
diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go
index 5d9d88a..3c597cc 100644
--- a/rust/config/x86_device.go
+++ b/rust/config/x86_device.go
@@ -27,6 +27,7 @@
 
 	x86ArchVariantRustFlags = map[string][]string{
 		"":                            []string{},
+		"alderlake":                   []string{"-C target-cpu=alderlake"},
 		"atom":                        []string{"-C target-cpu=atom"},
 		"broadwell":                   []string{"-C target-cpu=broadwell"},
 		"goldmont":                    []string{"-C target-cpu=goldmont"},
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 3d81b83..00b3ca5 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -184,12 +184,21 @@
     libs: ["ninja_rsp"],
 }
 
-python_test_host {
-    name: "lint_project_xml_test",
-    main: "lint_project_xml_test.py",
+python_binary_host {
+    name: "lint_strict_updatability_checks",
+    main: "lint_strict_updatability_checks.py",
     srcs: [
-        "lint_project_xml_test.py",
-        "lint_project_xml.py",
+        "lint_strict_updatability_checks.py",
+    ],
+    libs: ["ninja_rsp"],
+}
+
+python_test_host {
+    name: "lint_strict_updatability_checks_test",
+    main: "lint_strict_updatability_checks_test.py",
+    srcs: [
+        "lint_strict_updatability_checks_test.py",
+        "lint_strict_updatability_checks.py",
     ],
     libs: ["ninja_rsp"],
     test_suites: ["general-tests"],
diff --git a/scripts/lint_project_xml.py b/scripts/lint_project_xml.py
index c40b07d..ce6aa21 100755
--- a/scripts/lint_project_xml.py
+++ b/scripts/lint_project_xml.py
@@ -75,8 +75,6 @@
                       help='file containing the module\'s manifest.')
   parser.add_argument('--merged_manifest', dest='merged_manifest',
                       help='file containing merged manifest for the module and its dependencies.')
-  parser.add_argument('--baseline', dest='baseline_path',
-                      help='file containing baseline lint issues.')
   parser.add_argument('--library', dest='library', action='store_true',
                       help='mark the module as a library.')
   parser.add_argument('--test', dest='test', action='store_true',
@@ -94,8 +92,6 @@
                      help='treat a lint issue as a warning.')
   group.add_argument('--disable_check', dest='checks', action=check_action('ignore'), default=[],
                      help='disable a lint issue.')
-  group.add_argument('--disallowed_issues', dest='disallowed_issues', default=[],
-                     help='lint issues disallowed in the baseline file')
   return parser.parse_args()
 
 
@@ -140,30 +136,10 @@
   f.write("</lint>\n")
 
 
-def check_baseline_for_disallowed_issues(baseline, forced_checks):
-  issues_element = baseline.documentElement
-  if issues_element.tagName != 'issues':
-    raise RuntimeError('expected issues tag at root')
-  issues = issues_element.getElementsByTagName('issue')
-  disallowed = set()
-  for issue in issues:
-    id = issue.getAttribute('id')
-    if id in forced_checks:
-      disallowed.add(id)
-  return disallowed
-
-
 def main():
   """Program entry point."""
   args = parse_args()
 
-  if args.baseline_path:
-    baseline = minidom.parse(args.baseline_path)
-    disallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
-    if disallowed_issues:
-      sys.exit('disallowed issues %s found in lint baseline file %s for module %s'
-                         % (disallowed_issues, args.baseline_path, args.name))
-
   if args.project_out:
     with open(args.project_out, 'w') as f:
       write_project_xml(f, args)
diff --git a/scripts/lint_strict_updatability_checks.py b/scripts/lint_strict_updatability_checks.py
new file mode 100755
index 0000000..5b5dfd8
--- /dev/null
+++ b/scripts/lint_strict_updatability_checks.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+#
+
+"""This file checks baselines passed to Android Lint for checks that must not be baselined."""
+
+import argparse
+import sys
+from xml.dom import minidom
+
+from ninja_rsp import NinjaRspFileReader
+
+
+def parse_args():
+  """Parse commandline arguments."""
+
+  def convert_arg_line_to_args(arg_line):
+    for arg in arg_line.split():
+      if arg.startswith('#'):
+        return
+      if not arg.strip():
+        continue
+      yield arg
+
+  parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+  parser.convert_arg_line_to_args = convert_arg_line_to_args
+  parser.add_argument('--name', dest='name',
+                      help='name of the module.')
+  parser.add_argument('--baselines', dest='baselines', action='append', default=[],
+                      help='file containing whitespace separated list of baseline files.')
+  parser.add_argument('--disallowed_issues', dest='disallowed_issues', default=[],
+                     help='lint issues disallowed in the baseline file')
+  return parser.parse_args()
+
+
+def check_baseline_for_disallowed_issues(baseline, forced_checks):
+  issues_element = baseline.documentElement
+  if issues_element.tagName != 'issues':
+    raise RuntimeError('expected issues tag at root')
+  issues = issues_element.getElementsByTagName('issue')
+  disallowed = set()
+  for issue in issues:
+    id = issue.getAttribute('id')
+    if id in forced_checks:
+      disallowed.add(id)
+  return disallowed
+
+
+def main():
+  """Program entry point."""
+  args = parse_args()
+
+  error = False
+  for baseline_rsp_file in args.baselines:
+    for baseline_path in NinjaRspFileReader(baseline_rsp_file):
+      baseline = minidom.parse(baseline_path)
+      disallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
+      if disallowed_issues:
+        print('disallowed issues %s found in lint baseline file %s for module %s'
+                % (disallowed_issues, baseline_path, args.name))
+        error = True
+
+  if error:
+    sys.exit(1)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/lint_project_xml_test.py b/scripts/lint_strict_updatability_checks_test.py
old mode 100644
new mode 100755
similarity index 88%
rename from scripts/lint_project_xml_test.py
rename to scripts/lint_strict_updatability_checks_test.py
index 344691d..fd8610f
--- a/scripts/lint_project_xml_test.py
+++ b/scripts/lint_strict_updatability_checks_test.py
@@ -15,12 +15,12 @@
 # limitations under the License.
 #
 
-"""Unit tests for lint_project_xml.py."""
+"""Unit tests for lint_strict_updatability_checks.py."""
 
 import unittest
 from xml.dom import minidom
 
-import lint_project_xml
+import lint_strict_updatability_checks
 
 
 class CheckBaselineForDisallowedIssuesTest(unittest.TestCase):
@@ -44,7 +44,7 @@
       '</issues>\n')
 
   def test_check_baseline_for_disallowed_issues(self):
-    disallowed_issues = lint_project_xml.check_baseline_for_disallowed_issues(self.baseline_xml, ["foo", "bar", "qux"])
+    disallowed_issues = lint_strict_updatability_checks.check_baseline_for_disallowed_issues(self.baseline_xml, ["foo", "bar", "qux"])
     self.assertEqual({"foo", "bar"}, disallowed_issues)
 
 
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 09a7c9e..15e13db 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1360,10 +1360,9 @@
 }
 `),
 		snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
-			ctx := android.ModuleInstallPathContextForTesting(result.Config)
 			dexJarBuildPath := func(name string, kind android.SdkKind) string {
-				dep := result.Module(name, "android_common").(java.SdkLibraryDependency)
-				path := dep.SdkApiExportableStubDexJar(ctx, kind).Path()
+				sdkLibInfo, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), result.Module(name, "android_common"), java.SdkLibraryInfoProvider)
+				path := sdkLibInfo.ExportableStubDexJarPaths[kind].Path()
 				return path.RelativeToTop().String()
 			}
 
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index ddd0a80..e230795 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -196,16 +196,16 @@
 }
 
 var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{
-	Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs}",
+	Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs} ${extraTestRunnerConfigs}",
 	CommandDeps: []string{
 		"${AutoGenTestConfigScript}",
 		"${EmptyTestConfig}",
 		"$template",
 	},
-}, "name", "template", "extraConfigs")
+}, "name", "template", "extraConfigs", "extraTestRunnerConfigs")
 
 func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string,
-	testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool, configs []Config) android.Path {
+	testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool, configs []Config, testRunnerConfigs []Option) android.Path {
 	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	var configStrings []string
 	if autogenPath != nil {
@@ -220,15 +220,26 @@
 		extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
 		extraConfigs = fmt.Sprintf("--extra-configs '%s'", extraConfigs)
 
+		var testRunnerConfigStrings []string
+		for _, config := range testRunnerConfigs {
+			testRunnerConfigStrings = append(testRunnerConfigStrings, config.Config())
+		}
+		extraTestRunnerConfigs := strings.Join(testRunnerConfigStrings, fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent))
+		if len(extraTestRunnerConfigs) > 0 {
+			extraTestRunnerConfigs += fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent)
+		}
+		extraTestRunnerConfigs = fmt.Sprintf("--extra-test-runner-configs '%s'", extraTestRunnerConfigs)
+
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        autogenInstrumentationTest,
 			Description: "test config",
 			Input:       manifest,
 			Output:      autogenPath,
 			Args: map[string]string{
-				"name":         ctx.ModuleName(),
-				"template":     template,
-				"extraConfigs": extraConfigs,
+				"name":                   ctx.ModuleName(),
+				"template":               template,
+				"extraConfigs":           extraConfigs,
+				"extraTestRunnerConfigs": extraTestRunnerConfigs,
 			},
 		})
 		return autogenPath
diff --git a/ui/build/soong.go b/ui/build/soong.go
index eb51022..41425ac 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -27,6 +27,7 @@
 	"strings"
 	"sync"
 	"sync/atomic"
+	"syscall"
 	"time"
 
 	"android/soong/ui/tracer"
@@ -780,7 +781,7 @@
 				hasNewDep := false
 				for _, dep := range cachedGlob.Deps {
 					info, err := os.Stat(dep)
-					if errors.Is(err, fs.ErrNotExist) {
+					if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
 						hasNewDep = true
 						break
 					} else if err != nil {