Merge "Enforce partition property on apex system server jars" into main
diff --git a/android/Android.bp b/android/Android.bp
index c2bef0b..eb8c64d 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -71,6 +71,7 @@
         "module.go",
         "module_context.go",
         "module_info_json.go",
+        "module_proxy.go",
         "mutator.go",
         "namespace.go",
         "neverallow.go",
diff --git a/android/base_module_context.go b/android/base_module_context.go
index c7d7573..670537f 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -33,6 +33,8 @@
 
 	blueprintBaseModuleContext() blueprint.BaseModuleContext
 
+	EqualModules(m1, m2 Module) bool
+
 	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
 	// It is intended for use inside the visit functions of Visit* and WalkDeps.
 	OtherModuleName(m blueprint.Module) string
@@ -130,6 +132,14 @@
 	// function, it may be invalidated by future mutators.
 	VisitDirectDepsAllowDisabled(visit func(Module))
 
+	// VisitDirectDepsProxyAllowDisabled 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.
+	VisitDirectDepsProxyAllowDisabled(visit func(proxy Module))
+
 	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
 
 	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
@@ -155,6 +165,16 @@
 	// invalidated by future mutators.
 	WalkDeps(visit func(child, parent Module) bool)
 
+	// WalkDeps 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.  It skips
+	// any dependencies that are not an android.Module.
+	//
+	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
+	// invalidated by future mutators.
+	WalkDepsProxy(visit func(child, parent 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
@@ -214,15 +234,26 @@
 
 }
 
+func getWrappedModule(module blueprint.Module) blueprint.Module {
+	if mp, isProxy := module.(ModuleProxy); isProxy {
+		return mp.module
+	}
+	return module
+}
+
+func (b *baseModuleContext) EqualModules(m1, m2 Module) bool {
+	return b.bp.EqualModules(getWrappedModule(m1), getWrappedModule(m2))
+}
+
 func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
-	return b.bp.OtherModuleName(m)
+	return b.bp.OtherModuleName(getWrappedModule(m))
 }
 func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
 func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
 	b.bp.OtherModuleErrorf(m, fmt, args...)
 }
 func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
-	return b.bp.OtherModuleDependencyTag(m)
+	return b.bp.OtherModuleDependencyTag(getWrappedModule(m))
 }
 func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
 func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
@@ -395,6 +426,14 @@
 	})
 }
 
+func (b *baseModuleContext) VisitDirectDepsProxyAllowDisabled(visit func(proxy Module)) {
+	b.bp.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
+		visit(ModuleProxy{
+			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 {
@@ -466,6 +505,23 @@
 	})
 }
 
+func (b *baseModuleContext) WalkDepsProxy(visit func(Module, Module) bool) {
+	b.walkPath = []Module{ModuleProxy{blueprint.CreateModuleProxy(b.Module())}}
+	b.tagPath = []blueprint.DependencyTag{}
+	b.bp.WalkDepsProxy(func(child, parent blueprint.ModuleProxy) bool {
+		childAndroidModule := ModuleProxy{child}
+		parentAndroidModule := ModuleProxy{parent}
+		// record walkPath before visit
+		for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
+			b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+			b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
+		}
+		b.walkPath = append(b.walkPath, childAndroidModule)
+		b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
+		return visit(childAndroidModule, parentAndroidModule)
+	})
+}
+
 func (b *baseModuleContext) GetWalkPath() []Module {
 	return b.walkPath
 }
diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go
index 38f1382..d28831e 100644
--- a/android/compliance_metadata.go
+++ b/android/compliance_metadata.go
@@ -17,7 +17,6 @@
 import (
 	"bytes"
 	"encoding/csv"
-	"encoding/gob"
 	"fmt"
 	"slices"
 	"strconv"
@@ -126,32 +125,32 @@
 	properties map[string]string
 }
 
+type complianceMetadataInfoGob struct {
+	Properties map[string]string
+}
+
 func NewComplianceMetadataInfo() *ComplianceMetadataInfo {
 	return &ComplianceMetadataInfo{
 		properties: map[string]string{},
 	}
 }
 
-func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := encoder.Encode(c.properties)
-	if err != nil {
-		return nil, err
+func (m *ComplianceMetadataInfo) ToGob() *complianceMetadataInfoGob {
+	return &complianceMetadataInfoGob{
+		Properties: m.properties,
 	}
+}
 
-	return w.Bytes(), nil
+func (m *ComplianceMetadataInfo) FromGob(data *complianceMetadataInfoGob) {
+	m.properties = data.Properties
+}
+
+func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[complianceMetadataInfoGob](c)
 }
 
 func (c *ComplianceMetadataInfo) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := decoder.Decode(&c.properties)
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return blueprint.CustomGobDecode[complianceMetadataInfoGob](data, c)
 }
 
 func (c *ComplianceMetadataInfo) SetStringValue(propertyName string, value string) {
diff --git a/android/config.go b/android/config.go
index e519760..06d71c0 100644
--- a/android/config.go
+++ b/android/config.go
@@ -287,6 +287,10 @@
 	return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE")
 }
 
+func (c Config) ReleaseCreateAconfigStorageFile() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_CREATE_ACONFIG_STORAGE_FILE")
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
@@ -2086,6 +2090,10 @@
 	return PathsForSource(ctx, c.productVariables.OdmPropFiles)
 }
 
