Merge "cc: Add docstring for IsVndk() and UseVndk()"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index bf39404..2e4068d 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -166,6 +166,7 @@
 		"external/minijail":                      Bp2BuildDefaultTrueRecursively,
 		"external/objenesis":                     Bp2BuildDefaultTrueRecursively,
 		"external/openscreen":                    Bp2BuildDefaultTrueRecursively,
+		"external/ow2-asm":                       Bp2BuildDefaultTrueRecursively,
 		"external/pcre":                          Bp2BuildDefaultTrueRecursively,
 		"external/protobuf":                      Bp2BuildDefaultTrueRecursively,
 		"external/python/six":                    Bp2BuildDefaultTrueRecursively,
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index e2751d6..9ed8f78 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -1050,18 +1050,26 @@
 
 	for _, depset := range ctx.Config().BazelContext.AqueryDepsets() {
 		var outputs []Path
+		var orderOnlies []Path
 		for _, depsetDepHash := range depset.TransitiveDepSetHashes {
 			otherDepsetName := bazelDepsetName(depsetDepHash)
 			outputs = append(outputs, PathForPhony(ctx, otherDepsetName))
 		}
 		for _, artifactPath := range depset.DirectArtifacts {
-			outputs = append(outputs, PathForBazelOut(ctx, artifactPath))
+			pathInBazelOut := PathForBazelOut(ctx, artifactPath)
+			if artifactPath == "bazel-out/volatile-status.txt" {
+				// See https://bazel.build/docs/user-manual#workspace-status
+				orderOnlies = append(orderOnlies, pathInBazelOut)
+			} else {
+				outputs = append(outputs, pathInBazelOut)
+			}
 		}
 		thisDepsetName := bazelDepsetName(depset.ContentHash)
 		ctx.Build(pctx, BuildParams{
 			Rule:      blueprint.Phony,
 			Outputs:   []WritablePath{PathForPhony(ctx, thisDepsetName)},
 			Implicits: outputs,
+			OrderOnly: orderOnlies,
 		})
 	}
 
diff --git a/android/filegroup.go b/android/filegroup.go
index af4d89a..d21d146 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -122,16 +122,18 @@
 		if fg.ShouldConvertToProtoLibrary(ctx) {
 			// TODO(b/246997908): we can remove this tag if we could figure out a
 			// solution for this bug.
-			tags := []string{"manual"}
 			attrs := &ProtoAttrs{
 				Srcs:                srcs,
 				Strip_import_prefix: fg.properties.Path,
-				Tags:                tags,
 			}
 
+			tags := []string{"manual"}
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-				CommonAttributes{Name: fg.Name() + convertedProtoLibrarySuffix},
+				CommonAttributes{
+					Name: fg.Name() + convertedProtoLibrarySuffix,
+					Tags: bazel.MakeStringListAttribute(tags),
+				},
 				attrs)
 		}
 
diff --git a/android/license.go b/android/license.go
index cde5e6e..ab8431a 100644
--- a/android/license.go
+++ b/android/license.go
@@ -15,10 +15,12 @@
 package android
 
 import (
-	"android/soong/bazel"
 	"fmt"
-	"github.com/google/blueprint"
 	"os"
+
+	"github.com/google/blueprint"
+
+	"android/soong/bazel"
 )
 
 type licenseKindDependencyTag struct {
@@ -101,6 +103,14 @@
 }
 
 func (m *licenseModule) DepsMutator(ctx BottomUpMutatorContext) {
+	for i, license := range m.properties.License_kinds {
+		for j := i + 1; j < len(m.properties.License_kinds); j++ {
+			if license == m.properties.License_kinds[j] {
+				ctx.ModuleErrorf("Duplicated license kind: %q", license)
+				break
+			}
+		}
+	}
 	ctx.AddVariationDependencies(nil, licenseKindTag, m.properties.License_kinds...)
 }
 
