Merge "Revert "Migrate buildinfo.sh script into Soong"" into main
diff --git a/android/arch.go b/android/arch.go
index 4fe4345..9e79e31 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -693,6 +693,7 @@
 	m.base().commonProperties.CompileTarget = target
 	m.base().commonProperties.CompileMultiTargets = multiTargets
 	m.base().commonProperties.CompilePrimary = primaryTarget
+	m.base().commonProperties.ArchReady = true
 }
 
 // decodeMultilib returns the appropriate compile_multilib property for the module, or the default
diff --git a/android/arch_module_context.go b/android/arch_module_context.go
index 3cf4b41..a3a03af 100644
--- a/android/arch_module_context.go
+++ b/android/arch_module_context.go
@@ -35,6 +35,7 @@
 type archModuleContext struct {
 	// TODO: these should eventually go through a (possibly cached) provider like any other configuration instead
 	//  of being special cased.
+	ready         bool
 	os            OsType
 	target        Target
 	targetPrimary bool
@@ -42,6 +43,13 @@
 	primaryArch   bool
 }
 
+// ArchReady returns true if the arch mutator has run on the module. Before this returns
+// true, the module essentially doesn't have an arch and cannot make decisions based on
+// architecture.
+func (a *archModuleContext) ArchReady() bool {
+	return a.ready
+}
+
 func (a *archModuleContext) Target() Target {
 	return a.target
 }
diff --git a/android/base_module_context.go b/android/base_module_context.go
index 9be3fad..c4922f4 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -219,7 +219,7 @@
 
 	// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
 	// can be used to evaluate the final value of Configurable properties.
-	EvaluateConfiguration(parser.SelectType, string) (string, bool)
+	EvaluateConfiguration(parser.SelectType, string, string) (string, bool)
 }
 
 type baseModuleContext struct {
@@ -577,31 +577,6 @@
 	return sb.String()
 }
 
-func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, condition string) (string, bool) {
-	switch ty {
-	case parser.SelectTypeReleaseVariable:
-		if v, ok := m.Config().productVariables.BuildFlags[condition]; ok {
-			return v, true
-		}
-		return "", false
-	case parser.SelectTypeProductVariable:
-		// TODO(b/323382414): Might add these on a case-by-case basis
-		m.ModuleErrorf("TODO(b/323382414): Product variables are not yet supported in selects")
-		return "", false
-	case parser.SelectTypeSoongConfigVariable:
-		parts := strings.Split(condition, ":")
-		namespace := parts[0]
-		variable := parts[1]
-		if n, ok := m.Config().productVariables.VendorVars[namespace]; ok {
-			if v, ok := n[variable]; ok {
-				return v, true
-			}
-		}
-		return "", false
-	case parser.SelectTypeVariant:
-		m.ModuleErrorf("TODO(b/323382414): Variants are not yet supported in selects")
-		return "", false
-	default:
-		panic("Should be unreachable")
-	}
+func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) {
+	return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(ty, property, condition)
 }
diff --git a/android/early_module_context.go b/android/early_module_context.go
index 8f75773..cf1b5fc 100644
--- a/android/early_module_context.go
+++ b/android/early_module_context.go
@@ -15,9 +15,10 @@
 package android
 
 import (
-	"github.com/google/blueprint"
 	"os"
 	"text/scanner"
+
+	"github.com/google/blueprint"
 )
 
 // EarlyModuleContext provides methods that can be called early, as soon as the properties have
@@ -54,6 +55,9 @@
 	// PropertyErrorf reports an error at the line number of a property in the module definition.
 	PropertyErrorf(property, fmt string, args ...interface{})
 
+	// OtherModulePropertyErrorf reports an error at the line number of a property in the given module definition.
+	OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{})
+
 	// Failed returns true if any errors have been reported.  In most cases the module can continue with generating
 	// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error
 	// has prevented the module from creating necessary data it can return early when Failed returns true.
@@ -167,3 +171,7 @@
 func (e *earlyModuleContext) Namespace() *Namespace {
 	return e.EarlyModuleContext.Namespace().(*Namespace)
 }
