Merge "Disable tidy checks for generated code" into main
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index 3c79f19..402cf16 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -25,6 +25,7 @@
         "aconfig_declarations_test.go",
         "aconfig_values_test.go",
         "aconfig_value_set_test.go",
+        "all_aconfig_declarations_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index b55d7bf..78f506a 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -164,18 +164,3 @@
 	})
 
 }
-
-func SetAconfigFileMkEntries(m *android.ModuleBase, entries *android.AndroidMkEntries, aconfigFiles map[string]android.Paths) {
-	// TODO(b/311155208): The default container here should be system.
-	container := ""
-
-	if m.SocSpecific() {
-		container = "vendor"
-	} else if m.ProductSpecific() {
-		container = "product"
-	} else if m.SystemExtSpecific() {
-		container = "system_ext"
-	}
-
-	entries.SetPaths("LOCAL_ACONFIG_FILES", aconfigFiles[container])
-}
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index 36bea0e..b6c9023 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"fmt"
 )
 
 // A singleton module that collects all of the aconfig flags declared in the
@@ -35,6 +36,7 @@
 
 func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	// Find all of the aconfig_declarations modules
+	var packages = make(map[string]int)
 	var cacheFiles android.Paths
 	ctx.VisitAllModules(func(module android.Module) {
 		decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
@@ -42,8 +44,21 @@
 			return
 		}
 		cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
+		packages[decl.Package]++
 	})
 