+func (c *config) ExtraAllowedDepsTxt() string {
+	return String(c.productVariables.ExtraAllowedDepsTxt)
+}
+
 func (c *config) EnableUffdGc() string {
 	return String(c.productVariables.EnableUffdGc)
 }
diff --git a/android/depset_generic.go b/android/depset_generic.go
index 690987a..d04f88b 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -15,10 +15,9 @@
 package android
 
 import (
-	"bytes"
-	"encoding/gob"
-	"errors"
 	"fmt"
+
+	"github.com/google/blueprint"
 )
 
 // DepSet is designed to be conceptually compatible with Bazel's depsets:
@@ -68,28 +67,38 @@
 	transitive []*DepSet[T]
 }
 
-func (d *DepSet[T]) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(d.preorder), encoder.Encode(d.reverse),
-		encoder.Encode(d.order), encoder.Encode(d.direct), encoder.Encode(d.transitive))
-	if err != nil {
-		return nil, err
-	}
+type depSetGob[T depSettableType] struct {
+	Preorder   bool
+	Reverse    bool
+	Order      DepSetOrder
+	Direct     []T
+	Transitive []*DepSet[T]
+}
 
-	return w.Bytes(), nil
+func (d *DepSet[T]) ToGob() *depSetGob[T] {
+	return &depSetGob[T]{
+		Preorder:   d.preorder,
+		Reverse:    d.reverse,
+		Order:      d.order,
+		Direct:     d.direct,
+		Transitive: d.transitive,
+	}
+}
+
+func (d *DepSet[T]) FromGob(data *depSetGob[T]) {
+	d.preorder = data.Preorder
+	d.reverse = data.Reverse
+	d.order = data.Order
+	d.direct = data.Direct
+	d.transitive = data.Transitive
+}
+
+func (d *DepSet[T]) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[depSetGob[T]](d)
 }
 
 func (d *DepSet[T]) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&d.preorder), decoder.Decode(&d.reverse),
-		decoder.Decode(&d.order), decoder.Decode(&d.direct), decoder.Decode(&d.transitive))
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return blueprint.CustomGobDecode[depSetGob[T]](data, d)
 }
 
 // NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
diff --git a/android/init.go b/android/init.go
index b462292..1ace344 100644
--- a/android/init.go
+++ b/android/init.go
@@ -17,7 +17,12 @@
 import "encoding/gob"
 
 func init() {
+	gob.Register(extraFilesZip{})
+	gob.Register(InstallPath{})
+	gob.Register(ModuleGenPath{})
 	gob.Register(ModuleOutPath{})
+	gob.Register(OutputPath{})
 	gob.Register(PhonyPath{})
+	gob.Register(SourcePath{})
 	gob.Register(unstableInfo{})
 }
diff --git a/android/module.go b/android/module.go
index a1a9a4a..e3682fa 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,9 +15,6 @@
 package android
 
 import (
-	"bytes"
-	"encoding/gob"
-	"errors"
 	"fmt"
 	"net/url"
 	"path/filepath"
@@ -1806,6 +1803,26 @@
 
 var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]()
 
+type CommonPropertiesProviderData struct {
+	Enabled bool
+	// Whether the module has been replaced by a prebuilt
+	ReplacedByPrebuilt bool
+}
+
+var CommonPropertiesProviderKey = blueprint.NewProvider[CommonPropertiesProviderData]()
+
+type PrebuiltModuleProviderData struct {
+	// Empty for now
+}
+
+var PrebuiltModuleProviderKey = blueprint.NewProvider[PrebuiltModuleProviderData]()
+
+type HostToolProviderData struct {
+	HostToolPath OptionalPath
+}
+
+var HostToolProviderKey = blueprint.NewProvider[HostToolProviderData]()
+
 func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
 	ctx := &moduleContext{
 		module:            m.module,
@@ -2051,6 +2068,23 @@
 		})
 	}
 	buildComplianceMetadataProvider(ctx, m)
+
+	commonData := CommonPropertiesProviderData{
+		ReplacedByPrebuilt: m.commonProperties.ReplacedByPrebuilt,
+	}
+	if m.commonProperties.ForcedDisabled {
+		commonData.Enabled = false
+	} else {
+		commonData.Enabled = m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled)
+	}
+	SetProvider(ctx, CommonPropertiesProviderKey, commonData)
+	if p, ok := m.module.(PrebuiltInterface); ok && p.Prebuilt() != nil {
+		SetProvider(ctx, PrebuiltModuleProviderKey, PrebuiltModuleProviderData{})
+	}
+	if h, ok := m.module.(HostToolProvider); ok {
+		SetProvider(ctx, HostToolProviderKey, HostToolProviderData{
+			HostToolPath: h.HostToolPath()})
+	}
 }
 
 func SetJarJarPrefixHandler(handler func(ModuleContext)) {
@@ -2130,36 +2164,47 @@
 	orderOnlyDeps Paths
 	executable    bool
 	extraFiles    *extraFilesZip
-
-	absFrom string
+	absFrom       string
 }
 
-func (p *katiInstall) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(p.from), encoder.Encode(p.to),
-		encoder.Encode(p.implicitDeps), encoder.Encode(p.orderOnlyDeps),
-		encoder.Encode(p.executable), encoder.Encode(p.extraFiles),
-		encoder.Encode(p.absFrom))
-	if err != nil {
-		return nil, err
-	}
-
-	return w.Bytes(), nil
+type katiInstallGob struct {
+	From          Path
+	To            InstallPath
+	ImplicitDeps  Paths
+	OrderOnlyDeps Paths
+	Executable    bool
+	ExtraFiles    *extraFilesZip
+	AbsFrom       string
 }
 