diff --git a/android/license_test.go b/android/license_test.go
index 7222cd7..89e7f06 100644
--- a/android/license_test.go
+++ b/android/license_test.go
@@ -90,6 +90,36 @@
 		},
 	},
 	{
+		name: "must not duplicate license_kind",
+		fs: map[string][]byte{
+			"top/Android.bp": []byte(`
+				license_kind {
+					name: "top_by_exception_only",
+					conditions: ["by_exception_only"],
+					visibility: ["//visibility:private"],
+				}
+
+				license_kind {
+					name: "top_by_exception_only_2",
+					conditions: ["by_exception_only"],
+					visibility: ["//visibility:private"],
+				}
+
+				license {
+					name: "top_proprietary",
+					license_kinds: [
+						"top_by_exception_only",
+						"top_by_exception_only_2",
+						"top_by_exception_only"
+					],
+					visibility: ["//visibility:public"],
+				}`),
+		},
+		expectedErrors: []string{
+			`top/Android.bp:14:5: module "top_proprietary": Duplicated license kind: "top_by_exception_only"`,
+		},
+	},
+	{
 		name: "license_kind module must exist",
 		fs: map[string][]byte{
 			"top/Android.bp": []byte(`
diff --git a/android/neverallow.go b/android/neverallow.go
index 293bac8..ad9880a 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -59,6 +59,7 @@
 	AddNeverAllowRules(createInitFirstStageRules()...)
 	AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
 	AddNeverAllowRules(createBp2BuildRule())
+	AddNeverAllowRules(createCcStubsRule())
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -214,6 +215,17 @@
 	}
 }
 
+func createCcStubsRule() Rule {
+	ccStubsImplementationInstallableProjectsAllowedList := []string{
+		"packages/modules/Virtualization/vm_payload",
+	}
+
+	return NeverAllow().
+		NotIn(ccStubsImplementationInstallableProjectsAllowedList...).
+		WithMatcher("stubs.implementation_installable", isSetMatcherInstance).
+		Because("implementation_installable can only be used in allowed projects.")
+}
+
 func createUncompressDexRules() []Rule {
 	return []Rule{
 		NeverAllow().
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 4772799..5f5f9a1 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -367,6 +367,22 @@
 			"framework can't be used when building against SDK",
 		},
 	},
+	// Test for the rule restricting use of implementation_installable
+	{
+		name: `"implementation_installable" outside allowed list`,
+		fs: map[string][]byte{
+			"Android.bp": []byte(`
+				cc_library {
+					name: "outside_allowed_list",
+					stubs: {
+                                                implementation_installable: true,
+					},
+				}`),
+		},
+		expectedErrors: []string{
+			`module "outside_allowed_list": violates neverallow`,
+		},
+	},
 }
 
 var prepareForNeverAllowTest = GroupFixturePreparers(
@@ -419,6 +435,10 @@
 	Platform struct {
 		Shared_libs []string
 	}
+
+	Stubs struct {
+		Implementation_installable *bool
+	}
 }
 
 type mockCcLibraryModule struct {
diff --git a/android/proto.go b/android/proto.go
index 3cac9a1..8204f77 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -164,7 +164,6 @@
 	Srcs                bazel.LabelListAttribute
 	Strip_import_prefix *string
 	Deps                bazel.LabelListAttribute
-	Tags                []string
 }
 
 // For each package in the include_dirs property a proto_library target should
diff --git a/apex/apex.go b/apex/apex.go
index 04808c1..b1b4e47 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2301,7 +2301,7 @@
 				//
 				// Always include if we are a host-apex however since those won't have any
 				// system libraries.
-				if !am.DirectlyInAnyApex() {
+				if ch.IsStubsImplementationRequired() && !am.DirectlyInAnyApex() {
 					// we need a module name for Make
 					name := ch.ImplementationModuleNameForMake(ctx) + ch.Properties.SubName
 					if !android.InList(name, a.requiredDeps) {
diff --git a/bazel/configurability.go b/bazel/configurability.go
index a93aa00..3f4cc73 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -203,6 +203,11 @@
 	osAndInApexMap = map[string]string{
 		AndroidAndInApex:           "//build/bazel/rules/apex:android-in_apex",
 		AndroidAndNonApex:          "//build/bazel/rules/apex:android-non_apex",
+		osDarwin:                   "//build/bazel/platforms/os:darwin",
+		osLinux:                    "//build/bazel/platforms/os:linux",
+		osLinuxMusl:                "//build/bazel/platforms/os:linux_musl",
+		osLinuxBionic:              "//build/bazel/platforms/os:linux_bionic",
+		osWindows:                  "//build/bazel/platforms/os:windows",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
 	}
 
diff --git a/bazel/properties.go b/bazel/properties.go
index 823cda8..ee9609a 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -843,6 +843,26 @@
 // ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
 // the base value and included in default values as appropriate.
 func (lla *LabelListAttribute) ResolveExcludes() {
+	// If there are OsAndInApexAxis, we need to use
+	//   * includes from the OS & in APEX Axis for non-Android configs for libraries that need to be
+	//     included in non-Android OSes
+	//   * excludes from the OS Axis for non-Android configs, to exclude libraries that should _not_
+	//     be included in the non-Android OSes
+	if _, ok := lla.ConfigurableValues[OsAndInApexAxis]; ok {
+		inApexLabels := lla.ConfigurableValues[OsAndInApexAxis][ConditionsDefaultConfigKey]
+		for config, labels := range lla.ConfigurableValues[OsConfigurationAxis] {
+			// OsAndroid has already handled its excludes.
+			// We only need to copy the excludes from other arches, so if there are none, skip it.
+			if config == OsAndroid || len(labels.Excludes) == 0 {
+				continue
+			}
+			lla.ConfigurableValues[OsAndInApexAxis][config] = LabelList{
+				Includes: inApexLabels.Includes,
+				Excludes: labels.Excludes,
+			}
+		}
+	}
+
 	for axis, configToLabels := range lla.ConfigurableValues {
 		baseLabels := lla.Value.deepCopy()
 		for config, val := range configToLabels {
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 4c86374..61acf68 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -2976,6 +2976,63 @@
 	})
 }
 
+func TestCcLibraryExcludesLibsHost(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"bar.map.txt": "",
+		},
+		Blueprint: simpleModuleDoNotConvertBp2build("cc_library", "bazlib") + `
+cc_library {
+	name: "quxlib",
+	stubs: { symbol_file: "bar.map.txt", versions: ["current"] },
+	bazel_module: { bp2build_available: false },
+}
+cc_library {
+	name: "barlib",
+	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
+	bazel_module: { bp2build_available: false },
+}
+cc_library {
+	name: "foolib",
+	shared_libs: ["barlib", "quxlib"],
+	target: {
+		host: {
+			shared_libs: ["bazlib"],
+			exclude_shared_libs: ["barlib"],
+		},
+	},
+	include_build_directory: false,
+	bazel_module: { bp2build_available: true },
+}`,
+		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
+			"implementation_dynamic_deps": `select({
+        "//build/bazel/platforms/os:darwin": [":bazlib"],
+        "//build/bazel/platforms/os:linux": [":bazlib"],
+        "//build/bazel/platforms/os:linux_bionic": [":bazlib"],
+        "//build/bazel/platforms/os:linux_musl": [":bazlib"],
+        "//build/bazel/platforms/os:windows": [":bazlib"],
+        "//conditions:default": [],
+    }) + select({
+        "//build/bazel/platforms/os:darwin": [":quxlib"],
+        "//build/bazel/platforms/os:linux": [":quxlib"],
+        "//build/bazel/platforms/os:linux_bionic": [":quxlib"],
+        "//build/bazel/platforms/os:linux_musl": [":quxlib"],
+        "//build/bazel/platforms/os:windows": [":quxlib"],
+        "//build/bazel/rules/apex:android-in_apex": [
+            ":barlib_stub_libs_current",
+            ":quxlib_stub_libs_current",
+        ],
+        "//conditions:default": [
+            ":barlib",
+            ":quxlib",
+        ],
+    })`,
+		}),
+	})
+}
+
 func TestCcLibraryEscapeLdflags(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
 		ModuleTypeUnderTest:        "cc_library",
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 3750804..0f1a8b2 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -90,6 +90,7 @@
 }
 
 func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
+	t.Helper()
 	bp2buildSetup := func(ctx *android.TestContext) {
 		registerModuleTypes(ctx)
 		ctx.RegisterForBazelConversion()
@@ -98,6 +99,7 @@
 }
 
 func RunApiBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
+	t.Helper()
 	apiBp2BuildSetup := func(ctx *android.TestContext) {
 		registerModuleTypes(ctx)
 		ctx.RegisterForApiBazelConversion()
diff --git a/cc/cc.go b/cc/cc.go
index 9035e35..8b3f456 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1381,6 +1381,13 @@
 	return false
 }
 
+func (c *Module) IsStubsImplementationRequired() bool {
+	if lib := c.library; lib != nil {
+		return lib.isStubsImplementationRequired()
+	}
+	return false
+}
+
 // If this is a stubs library, ImplementationModuleName returns the name of the module that contains
 // the implementation.  If it is an implementation library it returns its own name.
 func (c *Module) ImplementationModuleName(ctx android.BaseModuleContext) string {
diff --git a/cc/library.go b/cc/library.go
index b639930..0729ff4 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -71,6 +71,12 @@
 		// List versions to generate stubs libs for. The version name "current" is always
 		// implicitly added.
 		Versions []string
+
+		// Whether to not require the implementation of the library to be installed if a
+		// client of the stubs is installed. Defaults to true; set to false if the
+		// implementation is made available by some other means, e.g. in a Microdroid
+		// virtual machine.
+		Implementation_installable *bool
 	}
 
 	// set the name of the output
@@ -1339,6 +1345,7 @@
 	buildStubs() bool
 	setBuildStubs(isLatest bool)
 	hasStubsVariants() bool
+	isStubsImplementationRequired() bool
 	setStubsVersion(string)
 	stubsVersion() string
 
@@ -2298,6 +2305,10 @@
 		len(library.Properties.Stubs.Versions) > 0
 }
 
+func (library *libraryDecorator) isStubsImplementationRequired() bool {
+	return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
+}
+
 func (library *libraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
 	if !library.hasStubsVariants() {
 		return nil
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index c420567..82db634 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -132,21 +132,21 @@
 	*android_bundle_proto.ApkDescription
 }
 
-func (m apkDescriptionMatcher) matches(config TargetConfig) bool {
-	return m.ApkDescription == nil || (apkTargetingMatcher{m.Targeting}).matches(config)
+func (m apkDescriptionMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
+	return m.ApkDescription == nil || (apkTargetingMatcher{m.Targeting}).matches(config, allAbisMustMatch)
 }
 
 type apkTargetingMatcher struct {
 	*android_bundle_proto.ApkTargeting
 }
 
-func (m apkTargetingMatcher) matches(config TargetConfig) bool {
+func (m apkTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
 	return m.ApkTargeting == nil ||
 		(abiTargetingMatcher{m.AbiTargeting}.matches(config) &&
 			languageTargetingMatcher{m.LanguageTargeting}.matches(config) &&
 			screenDensityTargetingMatcher{m.ScreenDensityTargeting}.matches(config) &&
 			sdkVersionTargetingMatcher{m.SdkVersionTargeting}.matches(config) &&
-			multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config))
+			multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config, allAbisMustMatch))
 }
 
 type languageTargetingMatcher struct {
@@ -215,33 +215,27 @@
 		}
 	}
 
-	m = append(multiAbiValue{}, m...)
-	sort.Slice(m, sortAbis(m))
-	other = append(multiAbiValue{}, other...)
-	sort.Slice(other, sortAbis(other))
+	sortedM := append(multiAbiValue{}, m...)
+	sort.Slice(sortedM, sortAbis(sortedM))
+	sortedOther := append(multiAbiValue{}, other...)
+	sort.Slice(sortedOther, sortAbis(sortedOther))
 
-	for i := 0; i < min(len(m), len(other)); i++ {
-		if multiAbiPriorities[m[i].Alias] > multiAbiPriorities[other[i].Alias] {
+	for i := 0; i < min(len(sortedM), len(sortedOther)); i++ {
+		if multiAbiPriorities[sortedM[i].Alias] > multiAbiPriorities[sortedOther[i].Alias] {
 			return 1
 		}
-		if multiAbiPriorities[m[i].Alias] < multiAbiPriorities[other[i].Alias] {
+		if multiAbiPriorities[sortedM[i].Alias] < multiAbiPriorities[sortedOther[i].Alias] {
 			return -1
 		}
 	}
 
-	if len(m) == len(other) {
-		return 0
-	}
-	if len(m) > len(other) {
-		return 1
-	}
-	return -1
+	return len(sortedM) - len(sortedOther)
 }
 
 // this logic should match the logic in bundletool at
 // https://github.com/google/bundletool/blob/ae0fc0162fd80d92ef8f4ef4527c066f0106942f/src/main/java/com/android/tools/build/bundletool/device/MultiAbiMatcher.java#L43
 // (note link is the commit at time of writing; but logic should always match the latest)
-func (t multiAbiTargetingMatcher) matches(config TargetConfig) bool {
+func (t multiAbiTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
 	if t.MultiAbiTargeting == nil {
 		return true
 	}
@@ -250,12 +244,19 @@
 	}
 
 	multiAbiIsValid := func(m multiAbiValue) bool {
+		numValid := 0
 		for _, abi := range m {
-			if _, ok := config.abis[abi.Alias]; !ok {
-				return false
+			if _, ok := config.abis[abi.Alias]; ok {
+				numValid += 1
 			}
 		}
-		return true
+		if numValid == 0 {
+			return false
+		} else if numValid > 0 && !allAbisMustMatch {
+			return true
+		} else {
+			return numValid == len(m)
+		}
 	}
 
 	// ensure that the current value is valid for our config
@@ -264,6 +265,7 @@
 	for _, multiAbi := range multiAbiSet {
 		if multiAbiIsValid(multiAbi.GetAbi()) {
 			valueSetContainsViableAbi = true
+			break
 		}
 	}
 
@@ -362,13 +364,13 @@
 	*android_bundle_proto.VariantTargeting
 }
 
-func (m variantTargetingMatcher) matches(config TargetConfig) bool {
+func (m variantTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
 	if m.VariantTargeting == nil {
 		return true
 	}
 	return sdkVersionTargetingMatcher{m.SdkVersionTargeting}.matches(config) &&
 		abiTargetingMatcher{m.AbiTargeting}.matches(config) &&
-		multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config) &&
+		multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config, allAbisMustMatch) &&
 		screenDensityTargetingMatcher{m.ScreenDensityTargeting}.matches(config) &&
 		textureCompressionFormatTargetingMatcher{m.TextureCompressionFormatTargeting}.matches(config)
 }
@@ -380,30 +382,42 @@
 
 // Return all entries matching target configuration
 func selectApks(toc Toc, targetConfig TargetConfig) SelectionResult {
-	var result SelectionResult
-	for _, variant := range (*toc).GetVariant() {
-		if !(variantTargetingMatcher{variant.GetTargeting()}.matches(targetConfig)) {
-			continue
-		}
-		for _, as := range variant.GetApkSet() {
-			if !(moduleMetadataMatcher{as.ModuleMetadata}.matches(targetConfig)) {
+	checkMatching := func(allAbisMustMatch bool) SelectionResult {
+		var result SelectionResult
+		for _, variant := range (*toc).GetVariant() {
+			if !(variantTargetingMatcher{variant.GetTargeting()}.matches(targetConfig, allAbisMustMatch)) {
 				continue
 			}
-			for _, apkdesc := range as.GetApkDescription() {
-				if (apkDescriptionMatcher{apkdesc}).matches(targetConfig) {
-					result.entries = append(result.entries, apkdesc.GetPath())
-					// TODO(asmundak): As it turns out, moduleName which we get from
-					// the ModuleMetadata matches the module names of the generated
-					// entry paths just by coincidence, only for the split APKs. We
-					// need to discuss this with bundletool folks.
-					result.moduleName = as.GetModuleMetadata().GetName()
+			for _, as := range variant.GetApkSet() {
+				if !(moduleMetadataMatcher{as.ModuleMetadata}.matches(targetConfig)) {
+					continue
+				}
+				for _, apkdesc := range as.GetApkDescription() {
+					if (apkDescriptionMatcher{apkdesc}).matches(targetConfig, allAbisMustMatch) {
+						result.entries = append(result.entries, apkdesc.GetPath())
+						// TODO(asmundak): As it turns out, moduleName which we get from
+						// the ModuleMetadata matches the module names of the generated
+						// entry paths just by coincidence, only for the split APKs. We
+						// need to discuss this with bundletool folks.
+						result.moduleName = as.GetModuleMetadata().GetName()
+					}
+				}
+				// we allow only a single module, so bail out here if we found one
+				if result.moduleName != "" {
+					return result
 				}
 			}
-			// we allow only a single module, so bail out here if we found one
-			if result.moduleName != "" {
-				return result
-			}
 		}
+		return result
+	}
+	result := checkMatching(true)
+	if result.moduleName == "" {
+		// if there are no matches where all of the ABIs are available in the
+		// TargetConfig, then search again with a looser requirement of at
+		// least one matching ABI
+		// NOTE(b/260130686): this logic diverges from the logic in bundletool
+		// https://github.com/google/bundletool/blob/ae0fc0162fd80d92ef8f4ef4527c066f0106942f/src/main/java/com/android/tools/build/bundletool/device/MultiAbiMatcher.java#L43
+		result = checkMatching(false)
 	}
 	return result
 }
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index c1d712d..9f52877 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -744,7 +744,11 @@
 							bp.Abi_X86_64: 0,
 						},
 					},
-					expected: SelectionResult{},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-x86.x86_64.apex",
+						}},
 				},
 				{
 					name: "multi-variant multi-target cross-target",
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index eefda19..609a29c 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -96,6 +96,8 @@
 	// quickly silence build errors. This flag should be used with caution and only as a temporary
 	// measure, as it masks real errors and affects performance.
 	RelaxUsesLibraryCheck bool
+
+	EnableUffdGc bool // preopt with the assumption that userfaultfd GC will be used on device.
 }
 
 var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars")
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index fdfd22e..e3404a5 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -495,6 +495,10 @@
 		cmd.FlagWithInput("--profile-file=", profile)
 	}
 
+	if global.EnableUffdGc {
+		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+	}
+
 	rule.Install(odexPath, odexInstallPath)
 	rule.Install(vdexPath, vdexInstallPath)
 }
diff --git a/docs/perf.md b/docs/perf.md
index 694dcf1..5b53c8d 100644
--- a/docs/perf.md
+++ b/docs/perf.md
@@ -42,16 +42,29 @@
 ```
 
 If the elapsed time is much longer than the critical path then additional
-parallelism on the build machine will improve total build times.  If there are
+parallelism on the build machine will improve total build times. If there are
 long individual times listed in the critical path then improving build times
 for those steps or adjusting dependencies so that those steps can run earlier
 in the build graph will improve total build times.
 
 ### Soong
 
-Soong can be traced and profiled using the standard Go tools. It understands
-the `-cpuprofile`, `-trace`, and `-memprofile` command line arguments, but we
-don't currently have an easy way to enable them in the context of a full build.
+Soong proper (i.e., `soong_build` executable that processes the blueprint
+files) can be traced and profiled using the standard Go tools. It understands
+the `-trace`, `-cpuprofile`, and `-memprofile` command line arguments.
+Setting `SOONG_PROFILE_CPU` and/or `SOONG_PROFILE_MEM` environment variables
+for the build enables respective profiling, e.g., running
+
+```shell
+SOONG_PROFILE_CPU=/tmp/foo m ..._
+```
+
+saves CPU profile for each Soong invocation in /tmp/foo._step_ file, where
+_step_ is Soong execution step. The main step is `build`. The others as
+`bp2build_files`, `bp2build_workspace`, `modulegraph`, `queryview`,
+`api_bp2build`, `soong_docs` (not all of them necessarily run during the build).
+The profiles can be inspected with `go tool pprof` from the command line or
+with _Run>Open Profiler Snapshot_ in IntelliJ IDEA.
 
 ### Kati
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index b3faae8..3effff6 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -752,6 +752,10 @@
 		cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
 	}
 
+	if global.EnableUffdGc {
+		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+	}
+
 	if global.BootFlags != "" {
 		cmd.Flag(global.BootFlags)
 	}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 2173dae..8a291ad 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -304,6 +304,9 @@
 		flags = append(flags, "-I"+src.String())
 	}
 
+	minSdkVersion := j.MinSdkVersion(ctx).ApiLevel.FinalOrFutureInt()
+	flags = append(flags, fmt.Sprintf("--min_sdk_version=%v", minSdkVersion))
+
 	return strings.Join(flags, " "), deps
 }
 