+	var numOffendingPkg = 0
+	for pkg, cnt := range packages {
+		if cnt > 1 {
+			fmt.Printf("%d aconfig_declarations found for package %s\n", cnt, pkg)
+			numOffendingPkg++
+		}
+	}
+
+	if numOffendingPkg > 0 {
+		panic(fmt.Errorf("Only one aconfig_declarations allowed for each package."))
+	}
+
 	// Generate build action for aconfig
 	this.intermediatePath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
 	ctx.Build(pctx, android.BuildParams{
diff --git a/aconfig/all_aconfig_declarations_test.go b/aconfig/all_aconfig_declarations_test.go
new file mode 100644
index 0000000..0b2021e
--- /dev/null
+++ b/aconfig/all_aconfig_declarations_test.go
@@ -0,0 +1,48 @@
+// 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 aconfig
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestTwoAconfigDeclarationsPerPackage(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name.foo",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"foo.aconfig",
+			],
+		}
+
+		aconfig_declarations {
+			name: "module_name.bar",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+	`
+	errMsg := "Only one aconfig_declarations allowed for each package."
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(errMsg)).
+		RunTestWithBp(t, bp)
+}
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
index 8df353d..50cd4de 100644
--- a/aconfig/codegen/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -77,8 +77,12 @@
 		ctx.AddDependency(ctx.Module(), ccDeclarationsTag, declarations)
 	}
 
-	// Add a dependency for the aconfig flags base library
-	deps.SharedLibs = append(deps.SharedLibs, baseLibDep)
+	mode := proptools.StringDefault(this.properties.Mode, "production")
+
+	// Add a dependency for the aconfig flags base library if it is not forced read only
+	if mode != "force-read-only" {
+		deps.SharedLibs = append(deps.SharedLibs, baseLibDep)
+	}
 	// TODO: It'd be really nice if we could reexport this library and not make everyone do it.
 
 	return deps
diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go
index d762e9b..ef92cc8 100644
--- a/aconfig/codegen/cc_aconfig_library_test.go
+++ b/aconfig/codegen/cc_aconfig_library_test.go
@@ -20,6 +20,8 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+
+	"github.com/google/blueprint"
 )
 
 var ccCodegenModeTestData = []struct {
@@ -164,3 +166,34 @@
 	android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 1, len(makeVar))
 	android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb")
 }
+
+func TestForceReadOnly(t *testing.T) {
+	t.Helper()
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		cc.PrepareForTestWithCcDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			cc_aconfig_library {
+				name: "my_cc_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				mode: "force-read-only",
+			}
+		`))
+
+	module := result.ModuleForTests("my_cc_aconfig_library", "android_arm64_armv8-a_shared").Module()
+	dependOnBaseLib := false
+	result.VisitDirectDeps(module, func(dep blueprint.Module) {
+		if dep.Name() == baseLibDep {
+			dependOnBaseLib = true
+		}
+	})
+	android.AssertBoolEquals(t, "should not have dependency on server_configuriable_flags",
+		dependOnBaseLib, false)
+}
diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
index 8d54b5b..7361d44 100644
--- a/aconfig/codegen/java_aconfig_library_test.go
+++ b/aconfig/codegen/java_aconfig_library_test.go
@@ -34,7 +34,7 @@
 		RunTestWithBp(t, bp+`
 			aconfig_declarations {
 				name: "my_aconfig_declarations_foo",
-				package: "com.example.package",
+				package: "com.example.package.foo",
 				srcs: ["foo.aconfig"],
 			}
 
@@ -45,7 +45,7 @@
 
 			aconfig_declarations {
 				name: "my_aconfig_declarations_bar",
-				package: "com.example.package",
+				package: "com.example.package.bar",
 				srcs: ["bar.aconfig"],
 			}
 
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index ddebec3..b10036e 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -49,7 +49,13 @@
 	if *mergedAconfigFiles == nil {
 		*mergedAconfigFiles = make(map[string]Paths)
 	}
-	ctx.VisitDirectDeps(func(module Module) {
+	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		// Walk our direct dependencies, ignoring blueprint Modules and disabled Android Modules.
+		aModule, _ := module.(Module)
+		if aModule == nil || !aModule.Enabled() {
+			return
+		}
+
 		if dep, _ := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); dep.IntermediateCacheOutputPath != nil {
 			(*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
 			return
@@ -90,3 +96,18 @@
 
 	return Paths{output}
 }
+
+func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
+	// TODO(b/311155208): The default container here should be system.
+	container := ""
+
+	if m.SocSpecific() {
+		container = "vendor"
+	} else if m.ProductSpecific() {
+		container = "product"
+	} else if m.SystemExtSpecific() {
+		container = "system_ext"
+	}
+
+	entries.SetPaths("LOCAL_ACONFIG_FILES", aconfigFiles[container])
+}
diff --git a/android/filegroup.go b/android/filegroup.go
index 0aabb68..bc881ed 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -55,6 +55,9 @@
 	DefaultableModuleBase
 	properties fileGroupProperties
 	srcs       Paths
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]Paths
 }
 
 var _ SourceFileProducer = (*fileGroup)(nil)
@@ -93,6 +96,7 @@
 		fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
 	}
 	SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
+	CollectDependencyAconfigFiles(ctx, &fg.mergedAconfigFiles)
 }
 
 func (fg *fileGroup) Srcs() Paths {
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 276b9ab..6564911 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -86,6 +86,7 @@
 
 	"LOCAL_ANNOTATION_PROCESSOR_CLASSES": skip, // Soong gets the processor classes from the plugin
 	"LOCAL_CTS_TEST_PACKAGE":             skip, // Obsolete
+	"LOCAL_XTS_TEST_PACKAGE":             skip, // Obsolete
 	"LOCAL_JACK_ENABLED":                 skip, // Obselete
 	"LOCAL_JACK_FLAGS":                   skip, // Obselete
 }
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 0580ae5..08bbb39 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -823,6 +823,26 @@
 `,
 	},
 	{
+		desc: "IGNORE_LOCAL_XTS_TEST_PACKAGE",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := FooTest
+LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_XTS_TEST_PACKAGE := foo.bar
+LOCAL_COMPATIBILITY_SUPPORT_FILES := file1
+include $(BUILD_CTS_PACKAGE)
+`,
+		expected: `
+android_test {
+    name: "FooTest",
+    defaults: ["cts_defaults"],
+    test_suites: ["cts"],
+
+    data: ["file1"],
+}
+`,
+	},
+	{
 		desc: "BUILD_CTS_*_JAVA_LIBRARY",
 		in: `
 include $(CLEAR_VARS)
diff --git a/apex/apex.go b/apex/apex.go
index ba636f1..b37c495 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -235,6 +235,9 @@
 	// List of filesystem images that are embedded inside this APEX bundle.
 	Filesystems []string
 
+	// List of prebuilt_etcs that are embedded inside this APEX bundle.
+	Prebuilts []string
+
 	// List of native libraries to exclude from this APEX.
 	Exclude_native_shared_libs []string
 
@@ -252,6 +255,9 @@
 
 	// List of filesystem images to exclude from this APEX bundle.
 	Exclude_filesystems []string
+
+	// List of prebuilt_etcs to exclude from this APEX bundle.
+	Exclude_prebuilts []string
 }
 
 // Merge combines another ApexNativeDependencies into this one
