Merge "Revert "bp2build conversion for Sanitize.Integer_overflow""
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index bf39404..24731e8 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,
@@ -725,7 +726,6 @@
 
 		// aar support
 		"prebuilt_car-ui-androidx-core-common",         // TODO(b/224773339), genrule dependency creates an .aar, not a .jar
-		"prebuilt_platform-robolectric-4.4-prebuilt",   // aosp/1999250, needs .aar support in Jars
 		"prebuilt_platform-robolectric-4.5.1-prebuilt", // aosp/1999250, needs .aar support in Jars
 		// ERROR: The dependencies for the following 1 jar(s) are not complete.
 		// 1.bazel-out/android_target-fastbuild/bin/prebuilts/tools/common/m2/_aar/robolectric-monitor-1.0.2-alpha1/classes_and_libs_merged.jar
@@ -1344,7 +1344,6 @@
 		"prebuilt_kotlin-stdlib-jdk8",
 		"prebuilt_kotlin-test",
 		// TODO(b/217750501) exclude_files property not supported
-		"prebuilt_platform-robolectric-4.4-prebuilt",
 		"prebuilt_platform-robolectric-4.5.1-prebuilt",
 		"prebuilt_currysrc_org.eclipse",
 	}
diff --git a/android/bazel.go b/android/bazel.go
index d30cb80..60989f6 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -341,16 +341,19 @@
 		// Exact dir match
 		return true
 	}
+	var i int
 	// Check if subtree match
-	for prefix, recursive := range a.keepExistingBuildFile {
-		if recursive {
-			if strings.HasPrefix(dir, prefix+"/") {
-				return true
-			}
+	for {
+		j := strings.Index(dir[i:], "/")
+		if j == -1 {
+			return false //default
+		}
+		prefix := dir[0 : i+j]
+		i = i + j + 1 // skip the "/"
+		if recursive, ok := a.keepExistingBuildFile[prefix]; ok && recursive {
+			return true
 		}
 	}
-	// Default
-	return false
 }
 
 var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist")
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index e2751d6..acb81a4 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -81,7 +81,7 @@
 	// all request-relevant information about a target and returns a string containing
 	// this information.
 	// The function should have the following properties:
-	//   - `target` is the only parameter to this function (a configured target).
+	//   - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
 	//   - The return value must be a string.
 	//   - The function body should not be indented outside of its own scope.
 	StarlarkFunctionBody() string
@@ -743,12 +743,12 @@
 }
 `
 	functionDefFormatString := `
-def %s(target):
+def %s(target, id_string):
 %s
 `
 	mainSwitchSectionFormatString := `
   if id_string in %s:
-    return id_string + ">>" + %s(target)
+    return id_string + ">>" + %s(target, id_string)
 `
 
 	for requestType := range requestTypeToCqueryIdEntries {
@@ -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/android/sdk.go b/android/sdk.go
index fc0a84e..bd2f5d1 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -232,6 +232,12 @@
 	// relative path) and add the dest to the zip.
 	CopyToSnapshot(src Path, dest string)
 
+	// EmptyFile returns the path to an empty file.
+	//
+	// This can be used by sdk member types that need to create an empty file in the snapshot, simply
+	// pass the value returned from this to the CopyToSnapshot() method.
+	EmptyFile() Path
+
 	// UnzipToSnapshot generates a rule that will unzip the supplied zip into the snapshot relative
 	// directory destDir.
 	UnzipToSnapshot(zipPath Path, destDir string)
@@ -258,14 +264,6 @@
 	// See sdk/update.go for more information.
 	AddPrebuiltModule(member SdkMember, moduleType string) BpModule
 
-	// AddInternalModule creates a new module in the generated Android.bp file that can only be
-	// referenced by one of the other modules in the snapshot.
-	//
-	// The created module's name is constructed by concatenating the name of this member and the
-	// nameSuffix, separated by "-". It also has the visibility property set to "//visibility:private"
-	// to prevent it from being inadvertently accessed from outside the snapshot.
-	AddInternalModule(properties SdkMemberProperties, moduleType string, nameSuffix string) BpModule
-
 	// SdkMemberReferencePropertyTag returns a property tag to use when adding a property to a
 	// BpModule that contains references to other sdk members.
 	//
@@ -924,12 +922,6 @@
 //
 // Contains common properties that apply across many different member types.
 type SdkMemberPropertiesBase struct {
-	// The name of the member.
-	//
-	// Ignore this property during optimization. This is needed because this property is the same for
-	// all variants of a member and so would be optimized away if it was not ignored.
-	MemberName string `sdk:"ignore"`
-
 	// The number of unique os types supported by the member variants.
 	//
 	// If a member has a variant with more than one os type then it will need to differentiate
@@ -953,10 +945,6 @@
 	Compile_multilib string `android:"arch_variant"`
 }
 
-func (b *SdkMemberPropertiesBase) Name() string {
-	return b.MemberName
-}
-
 // OsPrefix returns the os prefix to use for any file paths in the sdk.
 //
 // Is an empty string if the member only provides variants for a single os type, otherwise
@@ -982,8 +970,6 @@
 	// Base returns the base structure.
 	Base() *SdkMemberPropertiesBase
 
-	Name() string
-
 	// PopulateFromVariant populates this structure with information from a module variant.
 	//
 	// It will typically be called once for each variant of a member module that the SDK depends upon.
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/cquery/request_type.go b/bazel/cquery/request_type.go
index b675f17..e4830d3 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -50,7 +50,7 @@
 // all request-relevant information about a target and returns a string containing
 // this information.
 // The function should have the following properties:
-//   - `target` is the only parameter to this function (a configured target).
+//   - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
 //   - The return value must be a string.
 //   - The function body should not be indented outside of its own scope.
 func (g getOutputFilesRequestType) StarlarkFunctionBody() string {
@@ -75,7 +75,7 @@
 // all request-relevant information about a target and returns a string containing
 // this information.
 // The function should have the following properties:
-//   - `target` is the only parameter to this function (a configured target).
+//   - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
 //   - The return value must be a string.
 //   - The function body should not be indented outside of its own scope.
 func (g getPythonBinaryRequestType) StarlarkFunctionBody() string {
@@ -102,13 +102,16 @@
 // all request-relevant information about a target and returns a string containing
 // this information.
 // The function should have the following properties:
-//   - `target` is the only parameter to this function (a configured target).
+//   - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
 //   - The return value must be a string.
 //   - The function body should not be indented outside of its own scope.
 func (g getCcInfoType) StarlarkFunctionBody() string {
 	return `
 outputFiles = [f.path for f in target.files.to_list()]