diff --git a/java/fuzz_test.go b/java/fuzz_test.go
index 6e5d912..186c3aa 100644
--- a/java/fuzz_test.go
+++ b/java/fuzz_test.go
@@ -88,7 +88,7 @@
 
 	expected := "lib64/libjni.so"
 	if runtime.GOOS == "darwin" {
-		expected = "libjni.dylib"
+		expected = "lib64/libjni.dylib"
 	}
 
 	fooJniFilePaths := foo.jniFilePaths
diff --git a/java/java_test.go b/java/java_test.go
index 62c2845..ff15783 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1370,6 +1370,39 @@
 	}
 }
 
+func TestAidlFlagsMinSdkVersionDroidstubs(t *testing.T) {
+	bpTemplate := `
+	droidstubs {
+		name: "foo-stubs",
+		srcs: ["foo.aidl"],
+		%s
+		system_modules: "none",
+	}
+	`
+	testCases := []struct {
+		desc                  string
+		sdkVersionBp          string
+		minSdkVersionExpected string
+	}{
+		{
+			desc:                  "sdk_version not set, module compiles against private platform APIs",
+			sdkVersionBp:          ``,
+			minSdkVersionExpected: "10000",
+		},
+		{
+			desc:                  "sdk_version set to none, module does not build against an SDK",
+			sdkVersionBp:          `sdk_version: "none",`,
+			minSdkVersionExpected: "10000",
+		},
+	}
+	for _, tc := range testCases {
+		ctx := prepareForJavaTest.RunTestWithBp(t, fmt.Sprintf(bpTemplate, tc.sdkVersionBp))
+		aidlCmd := ctx.ModuleForTests("foo-stubs", "android_common").Rule("aidl").RuleParams.Command
+		expected := "--min_sdk_version=" + tc.minSdkVersionExpected
+		android.AssertStringDoesContain(t, "aidl command conatins incorrect min_sdk_version for testCse: "+tc.desc, aidlCmd, expected)
+	}
+}
+
 func TestAidlEnforcePermissions(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_library {
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 1f374b4..6cb549e 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -53,15 +53,6 @@
 	"SettingsGoogleOverlayCoral",
 	"SettingsGoogleOverlayFlame",
 	"SettingsLib",
-	"SettingsOverlayG020I",
-	"SettingsOverlayG020I_VN",
-	"SettingsOverlayG020J",
-	"SettingsOverlayG020M",
-	"SettingsOverlayG020N",
-	"SettingsOverlayG020P",
-	"SettingsOverlayG020Q",
-	"SettingsOverlayG025H",
-	"SettingsOverlayG5NZ6",
 	"SettingsRoboTests",
 	"SimContact",
 	"SimContacts",
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 2f9aee9..108a664 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -409,60 +409,6 @@
 		)
 	})
 