@@ -262,6 +268,7 @@
 	a.Binaries = append(a.Binaries, b.Binaries...)
 	a.Tests = append(a.Tests, b.Tests...)
 	a.Filesystems = append(a.Filesystems, b.Filesystems...)
+	a.Prebuilts = append(a.Prebuilts, b.Prebuilts...)
 
 	a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...)
 	a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...)
@@ -269,6 +276,7 @@
 	a.Exclude_binaries = append(a.Exclude_binaries, b.Exclude_binaries...)
 	a.Exclude_tests = append(a.Exclude_tests, b.Exclude_tests...)
 	a.Exclude_filesystems = append(a.Exclude_filesystems, b.Exclude_filesystems...)
+	a.Exclude_prebuilts = append(a.Exclude_prebuilts, b.Exclude_prebuilts...)
 }
 
 type apexMultilibProperties struct {
@@ -480,6 +488,9 @@
 	javaApisUsedByModuleFile     android.ModuleOutPath
 
 	aconfigFiles []android.Path
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 // apexFileClass represents a type of file that can be included in APEX.
@@ -711,6 +722,8 @@
 		android.RemoveListFromList(nativeModules.Rust_dyn_libs, nativeModules.Exclude_rust_dyn_libs)...)
 	ctx.AddFarVariationDependencies(target.Variations(), fsTag,
 		android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...)
+	ctx.AddFarVariationDependencies(target.Variations(), prebuiltTag,
+		android.RemoveListFromList(nativeModules.Prebuilts, nativeModules.Exclude_prebuilts)...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -2356,6 +2369,7 @@
 			return
 		}
 	}
+	android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles)
 
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// 3) some fields in apexBundle struct are configured
@@ -2515,6 +2529,9 @@
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 // apex_defaults provides defaultable properties to other apex modules.
@@ -2537,6 +2554,10 @@
 	android.OverrideModuleBase
 }
 
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles)
+}
+
 func (o *OverrideApex) GenerateAndroidBuildActions(_ android.ModuleContext) {
 	// All the overrides happen in the base module.
 }
@@ -2874,32 +2895,6 @@
 		"libz",
 		"libziparchive",
 	}
-	//
-	// Module separator
-	//
-	m["com.android.wifi"] = []string{
-		"PlatformProperties",
-		"android.hardware.wifi-V1.0-java",
-		"android.hardware.wifi-V1.0-java-constants",
-		"android.hardware.wifi-V1.1-java",
-		"android.hardware.wifi-V1.2-java",
-		"android.hardware.wifi-V1.3-java",
-		"android.hardware.wifi-V1.4-java",
-		"android.hardware.wifi.hostapd-V1.0-java",
-		"android.hardware.wifi.hostapd-V1.1-java",
-		"android.hardware.wifi.hostapd-V1.2-java",
-		"android.hardware.wifi.supplicant-V1.0-java",
-		"android.hardware.wifi.supplicant-V1.1-java",
-		"android.hardware.wifi.supplicant-V1.2-java",
-		"android.hardware.wifi.supplicant-V1.3-java",
-		"bouncycastle-unbundled",
-		"framework-wifi-util-lib",
-		"ksoap2",
-		"libnanohttpd",
-		"wifi-lite-protos",
-		"wifi-nano-protos",
-		"wifi-service-pre-jarjar",
-	}
 	return m
 }
 
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 188875a..c27b072 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -483,6 +483,9 @@
 	inputApex android.Path
 
 	provenanceMetaDataFile android.OutputPath
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type ApexFileProperties struct {
@@ -837,6 +840,8 @@
 		p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks...)
 		p.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, p.inputApex, p.installedFile)
 	}
+
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 }
 
 func (p *Prebuilt) ProvenanceMetaDataFile() android.OutputPath {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 786d2bc..7723dc3 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -15,8 +15,6 @@
 package cc
 
 import (
-	"android/soong/aconfig"
-
 	"github.com/google/blueprint/proptools"
 
 	"fmt"
@@ -127,7 +125,7 @@
 					entries.SetString("SOONG_SDK_VARIANT_MODULES",
 						"$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
 				}
-				aconfig.SetAconfigFileMkEntries(c.AndroidModuleBase(), entries, c.mergedAconfigFiles)
+				android.SetAconfigFileMkEntries(c.AndroidModuleBase(), entries, c.mergedAconfigFiles)
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
diff --git a/cc/cc.go b/cc/cc.go
index d34daec..fd7a38a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1994,6 +1994,10 @@
 	return false
 }
 
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles)
+}
+
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
 	// Handle the case of a test module split by `test_per_src` mutator.
 	//