-cc_info = providers(target)["CcInfo"]
+p = providers(target)
+cc_info = p.get("CcInfo")
+if not cc_info:
+  fail("%s did not provide CcInfo" % id_string)
 
 includes = cc_info.compilation_context.includes.to_list()
 system_includes = cc_info.compilation_context.system_includes.to_list()
@@ -120,8 +123,8 @@
 linker_inputs = cc_info.linking_context.linker_inputs.to_list()
 
 static_info_tag = "//build/bazel/rules/cc:cc_library_static.bzl%CcStaticLibraryInfo"
-if static_info_tag in providers(target):
-  static_info = providers(target)[static_info_tag]
+if static_info_tag in p:
+  static_info = p[static_info_tag]
   ccObjectFiles = [f.path for f in static_info.objects]
   rootStaticArchives = [static_info.root_static_archive.path]
 else:
@@ -141,14 +144,14 @@
 unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
 unstripped = ""
 
-if shared_info_tag in providers(target):
-  shared_info = providers(target)[shared_info_tag]
+if shared_info_tag in p:
+  shared_info = p[shared_info_tag]
   path = shared_info.output_file.path
   sharedLibraries.append(path)
   rootSharedLibraries += [path]
   unstripped = path
-  if unstripped_tag in providers(target):
-    unstripped = providers(target)[unstripped_tag].unstripped.path
+  if unstripped_tag in p:
+    unstripped = p[unstripped_tag].unstripped.path
 else:
   for linker_input in linker_inputs:
     for library in linker_input.libraries:
@@ -160,14 +163,13 @@
 
 toc_file = ""
 toc_file_tag = "//build/bazel/rules/cc:generate_toc.bzl%CcTocInfo"
-if toc_file_tag in providers(target):
-  toc_file = providers(target)[toc_file_tag].toc.path
+if toc_file_tag in p:
+  toc_file = p[toc_file_tag].toc.path
 else:
   # NOTE: It's OK if there's no ToC, as Soong just uses it for optimization
   pass
 
 tidy_files = []
-p = providers(target)
 clang_tidy_info = p.get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
 if clang_tidy_info:
   tidy_files = [v.path for v in clang_tidy_info.tidy_files.to_list()]
@@ -213,11 +215,14 @@
 // The returned string is the body of a Starlark function which obtains
 // all request-relevant information about a target and returns a string containing
 // this information. The function should have the following properties:
-//   - `target` is the only parameter to this function (a configured target).
+//   - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
 //   - The return value must be a string.
 //   - The function body should not be indented outside of its own scope.
 func (g getApexInfoType) StarlarkFunctionBody() string {
-	return `info = providers(target)["//build/bazel/rules/apex:apex.bzl%ApexInfo"]
+	return `
+info = providers(target).get("//build/bazel/rules/apex:apex.bzl%ApexInfo")
+if not info:
+  fail("%s did not provide ApexInfo" % id_string)
 bundle_key_info = info.bundle_key_info
 container_key_info = info.container_key_info
 return json_encode({
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 306e483..8b3f456 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1205,6 +1205,8 @@
 	return c
 }
 
+// UseVndk() returns true if this module is built against VNDK.
+// This means the vendor and product variants of a module.
 func (c *Module) UseVndk() bool {
 	return c.Properties.VndkVersion != ""
 }
@@ -1298,6 +1300,9 @@
 	return false
 }
 
+// IsVndk() returns true if this module has a vndk variant.
+// Note that IsVndk() returns true for all variants of vndk-enabled libraries. Not only vendor variant,
+// but also platform and product variants of vndk-enabled libraries return true for IsVndk().
 func (c *Module) IsVndk() bool {
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		return vndkdep.isVndk()
@@ -1376,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/Android.bp b/java/Android.bp
index 0bf7a0b..9d63319 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -91,6 +91,7 @@
         "dexpreopt_config_test.go",
         "droiddoc_test.go",
         "droidstubs_test.go",
+        "fuzz_test.go",
         "genrule_test.go",
         "hiddenapi_singleton_test.go",
         "jacoco_test.go",
diff --git a/java/app.go b/java/app.go
index e36808f..a822cbf 100755
--- a/java/app.go
+++ b/java/app.go
@@ -591,7 +591,7 @@
 		// Set a certificate to avoid panics later when accessing it.
 		mainCertificate = Certificate{
 			Key: android.PathForModuleOut(ctx, "missing.pk8"),
-			Pem: android.PathForModuleOut(ctx, "missing.pem"),
+			Pem: android.PathForModuleOut(ctx, "missing.x509.pem"),
 		}
 	}
 
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 0a2c945..186c3aa 100644
--- a/java/fuzz_test.go
+++ b/java/fuzz_test.go
@@ -65,9 +65,8 @@
 
 	osCommonTarget := result.Config.BuildOSCommonTarget.String()
 
-	osCommonTargetWithSan := osCommonTarget + "_asan" + "_fuzzer"
-	javac := result.ModuleForTests("foo", osCommonTargetWithSan).Rule("javac")
-	combineJar := result.ModuleForTests("foo", osCommonTargetWithSan).Description("for javac")
+	javac := result.ModuleForTests("foo", osCommonTarget).Rule("javac")
+	combineJar := result.ModuleForTests("foo", osCommonTarget).Description("for javac")
 
 	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
 		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
@@ -85,11 +84,11 @@
 	}
 
 	ctx := result.TestContext