-func (p *katiInstall) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&p.from), decoder.Decode(&p.to),
-		decoder.Decode(&p.implicitDeps), decoder.Decode(&p.orderOnlyDeps),
-		decoder.Decode(&p.executable), decoder.Decode(&p.extraFiles),
-		decoder.Decode(&p.absFrom))
-	if err != nil {
-		return err
+func (k *katiInstall) ToGob() *katiInstallGob {
+	return &katiInstallGob{
+		From:          k.from,
+		To:            k.to,
+		ImplicitDeps:  k.implicitDeps,
+		OrderOnlyDeps: k.orderOnlyDeps,
+		Executable:    k.executable,
+		ExtraFiles:    k.extraFiles,
+		AbsFrom:       k.absFrom,
 	}
+}
 
-	return nil
+func (k *katiInstall) FromGob(data *katiInstallGob) {
+	k.from = data.From
+	k.to = data.To
+	k.implicitDeps = data.ImplicitDeps
+	k.orderOnlyDeps = data.OrderOnlyDeps
+	k.executable = data.Executable
+	k.extraFiles = data.ExtraFiles
+	k.absFrom = data.AbsFrom
+}
+
+func (k *katiInstall) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[katiInstallGob](k)
+}
+
+func (k *katiInstall) GobDecode(data []byte) error {
+	return blueprint.CustomGobDecode[katiInstallGob](data, k)
 }
 
 type extraFilesZip struct {
@@ -2167,26 +2212,29 @@
 	dir InstallPath
 }
 
-func (p *extraFilesZip) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(p.zip), encoder.Encode(p.dir))
-	if err != nil {
-		return nil, err
-	}
-
-	return w.Bytes(), nil
+type extraFilesZipGob struct {
+	Zip Path
+	Dir InstallPath
 }
 
-func (p *extraFilesZip) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&p.zip), decoder.Decode(&p.dir))
-	if err != nil {
-		return err
+func (e *extraFilesZip) ToGob() *extraFilesZipGob {
+	return &extraFilesZipGob{
+		Zip: e.zip,
+		Dir: e.dir,
 	}
+}
 
-	return nil
+func (e *extraFilesZip) FromGob(data *extraFilesZipGob) {
+	e.zip = data.Zip
+	e.dir = data.Dir
+}
+
+func (e *extraFilesZip) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[extraFilesZipGob](e)
+}
+
+func (e *extraFilesZip) GobDecode(data []byte) error {
+	return blueprint.CustomGobDecode[extraFilesZipGob](data, e)
 }
 
 type katiInstalls []katiInstall
diff --git a/android/module_proxy.go b/android/module_proxy.go
new file mode 100644
index 0000000..bc5090e
--- /dev/null
+++ b/android/module_proxy.go
@@ -0,0 +1,203 @@
+package android
+
+import (
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+type ModuleProxy struct {
+	module blueprint.ModuleProxy
+}
+
+func (m ModuleProxy) Name() string {
+	return m.module.Name()
+}
+
+func (m ModuleProxy) GenerateBuildActions(context blueprint.ModuleContext) {
+	m.module.GenerateBuildActions(context)
+}
+
+func (m ModuleProxy) GenerateAndroidBuildActions(context ModuleContext) {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ComponentDepsMutator(ctx BottomUpMutatorContext) {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) DepsMutator(context BottomUpMutatorContext) {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) base() *ModuleBase {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Disable() {
+
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Enabled(ctx ConfigurableEvaluatorContext) bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Target() Target {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) MultiTargets() []Target {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ImageVariation() blueprint.Variation {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) Owner() string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInData() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInTestcases() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInSanitizerDir() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInRamdisk() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInVendorRamdisk() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInDebugRamdisk() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInRecovery() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInRoot() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInOdm() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInProduct() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInVendor() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallInSystemExt() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) InstallForceOS() (*OsType, *ArchType) {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) PartitionTag(d DeviceConfig) string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) HideFromMake() {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) IsHideFromMake() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) IsSkipInstall() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) MakeUninstallable() {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ReplacedByPrebuilt() {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) IsReplacedByPrebuilt() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ExportedToMake() bool {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) EffectiveLicenseKinds() []string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) EffectiveLicenseFiles() Paths {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) AddProperties(props ...interface{}) {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) GetProperties() []interface{} {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) BuildParamsForTests() []BuildParams {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) VariablesForTests() map[string]string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) String() string {
+	return m.module.Name()
+}
+
+func (m ModuleProxy) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) visibilityProperties() []visibilityProperty {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) HostRequiredModuleNames() []string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) TargetRequiredModuleNames() []string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string {
+	panic("method is not implemented on ModuleProxy")
+}
+
+func (m ModuleProxy) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator {
+	panic("method is not implemented on ModuleProxy")
+}
diff --git a/android/packaging.go b/android/packaging.go
index 0909936..3c64d56 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -15,9 +15,6 @@
 package android
 
 import (
-	"bytes"
-	"encoding/gob"
-	"errors"
 	"fmt"
 	"path/filepath"
 	"sort"
@@ -67,34 +64,53 @@
 	owner string
 }
 