+
+func (e *earlyModuleContext) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) {
+	e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args)
+}
diff --git a/android/module.go b/android/module.go
index cce4fa6..9f1d5ef 100644
--- a/android/module.go
+++ b/android/module.go
@@ -29,6 +29,7 @@
 	"android/soong/bazel"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/parser"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -123,6 +124,8 @@
 	// TransitivePackagingSpecs returns the PackagingSpecs for this module and any transitive
 	// dependencies with dependency tags for which IsInstallDepNeeded() returns true.
 	TransitivePackagingSpecs() []PackagingSpec
+
+	ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator
 }
 
 // Qualified id for a module
@@ -433,6 +436,10 @@
 	// Set by osMutator
 	CompileOS OsType `blueprint:"mutated"`
 
+	// Set to true after the arch mutator has run on this module and set CompileTarget,
+	// CompileMultiTargets, and CompilePrimary
+	ArchReady bool `blueprint:"mutated"`
+
 	// The Target of artifacts that this module variant is responsible for creating.
 	//
 	// Set by archMutator
@@ -1226,6 +1233,10 @@
 	return distFiles
 }
 
+func (m *ModuleBase) ArchReady() bool {
+	return m.commonProperties.ArchReady
+}
+
 func (m *ModuleBase) Target() Target {
 	return m.commonProperties.CompileTarget
 }
@@ -1749,6 +1760,7 @@
 	}
 
 	return archModuleContext{
+		ready:         m.commonProperties.ArchReady,
 		os:            m.commonProperties.CompileOS,
 		target:        m.commonProperties.CompileTarget,
 		targetPrimary: m.commonProperties.CompilePrimary,
@@ -2099,6 +2111,65 @@
 	return proptools.Bool(m.commonProperties.Native_bridge_supported)
 }
 
+type ConfigAndErrorContext interface {
+	Config() Config
+	OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})
+}
+
+type configurationEvalutor struct {
+	ctx ConfigAndErrorContext
+	m   Module
+}
+
+func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator {
+	return configurationEvalutor{
+		ctx: ctx,
+		m:   m.module,
+	}
+}
+
+func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args ...interface{}) {
+	e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args)
+}
+
+func (e configurationEvalutor) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) {
+	ctx := e.ctx
+	m := e.m
+	switch ty {
+	case parser.SelectTypeReleaseVariable:
+		if v, ok := ctx.Config().productVariables.BuildFlags[condition]; ok {
+			return v, true
+		}
+		return "", false
+	case parser.SelectTypeProductVariable:
+		// TODO(b/323382414): Might add these on a case-by-case basis
+		ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects")
+		return "", false
+	case parser.SelectTypeSoongConfigVariable:
+		parts := strings.Split(condition, ":")
+		namespace := parts[0]
+		variable := parts[1]
+		if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok {
+			if v, ok := n[variable]; ok {
+				return v, true
+			}
+		}
+		return "", false
+	case parser.SelectTypeVariant:
+		if condition == "arch" {
+			if !m.base().ArchReady() {
+				ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran")
+				return "", false
+			}
+			return m.base().Arch().ArchType.Name, true
+		}
+		ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition)
+		return "", false
+	default:
+		panic("Should be unreachable")
+	}
+}
+
 // ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current
 // variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
 // or if this variant is not overridden.
diff --git a/android/module_context.go b/android/module_context.go
index 1cab630..d3e2770 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -234,6 +234,8 @@
 	variables   map[string]string
 }
 
+var _ ModuleContext = &moduleContext{}
+
 func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
 	return pctx, BuildParams{
 		Rule:            ErrorRule,
diff --git a/android/selects_test.go b/android/selects_test.go
index aa9c521..b4e226f 100644
--- a/android/selects_test.go
+++ b/android/selects_test.go
@@ -231,11 +231,30 @@
 				my_string: proptools.StringPtr("c.cpp"),
 			},
 		},