-	foo := ctx.ModuleForTests("foo", osCommonTargetWithSan).Module().(*JavaFuzzLibrary)
+	foo := ctx.ModuleForTests("foo", osCommonTarget).Module().(*JavaFuzzLibrary)
 
-	expected := "libjni.so"
+	expected := "lib64/libjni.so"
 	if runtime.GOOS == "darwin" {
-		expected = "libjni.dylib"
+		expected = "lib64/libjni.dylib"
 	}
 
 	fooJniFilePaths := foo.jniFilePaths
diff --git a/java/invalid_implementation_jar.sh b/java/invalid_implementation_jar.sh
deleted file mode 100755
index 3820058..0000000
--- a/java/invalid_implementation_jar.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-
-# Copyright 2022 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.
-
-# Script to detect and report an attempt to access an invalid implementation
-# jar.
-
-MOD=$1
-
-cat <<EOF
-
-    $MOD is a java_library that generates a jar file which must not be accessed
-    from outside the mainline module that provides it. If you are seeing this
-    message it means that you are incorrectly attempting to use the jar file
-    from a java_import prebuilt of $MOD.
-
-    This is most likely due to an incorrect dependency on $MOD in an Android.mk
-    or Android.bp file. Please remove that dependency and replace with
-    something more appropriate, e.g. a dependency on an API provided by the
-    module.
-
-    If you do not know where the extraneous dependency was added then you can
-    run the following command to find a list of all the paths from the target
-    which you are trying to build to the target which produced this error.
-
-        prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-\${TARGET_PRODUCT}.ninja -t path <target> <invalid-jar>
-
-    Where <target> is the build target you specified on the command line which
-    produces this error and <invalid-jar> is the rule that failed with this
-    message. If you are specifying multiple build targets then you will need to
-    run the above command for every target until you find the cause.
-
-    The command will output one (of the possibly many) dependency paths from
-    <target> to <invalid-jar>, one file/phony target per line. e.g. it may
-    output something like this:
-
-        ....
-        out/soong/.intermediates/acme/broken/android_common/combined/broken.jar
-        out/soong/.intermediates/prebuilts/module_sdk/art/current/sdk/prebuilt_core-libart/android_common/combined/core-libart.jar
-        out/soong/.intermediates/prebuilts/module_sdk/art/current/sdk/art-module-sdk_core-libart-error/gen/this-file-will-never-be-created.jar
-
-    The last line is the failing target, the second to last line is a dependency
-    from the core-libart java_import onto the failing target, the third to last
-    line is the source of the dependency so you should look in acme/Android.bp
-    file for the "broken" module.
-
-EOF
-
-exit 1
diff --git a/java/java.go b/java/java.go
index ad46e98..25b6349 100644
--- a/java/java.go
+++ b/java/java.go
@@ -89,11 +89,11 @@
 var (
 	// Supports adding java header libraries to module_exports and sdk.
 	javaHeaderLibsSdkMemberType = &librarySdkMemberType{
-		SdkMemberTypeBase: android.SdkMemberTypeBase{
+		android.SdkMemberTypeBase{
 			PropertyName: "java_header_libs",
 			SupportsSdk:  true,
 		},
-		jarToExportGetter: func(_ android.SdkMemberContext, j *Library) android.Path {
+		func(_ android.SdkMemberContext, j *Library) android.Path {
 			headerJars := j.HeaderJars()
 			if len(headerJars) != 1 {
 				panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
@@ -101,8 +101,8 @@
 
 			return headerJars[0]
 		},
-		snapshotPathGetter:    sdkSnapshotFilePathForJar,
-		onlyCopyJarToSnapshot: copyEverythingToSnapshot,
+		sdkSnapshotFilePathForJar,
+		copyEverythingToSnapshot,
 	}
 
 	// Export implementation classes jar as part of the sdk.
@@ -116,12 +116,12 @@
 
 	// Supports adding java implementation libraries to module_exports but not sdk.
 	javaLibsSdkMemberType = &librarySdkMemberType{
-		SdkMemberTypeBase: android.SdkMemberTypeBase{
+		android.SdkMemberTypeBase{
 			PropertyName: "java_libs",
 		},
-		jarToExportGetter:     exportImplementationClassesJar,
-		snapshotPathGetter:    sdkSnapshotFilePathForJar,
-		onlyCopyJarToSnapshot: copyEverythingToSnapshot,
+		exportImplementationClassesJar,
+		sdkSnapshotFilePathForJar,
+		copyEverythingToSnapshot,
 	}
 
 	snapshotRequiresImplementationJar = func(ctx android.SdkMemberContext) bool {
@@ -146,11 +146,11 @@
 	// necessary. The java_boot_libs property to allow those modules to be exported as part of the
 	// sdk/module_exports without exposing any unnecessary information.
 	javaBootLibsSdkMemberType = &librarySdkMemberType{
-		SdkMemberTypeBase: android.SdkMemberTypeBase{
+		android.SdkMemberTypeBase{
 			PropertyName: "java_boot_libs",
 			SupportsSdk:  true,
 		},
-		jarToExportGetter: func(ctx android.SdkMemberContext, j *Library) android.Path {
+		func(ctx android.SdkMemberContext, j *Library) android.Path {
 			if snapshotRequiresImplementationJar(ctx) {
 				return exportImplementationClassesJar(ctx, j)
 			}
@@ -159,9 +159,9 @@
 			// jar for use by dexpreopting and boot jars package check. They do not need to provide an
 			// actual implementation jar but the java_import will need a file that exists so just copy an
 			// empty file. Any attempt to use that file as a jar will cause a build error.
-			return nil
+			return ctx.SnapshotBuilder().EmptyFile()
 		},
-		snapshotPathGetter: func(ctx android.SdkMemberContext, osPrefix, name string) string {
+		func(ctx android.SdkMemberContext, osPrefix, name string) string {
 			if snapshotRequiresImplementationJar(ctx) {
 				return sdkSnapshotFilePathForJar(ctx, osPrefix, name)
 			}
@@ -171,7 +171,7 @@
 			// TODO(b/175714559): Provide a proper error message in Soong not ninja.
 			return filepath.Join(osPrefix, "java_boot_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix)
 		},
-		onlyCopyJarToSnapshot: onlyCopyJarToSnapshot,
+		onlyCopyJarToSnapshot,
 	}
 
 	// Supports adding java systemserver libraries to module_exports and sdk.
@@ -185,27 +185,27 @@
 	// necessary. The java_systemserver_libs property to allow those modules to be exported as part of
 	// the sdk/module_exports without exposing any unnecessary information.
 	javaSystemserverLibsSdkMemberType = &librarySdkMemberType{
-		SdkMemberTypeBase: android.SdkMemberTypeBase{
+		android.SdkMemberTypeBase{
 			PropertyName: "java_systemserver_libs",
 			SupportsSdk:  true,
 
 			// This was only added in Tiramisu.
 			SupportedBuildReleaseSpecification: "Tiramisu+",
 		},
-		jarToExportGetter: func(ctx android.SdkMemberContext, j *Library) android.Path {
+		func(ctx android.SdkMemberContext, j *Library) android.Path {
 			// Java systemserver libs are only provided in the SDK to provide access to their dex
 			// implementation jar for use by dexpreopting. They do not need to provide an actual
 			// implementation jar but the java_import will need a file that exists so just copy an empty
 			// file. Any attempt to use that file as a jar will cause a build error.
-			return nil
+			return ctx.SnapshotBuilder().EmptyFile()
 		},
-		snapshotPathGetter: func(_ android.SdkMemberContext, osPrefix, name string) string {
+		func(_ android.SdkMemberContext, osPrefix, name string) string {
 			// Create a special name for the implementation jar to try and provide some useful information
 			// to a developer that attempts to compile against this.
 			// TODO(b/175714559): Provide a proper error message in Soong not ninja.
 			return filepath.Join(osPrefix, "java_systemserver_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix)
 		},
-		onlyCopyJarToSnapshot: onlyCopyJarToSnapshot,
+		onlyCopyJarToSnapshot,
 	}
 
 	// Supports adding java test libraries to module_exports but not sdk.
@@ -235,7 +235,7 @@
 	ImplementationAndResourcesJars android.Paths
 
 	// ImplementationJars is a list of jars that contain the implementations of classes in the
-	// module.
+	//module.
 	ImplementationJars android.Paths
 
 	// ResourceJars is a list of jars that contain the resources included in the module.
@@ -721,8 +721,7 @@
 	android.SdkMemberTypeBase
 
 	// Function to retrieve the appropriate output jar (implementation or header) from
-	// the library, if this returns nil then it is assumed that the snapshot must not provide access
-	// to the jar.
+	// the library.
 	jarToExportGetter func(ctx android.SdkMemberContext, j *Library) android.Path
 
 	// Function to compute the snapshot relative path to which the named library's
@@ -759,11 +758,7 @@
 type librarySdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
-	JarToExport android.Path `android:"arch_variant"`
-
-	// The path to a script to use when the jar is invalid.
-	InvalidJarScript android.Path
-
+	JarToExport     android.Path `android:"arch_variant"`
 	AidlIncludeDirs android.Paths
 
 	// The list of permitted packages that need to be passed to the prebuilts as they are used to
@@ -774,15 +769,7 @@
 func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	j := variant.(*Library)
 
-	memberType := ctx.MemberType().(*librarySdkMemberType)
-	p.JarToExport = memberType.jarToExportGetter(ctx, j)
-
-	// If no jar was provided for export then disallow access to it completely.
-	if p.JarToExport == nil {
-		// Copy the script to prevent access to the jar into the snapshot.
-		p.InvalidJarScript = android.PathForSource(ctx.SdkModuleContext(),
-			"build/soong/java/invalid_implementation_jar.sh")
-	}
+	p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(ctx, j)
 
 	p.AidlIncludeDirs = j.AidlIncludeDirs()
 
@@ -805,21 +792,6 @@
 		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
 	}
 
-	if scriptSrc := p.InvalidJarScript; scriptSrc != nil {
-		// Copy the script to prevent access to the jar into the snapshot.
-		scriptDest := filepath.Join("scripts", scriptSrc.Base())
-		builder.CopyToSnapshot(scriptSrc, scriptDest)
-
-		// Generate a genrule module that will invoke the script passing in the module name.
-		genrule := builder.AddInternalModule(p, "genrule", "error")
-		genRuleName := genrule.Name()
-		genrule.AddProperty("out", []string{"this-file-will-never-be-created.jar"})
-		genrule.AddProperty("tool_files", []string{scriptDest})
-		genrule.AddProperty("cmd", fmt.Sprintf("$(location %s) %s", scriptDest, p.Name()))
-
-		propertySet.AddPropertyWithTag("jars", []string{":" + genRuleName}, builder.SdkMemberReferencePropertyTag(true))
-	}
-
 	if len(p.PermittedPackages) > 0 {
 		propertySet.AddProperty("permitted_packages", p.PermittedPackages)
 	}
@@ -1580,8 +1552,8 @@
 	// name of the API surface
 	Api_surface *string
 
-	// list of API provider modules that consists this API surface
-	Api_providers []string
+	// list of Java API contribution modules that consists this API surface
+	Api_contributions []string
 
 	// List of flags to be passed to the javac compiler to generate jar file
 	Javacflags []string
@@ -1649,12 +1621,12 @@
 	}
 }
 
-var javaApiProviderTag = dependencyTag{name: "java-api-provider"}
+var javaApiContributionTag = dependencyTag{name: "java-api-contribution"}
 
 func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
-	apiProviders := al.properties.Api_providers
-	for _, apiProviderName := range apiProviders {
-		ctx.AddDependency(ctx.Module(), javaApiProviderTag, apiProviderName)
+	apiContributions := al.properties.Api_contributions
+	for _, apiContributionName := range apiContributions {
+		ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName)
 	}
 }
 
@@ -1673,16 +1645,11 @@
 
 	homeDir := android.PathForModuleOut(ctx, "metalava", "home")
 
-	apiProviders := al.properties.Api_providers
-	srcFiles := make([]android.Path, len(apiProviders))
-	for i, apiProviderName := range apiProviders {
-		apiProvider := ctx.GetDirectDepWithTag(apiProviderName, javaApiProviderTag)
-		if apiProvider == nil {
-			panic(fmt.Errorf("Java API provider module %s not found, called from %s", apiProviderName, al.Name()))
-		}
-		provider := ctx.OtherModuleProvider(apiProvider, JavaApiImportProvider).(JavaApiImportInfo)
-		srcFiles[i] = android.PathForModuleSrc(ctx, provider.ApiFile.String())
-	}
+	var srcFiles []android.Path
+	ctx.VisitDirectDepsWithTag(javaApiContributionTag, func(dep android.Module) {
+		provider := ctx.OtherModuleProvider(dep, JavaApiImportProvider).(JavaApiImportInfo)
+		srcFiles = append(srcFiles, android.PathForModuleSrc(ctx, provider.ApiFile.String()))
+	})
 
 	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir)
 
@@ -1857,7 +1824,7 @@
 }
 
 func (j *Import) commonBuildActions(ctx android.ModuleContext) {
-	// TODO(b/231322772) these should come from Bazel once available
+	//TODO(b/231322772) these should come from Bazel once available
 	j.sdkVersion = j.SdkVersion(ctx)
 	j.minSdkVersion = j.MinSdkVersion(ctx)
 
@@ -2460,7 +2427,7 @@
 		resources.Append(android.BazelLabelForModuleSrc(ctx, m.properties.Java_resources))
 	}
 
-	// TODO(b/179889880) handle case where glob includes files outside package
+	//TODO(b/179889880) handle case where glob includes files outside package
 	resDeps := ResourceDirsToFiles(
 		ctx,
 		m.properties.Java_resource_dirs,
@@ -2622,7 +2589,7 @@
 	}
 
 	epEnabled := m.properties.Errorprone.Enabled
-	// TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
+	//TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
 	if Bool(epEnabled) {
 		javacopts = append(javacopts, m.properties.Errorprone.Javacflags...)
 	}
@@ -2876,7 +2843,7 @@
 		HeaderJars:                     android.PathsIfNonNil(i.combinedClasspathFile),
 		ImplementationAndResourcesJars: android.PathsIfNonNil(i.combinedClasspathFile),
 		ImplementationJars:             android.PathsIfNonNil(i.combinedClasspathFile),
-		// TODO(b/240308299) include AIDL information from Bazel
+		//TODO(b/240308299) include AIDL information from Bazel
 	})
 
 	i.maybeInstall(ctx, jarName, outputFile)
diff --git a/java/java_test.go b/java/java_test.go
index 3f8cd8e..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 {
@@ -1823,13 +1856,13 @@
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
-			api_providers: ["foo1"],
+			api_contributions: ["foo1"],
 		}
 
 		java_api_library {
 			name: "bar2",
 			api_surface: "system",
-			api_providers: ["foo1", "foo2"],
+			api_contributions: ["foo1", "foo2"],
 		}
 		`,
 		map[string][]byte{
@@ -1876,13 +1909,13 @@
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
-			api_providers: ["foo1"],
+			api_contributions: ["foo1"],
 		}
 
 		java_api_library {
 			name: "bar2",
 			api_surface: "system",
-			api_providers: ["foo1", "foo2"],
+			api_contributions: ["foo1", "foo2"],
 		}
 		`,
 		map[string][]byte{
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/java/lint.go b/java/lint.go
index 9827159..7a6e5d9 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -190,10 +190,8 @@
 
 	extraCheckModules := l.properties.Lint.Extra_check_modules
 
-	if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
-		if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
-			extraCheckModules = strings.Split(checkOnlyModules, ",")
-		}
+	if extraCheckModulesEnv := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); extraCheckModulesEnv != "" {
+		extraCheckModules = append(extraCheckModules, strings.Split(extraCheckModulesEnv, ",")...)
 	}
 
 	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
diff --git a/java/sdk_library.go b/java/sdk_library.go
index fad1df7..56e5550 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1648,6 +1648,7 @@
 	// shared libs and static libs. So we need to add both of these libs to Libs property.
 	props.Libs = module.properties.Libs
 	props.Libs = append(props.Libs, module.properties.Static_libs...)
+	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
 	props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
 	props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
 	props.Java_version = module.properties.Java_version
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 096bca8..210bfc3 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -1385,3 +1385,29 @@
 			}
 		`)
 }
+
+func TestJavaSdkLibrary_StubOnlyLibs_PassedToDroidstubs(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			public: {
+				enabled: true,
+			},
+			stub_only_libs: ["bar-lib"],
+		}
+
+		java_library {
+			name: "bar-lib",
+			srcs: ["b.java"],
+		}
+		`)
+
+	// The foo.stubs.source should depend on bar-lib
+	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
+	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+}
diff --git a/rust/library.go b/rust/library.go
index c2ce9de..bc9c9aa 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -267,84 +267,94 @@
 var _ libraryInterface = (*libraryDecorator)(nil)
 var _ exportedFlagsProducer = (*libraryDecorator)(nil)
 
-// rust_library produces all rust variants.
+// rust_library produces all Rust variants (rust_library_dylib and
+// rust_library_rlib).
 func RustLibraryFactory() android.Module {
 	module, library := NewRustLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyRust()
 	return module.Init()
 }
 
-// rust_ffi produces all ffi variants.
+// rust_ffi produces all FFI variants (rust_ffi_shared and
+// rust_ffi_static).
 func RustFFIFactory() android.Module {
 	module, library := NewRustLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyFFI()
 	return module.Init()
 }
 
-// rust_library_dylib produces a dylib.
+// rust_library_dylib produces a Rust dylib (Rust crate type "dylib").
 func RustLibraryDylibFactory() android.Module {
 	module, library := NewRustLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyDylib()
 	return module.Init()
 }
 
-// rust_library_rlib produces an rlib.
+// rust_library_rlib produces an rlib (Rust crate type "rlib").
 func RustLibraryRlibFactory() android.Module {
 	module, library := NewRustLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyRlib()
 	return module.Init()
 }
 
-// rust_ffi_shared produces a shared library.
+// rust_ffi_shared produces a shared library (Rust crate type
+// "cdylib").
 func RustFFISharedFactory() android.Module {
 	module, library := NewRustLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyShared()
 	return module.Init()
 }
 
-// rust_ffi_static produces a static library.
+// rust_ffi_static produces a static library (Rust crate type
+// "staticlib").
 func RustFFIStaticFactory() android.Module {
 	module, library := NewRustLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyStatic()
 	return module.Init()
 }
 
-// rust_library_host produces all rust variants.
+// rust_library_host produces all Rust variants for the host
+// (rust_library_dylib_host and rust_library_rlib_host).
 func RustLibraryHostFactory() android.Module {
 	module, library := NewRustLibrary(android.HostSupported)
 	library.BuildOnlyRust()
 	return module.Init()
 }
 
-// rust_ffi_host produces all FFI variants.
+// rust_ffi_host produces all FFI variants for the host
+// (rust_ffi_static_host and rust_ffi_shared_host).
 func RustFFIHostFactory() android.Module {
 	module, library := NewRustLibrary(android.HostSupported)
 	library.BuildOnlyFFI()
 	return module.Init()
 }
 
-// rust_library_dylib_host produces a dylib.
+// rust_library_dylib_host produces a dylib for the host (Rust crate
+// type "dylib").
 func RustLibraryDylibHostFactory() android.Module {
 	module, library := NewRustLibrary(android.HostSupported)
 	library.BuildOnlyDylib()
 	return module.Init()
 }
 
-// rust_library_rlib_host produces an rlib.
+// rust_library_rlib_host produces an rlib for the host (Rust crate
+// type "rlib").
 func RustLibraryRlibHostFactory() android.Module {
 	module, library := NewRustLibrary(android.HostSupported)
 	library.BuildOnlyRlib()
 	return module.Init()
 }
 
-// rust_ffi_static_host produces a static library.
+// rust_ffi_static_host produces a static library for the host (Rust
+// crate type "staticlib").
 func RustFFIStaticHostFactory() android.Module {
 	module, library := NewRustLibrary(android.HostSupported)
 	library.BuildOnlyStatic()
 	return module.Init()
 }
 
-// rust_ffi_shared_host produces an shared library.
+// rust_ffi_shared_host produces an shared library for the host (Rust
+// crate type "cdylib").
 func RustFFISharedHostFactory() android.Module {
 	module, library := NewRustLibrary(android.HostSupported)
 	library.BuildOnlyShared()
diff --git a/rust/library_test.go b/rust/library_test.go
index 4633cc7..e3e4d0f 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -30,11 +30,11 @@
 			srcs: ["foo.rs"],
 			crate_name: "foo",
 		}
-                rust_ffi_host {
-                        name: "libfoo.ffi",
-                        srcs: ["foo.rs"],
-                        crate_name: "foo"
-                }`)
+		rust_ffi_host {
+			name: "libfoo.ffi",
+			srcs: ["foo.rs"],
+			crate_name: "foo"
+		}`)
 
 	// Test all variants are being built.
 	libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
@@ -45,7 +45,7 @@
 	rlibCrateType := "rlib"
 	dylibCrateType := "dylib"
 	sharedCrateType := "cdylib"
-	staticCrateType := "static"
+	staticCrateType := "staticlib"
 
 	// Test crate type for rlib is correct.
 	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 58c1647..1b64130 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -169,15 +169,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
-    jars: [":mysdk_core1-error"],
-}
-
-genrule {
-    name: "mysdk_core1-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) core1",
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/core1.jar"],
 }
 
 java_import {
@@ -185,15 +177,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
-    jars: [":mysdk_core2-error"],
-}
-
-genrule {
-    name: "mysdk_core2-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) core2",
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/core2.jar"],
 }
 `),
 		checkAllCopyRules(`
