Merge "Remove bp2build and bazel from soong_ui" into main
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 05a6371..9bf7564 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -20,6 +20,7 @@
 
 	"android/soong/android"
 	"android/soong/bazel"
+
 	"github.com/google/blueprint"
 )
 
@@ -116,9 +117,10 @@
 
 // Provider published by aconfig_value_set
 type DeclarationsProviderData struct {
-	Package          string
-	Container        string
-	IntermediatePath android.WritablePath
+	Package                     string
+	Container                   string
+	IntermediateCacheOutputPath android.WritablePath
+	IntermediateDumpOutputPath  android.WritablePath
 }
 
 var DeclarationsProviderKey = blueprint.NewProvider(DeclarationsProviderData{})
@@ -151,14 +153,14 @@
 
 	// Intermediate format
 	declarationFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
-	intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb")
+	intermediateCacheFilePath := android.PathForModuleOut(ctx, "intermediate.pb")
 	defaultPermission := ctx.Config().ReleaseAconfigFlagDefaultPermission()
 	inputFiles := make([]android.Path, len(declarationFiles))
 	copy(inputFiles, declarationFiles)
 	inputFiles = append(inputFiles, valuesFiles...)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aconfigRule,
-		Output:      intermediatePath,
+		Output:      intermediateCacheFilePath,
 		Inputs:      inputFiles,
 		Description: "aconfig_declarations",
 		Args: map[string]string{
@@ -170,10 +172,19 @@
 		},
 	})
 
+	intermediateDumpFilePath := android.PathForModuleOut(ctx, "intermediate.txt")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        aconfigTextRule,
+		Output:      intermediateDumpFilePath,
+		Inputs:      android.Paths{intermediateCacheFilePath},
+		Description: "aconfig_text",
+	})
+
 	ctx.SetProvider(DeclarationsProviderKey, DeclarationsProviderData{
-		Package:          module.properties.Package,
-		Container:        module.properties.Container,
-		IntermediatePath: intermediatePath,
+		Package:                     module.properties.Package,
+		Container:                   module.properties.Container,
+		IntermediateCacheOutputPath: intermediateCacheFilePath,
+		IntermediateDumpOutputPath:  intermediateDumpFilePath,
 	})
 
 }
@@ -182,8 +193,8 @@
 		*mergedAconfigFiles = make(map[string]android.Paths)
 	}
 	ctx.VisitDirectDeps(func(module android.Module) {
-		if dep := ctx.OtherModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData); dep.IntermediatePath != nil {
-			(*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediatePath)
+		if dep := ctx.OtherModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData); dep.IntermediateCacheOutputPath != nil {
+			(*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
 			return
 		}
 		if dep := ctx.OtherModuleProvider(module, TransitiveDeclarationsInfoProvider).(TransitiveDeclarationsInfo); len(dep.AconfigFiles) > 0 {
diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go
index e6bd87c..9035c71 100644
--- a/aconfig/aconfig_declarations_test.go
+++ b/aconfig/aconfig_declarations_test.go
@@ -41,7 +41,10 @@
 	depData := result.ModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData)
 	android.AssertStringEquals(t, "package", depData.Package, "com.example.package")
 	android.AssertStringEquals(t, "container", depData.Container, "com.android.foo")
-	if !strings.HasSuffix(depData.IntermediatePath.String(), "/intermediate.pb") {
-		t.Errorf("Missing intermediates path in provider: %s", depData.IntermediatePath.String())
+	if !strings.HasSuffix(depData.IntermediateCacheOutputPath.String(), "/intermediate.pb") {
+		t.Errorf("Missing intermediates proto path in provider: %s", depData.IntermediateCacheOutputPath.String())
+	}
+	if !strings.HasSuffix(depData.IntermediateDumpOutputPath.String(), "/intermediate.txt") {
+		t.Errorf("Missing intermediates text path in provider: %s", depData.IntermediateDumpOutputPath.String())
 	}
 }
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index 7ccb81a..2686e76 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -41,7 +41,7 @@
 			return
 		}
 		decl := ctx.ModuleProvider(module, DeclarationsProviderKey).(DeclarationsProviderData)
-		cacheFiles = append(cacheFiles, decl.IntermediatePath)
+		cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
 	})
 
 	// Generate build action for aconfig
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
index 7b68844..6855118 100644
--- a/aconfig/codegen/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -132,7 +132,7 @@
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:  cppRule,
-		Input: declarations.IntermediatePath,
+		Input: declarations.IntermediateCacheOutputPath,
 		Outputs: []android.WritablePath{
 			this.generatedCpp,
 			this.generatedH,
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index e2fb15b..211bdce 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -21,6 +21,7 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/java"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -86,7 +87,7 @@
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        javaRule,
-		Input:       declarations.IntermediatePath,
+		Input:       declarations.IntermediateCacheOutputPath,
 		Output:      srcJarPath,
 		Description: "aconfig.srcjar",
 		Args: map[string]string{
diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
index 3525de1..e587056 100644
--- a/aconfig/codegen/rust_aconfig_library.go
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -74,7 +74,7 @@
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:  rustRule,
-		Input: declarations.IntermediatePath,
+		Input: declarations.IntermediateCacheOutputPath,
 		Outputs: []android.WritablePath{
 			generatedSource,
 		},
diff --git a/aconfig/init.go b/aconfig/init.go
index 2e24db9..72f6bb6 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -40,6 +40,19 @@
 			Restat: true,
 		}, "release_version", "package", "declarations", "values", "default-permission")
 