@@ -4075,6 +4079,9 @@
 	android.ModuleBase
 	android.DefaultsModuleBase
 	android.ApexModuleBase
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 // cc_defaults provides a set of properties that can be inherited by other cc
diff --git a/cc/genrule.go b/cc/genrule.go
index 0c06ae6..0fb3e2d 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -79,15 +79,7 @@
 func (g *GenruleExtraProperties) ImageMutatorBegin(ctx android.BaseModuleContext) {}
 
 func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	if ctx.DeviceConfig().VndkVersion() == "" {
-		return true
-	}
-
-	if ctx.ProductSpecific() {
-		return false
-	}
-
-	return !(ctx.SocSpecific() || ctx.DeviceSpecific())
+	return !(ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific())
 }
 
 func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -115,26 +107,33 @@
 }
 
 func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string {
-	if ctx.DeviceConfig().VndkVersion() == "" {
-		return nil
-	}
-
 	var variants []string
-	if Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
-		vndkVersion := ctx.DeviceConfig().VndkVersion()
-		// If vndkVersion is current, we can always use PlatformVndkVersion.
-		// If not, we assume modules under proprietary paths are compatible for
-		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is
-		// PLATFORM_VNDK_VERSION.
-		if vndkVersion == "current" || !snapshot.IsVendorProprietaryModule(ctx) {
-			variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
-		} else {
-			variants = append(variants, VendorVariationPrefix+vndkVersion)
-		}
-	}
+	vndkVersion := ctx.DeviceConfig().VndkVersion()
+	vendorVariantRequired := Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific()
+	productVariantRequired := Bool(g.Product_available) || ctx.ProductSpecific()
 
-	if Bool(g.Product_available) || ctx.ProductSpecific() {
-		variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
+	if vndkVersion == "" {
+		if vendorVariantRequired {
+			variants = append(variants, VendorVariation)
+		}
+		if productVariantRequired {
+			variants = append(variants, ProductVariation)
+		}
+	} else {
+		if vendorVariantRequired {
+			// If vndkVersion is current, we can always use PlatformVndkVersion.
+			// If not, we assume modules under proprietary paths are compatible for
+			// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is
+			// PLATFORM_VNDK_VERSION.
+			if vndkVersion == "current" || !snapshot.IsVendorProprietaryModule(ctx) {
+				variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
+			} else {
+				variants = append(variants, VendorVariationPrefix+vndkVersion)
+			}
+		}
+		if productVariantRequired {
+			variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
+		}
 	}
 
 	return variants
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index 9295244..05c644f 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"reflect"
+	"slices"
 	"testing"
 
 	"android/soong/android"
@@ -186,3 +187,26 @@
 		})
 	}
 }
+
+func TestVendorProductVariantGenrule(t *testing.T) {
+	bp := `
+	cc_genrule {
+		name: "gen",
+		tool_files: ["tool"],
+		cmd: "$(location tool) $(in) $(out)",
+		out: ["out"],
+		vendor_available: true,
+		product_available: true,
+	}
+	`
+	t.Helper()
+	ctx := PrepareForTestWithCcIncludeVndk.RunTestWithBp(t, bp)
+
+	variants := ctx.ModuleVariantsForTests("gen")
+	if !slices.Contains(variants, "android_vendor_arm64_armv8-a") {
+		t.Errorf(`expected vendor variant, but does not exist in %v`, variants)
+	}
+	if !slices.Contains(variants, "android_product_arm64_armv8-a") {
+		t.Errorf(`expected product variant, but does not exist in %v`, variants)
+	}
+}
diff --git a/cc/library.go b/cc/library.go
index 52fa254..28eb80b 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1343,12 +1343,10 @@
 		fileName+".lsdump")
 }
 