@@ -203,7 +187,8 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-build/soong/java/invalid_implementation_jar.sh -> scripts/invalid_implementation_jar.sh
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core1.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core2.jar
 		`),
 		snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
 
@@ -372,18 +357,10 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: [":mysdk_mybootlib-error"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
     permitted_packages: ["mybootlib"],
 }
 
-genrule {
-    name: "mysdk_mybootlib-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) mybootlib",
-}
-
 java_sdk_library_import {
     name: "myothersdklibrary",
     prefer: false,
@@ -490,7 +467,7 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-build/soong/java/invalid_implementation_jar.sh -> scripts/invalid_implementation_jar.sh
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
@@ -510,7 +487,7 @@
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-build/soong/java/invalid_implementation_jar.sh -> scripts/invalid_implementation_jar.sh
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
@@ -899,18 +876,10 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: [":mysdk_mybootlib-error"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
     permitted_packages: ["mybootlib"],
 }
 
-genrule {
-    name: "mysdk_mybootlib-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) mybootlib",
-}
-
 java_sdk_library_import {
     name: "mynewlibrary",
     prefer: false,
@@ -961,7 +930,7 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-build/soong/java/invalid_implementation_jar.sh -> scripts/invalid_implementation_jar.sh
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/mynewlibrary.stubs/android_common/javac/mynewlibrary.stubs.jar -> sdk_library/public/mynewlibrary-stubs.jar
 .intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_api.txt -> sdk_library/public/mynewlibrary.txt
 .intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_removed.txt -> sdk_library/public/mynewlibrary-removed.txt
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index c6cb6c2..51903ce3 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -19,13 +19,11 @@
 	"testing"
 
 	"android/soong/android"
-	"android/soong/genrule"
 	"android/soong/java"
 )
 
 var prepareForSdkTestWithJava = android.GroupFixturePreparers(
 	java.PrepareForTestWithJavaBuildComponents,
-	genrule.PrepareForTestWithGenRuleBuildComponents,
 	PrepareForTestWithSdkBuildComponents,
 
 	// Ensure that all source paths are provided. This helps ensure that the snapshot generation is
@@ -36,7 +34,6 @@
 	// Files needs by most of the tests.
 	android.MockFS{
 		"Test.java": nil,
-		"build/soong/java/invalid_implementation_jar.sh": nil,
 	}.AddToFixture(),
 )
 
@@ -291,26 +288,18 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: [":mysdk_myjavalib-error"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar"],
     permitted_packages: ["pkg.myjavalib"],
 }
-
-genrule {
-    name: "mysdk_myjavalib-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) myjavalib",
-}
 `),
 		checkAllCopyRules(`
-build/soong/java/invalid_implementation_jar.sh -> scripts/invalid_implementation_jar.sh
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
 `),
 	)
 }
 
 func TestSnapshotWithJavaBootLibrary_UpdatableMedia(t *testing.T) {
-	runTest := func(t *testing.T, targetBuildRelease, expectedJarPath, expectedGenRule, expectedCopyRule string) {
+	runTest := func(t *testing.T, targetBuildRelease, expectedJarPath, expectedCopyRule string) {
 		result := android.GroupFixturePreparers(
 			prepareForSdkTestWithJava,
 			android.FixtureMergeEnv(map[string]string{
@@ -345,27 +334,20 @@
     jars: ["%s"],
     permitted_packages: ["pkg.media"],
 }
-%s`, expectedJarPath, expectedGenRule)),
+`, expectedJarPath)),
 			checkAllCopyRules(expectedCopyRule),
 		)
 	}
 
 	t.Run("updatable-media in S", func(t *testing.T) {
-		runTest(t, "S", "java/updatable-media.jar", "", `
+		runTest(t, "S", "java/updatable-media.jar", `
 .intermediates/updatable-media/android_common/package-check/updatable-media.jar -> java/updatable-media.jar
 `)
 	})
 
 	t.Run("updatable-media in T", func(t *testing.T) {
-		runTest(t, "Tiramisu", ":mysdk_updatable-media-error", `
-genrule {
-    name: "mysdk_updatable-media-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) updatable-media",
-}`, `
-build/soong/java/invalid_implementation_jar.sh -> scripts/invalid_implementation_jar.sh
+		runTest(t, "Tiramisu", "java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar", `
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar
 `)
 	})
 }
@@ -407,20 +389,12 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: [":myexports_myjavalib-error"],
+    jars: ["java_systemserver_libs/snapshot/jars/are/invalid/myjavalib.jar"],
     permitted_packages: ["pkg.myjavalib"],
 }