-func (p *PackagingSpec) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(p.relPathInPackage), encoder.Encode(p.srcPath),
-		encoder.Encode(p.symlinkTarget), encoder.Encode(p.executable),
-		encoder.Encode(p.effectiveLicenseFiles), encoder.Encode(p.partition),
-		encoder.Encode(p.skipInstall), encoder.Encode(p.aconfigPaths),
-		encoder.Encode(p.archType))
-	if err != nil {
-		return nil, err
-	}
+type packagingSpecGob struct {
+	RelPathInPackage string
+	SrcPath          Path
+	SymlinkTarget    string
+	Executable       bool
+	Partition        string
+	SkipInstall      bool
+	AconfigPaths     *Paths
+	ArchType         ArchType
+	Overrides        *[]string
+	Owner            string
+}
 
-	return w.Bytes(), nil
+func (p *PackagingSpec) ToGob() *packagingSpecGob {
+	return &packagingSpecGob{
+		RelPathInPackage: p.relPathInPackage,
+		SrcPath:          p.srcPath,
+		SymlinkTarget:    p.symlinkTarget,
+		Executable:       p.executable,
+		Partition:        p.partition,
+		SkipInstall:      p.skipInstall,
+		AconfigPaths:     p.aconfigPaths,
+		ArchType:         p.archType,
+		Overrides:        p.overrides,
+		Owner:            p.owner,
+	}
+}
+
+func (p *PackagingSpec) FromGob(data *packagingSpecGob) {
+	p.relPathInPackage = data.RelPathInPackage
+	p.srcPath = data.SrcPath
+	p.symlinkTarget = data.SymlinkTarget
+	p.executable = data.Executable
+	p.partition = data.Partition
+	p.skipInstall = data.SkipInstall
+	p.aconfigPaths = data.AconfigPaths
+	p.archType = data.ArchType
+	p.overrides = data.Overrides
+	p.owner = data.Owner
+}
+
+func (p *PackagingSpec) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[packagingSpecGob](p)
 }
 
 func (p *PackagingSpec) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&p.relPathInPackage), decoder.Decode(&p.srcPath),
-		decoder.Decode(&p.symlinkTarget), decoder.Decode(&p.executable),
-		decoder.Decode(&p.effectiveLicenseFiles), decoder.Decode(&p.partition),
-		decoder.Decode(&p.skipInstall), decoder.Decode(&p.aconfigPaths),
-		decoder.Decode(&p.archType))
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return blueprint.CustomGobDecode[packagingSpecGob](data, p)
 }
 
 func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
diff --git a/android/paths.go b/android/paths.go
index 1c8258e..9c2df65 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -15,9 +15,6 @@
 package android
 
 import (
-	"bytes"
-	"encoding/gob"
-	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -342,6 +339,11 @@
 	invalidReason string // Not applicable if path != nil. "" if the reason is unknown.
 }
 
+type optionalPathGob struct {
+	Path          Path
+	InvalidReason string
+}
+
 // OptionalPathForPath returns an OptionalPath containing the path.
 func OptionalPathForPath(path Path) OptionalPath {
 	return OptionalPath{path: path}
@@ -353,6 +355,26 @@
 	return OptionalPath{invalidReason: reason}
 }
 
+func (p *OptionalPath) ToGob() *optionalPathGob {
+	return &optionalPathGob{
+		Path:          p.path,
+		InvalidReason: p.invalidReason,
+	}
+}
+
+func (p *OptionalPath) FromGob(data *optionalPathGob) {
+	p.path = data.Path
+	p.invalidReason = data.InvalidReason
+}
+
+func (p OptionalPath) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[optionalPathGob](&p)
+}
+
+func (p *OptionalPath) GobDecode(data []byte) error {
+	return blueprint.CustomGobDecode[optionalPathGob](data, p)
+}
+
 // Valid returns whether there is a valid path
 func (p OptionalPath) Valid() bool {
 	return p.path != nil
@@ -1065,26 +1087,29 @@
 	rel  string
 }
 
-func (p basePath) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(p.path), encoder.Encode(p.rel))
-	if err != nil {
-		return nil, err
-	}
+type basePathGob struct {
+	Path string
+	Rel  string
+}
 
-	return w.Bytes(), nil
+func (p *basePath) ToGob() *basePathGob {
+	return &basePathGob{
+		Path: p.path,
+		Rel:  p.rel,
+	}
+}
+
+func (p *basePath) FromGob(data *basePathGob) {
+	p.path = data.Path
+	p.rel = data.Rel
+}
+
+func (p basePath) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[basePathGob](&p)
 }
 
 func (p *basePath) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&p.path), decoder.Decode(&p.rel))
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return blueprint.CustomGobDecode[basePathGob](data, p)
 }
 
 func (p basePath) Ext() string {
@@ -1337,26 +1362,32 @@
 	fullPath string
 }
 
-func (p OutputPath) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.outDir), encoder.Encode(p.fullPath))
-	if err != nil {
-		return nil, err
-	}
+type outputPathGob struct {
+	basePath
+	OutDir   string
+	FullPath string
+}
 