+	// For create-device-config-sysprops: Generate aconfig flag value map text file
+	aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
+		blueprint.RuleParams{
+			Command: `${aconfig} dump --format bool` +
+				` --cache ${in}` +
+				` --out ${out}.tmp` +
+				` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
+			CommandDeps: []string{
+				"${aconfig}",
+			},
+			Restat: true,
+		})
+
 	// For all_aconfig_declarations: Combine all parsed_flags proto files
 	AllDeclarationsRule = pctx.AndroidStaticRule("All_aconfig_declarations_dump",
 		blueprint.RuleParams{
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index e69a930..3364f50 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -22,7 +22,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/fs"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -479,8 +478,7 @@
 // copyOneFile copies a file and its permissions.  If forceExecutable is true it adds u+x to the
 // permissions.  If exists is allowFromNotExists it returns nil if the from path doesn't exist.
 // If write is onlyWriteIfChanged then the output file is compared to the input file and not written to
-// if it is the same, avoiding updating the timestamp. If from is a symlink, the symlink itself
-// will be copied, instead of what it points to.
+// if it is the same, avoiding updating the timestamp.
 func copyOneFile(from string, to string, forceExecutable bool, exists existsType,
 	write writeType) error {
 	err := os.MkdirAll(filepath.Dir(to), 0777)
@@ -488,7 +486,7 @@
 		return err
 	}
 
-	stat, err := os.Lstat(from)
+	stat, err := os.Stat(from)
 	if err != nil {
 		if os.IsNotExist(err) && exists == allowFromNotExists {
 			return nil
@@ -496,25 +494,6 @@
 		return err
 	}
 
-	if stat.Mode()&fs.ModeSymlink != 0 {
-		linkTarget, err := os.Readlink(from)
-		if err != nil {
-			return err
-		}
-		if write == onlyWriteIfChanged {
-			toLinkTarget, err := os.Readlink(to)
-			if err == nil && toLinkTarget == linkTarget {
-				return nil
-			}
-		}
-		err = os.Remove(to)
-		if err != nil && !os.IsNotExist(err) {
-			return err
-		}
-
-		return os.Symlink(linkTarget, to)
-	}
-
 	perm := stat.Mode()
 	if forceExecutable {
 		perm = perm | 0100 // u+x
diff --git a/java/aapt2.go b/java/aapt2.go
index 17ee6ee..445e912 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -202,7 +202,8 @@
 func aapt2Link(ctx android.ModuleContext,
 	packageRes, genJar, proguardOptions, rTxt android.WritablePath,
 	flags []string, deps android.Paths,
-	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) {
+	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths,
+	featureFlagsPaths android.Paths) {
 
 	var inFlags []string
 
@@ -255,6 +256,11 @@
 		})
 	}
 
+	for _, featureFlagsPath := range featureFlagsPaths {
+		deps = append(deps, featureFlagsPath)
+		inFlags = append(inFlags, "--feature-flags", "@"+featureFlagsPath.String())
+	}
+
 	// Note the absence of splitPackages. The caller is supposed to compose and provide --split flag
 	// values via the flags parameter when it wants to split outputs.
 	// TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably
diff --git a/java/aar.go b/java/aar.go
index 57a05d4..1ab4529 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -349,6 +349,7 @@
 	excludedLibs                   []string
 	enforceDefaultTargetSdkVersion bool
 	extraLinkFlags                 []string
+	aconfigTextFiles               android.Paths
 }
 
 func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptions) {
@@ -529,7 +530,8 @@
 		transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets())
 	}
 	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
-		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages)
+		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
+		opts.aconfigTextFiles)
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
 	if android.PrefixInList(linkFlags, "-A ") {
@@ -1193,7 +1195,7 @@
 
 	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
 	aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, a.rTxt,
-		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
+		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil)
 
 	a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
 	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true)
diff --git a/java/app.go b/java/app.go
index 0f46b4e..d8822af 100755
--- a/java/app.go
+++ b/java/app.go
@@ -22,7 +22,9 @@
 	"path/filepath"
 	"strings"
 
+	"android/soong/aconfig"
 	"android/soong/testing"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -170,6 +172,9 @@
 	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
 	// from PRODUCT_PACKAGES.
 	Overrides []string
+
+	// Names of aconfig_declarations modules that specify aconfig flags that the app depends on.
+	Flags_packages []string
 }
 
 type AndroidApp struct {
@@ -316,6 +321,10 @@
 				`must be names of android_app_certificate modules in the form ":module"`)
 		}
 	}
+
+	for _, aconfig_declaration := range a.overridableAppProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -500,13 +509,27 @@
 	if a.Updatable() {
 		a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion
 	}
+
+	var aconfigTextFilePaths android.Paths
+	ctx.VisitDirectDepsWithTag(aconfigDeclarationTag, func(dep android.Module) {
+		if provider, ok := ctx.OtherModuleProvider(dep, aconfig.DeclarationsProviderKey).(aconfig.DeclarationsProviderData); ok {
+			aconfigTextFilePaths = append(aconfigTextFilePaths, provider.IntermediateDumpOutputPath)
+		} else {
+			ctx.ModuleErrorf("Only aconfig_declarations module type is allowed for "+
+				"flags_packages property, but %s is not aconfig_declarations module type",
+				dep.Name(),
+			)
+		}
+	})
+
 	a.aapt.buildActions(ctx,
 		aaptBuildActionOptions{
-			android.SdkContext(a),
-			a.classLoaderContexts,
-			a.usesLibraryProperties.Exclude_uses_libs,
-			a.enforceDefaultTargetSdkVersion(),
-			aaptLinkFlags,
+			sdkContext:                     android.SdkContext(a),
+			classLoaderContexts:            a.classLoaderContexts,
+			excludedLibs:                   a.usesLibraryProperties.Exclude_uses_libs,
+			enforceDefaultTargetSdkVersion: a.enforceDefaultTargetSdkVersion(),
+			extraLinkFlags:                 aaptLinkFlags,
+			aconfigTextFiles:               aconfigTextFilePaths,
 		},
 	)
 
diff --git a/java/app_test.go b/java/app_test.go
index 5cb4a23..0936b28 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -4333,3 +4333,48 @@
 	)
 
 }
+
+func TestAppFlagsPackages(t *testing.T) {
+	ctx := testApp(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			flags_packages: [
+				"bar",
+				"baz",
+			],
+		}
+		aconfig_declarations {
+			name: "bar",
+			package: "com.example.package",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+		aconfig_declarations {
+			name: "baz",
+			package: "com.example.package",
+			srcs: [
+				"baz.aconfig",
+			],
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+
+	// android_app module depends on aconfig_declarations listed in flags_packages
+	android.AssertBoolEquals(t, "foo expected to depend on bar", true,
+		CheckModuleHasDependency(t, ctx, "foo", "android_common", "bar"))
+
+	android.AssertBoolEquals(t, "foo expected to depend on baz", true,
+		CheckModuleHasDependency(t, ctx, "foo", "android_common", "baz"))
+
+	aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link")
+	linkInFlags := aapt2LinkRule.Args["inFlags"]
+	android.AssertStringDoesContain(t,
+		"aapt2 link command expected to pass feature flags arguments",
+		linkInFlags,
+		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
+	)
+}
diff --git a/java/java.go b/java/java.go
index 2236d05..d5d22b2 100644
--- a/java/java.go
+++ b/java/java.go
@@ -409,6 +409,7 @@
 	syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
 	javaApiContributionTag  = dependencyTag{name: "java-api-contribution"}
 	depApiSrcsTag           = dependencyTag{name: "dep-api-srcs"}
+	aconfigDeclarationTag   = dependencyTag{name: "aconfig-declaration"}
 	jniInstallTag           = installDependencyTag{name: "jni install"}
 	binaryInstallTag        = installDependencyTag{name: "binary install"}
 	usesLibReqTag           = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false)
diff --git a/java/java_test.go b/java/java_test.go
index 0c750eb..d4b056b 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -26,6 +26,7 @@
 
 	"github.com/google/blueprint/proptools"
 
+	"android/soong/aconfig"
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
@@ -47,6 +48,8 @@
 	cc.PrepareForTestWithCcBuildComponents,
 	// Include all the default java modules.
 	PrepareForTestWithDexpreopt,
+	// Include aconfig modules.
+	aconfig.PrepareForTestWithAconfigBuildComponents,
 )
 
 func TestMain(m *testing.M) {
diff --git a/java/robolectric.go b/java/robolectric.go
index a66b310..45621fd 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -67,7 +67,7 @@
 	// instead of the one built from source in external/robolectric-shadows.
 	Robolectric_prebuilt_version *string
 
-	// Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectri
+	// Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectric
 	// to use.  /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows
 	Upstream *bool
 }
diff --git a/rust/Android.bp b/rust/Android.bp
index c5b2000..637042d 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -7,6 +7,7 @@
     pkgPath: "android/soong/rust",
     deps: [
         "soong",
+        "soong-aconfig",
         "soong-android",
         "soong-bloaty",
         "soong-cc",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index e02c3f6..733ffc5 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -66,7 +66,8 @@
 				if mod.UseVndk() {
 					entries.SetBool("LOCAL_USE_VNDK", true)
 				}
-
+				// TODO(b/311155208): The container here should be system.
+				entries.SetPaths("LOCAL_ACONFIG_FILES", mod.mergedAconfigFiles[""])
 			},
 		},
 	}
diff --git a/rust/rust.go b/rust/rust.go
index 3d51a13..ddebb75 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -26,6 +26,7 @@
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
+	"android/soong/aconfig"
 	"android/soong/android"
 	"android/soong/cc"
 	cc_config "android/soong/cc/config"
@@ -176,6 +177,9 @@
 	transitiveAndroidMkSharedLibs *android.DepSet[string]
 
 	android.BazelModuleBase
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 func (mod *Module) Header() bool {
@@ -1006,6 +1010,8 @@
 	if mod.testModule {
 		ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 	}
+
+	aconfig.CollectDependencyAconfigFiles(ctx, &mod.mergedAconfigFiles)
 }
 
 func (mod *Module) deps(ctx DepsContext) Deps {