-
-genrule {
-    name: "myexports_myjavalib-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) myjavalib",
-}
 `),
 		checkAllCopyRules(`
-build/soong/java/invalid_implementation_jar.sh -> scripts/invalid_implementation_jar.sh
+.intermediates/myexports/common_os/empty -> java_systemserver_libs/snapshot/jars/are/invalid/myjavalib.jar
 `),
 	)
 }
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/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 9540a6b..1ac405d 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -119,18 +119,10 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: [":mysdk_mylib-error"],
+    jars: ["java_systemserver_libs/snapshot/jars/are/invalid/mylib.jar"],
     permitted_packages: ["mylib"],
 }
 
-genrule {
-    name: "mysdk_mylib-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) mylib",
-}
-
 prebuilt_systemserverclasspath_fragment {
     name: "mysystemserverclasspathfragment",
     prefer: false,
@@ -188,18 +180,10 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: [":mysdk_mylib-error"],
+    jars: ["java_systemserver_libs/snapshot/jars/are/invalid/mylib.jar"],
     permitted_packages: ["mylib"],
 }
 
-genrule {
-    name: "mysdk_mylib-error",
-    visibility: ["//visibility:private"],
-    out: ["this-file-will-never-be-created.jar"],
-    tool_files: ["scripts/invalid_implementation_jar.sh"],
-    cmd: "$(location scripts/invalid_implementation_jar.sh) mylib",
-}
-
 prebuilt_systemserverclasspath_fragment {
     name: "mysystemserverclasspathfragment",
     prefer: false,
diff --git a/sdk/update.go b/sdk/update.go
index 6ebbf09..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
@@ -1049,6 +1014,9 @@
 	filesToZip  android.Paths
 	zipsToMerge android.Paths
 
+	// The path to an empty file.
+	emptyFile android.WritablePath
+
 	prebuiltModules map[string]*bpModule
 	prebuiltOrder   []*bpModule
 
@@ -1108,6 +1076,19 @@
 	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
 }
 
+func (s *snapshotBuilder) EmptyFile() android.Path {
+	if s.emptyFile == nil {
+		ctx := s.ctx
+		s.emptyFile = android.PathForModuleOut(ctx, "empty")
+		s.ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Touch,
+			Output: s.emptyFile,
+		})
+	}
+
+	return s.emptyFile
+}
+
 func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
 	name := member.Name()
 	if s.prebuiltModules[name] != nil {
@@ -1184,24 +1165,6 @@
 	return m
 }
 
-func (s *snapshotBuilder) AddInternalModule(properties android.SdkMemberProperties, moduleType string, nameSuffix string) android.BpModule {
-	name := properties.Name() + "-" + nameSuffix
-
-	if s.prebuiltModules[name] != nil {
-		panic(fmt.Sprintf("Duplicate module detected, module %s has already been added", name))
-	}
-
-	m := s.bpFile.newModule(moduleType)
-	m.AddProperty("name", name)
-	m.AddProperty("visibility", []string{"//visibility:private"})
-
-	s.prebuiltModules[name] = m
-	s.prebuiltOrder = append(s.prebuiltOrder, m)
-
-	s.allMembersByName[name] = struct{}{}
-	return m
-}
-
 func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
 	// If neither device or host is supported then this module does not support either so will not
 	// recognize the properties.
@@ -1232,23 +1195,18 @@
 // Get a name for sdk snapshot member. If the member is private then generate a snapshot specific
 // name. As part of the processing this checks to make sure that any required members are part of
 // the snapshot.
-func (s *snapshotBuilder) snapshotSdkMemberName(reference string, required bool) string {
-	prefix := ""
-	name := strings.TrimPrefix(reference, ":")
-	if name != reference {
-		prefix = ":"
-	}
+func (s *snapshotBuilder) snapshotSdkMemberName(name string, required bool) string {
 	if _, ok := s.allMembersByName[name]; !ok {
 		if required {
 			s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", name)
 		}
-		return reference
+		return name
 	}
 
 	if s.isInternalMember(name) {
-		return prefix + s.ctx.ModuleName() + "_" + name
+		return s.ctx.ModuleName() + "_" + name
 	} else {
-		return reference
+		return name
 	}
 }
 
@@ -2026,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)
@@ -2064,7 +2005,6 @@
 	variantPropertiesFactory := func() android.SdkMemberProperties {
 		properties := memberType.CreateVariantPropertiesStruct()
 		base := properties.Base()
-		base.MemberName = member.Name()
 		base.Os_count = osCount
 		return properties
 	}
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{