-	return w.Bytes(), nil
+func (p *OutputPath) ToGob() *outputPathGob {
+	return &outputPathGob{
+		basePath: p.basePath,
+		OutDir:   p.outDir,
+		FullPath: p.fullPath,
+	}
+}
+
+func (p *OutputPath) FromGob(data *outputPathGob) {
+	p.basePath = data.basePath
+	p.outDir = data.OutDir
+	p.fullPath = data.FullPath
+}
+
+func (p OutputPath) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[outputPathGob](&p)
 }
 
 func (p *OutputPath) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.outDir), decoder.Decode(&p.fullPath))
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return blueprint.CustomGobDecode[outputPathGob](data, p)
 }
 
 func (p OutputPath) withRel(rel string) OutputPath {
@@ -1756,30 +1787,41 @@
 	fullPath string
 }
 
-func (p *InstallPath) GobEncode() ([]byte, error) {
-	w := new(bytes.Buffer)
-	encoder := gob.NewEncoder(w)
-	err := errors.Join(encoder.Encode(p.basePath), encoder.Encode(p.soongOutDir),
-		encoder.Encode(p.partitionDir), encoder.Encode(p.partition),
-		encoder.Encode(p.makePath), encoder.Encode(p.fullPath))
-	if err != nil {
-		return nil, err
-	}
+type installPathGob struct {
+	basePath
+	SoongOutDir  string
+	PartitionDir string
+	Partition    string
+	MakePath     bool
+	FullPath     string
+}
 
-	return w.Bytes(), nil
+func (p *InstallPath) ToGob() *installPathGob {
+	return &installPathGob{
+		basePath:     p.basePath,
+		SoongOutDir:  p.soongOutDir,
+		PartitionDir: p.partitionDir,
+		Partition:    p.partition,
+		MakePath:     p.makePath,
+		FullPath:     p.fullPath,
+	}
+}
+
+func (p *InstallPath) FromGob(data *installPathGob) {
+	p.basePath = data.basePath
+	p.soongOutDir = data.SoongOutDir
+	p.partitionDir = data.PartitionDir
+	p.partition = data.Partition
+	p.makePath = data.MakePath
+	p.fullPath = data.FullPath
+}
+
+func (p InstallPath) GobEncode() ([]byte, error) {
+	return blueprint.CustomGobEncode[installPathGob](&p)
 }
 
 func (p *InstallPath) GobDecode(data []byte) error {
-	r := bytes.NewBuffer(data)
-	decoder := gob.NewDecoder(r)
-	err := errors.Join(decoder.Decode(&p.basePath), decoder.Decode(&p.soongOutDir),
-		decoder.Decode(&p.partitionDir), decoder.Decode(&p.partition),
-		decoder.Decode(&p.makePath), decoder.Decode(&p.fullPath))
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return blueprint.CustomGobDecode[installPathGob](data, p)
 }
 
 // Will panic if called from outside a test environment.
diff --git a/android/provider.go b/android/provider.go
index 5ded4cc..81d17a1 100644
--- a/android/provider.go
+++ b/android/provider.go
@@ -24,7 +24,7 @@
 // OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
 // TopDownMutatorContext.
 func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) {
-	value, ok := ctx.otherModuleProvider(module, provider)
+	value, ok := ctx.otherModuleProvider(getWrappedModule(module), provider)
 	if !ok {
 		var k K
 		return k, false
diff --git a/android/variable.go b/android/variable.go
index 1aaa70a..417ba89 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -522,6 +522,10 @@
 	DeviceProductCompatibilityMatrixFile   []string `json:",omitempty"`
 
 	PartitionVarsForSoongMigrationOnlyDoNotUse PartitionVariables
+
+	ExtraAllowedDepsTxt *string `json:",omitempty"`
+
+	AdbKeys *string `json:",omitempty"`
 }
 
 type PartitionQualifiedVariablesType struct {
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index f405cb2..00dd446 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -18,6 +18,7 @@
 
 import (
 	"encoding/json"
+	"strings"
 
 	"github.com/google/blueprint"
 
@@ -58,9 +59,9 @@
 
 	// Diff two given lists while ignoring comments in the allowed deps file.
 	diffAllowedApexDepsInfoRule = pctx.AndroidStaticRule("diffAllowedApexDepsInfoRule", blueprint.RuleParams{
-		Description: "Diff ${allowed_deps} and ${new_allowed_deps}",
+		Description: "Diff ${allowed_deps_list} and ${new_allowed_deps}",
 		Command: `
-			if grep -v '^#' ${allowed_deps} | diff -B - ${new_allowed_deps}; then
+			if grep -v -h '^#' ${allowed_deps_list} | sort -u -f| diff -B -u - ${new_allowed_deps}; then
 			   touch ${out};
 			else
 				echo -e "\n******************************";
@@ -81,10 +82,15 @@
 				exit 1;
 			fi;
 		`,
-	}, "allowed_deps", "new_allowed_deps")
+	}, "allowed_deps_list", "new_allowed_deps")
 )
 
 func (s *apexDepsInfoSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	allowedDepsSources := []android.OptionalPath{android.ExistentPathForSource(ctx, "packages/modules/common/build/allowed_deps.txt")}
+	extraAllowedDepsPath := ctx.Config().ExtraAllowedDepsTxt()
+	if extraAllowedDepsPath != "" {
+		allowedDepsSources = append(allowedDepsSources, android.ExistentPathForSource(ctx, extraAllowedDepsPath))
+	}
 	updatableFlatLists := android.Paths{}
 	ctx.VisitAllModules(func(module android.Module) {
 		if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok {
@@ -96,37 +102,42 @@
 			}
 		}
 	})