-	t.Run("SOONG_SDK_SNAPSHOT_PREFER=true", func(t *testing.T) {
-		result := android.GroupFixturePreparers(
-			preparer,
-			android.FixtureMergeEnv(map[string]string{
-				"SOONG_SDK_SNAPSHOT_PREFER": "true",
-			}),
-		).RunTest(t)
-
-		checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
-
-		CheckSnapshot(t, result, "mysdk", "",
-			checkAndroidBpContents(`
-// This is auto-generated. DO NOT EDIT.
-
-java_import {
-    name: "myjavalib",
-    prefer: true,
-    visibility: ["//visibility:public"],
-    apex_available: ["//apex_available:platform"],
-    jars: ["java/myjavalib.jar"],
-}
-			`),
-		)
-	})
-
-	t.Run("SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR=module:build_from_source", func(t *testing.T) {
-		result := android.GroupFixturePreparers(
-			preparer,
-			android.FixtureMergeEnv(map[string]string{
-				"SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR": "module:build_from_source",
-			}),
-		).RunTest(t)
-
-		checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
-
-		CheckSnapshot(t, result, "mysdk", "",
-			checkAndroidBpContents(`
-// This is auto-generated. DO NOT EDIT.
-
-java_import {
-    name: "myjavalib",
-    prefer: false,
-    use_source_config_var: {
-        config_namespace: "module",
-        var_name: "build_from_source",
-    },
-    visibility: ["//visibility:public"],
-    apex_available: ["//apex_available:platform"],
-    jars: ["java/myjavalib.jar"],
-}
-			`),
-		)
-	})
-
 	t.Run("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S", func(t *testing.T) {
 		result := android.GroupFixturePreparers(
 			prepareForSdkTestWithJava,
diff --git a/sdk/update.go b/sdk/update.go
index 92a13fa..baa2033 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -34,41 +34,6 @@
 // Environment variables that affect the generated snapshot
 // ========================================================
 //
-// SOONG_SDK_SNAPSHOT_PREFER
-//     By default every module in the generated snapshot has prefer: false. Building it
-//     with SOONG_SDK_SNAPSHOT_PREFER=true will force them to use prefer: true.
-//
-// SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR
-//     If set this specifies the Soong config var that can be used to control whether the prebuilt
-//     modules from the generated snapshot or the original source modules. Values must be a colon
-//     separated pair of strings, the first of which is the Soong config namespace, and the second
-//     is the name of the variable within that namespace.
-//
-//     The config namespace and var name are used to set the `use_source_config_var` property. That
-//     in turn will cause the generated prebuilts to use the soong config variable to select whether
-//     source or the prebuilt is used.
-//     e.g. If an sdk snapshot is built using:
-//       m SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR=acme:build_from_source sdkextensions-sdk
-//     Then the resulting snapshot will include:
-//       use_source_config_var: {
-//         config_namespace: "acme",
-//         var_name: "build_from_source",
-//       }
-//
-//     Assuming that the config variable is defined in .mk using something like:
-//       $(call add_soong_config_namespace,acme)
-//       $(call add_soong_config_var_value,acme,build_from_source,true)
-//
-//     Then when the snapshot is unpacked in the repository it will have the following behavior:
-//       m droid - will use the sdkextensions-sdk prebuilts if present. Otherwise, it will use the
-//           sources.
-//       m SOONG_CONFIG_acme_build_from_source=true droid - will use the sdkextensions-sdk
-//            sources, if present. Otherwise, it will use the prebuilts.
-//
-//     This is a temporary mechanism to control the prefer flags and will be removed once a more
-//     maintainable solution has been implemented.
-//     TODO(b/174997203): Remove when no longer necessary.
-//
 // SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE
 //     This allows the target build release (i.e. the release version of the build within which
 //     the snapshot will be used) of the snapshot to be specified. If unspecified then it defaults
@@ -2019,29 +1984,12 @@
 
 	// Do not add the prefer property if the member snapshot module is a source module type.
 	moduleCtx := ctx.sdkMemberContext
-	config := moduleCtx.Config()
 	if !memberType.UsesSourceModuleTypeInSnapshot() {
-		// Set the prefer based on the environment variable. This is a temporary work around to allow a
-		// snapshot to be created that sets prefer: true.
-		// TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
-		//  dynamically at build time not at snapshot generation time.
-		prefer := config.IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
-
 		// Set prefer. Setting this to false is not strictly required as that is the default but it does
 		// provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
 		// check the behavior when a prebuilt is preferred. It also makes it explicit what the default
 		// behavior is for the module.
-		bpModule.insertAfter("name", "prefer", prefer)
-
-		configVar := config.Getenv("SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR")
-		if configVar != "" {
-			parts := strings.Split(configVar, ":")
-			cfp := android.ConfigVarProperties{
-				Config_namespace: proptools.StringPtr(parts[0]),
-				Var_name:         proptools.StringPtr(parts[1]),
-			}
-			bpModule.insertAfter("prefer", "use_source_config_var", cfp)
-		}
+		bpModule.insertAfter("name", "prefer", false)
 	}
 
 	variants := selectApexVariantsWhereAvailable(ctx, member.variants)
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index adc56ac..b3b3866 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -154,10 +154,7 @@
 	"HOST_CROSS_OS",
 	"BUILD_ID",
 	"OUT_DIR",
-	"SOONG_SDK_SNAPSHOT_PREFER",
 	"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE",
-	"SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR",
-	"SOONG_SDK_SNAPSHOT_VERSION",
 }
 
 func Banner(make_vars map[string]string) string {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index c0bee4e..abaf5ae 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -195,6 +195,12 @@
 
 	allArgs = append(allArgs, commonArgs...)
 	allArgs = append(allArgs, environmentArgs(config, name)...)
+	if profileCpu := os.Getenv("SOONG_PROFILE_CPU"); profileCpu != "" {
+		allArgs = append(allArgs, "--cpuprofile", profileCpu+"."+name)
+	}
+	if profileMem := os.Getenv("SOONG_PROFILE_MEM"); profileMem != "" {
+		allArgs = append(allArgs, "--memprofile", profileMem+"."+name)
+	}
 	allArgs = append(allArgs, "Android.bp")
 
 	return bootstrap.PrimaryBuilderInvocation{