+		{
+			name: "Select on variant",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(variant("arch"), {
+					"x86": "my_x86",
+					"x86_64": "my_x86_64",
+					"arm": "my_arm",
+					"arm64": "my_arm64",
+					_: "my_default",
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("my_arm64"),
+			},
+		},
 	}
 
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			fixtures := GroupFixturePreparers(
+				PrepareForTestWithArchMutator,
 				FixtureRegisterWithContext(func(ctx RegistrationContext) {
 					ctx.RegisterModuleType("my_module_type", newSelectsMockModule)
 				}),
@@ -249,8 +268,8 @@
 			result := fixtures.RunTestWithBp(t, tc.bp)
 
 			if tc.expectedError == "" {
-				m := result.ModuleForTests("foo", "")
-				p, _ := OtherModuleProvider[selectsTestProvider](result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
+				m := result.ModuleForTests("foo", "android_arm64_armv8-a")
+				p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
 				if !reflect.DeepEqual(p, tc.provider) {
 					t.Errorf("Expected:\n  %q\ngot:\n  %q", tc.provider.String(), p.String())
 				}
@@ -310,7 +329,7 @@
 func newSelectsMockModule() Module {
 	m := &selectsMockModule{}
 	m.AddProperties(&m.properties)
-	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibFirst)
 	InitDefaultableModule(m)
 	return m
 }
diff --git a/android/singleton.go b/android/singleton.go
index 5f93996..76df1eb 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -87,6 +87,9 @@
 	// builder whenever a file matching the pattern as added or removed, without rerunning if a
 	// file that does not match the pattern is added to a searched directory.
 	GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+	// OtherModulePropertyErrorf reports an error on the line number of the given property of the given module
+	OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{})
 }
 
 type singletonAdaptor struct {
@@ -279,3 +282,7 @@
 func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
 	return s.SingletonContext.ModuleProvider(module, provider)
 }