-
-	allowedDepsSource := android.ExistentPathForSource(ctx, "packages/modules/common/build/allowed_deps.txt")
 	newAllowedDeps := android.PathForOutput(ctx, "apex", "depsinfo", "new-allowed-deps.txt")
 	s.allowedApexDepsInfoCheckResult = android.PathForOutput(ctx, newAllowedDeps.Rel()+".check")
-
-	if !allowedDepsSource.Valid() {
+	hasOneValidDepsPath := false
+	for _, allowedDepsSource := range allowedDepsSources {
+		if allowedDepsSource.Valid() {
+			hasOneValidDepsPath = true
+			updatableFlatLists = append(updatableFlatLists, allowedDepsSource.Path())
+		}
+	}
+	allowedDepsStrList := make([]string, len(allowedDepsSources))
+	for _, value := range allowedDepsSources {
+		allowedDepsStrList = append(allowedDepsStrList, value.String())
+	}
+	allowedDepsListString := strings.Join(allowedDepsStrList, " ")
+	if !hasOneValidDepsPath {
 		// Unbundled projects may not have packages/modules/common/ checked out; ignore those.
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   android.Touch,
 			Output: s.allowedApexDepsInfoCheckResult,
 		})
 	} else {
-		allowedDeps := allowedDepsSource.Path()
-
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   generateApexDepsInfoFilesRule,
-			Inputs: append(updatableFlatLists, allowedDeps),
+			Inputs: updatableFlatLists,
 			Output: newAllowedDeps,
 		})
-
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   diffAllowedApexDepsInfoRule,
 			Input:  newAllowedDeps,
 			Output: s.allowedApexDepsInfoCheckResult,
 			Args: map[string]string{
-				"allowed_deps":     allowedDeps.String(),
-				"new_allowed_deps": newAllowedDeps.String(),
+				"allowed_deps_list": allowedDepsListString,
+				"new_allowed_deps":  newAllowedDeps.String(),
 			},
 		})
 	}
-
 	ctx.Phony("apex-allowed-deps-check", s.allowedApexDepsInfoCheckResult)
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 153ee31..1d2f3fb 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2185,6 +2185,151 @@
 		flatlist, "yourlib(minSdkVersion:29)")
 }
 
+func TestTrackCustomAllowedDepsInvalidDefaultTxt(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: true,
+			native_shared_libs: [
+				"mylib",
+				"yourlib",
+			],
+			min_sdk_version: "29",
+		}
+
+		apex {
+			name: "myapex2",
+			key: "myapex.key",
+			updatable: false,
+			native_shared_libs: ["yourlib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libbar"],
+			min_sdk_version: "29",
+			apex_available: ["myapex"],
+		}
+
+		cc_library {
+			name: "libbar",
+			stubs: { versions: ["29", "30"] },
+		}
+
+		cc_library {
+			name: "yourlib",
+			srcs: ["mylib.cpp"],
+			min_sdk_version: "29",
+			apex_available: ["myapex", "myapex2", "//apex_available:platform"],
+		}
+	`, withFiles(android.MockFS{
+		"packages/modules/common/build/custom_allowed_deps.txt": nil,
+	}),
+		android.FixtureModifyProductVariables(
+			func(variables android.FixtureProductVariables) {
+				variables.ExtraAllowedDepsTxt = proptools.StringPtr("packages/modules/common/build/custom_allowed_deps.txt")
+			},
+		))
+
+	depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+	inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
+	android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
+		"out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt")
+	android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
+		"out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt")
+
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
+	flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+		myapex.Output("depsinfo/flatlist.txt")), "\n")
+	android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+		flatlist, "libbar(minSdkVersion:(no version)) (external)")
+	android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
+		flatlist, "mylib:(minSdkVersion:29)")
+	android.AssertStringListContains(t, "track platform-available lib",
+		flatlist, "yourlib(minSdkVersion:29)")
+}
+
+func TestTrackCustomAllowedDepsWithDefaultTxt(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: true,
+			native_shared_libs: [
+				"mylib",
+				"yourlib",
+			],
+			min_sdk_version: "29",
+		}
+
+		apex {
+			name: "myapex2",
+			key: "myapex.key",
+			updatable: false,
+			native_shared_libs: ["yourlib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libbar"],
+			min_sdk_version: "29",
+			apex_available: ["myapex"],
+		}
+
+		cc_library {
+			name: "libbar",
+			stubs: { versions: ["29", "30"] },
+		}
+
+		cc_library {
+			name: "yourlib",
+			srcs: ["mylib.cpp"],
+			min_sdk_version: "29",
+			apex_available: ["myapex", "myapex2", "//apex_available:platform"],
+		}
+	`, withFiles(android.MockFS{
+		"packages/modules/common/build/custom_allowed_deps.txt": nil,
+		"packages/modules/common/build/allowed_deps.txt":        nil,
+	}),
+		android.FixtureModifyProductVariables(
+			func(variables android.FixtureProductVariables) {
+				variables.ExtraAllowedDepsTxt = proptools.StringPtr("packages/modules/common/build/custom_allowed_deps.txt")
+			},
+		))
+
+	depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+	inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
+	android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
+		"out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt")
+	android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
+		"out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt")
+
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
+	flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+		myapex.Output("depsinfo/flatlist.txt")), "\n")
+	android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+		flatlist, "libbar(minSdkVersion:(no version)) (external)")
+	android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
+		flatlist, "mylib:(minSdkVersion:29)")
+	android.AssertStringListContains(t, "track platform-available lib",
+		flatlist, "yourlib(minSdkVersion:29)")
+}
+
 func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