-func getRefAbiDumpDir(isNdk, isVndk bool) string {
+func getRefAbiDumpDir(isNdk bool) string {
 	var dirName string
 	if isNdk {
 		dirName = "ndk"
-	} else if isVndk {
-		dirName = "vndk"
 	} else {
 		dirName = "platform"
 	}
@@ -1374,11 +1372,8 @@
 	}
 }
 
-func currRefAbiDumpVersion(ctx ModuleContext, isVndk bool) string {
-	if isVndk {
-		// Each version of VNDK is independent, so follow the VNDK version which is the codename or PLATFORM_SDK_VERSION.
-		return ctx.Module().(*Module).VndkVersion()
-	} else if ctx.Config().PlatformSdkFinal() {
+func currRefAbiDumpVersion(ctx ModuleContext) string {
+	if ctx.Config().PlatformSdkFinal() {
 		// After sdk finalization, the ABI of the latest API level must be consistent with the source code,
 		// so choose PLATFORM_SDK_VERSION as the current version.
 		return ctx.Config().PlatformSdkVersion().String()
@@ -1427,13 +1422,13 @@
 }
 
 func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
-	baseName string, isLlndkOrNdk, allowExtensions bool) {
+	baseName string, isLlndkOrNdk bool) {
 
 	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
 	errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName
 
 	library.sourceAbiDiff(ctx, referenceDump, baseName, "",
-		isLlndkOrNdk, allowExtensions, "current", errorMessage)
+		isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage)
 }
 
 func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
@@ -1463,10 +1458,9 @@
 		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
 		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
 		// The logic must be consistent with classifySourceAbiDump.
-		isVndk := ctx.useVndk() && ctx.isVndk()
 		isNdk := ctx.isNdk(ctx.Config())
 		isLlndk := ctx.isImplementationForLLNDKPublic()
-		currVersion := currRefAbiDumpVersion(ctx, isVndk)
+		currVersion := currRefAbiDumpVersion(ctx)
 		library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
 			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
 			headerAbiChecker.Exclude_symbol_versions,
@@ -1475,26 +1469,24 @@
 
 		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
 
-		dumpDir := getRefAbiDumpDir(isNdk, isVndk)
+		dumpDir := getRefAbiDumpDir(isNdk)
 		binderBitness := ctx.DeviceConfig().BinderBitness()
-		// If NDK or PLATFORM library, check against previous version ABI.
-		if !isVndk {
-			prevVersionInt := prevRefAbiDumpVersion(ctx, dumpDir)
-			prevVersion := strconv.Itoa(prevVersionInt)
-			prevDumpDir := filepath.Join(dumpDir, prevVersion, binderBitness)
-			prevDumpFile := getRefAbiDumpFile(ctx, prevDumpDir, fileName)
-			if prevDumpFile.Valid() {
-				library.crossVersionAbiDiff(ctx, prevDumpFile.Path(),
-					fileName, isLlndk || isNdk,
-					strconv.Itoa(prevVersionInt+1), prevVersion)
-			}
+		// Check against the previous version.
+		prevVersionInt := prevRefAbiDumpVersion(ctx, dumpDir)
+		prevVersion := strconv.Itoa(prevVersionInt)
+		prevDumpDir := filepath.Join(dumpDir, prevVersion, binderBitness)
+		prevDumpFile := getRefAbiDumpFile(ctx, prevDumpDir, fileName)
+		if prevDumpFile.Valid() {
+			library.crossVersionAbiDiff(ctx, prevDumpFile.Path(),
+				fileName, isLlndk || isNdk,
+				strconv.Itoa(prevVersionInt+1), prevVersion)
 		}
 		// Check against the current version.
 		currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness)
 		currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName)
 		if currDumpFile.Valid() {
 			library.sameVersionAbiDiff(ctx, currDumpFile.Path(),
-				fileName, isLlndk || isNdk, ctx.IsVndkExt())
+				fileName, isLlndk || isNdk)
 		}
 		// Check against the opt-in reference dumps.
 		for i, optInDumpDir := range headerAbiChecker.Ref_dump_dirs {
diff --git a/cc/sabi.go b/cc/sabi.go
index 1310685..9f5781f 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -105,30 +105,17 @@
 	if headerAbiChecker.explicitlyDisabled() {
 		return ""
 	}
-	// Return NDK if the library is both NDK and LLNDK.
-	if m.IsNdk(ctx.Config()) {
-		return "NDK"
-	}
-	if m.isImplementationForLLNDKPublic() {
-		return "LLNDK"
-	}
-	if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate() {
-		if m.IsVndkSp() {
-			if m.IsVndkExt() {
-				return "VNDK-SP-ext"
-			} else {
-				return "VNDK-SP"
-			}
-		} else {
-			if m.IsVndkExt() {
-				return "VNDK-ext"
-			} else {
-				return "VNDK-core"
-			}
+	if !m.InProduct() && !m.InVendor() {
+		// Return NDK if the library is both NDK and LLNDK.
+		if m.IsNdk(ctx.Config()) {
+			return "NDK"
 		}
-	}
-	if m.library.hasStubsVariants() && !m.InProduct() && !m.InVendor() {
-		return "PLATFORM"
+		if m.isImplementationForLLNDKPublic() {
+			return "LLNDK"
+		}
+		if m.library.hasStubsVariants() {
+			return "PLATFORM"
+		}
 	}
 	if headerAbiChecker.enabled() {
 		if m.InProduct() {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 66df101..7642378 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -155,6 +155,9 @@
 	additionalDependencies *android.Paths
 
 	makeClass string
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type Defaults struct {
@@ -365,6 +368,7 @@
 		symlinks:       p.properties.Symlinks,
 	}
 	p.addInstallRules(ctx, ip)
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 }
 
 type installProperties struct {
@@ -433,11 +437,16 @@
 				if p.additionalDependencies != nil {
 					entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", p.additionalDependencies.Strings()...)
 				}
+				android.SetAconfigFileMkEntries(p.AndroidModuleBase(), entries, p.mergedAconfigFiles)
 			},
 		},
 	}}
 }
 