+
+func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) {
+	s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args)
+}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 460f1ff..1dd479c 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -511,6 +511,22 @@
 		`,
 	},
 	{
+		// Unsupported function case because that doesn't work in bp
+		desc: "error for unsupported functions",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(filter-out filter-out-file.java ,$(call all-java-files-under, src))
+LOCAL_PACKAGE_NAME := foo
+include $(BUILD_PACKAGE)
+`,
+		expected: `
+android_app {
+	name: "foo",
+	srcs: ["UNSUPPORTED FUNCTION:filter-out filter-out-file.java  src/**/*.java"],
+}
+		`,
+	},
+	{
 		desc: "ignore all-makefiles-under",
 		in: `
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/androidmk/parser/scope.go b/androidmk/parser/scope.go
index 8111c89..e1a523a 100644
--- a/androidmk/parser/scope.go
+++ b/androidmk/parser/scope.go
@@ -14,9 +14,7 @@
 
 package parser
 
-import (
-	"strings"
-)
+import "strings"
 
 type Scope interface {
 	Get(name string) string
@@ -88,7 +86,7 @@
 			if fname == "call" {
 				return scope.Call(argVals[0], argVals[1:]), true
 			} else {
-				return []string{"__builtin_func:" + fname + " " + strings.Join(argVals, " ")}, true
+				return []string{"UNSUPPORTED FUNCTION:" + fname + " " + strings.Join(argVals, " ")}, true
 			}
 		}
 	}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 183e818..64193b1 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -325,13 +325,6 @@
 	if runtime.GOOS == "darwin" {
 		return false
 	}
-	// abidw doesn't currently handle top-byte-ignore correctly. Disable ABI
-	// dumping for those configs while we wait for a fix. We'll still have ABI
-	// checking coverage from non-hwasan builds.
-	// http://b/190554910
-	if android.InList("hwaddress", config.SanitizeDevice()) {
-		return false
-	}
 	// http://b/156513478
 	return config.ReleaseNdkAbiMonitored()
 }
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index 78ce377..5028a49 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -56,19 +56,40 @@
 	output := root.Join(ctx, "system", "etc", "linker.config.pb")
 
 	// we need "Module"s for packaging items
-	var otherModules []android.Module
+	modulesInPackageByModule := make(map[android.Module]bool)
+	modulesInPackageByName := make(map[string]bool)
+
 	deps := s.gatherFilteredPackagingSpecs(ctx)
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		for _, ps := range child.PackagingSpecs() {
 			if _, ok := deps[ps.RelPathInPackage()]; ok {
-				otherModules = append(otherModules, child)
+				modulesInPackageByModule[child] = true
+				modulesInPackageByName[child.Name()] = true
+				return true
 			}
 		}
 		return true
 	})
 
+	provideModules := make([]android.Module, 0, len(modulesInPackageByModule))
+	for mod := range modulesInPackageByModule {
+		provideModules = append(provideModules, mod)
+	}
+
+	var requireModules []android.Module
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		_, parentInPackage := modulesInPackageByModule[parent]
+		_, childInPackageName := modulesInPackageByName[child.Name()]
+
+		// When parent is in the package, and child (or its variant) is not, this can be from an interface.
+		if parentInPackage && !childInPackageName {
+			requireModules = append(requireModules, child)
+		}
+		return true
+	})
+
 	builder := android.NewRuleBuilder(pctx, ctx)
-	linkerconfig.BuildLinkerConfig(ctx, builder, input, otherModules, output)
+	linkerconfig.BuildLinkerConfig(ctx, builder, input, provideModules, requireModules, output)
 	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
 	return output
 }
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 78b62d9..98aa408 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -89,7 +89,7 @@
 	output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
 
 	builder := android.NewRuleBuilder(pctx, ctx)
-	BuildLinkerConfig(ctx, builder, input, nil, output)
+	BuildLinkerConfig(ctx, builder, input, nil, nil, output)
 	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
 
 	l.outputFilePath = output
@@ -101,7 +101,7 @@
 }
 
 func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
-	input android.Path, otherModules []android.Module, output android.OutputPath) {
+	input android.Path, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) {
 
 	// First, convert the input json to protobuf format
 	interimOutput := android.PathForModuleOut(ctx, "temp.pb")
@@ -111,9 +111,9 @@
 		FlagWithInput("-s ", input).
 		FlagWithOutput("-o ", interimOutput)
 
-	// Secondly, if there's provideLibs gathered from otherModules, append them
+	// Secondly, if there's provideLibs gathered from provideModules, append them
 	var provideLibs []string
-	for _, m := range otherModules {
+	for _, m := range provideModules {
 		if c, ok := m.(*cc.Module); ok && cc.IsStubTarget(c) {
 			for _, ps := range c.PackagingSpecs() {
 				provideLibs = append(provideLibs, ps.FileName())
@@ -122,18 +122,45 @@
 	}
 	provideLibs = android.FirstUniqueStrings(provideLibs)
 	sort.Strings(provideLibs)
+
+	var requireLibs []string
+	for _, m := range requireModules {
+		if c, ok := m.(*cc.Module); ok && c.HasStubsVariants() && !c.Host() {
+			requireLibs = append(requireLibs, c.ImplementationModuleName(ctx)+".so")
+		}
+	}
+
+	requireLibs = android.FirstUniqueStrings(requireLibs)
+	sort.Strings(requireLibs)
+
 	if len(provideLibs) > 0 {
+		prevOutput := interimOutput
+		interimOutput = android.PathForModuleOut(ctx, "temp_provideLibs.pb")
 		builder.Command().
 			BuiltTool("conv_linker_config").
 			Flag("append").
-			FlagWithInput("-s ", interimOutput).
-			FlagWithOutput("-o ", output).
+			FlagWithInput("-s ", prevOutput).
+			FlagWithOutput("-o ", interimOutput).
 			FlagWithArg("--key ", "provideLibs").
 			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
-	} else {
-		// If nothing to add, just cp to the final output
-		builder.Command().Text("cp").Input(interimOutput).Output(output)
+		builder.Temporary(prevOutput)
 	}
+	if len(requireLibs) > 0 {
+		prevOutput := interimOutput
+		interimOutput = android.PathForModuleOut(ctx, "temp_requireLibs.pb")
+		builder.Command().
+			BuiltTool("conv_linker_config").
+			Flag("append").
+			FlagWithInput("-s ", prevOutput).
+			FlagWithOutput("-o ", interimOutput).
+			FlagWithArg("--key ", "requireLibs").
+			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(requireLibs, " ")))
+		builder.Temporary(prevOutput)
+	}
+
+	// cp to the final output
+	builder.Command().Text("cp").Input(interimOutput).Output(output)
+
 	builder.Temporary(interimOutput)
 	builder.DeleteTemporaryFiles()
 }