diff --git a/etc/Android.bp b/etc/Android.bp
index 580c54f..8e043b8 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -11,6 +11,7 @@
         "soong-android",
     ],
     srcs: [
+        "adb_keys.go",
         "install_symlink.go",
         "otacerts_zip.go",
         "prebuilt_etc.go",
diff --git a/etc/adb_keys.go b/etc/adb_keys.go
new file mode 100644
index 0000000..1bce2f1
--- /dev/null
+++ b/etc/adb_keys.go
@@ -0,0 +1,66 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package etc
+
+import (
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("adb_keys", AdbKeysModuleFactory)
+}
+
+type AdbKeysModule struct {
+	android.ModuleBase
+	outputPath  android.OutputPath
+	installPath android.InstallPath
+}
+
+func AdbKeysModuleFactory() android.Module {
+	module := &AdbKeysModule{}
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
+
+func (m *AdbKeysModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	productVariables := ctx.Config().ProductVariables()
+	if !(android.Bool(productVariables.Debuggable) && len(android.String(productVariables.AdbKeys)) > 0) {
+		m.Disable()
+		m.SkipInstall()
+		return
+	}
+
+	m.outputPath = android.PathForModuleOut(ctx, "adb_keys").OutputPath
+	input := android.ExistentPathForSource(ctx, android.String(productVariables.AdbKeys))
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Output: m.outputPath,
+		Input:  input.Path(),
+	})
+	m.installPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().ProductPath(), "etc/security")
+	ctx.InstallFile(m.installPath, "adb_keys", m.outputPath)
+}
+
+func (m *AdbKeysModule) AndroidMkEntries() []android.AndroidMkEntries {
+	if m.IsSkipInstall() {
+		return []android.AndroidMkEntries{}
+	}
+
+	return []android.AndroidMkEntries{
+		{
+			Class:      "ETC",
+			OutputFile: android.OptionalPathForPath(m.outputPath),
+		}}
+}
diff --git a/filesystem/aconfig_files.go b/filesystem/aconfig_files.go
index 8af2ffa..608fccd 100644
--- a/filesystem/aconfig_files.go
+++ b/filesystem/aconfig_files.go
@@ -76,10 +76,13 @@
 		cmd.ImplicitOutput(outputPath)
 		f.appendToEntry(ctx, outputPath)
 	}
-	generatePartitionAconfigStorageFile("package_map", "package.map")
-	generatePartitionAconfigStorageFile("flag_map", "flag.map")
-	generatePartitionAconfigStorageFile("flag_val", "flag.val")
-	generatePartitionAconfigStorageFile("flag_info", "flag.info")
+
+	if ctx.Config().ReleaseCreateAconfigStorageFile() {
+		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/golang/golang.go b/golang/golang.go
index 618a085..6ee924f 100644
--- a/golang/golang.go
+++ b/golang/golang.go
@@ -22,6 +22,7 @@
 
 import (
 	"android/soong/android"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 )
@@ -46,7 +47,7 @@
 func goPackageModuleFactory() android.Module {
 	module := &GoPackage{}
 	module.AddProperties(module.Properties()...)
-	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+	android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst)
 	return module
 }
 
diff --git a/java/aar.go b/java/aar.go
index 7d73b03..41cc24a 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -483,9 +483,9 @@
 	}
 
 	linkFlags = append(linkFlags, "--no-static-lib-packages")