+func (p *PrebuiltEtc) AndroidModuleBase() *android.ModuleBase {
+	return &p.ModuleBase
+}
+
 func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
 	p.installDirBase = dirBase
 	p.AddProperties(&p.properties)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 87f6392..fbda074 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -184,6 +184,9 @@
 
 	subName string
 	subDir  string
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type taskFunc func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask
@@ -610,6 +613,24 @@
 		})
 		g.outputDeps = android.Paths{phonyFile}
 	}
+	android.CollectDependencyAconfigFiles(ctx, &g.mergedAconfigFiles)
+}
+
+func (g *Module) AndroidMkEntries() []android.AndroidMkEntries {
+	ret := android.AndroidMkEntries{
+		OutputFile: android.OptionalPathForPath(g.outputFiles[0]),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				android.SetAconfigFileMkEntries(g.AndroidModuleBase(), entries, g.mergedAconfigFiles)
+			},
+		},
+	}
+
+	return []android.AndroidMkEntries{ret}
+}
+
+func (g *Module) AndroidModuleBase() *android.ModuleBase {
+	return &g.ModuleBase
 }
 
 // Collect information for opening IDE project files in java/jdeps.go.
diff --git a/java/aar.go b/java/aar.go
index 15a542e..7fc39b6 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -980,6 +980,9 @@
 
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.ApiLevel
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 var _ android.OutputFileProducer = (*AARImport)(nil)
@@ -1274,6 +1277,7 @@
 	android.SetProvider(ctx, JniPackageProvider, JniPackageInfo{
 		JniPackages: a.jniPackages,
 	})
+	android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles)
 }
 
 func (a *AARImport) HeaderJars() android.Paths {
diff --git a/java/androidmk.go b/java/androidmk.go
index cbf9abb..cc0efe9 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -19,7 +19,6 @@
 	"io"
 	"strings"
 
-	"android/soong/aconfig"
 	"android/soong/android"
 
 	"github.com/google/blueprint/proptools"
@@ -129,7 +128,7 @@
 					if library.dexpreopter.configPath != nil {
 						entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath)
 					}
-					aconfig.SetAconfigFileMkEntries(&library.ModuleBase, entries, library.mergedAconfigFiles)
+					android.SetAconfigFileMkEntries(&library.ModuleBase, entries, library.mergedAconfigFiles)
 				},
 			},
 		})
@@ -302,7 +301,7 @@
 					if len(binary.dexpreopter.builtInstalled) > 0 {
 						entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
 					}