-	if a.isLibrary && a.useResourceProcessorBusyBox(ctx) {
-		// When building an android_library using ResourceProcessorBusyBox pass --merge-only to skip resource
-		// references validation until the final app link step when all static libraries are present.
+	if a.isLibrary {
+		// Pass --merge-only to skip resource references validation until the final
+		// app link step when when all static libraries are present.
 		linkFlags = append(linkFlags, "--merge-only")
 	}
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 0539d25..2dff6cd 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -313,6 +313,7 @@
 			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 				func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 					entries.SetBool("LOCAL_STRIP_MODULE", false)
+					entries.AddStrings("LOCAL_REQUIRED_MODULES", binary.androidMkNamesOfJniLibs...)
 				},
 			},
 			ExtraFooters: []android.AndroidMkExtraFootersFunc{
diff --git a/java/base.go b/java/base.go
index fc21c44..7a95735 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1628,7 +1628,7 @@
 
 	if j.ravenizer.enabled {
 		ravenizerInput := outputFile
-		ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", jarName)
+		ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", "", jarName)
 		ravenizerArgs := ""
 		if proptools.Bool(j.properties.Ravenizer.Strip_mockito) {
 			ravenizerArgs = "--strip-mockito"
@@ -1637,6 +1637,14 @@
 		outputFile = ravenizerOutput
 		localImplementationJars = android.Paths{ravenizerOutput}
 		completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
+		if combinedResourceJar != nil {
+			ravenizerInput = combinedResourceJar
+			ravenizerOutput = android.PathForModuleOut(ctx, "ravenizer", "resources", jarName)
+			TransformRavenizer(ctx, ravenizerOutput, ravenizerInput, ravenizerArgs)
+			combinedResourceJar = ravenizerOutput
+			localResourceJars = android.Paths{ravenizerOutput}
+			completeStaticLibsResourceJars = android.NewDepSet(android.PREORDER, localResourceJars, nil)
+		}
 	}
 
 	if j.shouldApiMapper() {
diff --git a/java/java.go b/java/java.go
index 661422b..018850f 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1795,8 +1795,7 @@
 	// Name of the class containing main to be inserted into the manifest as Main-Class.
 	Main_class *string
 
-	// Names of modules containing JNI libraries that should be installed alongside the host
-	// variant of the binary.
+	// Names of modules containing JNI libraries that should be installed alongside the binary.
 	Jni_libs []string `android:"arch_variant"`
 }
 
@@ -1809,6 +1808,8 @@
 
 	wrapperFile android.Path
 	binaryFile  android.InstallPath
+
+	androidMkNamesOfJniLibs []string
 }
 
 func (j *Binary) HostToolPath() android.OptionalPath {
@@ -1880,6 +1881,21 @@
 			ctx.ModuleName()+ext, j.wrapperFile)
 
 		setOutputFiles(ctx, j.Library.Module)
+
+		// Set the jniLibs of this binary.
+		// These will be added to `LOCAL_REQUIRED_MODULES`, and the kati packaging system will
+		// install these alongside the java binary.
+		ctx.VisitDirectDepsWithTag(jniInstallTag, func(jni android.Module) {
+			// Use the BaseModuleName of the dependency (without any prebuilt_ prefix)
+			bmn, _ := jni.(interface{ BaseModuleName() string })
+			j.androidMkNamesOfJniLibs = append(j.androidMkNamesOfJniLibs, bmn.BaseModuleName()+":"+jni.Target().Arch.ArchType.Bitness())
+		})
+		// Check that native libraries are not listed in `required`. Prompt users to use `jni_libs` instead.
+		ctx.VisitDirectDepsWithTag(android.RequiredDepTag, func(dep android.Module) {
+			if _, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider); hasSharedLibraryInfo {
+				ctx.ModuleErrorf("cc_library %s is no longer supported in `required` of java_binary modules. Please use jni_libs instead.", dep.Name())
+			}
+		})
 	}
 }
 
@@ -1888,11 +1904,9 @@
 		j.deps(ctx)
 	}
 	// These dependencies ensure the installation rules will install the jar file when the
-	// wrapper is installed, and the jni libraries on host when the wrapper is installed.
-	if ctx.Arch().ArchType != android.Common && ctx.Os().Class == android.Host {
-		ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...)
-	}
+	// wrapper is installed, and the jni libraries when the wrapper is installed.
 	if ctx.Arch().ArchType != android.Common {
+		ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...)
 		ctx.AddVariationDependencies(
 			[]blueprint.Variation{{Mutator: "arch", Variation: android.CommonArch.String()}},
 			binaryInstallTag, ctx.ModuleName())
diff --git a/java/java_test.go b/java/java_test.go
index db154ce..24dabdb1 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -3102,7 +3102,7 @@
 	}
 }
 
-// Test that a dependency edge is created to the "first" variant of a native library listed in `required` of java_binary
+// Test that a dependency edge is created to the matching variant of a native library listed in `jni_libs` of java_binary
 func TestNativeRequiredDepOfJavaBinary(t *testing.T) {
 	findDepsOfModule := func(ctx *android.TestContext, module android.Module, depName string) []blueprint.Module {
 		var ret []blueprint.Module
@@ -3118,7 +3118,7 @@
 java_binary {
 	name: "myjavabin",
 	main_class: "com.android.MyJava",
-	required: ["mynativelib"],
+	jni_libs: ["mynativelib"],
 }
 cc_library_shared {
 	name: "mynativelib",
diff --git a/java/sdk_library.go b/java/sdk_library.go
index f308772..dfbde0e 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -2481,19 +2481,3 @@
 		propertySet.AddProperty("doctag_files", dests)
 	}
 }
-
-// TODO(b/358613520): This can be removed when modules are no longer allowed to depend on the top-level library.
-func (s *SdkLibrary) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) {
-	s.Library.IDEInfo(ctx, dpInfo)
-	if s.implLibraryModule != nil {
-		dpInfo.Deps = append(dpInfo.Deps, s.implLibraryModule.Name())
-	} else {
-		// This java_sdk_library does not have an implementation (it sets `api_only` to true).
-		// Examples of this are `art.module.intra.core.api` (IntraCore api surface).
-		// Return the "public" stubs for these.
-		stubPaths := s.findClosestScopePath(apiScopePublic)
-		if len(stubPaths.stubsHeaderPath) > 0 {
-			dpInfo.Jars = append(dpInfo.Jars, stubPaths.stubsHeaderPath[0].String())
-		}
-	}
-}
diff --git a/rust/compiler.go b/rust/compiler.go
index 5bce16b..fd86917 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -154,7 +154,7 @@
 
 	// list of rust automatic crate dependencies.
 	// Rustlibs linkage is rlib for host targets and dylib for device targets.
-	Rustlibs []string `android:"arch_variant"`
+	Rustlibs proptools.Configurable[[]string] `android:"arch_variant"`
 
 	// list of rust proc_macro crate dependencies
 	Proc_macros []string `android:"arch_variant"`
@@ -497,7 +497,7 @@
 
 func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
 	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
-	deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
+	deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs.GetOrDefault(ctx, nil)...)
 	deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
 	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
 	deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...)