-					aconfig.SetAconfigFileMkEntries(&binary.ModuleBase, entries, binary.mergedAconfigFiles)
+					android.SetAconfigFileMkEntries(&binary.ModuleBase, entries, binary.mergedAconfigFiles)
 				},
 			},
 			ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -455,7 +454,7 @@
 				entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports)
 
 				if app.Name() != "framework-res" {
-					aconfig.SetAconfigFileMkEntries(&app.ModuleBase, entries, app.mergedAconfigFiles)
+					android.SetAconfigFileMkEntries(&app.ModuleBase, entries, app.mergedAconfigFiles)
 				}
 			},
 		},
@@ -533,7 +532,7 @@
 		entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
 		entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.combinedExportedProguardFlagsFile)
 		entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true)
-		aconfig.SetAconfigFileMkEntries(&a.ModuleBase, entries, a.mergedAconfigFiles)
+		android.SetAconfigFileMkEntries(&a.ModuleBase, entries, a.mergedAconfigFiles)
 	})
 
 	return entriesList
diff --git a/java/app_import.go b/java/app_import.go
index ff0f5fe..997274c 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -86,6 +86,9 @@
 	hideApexVariantFromMake bool
 
 	provenanceMetaDataFile android.OutputPath
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type AndroidAppImportProperties struct {
@@ -377,6 +380,7 @@
 		artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk)
 		a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath)
 	}
+	android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles)
 
 	// TODO: androidmk converter jni libs
 }
diff --git a/java/app_test.go b/java/app_test.go
index 3ee94d5..362bef9 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -4347,14 +4347,14 @@
 		}
 		aconfig_declarations {
 			name: "bar",
-			package: "com.example.package",
+			package: "com.example.package.bar",
 			srcs: [
 				"bar.aconfig",
 			],
 		}
 		aconfig_declarations {
 			name: "baz",
-			package: "com.example.package",
+			package: "com.example.package.baz",
 			srcs: [
 				"baz.aconfig",
 			],
diff --git a/java/droidstubs.go b/java/droidstubs.go
index bdbaf92..04e6be8 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -89,6 +89,9 @@
 	metadataZip android.WritablePath
 	metadataDir android.WritablePath
 
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
+
 	exportableApiFile                 android.WritablePath
 	exportableRemovedApiFile          android.WritablePath
 	exportableNullabilityWarningsFile android.WritablePath
@@ -1255,6 +1258,7 @@
 
 		rule.Build("nullabilityWarningsCheck", "nullability warnings check")
 	}
+	android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles)
 }
 
 func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
diff --git a/python/binary.go b/python/binary.go
index 85084a4..d6750c6 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -71,6 +71,9 @@
 	installedDest android.Path
 
 	androidMkSharedLibs []string
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 var _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
@@ -103,6 +106,7 @@
 	p.buildBinary(ctx)
 	p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
 		p.installSource.Base(), p.installSource)
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 }
 
 func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
@@ -166,6 +170,7 @@
 			entries.SetString("LOCAL_MODULE_STEM", stem)
 			entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
 			entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
+			android.SetAconfigFileMkEntries(&p.ModuleBase, entries, p.mergedAconfigFiles)
 		})
 
 	return []android.AndroidMkEntries{entries}
diff --git a/python/test.go b/python/test.go
index 782f39f..7eb9136 100644
--- a/python/test.go
+++ b/python/test.go
@@ -149,6 +149,7 @@
 	// just use buildBinary() so that the binary is not installed into the location
 	// it would be for regular binaries.
 	p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 	p.buildBinary(ctx)
 
 	var configs []tradefed.Option
@@ -228,6 +229,7 @@
 			}
 
 			entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true))
+			android.SetAconfigFileMkEntries(&p.ModuleBase, entries, p.mergedAconfigFiles)
 
 			p.testProperties.Test_options.SetAndroidMkEntries(entries)
 		})
diff --git a/rust/androidmk.go b/rust/androidmk.go
index c355a56..17fd2d8 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -17,7 +17,6 @@
 import (
 	"path/filepath"
 
-	"android/soong/aconfig"
 	"android/soong/android"
 )
 
@@ -67,7 +66,7 @@
 				if mod.UseVndk() {
 					entries.SetBool("LOCAL_USE_VNDK", true)
 				}
-				aconfig.SetAconfigFileMkEntries(mod.AndroidModuleBase(), entries, mod.mergedAconfigFiles)
+				android.SetAconfigFileMkEntries(mod.AndroidModuleBase(), entries, mod.mergedAconfigFiles)
 			},
 		},
 	}