Merge changes I6ddb47d7,I3df3d304

* changes:
  [hwasan] Increase BB to explore for reachability
  [hwasan] Also pass use-after-scope flag in LTO
diff --git a/android/Android.bp b/android/Android.bp
index 94d2c04..2ccccf0 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -19,6 +19,7 @@
         "soong-shared",
         "soong-starlark",
         "soong-starlark-format",
+        "soong-ui-bp2build_metrics_proto",
         "soong-ui-metrics_proto",
         "soong-android-allowlists",
 
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 5da50cd..34a6860 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -141,6 +141,7 @@
 		"external/f2fs-tools":                    Bp2BuildDefaultTrue,
 		"external/flac":                          Bp2BuildDefaultTrueRecursively,
 		"external/fmtlib":                        Bp2BuildDefaultTrueRecursively,
+		"external/fsverity-utils":                Bp2BuildDefaultTrueRecursively,
 		"external/guava":                         Bp2BuildDefaultTrueRecursively,
 		"external/google-benchmark":              Bp2BuildDefaultTrueRecursively,
 		"external/googletest":                    Bp2BuildDefaultTrueRecursively,
@@ -189,6 +190,7 @@
 		"external/python/six":                    Bp2BuildDefaultTrueRecursively,
 		"external/rappor":                        Bp2BuildDefaultTrueRecursively,
 		"external/scudo":                         Bp2BuildDefaultTrueRecursively,
+		"external/selinux/checkpolicy":           Bp2BuildDefaultTrueRecursively,
 		"external/selinux/libselinux":            Bp2BuildDefaultTrueRecursively,
 		"external/selinux/libsepol":              Bp2BuildDefaultTrueRecursively,
 		"external/speex":                         Bp2BuildDefaultTrueRecursively,
@@ -333,6 +335,7 @@
 		"system/apex":                                            Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
 		"system/apex/apexer":                                     Bp2BuildDefaultTrue,
 		"system/apex/libs":                                       Bp2BuildDefaultTrueRecursively,
+		"system/apex/libs/libapexsupport":                        Bp2BuildDefaultFalseRecursively, // TODO(b/267572288): depends on rust
 		"system/apex/proto":                                      Bp2BuildDefaultTrueRecursively,
 		"system/apex/tools":                                      Bp2BuildDefaultTrueRecursively,
 		"system/core/debuggerd":                                  Bp2BuildDefaultTrueRecursively,
@@ -346,6 +349,7 @@
 		"system/core/libprocessgroup":                            Bp2BuildDefaultTrue,
 		"system/core/libprocessgroup/cgrouprc":                   Bp2BuildDefaultTrue,
 		"system/core/libprocessgroup/cgrouprc_format":            Bp2BuildDefaultTrue,
+		"system/core/libsparse":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/libsuspend":                                 Bp2BuildDefaultTrue,
 		"system/core/libsystem":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/libsysutils":                                Bp2BuildDefaultTrueRecursively,
@@ -354,7 +358,9 @@
 		"system/core/mkbootfs":                                   Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoparser":     Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoserializer": Bp2BuildDefaultTrueRecursively,
+		"system/extras/f2fs_utils":                               Bp2BuildDefaultTrueRecursively,
 		"system/extras/toolchain-extras":                         Bp2BuildDefaultTrue,
+		"system/extras/verity":                                   Bp2BuildDefaultTrueRecursively,
 		"system/hardware/interfaces/media":                       Bp2BuildDefaultTrueRecursively,
 		"system/incremental_delivery/incfs":                      Bp2BuildDefaultTrue,
 		"system/libartpalette":                                   Bp2BuildDefaultTrueRecursively,
@@ -384,6 +390,7 @@
 		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
 		"system/memory/libmemunreachable":                        Bp2BuildDefaultTrueRecursively,
 		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
+		"system/security/fsverity":                               Bp2BuildDefaultTrueRecursively,
 		"system/testing/gtest_extras":                            Bp2BuildDefaultTrueRecursively,
 		"system/timezone/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/timezone/output_data":                            Bp2BuildDefaultTrueRecursively,
@@ -456,6 +463,9 @@
 
 		// TODO(b/266459895): remove this and the placeholder BUILD file after re-enabling libunwindstack
 		"external/rust/crates/rustc-demangle-capi":/* recursive = */ false,
+
+		// Used for testing purposes only. Should not actually exist in the real source tree.
+		"testpkg/keep_build_file":/* recursive = */ false,
 	}
 
 	Bp2buildModuleAlwaysConvertList = []string{
@@ -577,12 +587,11 @@
 		//frameworks/base/core/java
 		"IDropBoxManagerService_aidl",
 
-		//system/core/libsparse
-		"libsparse",
-
 		//system/extras/ext4_utils
 		"libext4_utils",
 		"mke2fs_conf",
+		"mkuserimg_mke2fs",
+		"blk_alloc_to_base_fs",
 
 		//system/extras/libfec
 		"libfec",
@@ -590,10 +599,6 @@
 		//system/extras/squashfs_utils
 		"libsquashfs_utils",
 
-		//system/extras/verity/fec
-		"fec",
-		"boot_signer",
-
 		//packages/apps/Car/libs/car-ui-lib/car-ui-androidx
 		// genrule dependencies for java_imports
 		"car-ui-androidx-annotation-nodeps",
@@ -837,7 +842,6 @@
 
 		"linker",    // TODO(b/228316882): cc_binary uses link_crt
 		"versioner", // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
-		"tjbench",   // TODO(b/240563612): Stem property
 
 		// requires host tools for apexer
 		"apexer_test", "apexer_test_host_tools", "host_apex_verifier",
@@ -846,9 +850,6 @@
 		"libbase_ndk",  // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
 		"bouncycastle", // TODO(b/274474005): Need support for custom system_modules.
 
-		// python protos
-		"libprotobuf-python", // Has a handcrafted alternative
-
 		// genrule incompatibilities
 		"brotli-fuzzer-corpus",                                       // TODO(b/202015218): outputs are in location incompatible with bazel genrule handling.
 		"platform_tools_properties", "build_tools_source_properties", // TODO(b/203369847): multiple genrules in the same package creating the same file
@@ -1428,16 +1429,12 @@
 		"merge_ota",
 
 		// releasetools
-		"releasetools_fsverity_metadata_generator",
 		"verity_utils",
 		"check_ota_package_signature",
 		"check_target_files_vintf",
 		"releasetools_check_target_files_vintf",
-		"releasetools_verity_utils",
-		"build_image",
 		"ota_from_target_files",
 		"releasetools_ota_from_target_files",
-		"releasetools_build_image",
 		"add_img_to_target_files",
 		"releasetools_add_img_to_target_files",
 		"fsverity_metadata_generator",
@@ -1489,8 +1486,22 @@
 		"tradefed",
 		"permissive_mte_test",
 		"ICU4CTestRunner",
+		"DeviceLongPollingStubTest",
 
 		"HelloWorldHostTest", // TODO(b/280452825): Convert HelloWorldHostTest to b test
+
+		"libprotobuf-full-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
+		"libprotobuf-lite-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
+
+		"logcat", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
+
+		"expresscatalogvalidator", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
+
+		// depends on other //art modules
+		"libart-for-test",
+		"libart_generated_headers",
+		"libart-runtime-gtest",
+		"libartd-runtime-gtest",
 	}
 
 	MixedBuildsDisabledList = []string{
@@ -1510,9 +1521,6 @@
 		"libadb_pairing_connection_static",
 		"libadb_pairing_server", "libadb_pairing_server_static",
 
-		// TODO(b/240563612) Needing `stem` selection support for cc_binary
-		"crasher",
-
 		// java_import[_host] issues
 		// tradefed prebuilts depend on libprotobuf
 		"prebuilt_tradefed",
diff --git a/android/bazel.go b/android/bazel.go
index d326634..1bfbdec 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -17,8 +17,10 @@
 import (
 	"bufio"
 	"errors"
+	"fmt"
 	"strings"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -73,6 +75,21 @@
 
 	// MissingBp2buildDep stores the module names of direct dependency that were not found
 	MissingDeps []string `blueprint:"mutated"`
+
+	// If non-nil, indicates that the module could not be converted successfully
+	// with bp2build. This will describe the reason the module could not be converted.
+	UnconvertedReason *UnconvertedReason
+}
+
+// The reason a module could not be converted to a BUILD target via bp2build.
+// This should match bp2build_metrics_proto.UnconvertedReason, but omits private
+// proto-related fields that prevent copying this struct.
+type UnconvertedReason struct {
+	// Should correspond to a valid value in bp2build_metrics_proto.UnconvertedReasonType.
+	// A raw int is used here instead, because blueprint logic requires that all transitive
+	// fields of module definitions be primitives.
+	ReasonType int
+	Detail     string
 }
 
 type BazelModuleProperties struct {
@@ -137,6 +154,12 @@
 	GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
 	ShouldConvertWithBp2build(ctx BazelConversionContext) bool
 	shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool
+
+	// ConvertWithBp2build either converts the module to a Bazel build target or
+	// declares the module as unconvertible (for logging and metrics).
+	// Modules must implement this function to be bp2build convertible. The function
+	// must either create at least one Bazel target module (using ctx.CreateBazelTargetModule or
+	// its related functions), or declare itself unconvertible using ctx.MarkBp2buildUnconvertible.
 	ConvertWithBp2build(ctx TopDownMutatorContext)
 
 	// namespacedVariableProps is a map from a soong config variable namespace
@@ -232,7 +255,7 @@
 	if b.ShouldConvertWithBp2build(ctx) {
 		return bp2buildModuleLabel(ctx, module)
 	}
-	return "" // no label for unconverted module
+	panic(fmt.Errorf("requested non-existent label for module ", module.Name()))
 }
 
 type Bp2BuildConversionAllowlist struct {
@@ -533,16 +556,32 @@
 }
 
 func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("bp2build_conversion", convertWithBp2build).Parallel()
+	ctx.TopDown("bp2build_conversion", bp2buildConversionMutator).Parallel()
 }
 
-func convertWithBp2build(ctx TopDownMutatorContext) {
-	bModule, ok := ctx.Module().(Bazelable)
-	if !ok || !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
+func bp2buildConversionMutator(ctx TopDownMutatorContext) {
+	if ctx.Config().HasBazelBuildTargetInSource(ctx) {
+		// Defer to the BUILD target. Generating an additional target would
+		// cause a BUILD file conflict.
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, "")
 		return
 	}
 
+	bModule, ok := ctx.Module().(Bazelable)
+	if !ok {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
+		return
+	}
+	// TODO: b/285631638 - Differentiate between denylisted modules and missing bp2build capabilities.
+	if !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
+		return
+	}
 	bModule.ConvertWithBp2build(ctx)
+
+	if !ctx.Module().base().IsConvertedByBp2build() && ctx.Module().base().GetUnconvertedReason() == nil {
+		panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", ctx.ModuleName()))
+	}
 }
 
 func registerApiBp2buildConversionMutator(ctx RegisterMutatorsContext) {
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index d71eca2..f4b368b 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -28,7 +28,7 @@
 	"android/soong/android/allowlists"
 	"android/soong/bazel/cquery"
 	"android/soong/shared"
-	"android/soong/starlark_fmt"
+	"android/soong/starlark_import"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/metrics"
@@ -44,34 +44,6 @@
 		Description: "",
 		CommandDeps: []string{"${bazelBuildRunfilesTool}"},
 	}, "outDir")
-	allowedBazelEnvironmentVars = []string{
-		// clang-tidy
-		"ALLOW_LOCAL_TIDY_TRUE",
-		"DEFAULT_TIDY_HEADER_DIRS",
-		"TIDY_TIMEOUT",
-		"WITH_TIDY",
-		"WITH_TIDY_FLAGS",
-		"TIDY_EXTERNAL_VENDOR",
-
-		"SKIP_ABI_CHECKS",
-		"UNSAFE_DISABLE_APEX_ALLOWED_DEPS_CHECK",
-		"AUTO_ZERO_INITIALIZE",
-		"AUTO_PATTERN_INITIALIZE",
-		"AUTO_UNINITIALIZE",
-		"USE_CCACHE",
-		"LLVM_NEXT",
-		"LLVM_PREBUILTS_VERSION",
-		"LLVM_RELEASE_VERSION",
-		"ALLOW_UNKNOWN_WARNING_OPTION",
-
-		"UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT",
-
-		// Overrides the version in the apex_manifest.json. The version is unique for
-		// each branch (internal, aosp, mainline releases, dessert releases).  This
-		// enables modules built on an older branch to be installed against a newer
-		// device for development purposes.
-		"OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION",
-	}
 )
 
 func registerMixedBuildsMutator(ctx RegisterMutatorsContext) {
@@ -187,6 +159,9 @@
 	// Returns the results of the GetCcUnstrippedInfo query
 	GetCcUnstrippedInfo(label string, cfgkey configKey) (cquery.CcUnstrippedInfo, error)
 
+	// Returns the results of the GetPrebuiltFileInfo query
+	GetPrebuiltFileInfo(label string, cfgKey configKey) (cquery.PrebuiltFileInfo, error)
+
 	// ** end Cquery Results Retrieval Functions
 
 	// Issues commands to Bazel to receive results for all cquery requests
@@ -254,8 +229,6 @@
 	bazelEnabledModules map[string]bool
 	// DCLA modules are enabled when used in apex.
 	bazelDclaEnabledModules map[string]bool
-	// If true, modules are bazel-enabled by default, unless present in bazelDisabledModules.
-	modulesDefaultToBazel bool
 
 	targetProduct      string
 	targetBuildVariant string
@@ -272,11 +245,12 @@
 type MockBazelContext struct {
 	OutputBaseDir string
 
-	LabelToOutputFiles  map[string][]string
-	LabelToCcInfo       map[string]cquery.CcInfo
-	LabelToPythonBinary map[string]string
-	LabelToApexInfo     map[string]cquery.ApexInfo
-	LabelToCcBinary     map[string]cquery.CcUnstrippedInfo
+	LabelToOutputFiles      map[string][]string
+	LabelToCcInfo           map[string]cquery.CcInfo
+	LabelToPythonBinary     map[string]string
+	LabelToApexInfo         map[string]cquery.ApexInfo
+	LabelToCcBinary         map[string]cquery.CcUnstrippedInfo
+	LabelToPrebuiltFileInfo map[string]cquery.PrebuiltFileInfo
 
 	BazelRequests map[string]bool
 }
@@ -325,6 +299,14 @@
 	return result, nil
 }
 
+func (m MockBazelContext) GetPrebuiltFileInfo(label string, _ configKey) (cquery.PrebuiltFileInfo, error) {
+	result, ok := m.LabelToPrebuiltFileInfo[label]
+	if !ok {
+		return cquery.PrebuiltFileInfo{}, fmt.Errorf("no target with label %q in LabelToPrebuiltFileInfo", label)
+	}
+	return result, nil
+}
+
 func (m MockBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
 	panic("unimplemented")
 }
@@ -433,6 +415,14 @@
 	return cquery.CcUnstrippedInfo{}, fmt.Errorf("no bazel response for %s", key)
 }
 
+func (bazelCtx *mixedBuildBazelContext) GetPrebuiltFileInfo(label string, cfgKey configKey) (cquery.PrebuiltFileInfo, error) {
+	key := makeCqueryKey(label, cquery.GetPrebuiltFileInfo, cfgKey)
+	if rawString, ok := bazelCtx.results[key]; ok {
+		return cquery.GetPrebuiltFileInfo.ParseResult(strings.TrimSpace(rawString))
+	}
+	return cquery.PrebuiltFileInfo{}, fmt.Errorf("no bazel response for %s", key)
+}
+
 func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
 	panic("unimplemented")
 }
@@ -454,6 +444,10 @@
 	panic("implement me")
 }
 
+func (n noopBazelContext) GetPrebuiltFileInfo(_ string, _ configKey) (cquery.PrebuiltFileInfo, error) {
+	panic("implement me")
+}
+
 func (n noopBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
 	panic("unimplemented")
 }
@@ -501,10 +495,8 @@
 		for enabledAdHocModule := range forceEnabled {
 			enabledModules[enabledAdHocModule] = true
 		}
-	case BazelDevMode:
-		AddToStringSet(disabledModules, allowlists.MixedBuildsDisabledList)
 	default:
-		panic("Expected BazelProdMode, BazelStagingMode, or BazelDevMode")
+		panic("Expected BazelProdMode or BazelStagingMode")
 	}
 	return enabledModules, disabledModules
 }
@@ -522,7 +514,7 @@
 }
 
 func NewBazelContext(c *config) (BazelContext, error) {
-	if c.BuildMode != BazelProdMode && c.BuildMode != BazelStagingMode && c.BuildMode != BazelDevMode {
+	if c.BuildMode != BazelProdMode && c.BuildMode != BazelStagingMode {
 		return noopBazelContext{}, nil
 	}
 
@@ -586,7 +578,6 @@
 	return &mixedBuildBazelContext{
 		bazelRunner:             &builtinBazelRunner{c.UseBazelProxy, absolutePath(c.outDir)},
 		paths:                   &paths,
-		modulesDefaultToBazel:   c.BuildMode == BazelDevMode,
 		bazelEnabledModules:     enabledModules,
 		bazelDisabledModules:    disabledModules,
 		bazelDclaEnabledModules: dclaEnabledModules,
@@ -610,7 +601,7 @@
 		return true
 	}
 
-	return context.modulesDefaultToBazel
+	return false
 }
 
 func (context *mixedBuildBazelContext) IsModuleDclaAllowed(moduleName string) bool {
@@ -665,26 +656,20 @@
 
 func (context *mixedBuildBazelContext) createBazelCommand(config Config, runName bazel.RunName, command bazelCommand,
 	extraFlags ...string) bazel.CmdRequest {
+	if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
+		panic("Unknown GOOS: " + runtime.GOOS)
+	}
 	cmdFlags := []string{
 		"--output_base=" + absolutePath(context.paths.outputBase),
 		command.command,
 		command.expression,
 		"--profile=" + shared.BazelMetricsFilename(context.paths, runName),
 
-		// We don't need to set --host_platforms because it's set in bazelrc files
-		// that the bazel shell script wrapper passes
-
-		// Optimize Ninja rebuilds by ensuring Bazel write into product-agnostic
-		// output paths for the configured targets that shouldn't be affected by
-		// TARGET_PRODUCT. Otherwise product agnostic modules will be rebuilt by
-		// Ninja when the product changes, unconditionally.
-		//
-		// For example, Mainline APEXes should be identical regardless of the
-		// product (modulo arch/cpu).
-		//
-		// This flag forcibly disables the platform prefix in the intermediate
-		// outputs during a mixed build.
-		"--noexperimental_platform_in_output_dir",
+		"--host_platform=@soong_injection//product_config_platforms:mixed_builds_product-" + context.targetBuildVariant + "_" + runtime.GOOS + "_x86_64",
+		// Don't specify --platforms, because on some products/branches (like kernel-build-tools)
+		// the main platform for mixed_builds_product-variant doesn't exist because an arch isn't
+		// specified in product config. The derivative platforms that config_node transitions into
+		// will still work.
 
 		// Suppress noise
 		"--ui_event_filters=-INFO",
@@ -704,7 +689,11 @@
 		// explicitly in BUILD files.
 		"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
 	}
-	for _, envvar := range allowedBazelEnvironmentVars {
+	capturedEnvVars, err := starlark_import.GetStarlarkValue[[]string]("captured_env_vars")
+	if err != nil {
+		panic(err)
+	}
+	for _, envvar := range capturedEnvVars {
 		val := config.Getenv(envvar)
 		if val == "" {
 			continue
@@ -731,9 +720,9 @@
 #####################################################
 def _config_node_transition_impl(settings, attr):
     if attr.os == "android" and attr.arch == "target":
-        target = "current_product-{VARIANT}"
+        target = "mixed_builds_product-{VARIANT}"
     else:
-        target = "current_product-{VARIANT}_%s_%s" % (attr.os, attr.arch)
+        target = "mixed_builds_product-{VARIANT}_%s_%s" % (attr.os, attr.arch)
     apex_name = ""
     if attr.within_apex:
         # //build/bazel/rules/apex:apex_name has to be set to a non_empty value,
@@ -970,9 +959,9 @@
   platform_name = platforms[0].name
   if platform_name == "host":
     return "HOST"
-  if not platform_name.startswith("current_product-{TARGET_BUILD_VARIANT}"):
-    fail("expected platform name of the form 'current_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'current_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
-  platform_name = platform_name.removeprefix("current_product-{TARGET_BUILD_VARIANT}").removeprefix("_")
+  if not platform_name.startswith("mixed_builds_product-{TARGET_BUILD_VARIANT}"):
+    fail("expected platform name of the form 'mixed_builds_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'mixed_builds_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
+  platform_name = platform_name.removeprefix("mixed_builds_product-{TARGET_BUILD_VARIANT}").removeprefix("_")
   config_key = ""
   if not platform_name:
     config_key = "target|android"
@@ -981,7 +970,7 @@
   elif platform_name.startswith("linux_"):
     config_key = platform_name.removeprefix("linux_") + "|linux"
   else:
-    fail("expected platform name of the form 'current_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'current_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
+    fail("expected platform name of the form 'mixed_builds_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'mixed_builds_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
 
   within_apex = buildoptions.get("//build/bazel/rules/apex:within_apex")
   apex_sdk_version = buildoptions.get("//build/bazel/rules/apex:min_sdk_version")
@@ -1423,13 +1412,3 @@
 func bazelDepsetName(contentHash string) string {
 	return fmt.Sprintf("bazel_depset_%s", contentHash)
 }
-
-func EnvironmentVarsFile(config Config) string {
-	return fmt.Sprintf(bazel.GeneratedBazelFileWarning+`
-_env = %s
-
-env = _env
-`,
-		starlark_fmt.PrintStringList(allowedBazelEnvironmentVars, 0),
-	)
-}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index b17b765..a81a878 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -263,7 +263,6 @@
 	}
 
 	bazelContext := &mixedBuildBazelContext{
-		modulesDefaultToBazel:   false,
 		bazelEnabledModules:     enabledModules,
 		bazelDisabledModules:    disabledModules,
 		bazelDclaEnabledModules: dclaEnabledModules,
diff --git a/android/config.go b/android/config.go
index d4703ff..242be18 100644
--- a/android/config.go
+++ b/android/config.go
@@ -96,7 +96,6 @@
 	MultitreeBuild bool
 
 	BazelMode                bool
-	BazelModeDev             bool
 	BazelModeStaging         bool
 	BazelForceEnabledModules string
 
@@ -132,11 +131,6 @@
 	// Generate a documentation file for module type definitions and exit.
 	GenerateDocFile
 
-	// Use bazel during analysis of many allowlisted build modules. The allowlist
-	// is considered a "developer mode" allowlist, as some modules may be
-	// allowlisted on an experimental basis.
-	BazelDevMode
-
 	// Use bazel during analysis of a few allowlisted build modules. The allowlist
 	// is considered "staging, as these are modules being prepared to be released
 	// into prod mode shortly after.
@@ -291,6 +285,10 @@
 	// "--bazel-force-enabled-modules"
 	bazelForceEnabledModules map[string]struct{}
 
+	// Names of Bazel targets as defined by BUILD files in the source tree,
+	// keyed by the directory in which they are defined.
+	bazelTargetsByDir map[string][]string
+
 	// If true, for any requests to Bazel, communicate with a Bazel proxy using
 	// unix sockets, instead of spawning Bazel as a subprocess.
 	UseBazelProxy bool
@@ -618,7 +616,6 @@
 	setBuildMode(cmdArgs.BazelApiBp2buildDir, ApiBp2build)
 	setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
 	setBuildMode(cmdArgs.DocFile, GenerateDocFile)
-	setBazelMode(cmdArgs.BazelModeDev, "--bazel-mode-dev", BazelDevMode)
 	setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode)
 	setBazelMode(cmdArgs.BazelModeStaging, "--bazel-mode-staging", BazelStagingMode)
 
@@ -722,7 +719,7 @@
 		return true
 	}).(bool)
 
-	bazelModeEnabled := c.BuildMode == BazelProdMode || c.BuildMode == BazelDevMode || c.BuildMode == BazelStagingMode
+	bazelModeEnabled := c.BuildMode == BazelProdMode || c.BuildMode == BazelStagingMode
 	return globalMixedBuildsSupport && bazelModeEnabled
 }
 
@@ -1684,10 +1681,6 @@
 	return c.productVariables.InterPartitionJavaLibraryAllowList
 }
 
-func (c *config) InstallExtraFlattenedApexes() bool {
-	return Bool(c.productVariables.InstallExtraFlattenedApexes)
-}
-
 func (c *config) ProductHiddenAPIStubs() []string {
 	return c.productVariables.ProductHiddenAPIStubs
 }
@@ -2002,6 +1995,20 @@
 	}
 }
 
+func (c *config) HasBazelBuildTargetInSource(ctx BaseModuleContext) bool {
+	moduleName := ctx.Module().Name()
+	for _, buildTarget := range c.bazelTargetsByDir[ctx.ModuleDir()] {
+		if moduleName == buildTarget {
+			return true
+		}
+	}
+	return false
+}
+
+func (c *config) SetBazelBuildFileTargets(bazelTargetsByDir map[string][]string) {
+	c.bazelTargetsByDir = bazelTargetsByDir
+}
+
 // ApiSurfaces directory returns the source path inside the api_surfaces repo
 // (relative to workspace root).
 func (c *config) ApiSurfacesDir(s ApiSurface, version string) string {
diff --git a/android/defaults.go b/android/defaults.go
index 31d6014..e0e6e5c 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -17,6 +17,7 @@
 import (
 	"reflect"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -179,7 +180,10 @@
 
 // ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are
 // *NOT* converted with bp2build
-func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {}
+func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {
+	// Defaults types are never convertible.
+	ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
+}
 
 func InitDefaultsModule(module DefaultsModule) {
 	commonProperties := &commonProperties{}
diff --git a/android/filegroup.go b/android/filegroup.go
index c042ff1..3b86655 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -21,6 +21,7 @@
 
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 )
@@ -82,7 +83,6 @@
 type bazelAidlLibraryAttributes struct {
 	Srcs                bazel.LabelListAttribute
 	Strip_import_prefix *string
-	Deps                bazel.LabelListAttribute
 }
 
 // api srcs can be contained in filegroups.
@@ -112,6 +112,7 @@
 			if len(srcs.Value.Includes) > 1 {
 				ctx.ModuleErrorf("filegroup '%s' cannot contain a file with the same name", fg.Name())
 			}
+			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_SRC_NAME_COLLISION, "")
 			return
 		}
 	}
@@ -121,12 +122,9 @@
 	// and then convert
 	if fg.ShouldConvertToAidlLibrary(ctx) {
 		tags := []string{"apex_available=//apex_available:anyapex"}
-		deps := bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, fg.properties.Aidl.Deps))
-
 		attrs := &bazelAidlLibraryAttributes{
 			Srcs:                srcs,
 			Strip_import_prefix: fg.properties.Path,
-			Deps:                deps,
 		}
 
 		props := bazel.BazelTargetModuleProperties{
@@ -203,14 +201,6 @@
 	// Create a make variable with the specified name that contains the list of files in the
 	// filegroup, relative to the root of the source tree.
 	Export_to_make_var *string
-
-	// aidl is explicitly provided for implicit aidl dependencies
-	// TODO(b/278298615): aidl prop is a no-op in Soong and is an escape hatch
-	// to include implicit aidl dependencies for bazel migration compatibility
-	Aidl struct {
-		// List of aidl files or filegroup depended on by srcs
-		Deps []string `android:"path"`
-	}
 }
 
 type fileGroup struct {
diff --git a/android/module.go b/android/module.go
index ba32710..726fa85 100644
--- a/android/module.go
+++ b/android/module.go
@@ -30,6 +30,7 @@
 	"text/scanner"
 
 	"android/soong/bazel"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -483,6 +484,7 @@
 	TargetRequiredModuleNames() []string
 
 	ModuleSubDir() string
+	SoongConfigTraceHash() string
 
 	Variable(pctx PackageContext, name, value string)
 	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
@@ -565,6 +567,8 @@
 
 	// IsConvertedByBp2build returns whether this module was converted via bp2build
 	IsConvertedByBp2build() bool
+	GetUnconvertedReason() *UnconvertedReason
+
 	// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module
 	Bp2buildTargets() []bp2buildInfo
 	GetUnconvertedBp2buildDeps() []string
@@ -987,7 +991,11 @@
 	// Bazel conversion status
 	BazelConversionStatus BazelConversionStatus `blueprint:"mutated"`
 
-	// SoongConfigTrace records accesses to VendorVars (soong_config)
+	// SoongConfigTrace records accesses to VendorVars (soong_config). The trace will be hashed
+	// and used as a subdir of PathForModuleOut.  Note that we mainly focus on incremental
+	// builds among similar products (e.g. aosp_cf_x86_64_phone and aosp_cf_x86_64_foldable),
+	// and there are variables other than soong_config, which isn't captured by soong config
+	// trace, but influence modules among products.
 	SoongConfigTrace     soongConfigTrace `blueprint:"mutated"`
 	SoongConfigTraceHash string           `blueprint:"mutated"`
 }
@@ -1591,14 +1599,31 @@
 }
 
 func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
+	if m.commonProperties.BazelConversionStatus.UnconvertedReason != nil {
+		panic(fmt.Errorf("bp2build: module '%s' marked unconvertible and also is converted", m.Name()))
+	}
 	m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info)
 }
 
+func (m *ModuleBase) setBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
+	if len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0 {
+		panic(fmt.Errorf("bp2build: module '%s' marked unconvertible and also is converted", m.Name()))
+	}
+	m.commonProperties.BazelConversionStatus.UnconvertedReason = &UnconvertedReason{
+		ReasonType: int(reasonType),
+		Detail:     detail,
+	}
+}
+
 // IsConvertedByBp2build returns whether this module was converted via bp2build.
 func (m *ModuleBase) IsConvertedByBp2build() bool {
 	return len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0
 }
 
+func (m *ModuleBase) GetUnconvertedReason() *UnconvertedReason {
+	return m.commonProperties.BazelConversionStatus.UnconvertedReason
+}
+
 // Bp2buildTargets returns the Bazel targets bp2build generated for this module.
 func (m *ModuleBase) Bp2buildTargets() []bp2buildInfo {
 	return m.commonProperties.BazelConversionStatus.Bp2buildInfo
@@ -3192,7 +3217,7 @@
 	return m.bp.ModuleSubDir()
 }
 
-func (m *moduleContext) ModuleSoongConfigHash() string {
+func (m *moduleContext) SoongConfigTraceHash() string {
 	return m.module.base().commonProperties.SoongConfigTraceHash
 }
 
diff --git a/android/mutator.go b/android/mutator.go
index 4185315..2ec051e 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/bazel"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 )
@@ -271,6 +272,10 @@
 	// any platform for which this bool attribute is false.
 	CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute)
 
+	// MarkBp2buildUnconvertible registers the current module as "unconvertible to bp2build" for the
+	// given reason.
+	MarkBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string)
+
 	// CreateBazelTargetAliasInDir creates an alias definition in `dir` directory.
 	// This function can be used to create alias definitions in a directory that is different
 	// from the directory of the visited Soong module.
@@ -718,6 +723,12 @@
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
 }
 
+func (t *topDownMutatorContext) MarkBp2buildUnconvertible(
+	reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
+	mod := t.Module()
+	mod.base().setBp2buildUnconvertible(reasonType, detail)
+}
+
 var (
 	bazelAliasModuleProperties = bazel.BazelTargetModuleProperties{
 		Rule_class: "alias",
diff --git a/android/paths.go b/android/paths.go
index 0f3d972..94fa89c 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1472,14 +1472,11 @@
 	ModuleName() string
 	ModuleDir() string
 	ModuleSubDir() string
+	SoongConfigTraceHash() string
 }
 
 func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
-	soongConfigHash := ""
-	if i, ok := ctx.(interface{ ModuleSoongConfigHash() string }); ok {
-		soongConfigHash = i.ModuleSoongConfigHash()
-	}
-	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), soongConfigHash)
+	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), ctx.SoongConfigTraceHash())
 }
 
 // PathForModuleOut returns a Path representing the paths... under the module's
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 5cc7e4a..3a2cb1a 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -200,6 +200,22 @@
 	}
 }
 
+// Asserts that each of the Paths in actual end with the corresponding string
+// from expected. Useful to test that output paths contain expected items without
+// hard-coding where intermediate files might be located.
+func AssertPathsEndWith(t *testing.T, message string, expected []string, actual []Path) {
+	t.Helper()
+	if len(expected) != len(actual) {
+		t.Errorf("%s (length): expected %d, actual %d", message, len(expected), len(actual))
+		return
+	}
+	for i := range expected {
+		if !strings.HasSuffix(actual[i].String(), expected[i]) {
+			t.Errorf("%s (item %d): expected '%s', actual '%s'", message, i, expected[i], actual[i].String())
+		}
+	}
+}
+
 // AssertDeepEquals checks if the expected and actual values are equal using reflect.DeepEqual and
 // if they are not then it reports an error prefixed with the supplied message and including a
 // reason for why it failed.
diff --git a/android/variable.go b/android/variable.go
index 6362953..c5f1823 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -431,8 +431,6 @@
 	EnforceInterPartitionJavaSdkLibrary *bool    `json:",omitempty"`
 	InterPartitionJavaLibraryAllowList  []string `json:",omitempty"`
 
-	InstallExtraFlattenedApexes *bool `json:",omitempty"`
-
 	BoardUsesRecoveryAsBoot *bool `json:",omitempty"`
 
 	BoardKernelBinaries                []string `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 32d7250..51c67d0 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2151,10 +2151,6 @@
 		} else {
 			a.suffix = ""
 			a.primaryApexType = true
-
-			if ctx.Config().InstallExtraFlattenedApexes() {
-				a.makeModulesToInstall = append(a.makeModulesToInstall, a.Name()+flattenedSuffix)
-			}
 		}
 	case zipApex:
 		if proptools.String(a.properties.Payload_type) == "zip" {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c781be4..984ca41 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -786,18 +786,16 @@
 }
 
 func TestFileContexts(t *testing.T) {
-	for _, useFileContextsAsIs := range []bool{true, false} {
+	for _, vendor := range []bool{true, false} {
 		prop := ""
-		if useFileContextsAsIs {
-			prop = "use_file_contexts_as_is: true,\n"
+		if vendor {
+			prop = "vendor: true,\n"
 		}
 		ctx := testApex(t, `
 			apex {
 				name: "myapex",
 				key: "myapex.key",
-				file_contexts: "file_contexts",
 				updatable: false,
-				vendor: true,
 				`+prop+`
 			}
 
@@ -806,18 +804,17 @@
 				public_key: "testkey.avbpubkey",
 				private_key: "testkey.pem",
 			}
-		`, withFiles(map[string][]byte{
-			"file_contexts": nil,
-		}))
+		`)
 
 		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("file_contexts")
-		forceLabellingCommand := "apex_manifest\\\\.pb u:object_r:system_file:s0"
-		if useFileContextsAsIs {
-			android.AssertStringDoesNotContain(t, "should force-label",
-				rule.RuleParams.Command, forceLabellingCommand)
+		if vendor {
+			android.AssertStringDoesContain(t, "should force-label as vendor_apex_metadata_file",
+				rule.RuleParams.Command,
+				"apex_manifest\\\\.pb u:object_r:vendor_apex_metadata_file:s0")
 		} else {
-			android.AssertStringDoesContain(t, "shouldn't force-label",
-				rule.RuleParams.Command, forceLabellingCommand)
+			android.AssertStringDoesContain(t, "should force-label as system_file",
+				rule.RuleParams.Command,
+				"apex_manifest\\\\.pb u:object_r:system_file:s0")
 		}
 	}
 }
@@ -6125,32 +6122,6 @@
 	ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :testdata/baz\n")
 }
 
-func TestInstallExtraFlattenedApexes(t *testing.T) {
-	ctx := testApex(t, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			updatable: false,
-		}
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-	`,
-		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.InstallExtraFlattenedApexes = proptools.BoolPtr(true)
-		}),
-	)
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
-	ensureListContains(t, ab.makeModulesToInstall, "myapex.flattened")
-	mk := android.AndroidMkDataForTest(t, ctx, ab)
-	var builder strings.Builder
-	mk.Custom(&builder, ab.Name(), "TARGET_", "", mk)
-	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := apex_manifest.pb.myapex apex_pubkey.myapex myapex.flattened\n")
-}
-
 func TestErrorsIfDepsAreNotEnabled(t *testing.T) {
 	testApexError(t, `module "myapex" .* depends on disabled module "libfoo"`, `
 		apex {
diff --git a/apex/builder.go b/apex/builder.go
index c691a33..a2fe2a0 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -330,7 +330,7 @@
 // buildFileContexts create build rules to append an entry for apex_manifest.pb to the file_contexts
 // file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from
 // the file_contexts property of this APEX. This is to make sure that the manifest file is correctly
-// labeled as system_file.
+// labeled as system_file or vendor_apex_metadata_file.
 func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
 	var fileContexts android.Path
 	var fileContextsDir string
@@ -362,6 +362,13 @@
 	output := android.PathForModuleOut(ctx, "file_contexts")
 	rule := android.NewRuleBuilder(pctx, ctx)
 
+	forceLabel := "u:object_r:system_file:s0"
+	if a.SocSpecific() && !a.vndkApex {
+		// APEX on /vendor should label ./ and ./apex_manifest.pb as vendor_apex_metadata_file.
+		// The reason why we skip VNDK APEX is that aosp_{pixel device} targets install VNDK APEX on /vendor
+		// even though VNDK APEX is supposed to be installed on /system. (See com.android.vndk.current.on_vendor)
+		forceLabel = "u:object_r:vendor_apex_metadata_file:s0"
+	}
 	switch a.properties.ApexType {
 	case imageApex:
 		// remove old file
@@ -371,9 +378,9 @@
 		// new line
 		rule.Command().Text("echo").Text(">>").Output(output)
 		if !useFileContextsAsIs {
-			// force-label /apex_manifest.pb and / as system_file so that apexd can read them
-			rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
-			rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+			// force-label /apex_manifest.pb and /
+			rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output)
+			rule.Command().Text("echo").Text("/").Text(forceLabel).Text(">>").Output(output)
 		}
 	case flattenedApex:
 		// For flattened apexes, install path should be prepended.
@@ -388,9 +395,9 @@
 		// new line
 		rule.Command().Text("echo").Text(">>").Output(output)
 		if !useFileContextsAsIs {
-			// force-label /apex_manifest.pb and / as system_file so that apexd can read them
-			rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
-			rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
+			// force-label /apex_manifest.pb and /
+			rule.Command().Text("echo").Text(apexPath + "/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output)
+			rule.Command().Text("echo").Text(apexPath + "/").Text(forceLabel).Text(">>").Output(output)
 		}
 	default:
 		panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
diff --git a/apex/deapexer.go b/apex/deapexer.go
index fed9cd1..3b7c77d 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -140,7 +140,6 @@
 			Tool(android.PathForSource(ctx, "build/soong/scripts/unpack-prebuilt-apex.sh")).
 			BuiltTool("deapexer").
 			BuiltTool("debugfs").
-			BuiltTool("blkid").
 			BuiltTool("fsck.erofs").
 			Input(p.inputApex).
 			Text(deapexerOutput.String())
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index ca96f23..791c6bc 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -11,6 +11,7 @@
 	GetCcInfo           = &getCcInfoType{}
 	GetApexInfo         = &getApexInfoType{}
 	GetCcUnstrippedInfo = &getCcUnstrippedInfoType{}
+	GetPrebuiltFileInfo = &getPrebuiltFileInfo{}
 )
 
 type CcAndroidMkInfo struct {
@@ -375,3 +376,51 @@
 	}
 	return nil
 }
+
+type getPrebuiltFileInfo struct{}
+
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
+func (g getPrebuiltFileInfo) Name() string {
+	return "getPrebuiltFileInfo"
+}
+
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// 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:
+//   - 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 getPrebuiltFileInfo) StarlarkFunctionBody() string {
+	return `
+p = providers(target)
+prebuilt_file_info = p.get("//build/bazel/rules:prebuilt_file.bzl%PrebuiltFileInfo")
+if not prebuilt_file_info:
+  fail("%s did not provide PrebuiltFileInfo" % id_string)
+
+return json.encode({
+	"Src": prebuilt_file_info.src.path,
+	"Dir": prebuilt_file_info.dir,
+	"Filename": prebuilt_file_info.filename,
+	"Installable": prebuilt_file_info.installable,
+})`
+}
+
+type PrebuiltFileInfo struct {
+	// TODO: b/207489266 - Fully support all properties in prebuilt_file
+	Src         string
+	Dir         string
+	Filename    string
+	Installable bool
+}
+
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getPrebuiltFileInfo) ParseResult(rawString string) (PrebuiltFileInfo, error) {
+	var info PrebuiltFileInfo
+	err := parseJson(rawString, &info)
+	return info, err
+}
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index 66d0cc5..7224496 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -72,8 +72,13 @@
 load("//{PRODUCT_FOLDER}:soong.variables.bzl", _soong_variables = "variables")
 load("@//build/bazel/product_config:android_product.bzl", "android_product")
 
+# Bazel will qualify its outputs by the platform name. When switching between products, this
+# means that soong-built files that depend on bazel-built files will suddenly get different
+# dependency files, because the path changes, and they will be rebuilt. In order to avoid this
+# extra rebuilding, make mixed builds always use a single platform so that the bazel artifacts
+# are always under the same path.
 android_product(
-    name = "current_product-{VARIANT}",
+    name = "mixed_builds_product-{VARIANT}",
     soong_variables = _soong_variables,
 )
 `)),
@@ -86,7 +91,7 @@
 # TODO: When we start generating the platforms for more than just the
 # currently lunched product, they should all be listed here
 product_labels = [
-  "@soong_injection//product_config_platforms:current_product-{VARIANT}",
+  "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}",
   "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"
 ]
 `)),
@@ -94,38 +99,25 @@
 			"product_config_platforms",
 			"common.bazelrc",
 			productReplacer.Replace(`
-# current_product refers to the current TARGET_PRODUCT set, usually through
-# 'lunch' or 'banchan'.  Every build will have a primary TARGET_PRODUCT, but
-# bazel supports using other products in tests or configuration transitions. The
-# other products can be found in
-# @soong_injection//product_config_platforms/products/...
-build --platforms @soong_injection//product_config_platforms:current_product-{VARIANT}_linux_x86_64
+build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
 
-build:android --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}
-build:linux_x86_64 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_x86_64
-build:linux_bionic_x86_64 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_bionic_x86_64
-build:linux_musl_x86 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_musl_x86
-build:linux_musl_x86_64 --platforms=@soong_injection//product_config_platforms:current_product-{VARIANT}_linux_musl_x86_64
+build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
+build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
+build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
+build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
+build:linux_musl_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64
 `)),
 		newFile(
 			"product_config_platforms",
 			"linux.bazelrc",
 			productReplacer.Replace(`
-build --host_platform @soong_injection//product_config_platforms:current_product-{VARIANT}_linux_x86_64
+build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
 `)),
 		newFile(
 			"product_config_platforms",
 			"darwin.bazelrc",
 			productReplacer.Replace(`
-build --host_platform product_config_platforms:current_product-{VARIANT}_darwin_x86_64
-`)),
-		newFile(
-			"product_config_platforms",
-			"platform_mappings",
-			productReplacer.Replace(`
-flags:
-  --cpu=k8
-	@soong_injection//product_config_platforms:current_product-{VARIANT}
+build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
 `)),
 	}
 
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index a860484..46a5bd8 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -28,6 +28,7 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/starlark_fmt"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -283,12 +284,15 @@
 				// target in a BUILD file, we don't autoconvert them.
 
 				// Log the module.
-				metrics.AddConvertedModule(m, moduleType, dir, Handcrafted)
+				metrics.AddUnconvertedModule(m, moduleType, dir,
+					android.UnconvertedReason{
+						ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE),
+					})
 			} else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
 				// Handle modules converted to generated targets.
 
 				// Log the module.
-				metrics.AddConvertedModule(aModule, moduleType, dir, Generated)
+				metrics.AddConvertedModule(aModule, moduleType, dir)
 
 				// Handle modules with unconverted deps. By default, emit a warning.
 				if unconvertedDeps := aModule.GetUnconvertedBp2buildDeps(); len(unconvertedDeps) > 0 {
@@ -324,8 +328,18 @@
 			} else if _, ok := ctx.Config().BazelModulesForceEnabledByFlag()[m.Name()]; ok && m.Name() != "" {
 				err := fmt.Errorf("Force Enabled Module %s not converted", m.Name())
 				errs = append(errs, err)
+			} else if aModule, ok := m.(android.Module); ok {
+				reason := aModule.GetUnconvertedReason()
+				if reason == nil {
+					panic(fmt.Errorf("module '%s' was neither converted nor marked unconvertible with bp2build", aModule.Name()))
+				} else {
+					metrics.AddUnconvertedModule(m, moduleType, dir, *reason)
+				}
+				return
 			} else {
-				metrics.AddUnconvertedModule(moduleType)
+				metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
+					ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
+				})
 				return
 			}
 		case QueryView:
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 610a9ca..ab6e4a5 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -868,6 +868,25 @@
 	})
 }
 
+func TestCcBinaryWithSanitizerBlocklist(t *testing.T) {
+	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary has the correct feature when sanitize.blocklist is provided",
+		blueprint: `
+{rule_name} {
+	name: "foo",
+	sanitize: {
+		blocklist: "foo_blocklist.txt",
+	},
+}`,
+		targets: []testBazelTarget{
+			{"cc_binary", "foo", AttrNameToString{
+				"local_includes": `["."]`,
+				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+			}},
+		},
+	})
+}
+
 func TestCcBinaryWithThinLto(t *testing.T) {
 	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
 		description: "cc_binary has correct features when thin LTO is enabled",
@@ -1106,3 +1125,60 @@
 		},
 	})
 }
+
+func TestCcBinaryExplicitlyDisablesCfiWhenFalse(t *testing.T) {
+	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary disables cfi when explciitly set to false in the bp",
+		blueprint: `
+{rule_name} {
+	name: "foo",
+	sanitize: {
+		cfi: false,
+	},
+}
+`,
+		targets: []testBazelTarget{
+			{"cc_binary", "foo", AttrNameToString{
+				"features":       `["-android_cfi"]`,
+				"local_includes": `["."]`,
+			}},
+		},
+	})
+}
+
+func TestCcBinaryStem(t *testing.T) {
+	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary with stem property",
+		blueprint: `
+cc_binary {
+	name: "foo_with_stem_simple",
+	stem: "foo",
+}
+cc_binary {
+	name: "foo_with_arch_variant_stem",
+	arch: {
+		arm: {
+			stem: "foo-arm",
+		},
+		arm64: {
+			stem: "foo-arm64",
+		},
+	},
+}
+`,
+		targets: []testBazelTarget{
+			{"cc_binary", "foo_with_stem_simple", AttrNameToString{
+				"stem":           `"foo"`,
+				"local_includes": `["."]`,
+			}},
+			{"cc_binary", "foo_with_arch_variant_stem", AttrNameToString{
+				"stem": `select({
+        "//build/bazel/platforms/arch:arm": "foo-arm",
+        "//build/bazel/platforms/arch:arm64": "foo-arm64",
+        "//conditions:default": None,
+    })`,
+				"local_includes": `["."]`,
+			}},
+		},
+	})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index c2dba67..1e3d72e 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -4179,6 +4179,32 @@
 	})
 }
 
+func TestCcLibraryWithSanitizerBlocklist(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library has correct feature when sanitize.blocklist is provided",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+		name: "foo",
+		sanitize: {
+			blocklist: "foo_blocklist.txt",
+		},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
 func TestCcLibraryWithUBSanPropertiesArchSpecific(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
 		Description:                "cc_library has correct feature select when UBSan props are specified in arch specific blocks",
@@ -4812,3 +4838,68 @@
 		},
 	})
 }
+
+func TestCcLibraryExplicitlyDisablesCfiWhenFalse(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library disables cfi when explciitly set to false in the bp",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "foo",
+	sanitize: {
+		cfi: false,
+	},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"features":       `["-android_cfi"]`,
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features":       `["-android_cfi"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryWithStem(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with stem property",
+		ModuleTypeUnderTest:        "cc_library_shared",
+		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+		Blueprint: soongCcLibraryPreamble + `
+cc_library_shared {
+	name: "foo_with_stem_simple",
+	stem: "foo",
+}
+cc_library_shared {
+	name: "foo_with_arch_variant_stem",
+	arch: {
+		arm: {
+			stem: "foo-arm",
+		},
+		arm64: {
+			stem: "foo-arm64",
+		},
+	},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_shared", "foo_with_stem_simple", AttrNameToString{
+				"stem":           `"foo"`,
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo_with_arch_variant_stem", AttrNameToString{
+				"stem": `select({
+        "//build/bazel/platforms/arch:arm": "foo-arm",
+        "//build/bazel/platforms/arch:arm64": "foo-arm64",
+        "//conditions:default": None,
+    })`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 7f0ba44..a16cfb3 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -1212,6 +1212,26 @@
 	})
 }
 
+func TestCcLibrarySharedWithSanitizerBlocklist(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared has correct features when sanitize.blocklist is provided",
+		Blueprint: `
+cc_library_shared {
+	name: "foo",
+	sanitize: {
+		blocklist: "foo_blocklist.txt",
+	},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
 func TestCcLibrarySharedWithThinLto(t *testing.T) {
 	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
 		Description: "cc_library_shared has correct features when thin lto is enabled",
@@ -1515,3 +1535,23 @@
 		},
 	})
 }
+
+func TestCcLibrarySharedExplicitlyDisablesCfiWhenFalse(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared disables cfi when explciitly set to false in the bp",
+		Blueprint: `
+cc_library_shared {
+	name: "foo",
+	sanitize: {
+		cfi: false,
+	},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features":       `["-android_cfi"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index f537871..b473f27 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1905,6 +1905,26 @@
 	})
 }
 
+func TestCcLibraryStaticWithSanitizerBlocklist(t *testing.T) {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static has correct features when sanitize.blocklist is provided",
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	sanitize: {
+		blocklist: "foo_blocklist.txt",
+	},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"features":       `["ubsan_blocklist_foo_blocklist_txt"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
 func TestCcLibraryStaticWithThinLto(t *testing.T) {
 	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
 		Description: "cc_library_static has correct features when thin lto is enabled",
@@ -2145,3 +2165,23 @@
 		},
 	})
 }
+
+func TestCcLibraryStaticExplicitlyDisablesCfiWhenFalse(t *testing.T) {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static disables cfi when explciitly set to false in the bp",
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	sanitize: {
+		cfi: false,
+	},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"features":       `["-android_cfi"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index f598332..d5f2386 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -73,7 +73,6 @@
 	files = append(files, newFile("api_levels", "platform_versions.bzl", platformVersionContents(cfg)))
 
 	files = append(files, newFile("allowlists", GeneratedBuildFileName, ""))
-	files = append(files, newFile("allowlists", "env.bzl", android.EnvironmentVarsFile(cfg)))
 	// TODO(b/262781701): Create an alternate soong_build entrypoint for writing out these files only when requested
 	files = append(files, newFile("allowlists", "mixed_build_prod_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelProdMode), "\n")+"\n"))
 	files = append(files, newFile("allowlists", "mixed_build_staging_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelStagingMode), "\n")+"\n"))
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 379f83b..00ffd79 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -167,10 +167,6 @@
 		},
 		{
 			dir:      "allowlists",
-			basename: "env.bzl",
-		},
-		{
-			dir:      "allowlists",
 			basename: "mixed_build_prod_allowlist.txt",
 		},
 		{
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index 273d556..7ce559d 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -105,42 +105,6 @@
 	}
 }
 
-func TestFilegroupWithAidlDeps(t *testing.T) {
-	bp := `
-	filegroup {
-		name: "bar",
-		srcs: ["bar.aidl"],
-	}
-	filegroup {
-		name: "foo",
-		srcs: ["aidl/foo.aidl"],
-		path: "aidl",
-		aidl: {
-			deps: [":bar"],
-		}
-	}`
-
-	t.Run("filegroup with aidl deps", func(t *testing.T) {
-		expectedBazelTargets := []string{
-			MakeBazelTargetNoRestrictions("aidl_library", "bar", AttrNameToString{
-				"srcs": `["bar.aidl"]`,
-				"tags": `["apex_available=//apex_available:anyapex"]`,
-			}),
-			MakeBazelTargetNoRestrictions("aidl_library", "foo", AttrNameToString{
-				"srcs":                `["aidl/foo.aidl"]`,
-				"strip_import_prefix": `"aidl"`,
-				"deps":                `[":bar"]`,
-				"tags":                `["apex_available=//apex_available:anyapex"]`,
-			}),
-		}
-		runFilegroupTestCase(t, Bp2buildTestCase{
-			Description:          "filegroup with aidl deps",
-			Blueprint:            bp,
-			ExpectedBazelTargets: expectedBazelTargets,
-		})
-	})
-}
-
 func TestFilegroupWithAidlAndNonAidlSrcs(t *testing.T) {
 	runFilegroupTestCase(t, Bp2buildTestCase{
 		Description: "filegroup with aidl and non-aidl srcs",
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
index 4845973..e808340 100644
--- a/bp2build/gensrcs_conversion_test.go
+++ b/bp2build/gensrcs_conversion_test.go
@@ -33,7 +33,8 @@
                 name: "foo",
                 srcs: ["test/input.txt", ":external_files"],
                 tool_files: ["program.py"],
-                cmd: "$(location program.py) $(in) $(out)",
+                cmd: "$(location program.py) $(in) $(out) $(location foo/file.txt) $(location :external_files)",
+                data: ["foo/file.txt", ":external_files"],
                 output_extension: "out",
                 bazel_module: { bp2build_available: true },
 			}`,
@@ -44,7 +45,11 @@
     ]`,
 				"tools":            `["program.py"]`,
 				"output_extension": `"out"`,
-				"cmd":              `"$(location program.py) $(SRC) $(OUT)"`,
+				"cmd":              `"$(location program.py) $(SRC) $(OUT) $(location foo/file.txt) $(location :external_files__BP2BUILD__MISSING__DEP)"`,
+				"data": `[
+        "foo/file.txt",
+        ":external_files__BP2BUILD__MISSING__DEP",
+    ]`,
 			},
 		},
 		{
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index e51f608..39e55c4 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -68,7 +68,7 @@
 			}),
 			MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
 				"main_class": `"com.android.test.MainClass"`,
-				"jvm_flags":  `["-Djava.library.path=$${RUNPATH}other"]`,
+				"jvm_flags":  `["-Djava.library.path=$${RUNPATH}other/jni-lib-1"]`,
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index a020650..00f21c8 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -38,6 +38,7 @@
 			RuleClassCount:           make(map[string]uint64),
 			ConvertedModuleTypeCount: make(map[string]uint64),
 			TotalModuleTypeCount:     make(map[string]uint64),
+			UnconvertedModules:       make(map[string]*bp2build_metrics_proto.UnconvertedReason),
 		},
 		convertedModulePathMap: make(map[string]string),
 	}
@@ -149,11 +150,6 @@
 	metrics.serialized.Events = append(metrics.serialized.Events, event)
 }
 
-func (metrics *CodegenMetrics) AddUnconvertedModule(moduleType string) {
-	metrics.serialized.UnconvertedModuleCount += 1
-	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
-}
-
 func (metrics *CodegenMetrics) SetSymlinkCount(n uint64) {
 	if m := metrics.serialized.WorkspaceSymlinkCount; m != 0 {
 		fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceSymlinkCount of %d", m)
@@ -187,7 +183,7 @@
 	Handcrafted
 )
 
-func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string, conversionType ConversionType) {
+func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string) {
 	//a package module has empty name
 	if moduleType == "package" {
 		return
@@ -198,10 +194,25 @@
 	metrics.convertedModulePathMap[moduleName] = "//" + dir
 	metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
 	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
+	metrics.serialized.GeneratedModuleCount += 1
+}
 
-	if conversionType == Handcrafted {
+func (metrics *CodegenMetrics) AddUnconvertedModule(m blueprint.Module, moduleType string, dir string,
+	reason android.UnconvertedReason) {
+	//a package module has empty name
+	if moduleType == "package" {
+		return
+	}
+	// Undo prebuilt_ module name prefix modifications
+	moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
+	metrics.serialized.UnconvertedModules[moduleName] = &bp2build_metrics_proto.UnconvertedReason{
+		Type:   bp2build_metrics_proto.UnconvertedReasonType(reason.ReasonType),
+		Detail: reason.Detail,
+	}
+	metrics.serialized.UnconvertedModuleCount += 1
+	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
+
+	if reason.ReasonType == int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) {
 		metrics.serialized.HandCraftedModuleCount += 1
-	} else if conversionType == Generated {
-		metrics.serialized.GeneratedModuleCount += 1
 	}
 }
diff --git a/bp2build/testing.go b/bp2build/testing.go
index fd99ff0..140b214 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -76,10 +76,19 @@
 	Description                string
 	ModuleTypeUnderTest        string
 	ModuleTypeUnderTestFactory android.ModuleFactory
-	Blueprint                  string
-	ExpectedBazelTargets       []string
-	Filesystem                 map[string]string
-	Dir                        string
+	// Text to add to the toplevel, root Android.bp file. If Dir is not set, all
+	// ExpectedBazelTargets are assumed to be generated by this file.
+	Blueprint string
+	// ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
+	// Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
+	ExpectedBazelTargets []string
+	Filesystem           map[string]string
+	// Dir sets the directory which will be compared against the targets in ExpectedBazelTargets.
+	// This should used in conjunction with the Filesystem property to check for targets
+	// generated from a directory that is not the root.
+	// If not set, all ExpectedBazelTargets are assumed to be generated by the text in the
+	// Blueprint property.
+	Dir string
 	// An error with a string contained within the string of the expected error
 	ExpectedErr         error
 	UnconvertedDepsMode unconvertedDepsMode
@@ -137,6 +146,10 @@
 				})
 			}
 			ctx.RegisterBp2BuildConfig(bp2buildConfig)
+			// This setting is added to bp2build invocations. It prevents bp2build
+			// from cloning modules to their original state after mutators run. This
+			// would lose some data intentionally set by these mutators.
+			ctx.SkipCloneModulesAfterMutators = true
 		}),
 		android.FixtureModifyEnv(func(env map[string]string) {
 			if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
@@ -201,7 +214,11 @@
 		return
 	}
 
-	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
+	codegenMode := Bp2Build
+	if ctx.Config().BuildMode == android.ApiBp2build {
+		codegenMode = ApiBp2build
+	}
+	codegenCtx := NewCodegenContext(config, ctx.Context, codegenMode, "")
 	res, errs := GenerateBazelTargets(codegenCtx, false)
 	if bazelResult.CollateErrs(errs) {
 		return
diff --git a/cc/binary.go b/cc/binary.go
index 98b9923..5ba33a2 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -512,7 +512,7 @@
 		}
 		binary.baseInstaller.subDir = "bootstrap"
 	}
-	binary.baseInstaller.installExecutable(ctx, file)
+	binary.baseInstaller.install(ctx, file)
 
 	var preferredArchSymlinkPath android.OptionalPath
 	for _, symlink := range binary.symlinks {
@@ -609,6 +609,9 @@
 		baseAttrs.implementationDeps.Add(baseAttrs.protoDependency)
 	}
 
+	// binaries don't have implementation_whole_archive_deps
+	baseAttrs.wholeArchiveDeps.Append(baseAttrs.implementationWholeArchiveDeps)
+
 	attrs := binaryAttributes{
 		binaryLinkerAttrs: binaryLinkerAttrs,
 
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 34cc574..d09cdcd 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -434,6 +434,7 @@
 
 	features bazel.StringListAttribute
 
+	stem   bazel.StringAttribute
 	suffix bazel.StringAttribute
 
 	fdoProfile bazel.LabelAttribute
@@ -819,6 +820,9 @@
 						compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, versions)
 					}
 				}
+				if stem := libraryProps.Stem; stem != nil {
+					compilerAttrs.stem.SetSelectValue(axis, cfg, stem)
+				}
 				if suffix := libraryProps.Suffix; suffix != nil {
 					compilerAttrs.suffix.SetSelectValue(axis, cfg, suffix)
 				}
@@ -1737,6 +1741,7 @@
 
 type binaryLinkerAttrs struct {
 	Linkshared *bool
+	Stem       bazel.StringAttribute
 	Suffix     bazel.StringAttribute
 }
 
@@ -1754,6 +1759,9 @@
 			// nonconfigurable attribute. Only 4 AOSP modules use this feature, defer handling
 			ctx.ModuleErrorf("bp2build cannot migrate a module with arch/target-specific static_executable values")
 		}
+		if stem := linkerProps.Stem; stem != nil {
+			attrs.Stem.SetSelectValue(axis, config, stem)
+		}
 		if suffix := linkerProps.Suffix; suffix != nil {
 			attrs.Suffix.SetSelectValue(axis, config, suffix)
 		}
@@ -1773,7 +1781,15 @@
 			for _, sanitizer := range sanitizerProps.Sanitize.Misc_undefined {
 				features = append(features, "ubsan_"+sanitizer)
 			}
-			if proptools.Bool(sanitizerProps.Sanitize.Cfi) {
+			blocklist := sanitizerProps.Sanitize.Blocklist
+			if blocklist != nil {
+				// Format the blocklist name to be used in a feature name
+				blocklistFeatureSuffix := strings.Replace(strings.ToLower(*blocklist), ".", "_", -1)
+				features = append(features, "ubsan_blocklist_"+blocklistFeatureSuffix)
+			}
+			if sanitizerProps.Sanitize.Cfi != nil && !proptools.Bool(sanitizerProps.Sanitize.Cfi) {
+				features = append(features, "-android_cfi")
+			} else if proptools.Bool(sanitizerProps.Sanitize.Cfi) {
 				features = append(features, "android_cfi")
 				if proptools.Bool(sanitizerProps.Sanitize.Config.Cfi_assembly_support) {
 					features = append(features, "android_cfi_assembly_support")
diff --git a/cc/cc.go b/cc/cc.go
index 426bac8..d67f3ad 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -24,6 +24,7 @@
 	"strconv"
 	"strings"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -1077,6 +1078,10 @@
 	return false
 }
 
+func (c *Module) RustLibraryInterface() bool {
+	return false
+}
+
 func (c *Module) IsFuzzModule() bool {
 	if _, ok := c.compiler.(*fuzzBinary); ok {
 		return true
@@ -1913,14 +1918,14 @@
 // IsMixedBuildSupported returns true if the module should be analyzed by Bazel
 // in any of the --bazel-mode(s).
 func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	if !allEnabledSanitizersSupportedByBazel(c) {
+	if !allEnabledSanitizersSupportedByBazel(ctx, c) {
 		//TODO(b/278772861) support sanitizers in Bazel rules
 		return false
 	}
 	return c.bazelHandler != nil
 }
 
-func allEnabledSanitizersSupportedByBazel(c *Module) bool {
+func allEnabledSanitizersSupportedByBazel(ctx android.BaseModuleContext, c *Module) bool {
 	if c.sanitize == nil {
 		return true
 	}
@@ -1930,7 +1935,6 @@
 		sanitizeProps.Safestack,
 		sanitizeProps.Scudo,
 		BoolPtr(len(c.sanitize.Properties.Sanitize.Recover) > 0),
-		BoolPtr(c.sanitize.Properties.Sanitize.Blocklist != nil),
 	}
 	for _, san := range unsupportedSanitizers {
 		if Bool(san) {
@@ -1943,12 +1947,17 @@
 			// TODO(b/261058727): enable mixed builds for all modules with UBSan
 			// Currently we can only support ubsan when minimum runtime is used.
 			ubsanEnabled := Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
-			if ubsanEnabled && !c.MinimalRuntimeNeeded() {
-				return false
+			if !ubsanEnabled || c.MinimalRuntimeNeeded() {
+				continue
 			}
 		} else if san == cfi {
-			continue
-		} else if c.sanitize.isSanitizerEnabled(san) {
+			apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+			// Only allow cfi if this is an apex variant
+			if !apexInfo.IsForPlatform() {
+				continue
+			}
+		}
+		if c.sanitize.isSanitizerEnabled(san) {
 			return false
 		}
 	}
@@ -4095,6 +4104,8 @@
 		} else {
 			sharedOrStaticLibraryBp2Build(ctx, c, false)
 		}
+	default:
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
 	}
 }
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 701c3bb..859059e 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4981,7 +4981,7 @@
 	cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
 
 	cflags := []string{"-Werror", "-std=candcpp"}
-	cstd := []string{"-std=gnu11", "-std=conly"}
+	cstd := []string{"-std=gnu17", "-std=conly"}
 	cppstd := []string{"-std=gnu++17", "-std=cpp", "-fno-rtti"}
 
 	lastIncludes := []string{
diff --git a/cc/config/global.go b/cc/config/global.go
index d63e324..8ff5f55 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -298,9 +298,9 @@
 		"-w",
 	}
 
-	CStdVersion               = "gnu11"
+	CStdVersion               = "gnu17"
 	CppStdVersion             = "gnu++17"
-	ExperimentalCStdVersion   = "gnu17"
+	ExperimentalCStdVersion   = "gnu2x"
 	ExperimentalCppStdVersion = "gnu++2a"
 
 	// prebuilts/clang default settings.
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index a63d5c2..3bc1e69 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -29,12 +29,14 @@
 		// A temporary fix for SExtWRemoval miscompilation bug.
 		"-mllvm",
 		"-riscv-disable-sextw-removal=true",
+		"-march=rv64gc_zba_zbb_zbs",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
 
 	riscv64Ldflags = []string{
 		"-Wl,--hash-style=gnu",
+		"-march=rv64gc_zba_zbb_zbs",
 	}
 
 	riscv64Lldflags = append(riscv64Ldflags,
diff --git a/cc/fuzz.go b/cc/fuzz.go
index c897501..636ad85 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -535,6 +535,17 @@
 	})
 
 	ctx.WalkDeps(func(child, parent android.Module) bool {
+
+		// If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive
+		// shared dependencies (even for rust_ffi_static)
+		if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() {
+			if recursed[ctx.OtherModuleName(child)] {
+				return false
+			}
+			recursed[ctx.OtherModuleName(child)] = true
+			return true
+		}
+
 		if !IsValidSharedDependency(child) {
 			return false
 		}
diff --git a/cc/installer.go b/cc/installer.go
index 716a0df..e2c0e7b 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -100,10 +100,6 @@
 	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
 }
 
-func (installer *baseInstaller) installExecutable(ctx ModuleContext, file android.Path) {
-	installer.path = ctx.InstallExecutable(installer.installDir(ctx), file.Base(), file)
-}
-
 func (installer *baseInstaller) everInstallable() bool {
 	// Most cc modules are installable.
 	return true
diff --git a/cc/library.go b/cc/library.go
index 98096a8..47df53e 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -408,6 +408,7 @@
 		sharedTargetAttrs.Stubs_symbol_file = compilerAttrs.stubsSymbolFile
 	}
 
+	sharedTargetAttrs.Stem = compilerAttrs.stem
 	sharedTargetAttrs.Suffix = compilerAttrs.suffix
 
 	for axis, configToProps := range m.GetArchVariantProperties(ctx, &LibraryProperties{}) {
@@ -2987,6 +2988,7 @@
 
 			Features: *features,
 
+			Stem:   compilerAttrs.stem,
 			Suffix: compilerAttrs.suffix,
 
 			bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, module),
@@ -3072,6 +3074,7 @@
 
 	Inject_bssl_hash bazel.BoolAttribute
 
+	Stem   bazel.StringAttribute
 	Suffix bazel.StringAttribute
 
 	bazelCcHeaderAbiCheckerAttributes
diff --git a/cc/linkable.go b/cc/linkable.go
index 557f5d2..976a382 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -100,6 +100,9 @@
 	CcLibrary() bool
 	CcLibraryInterface() bool
 
+	// RustLibraryInterface returns true if this is a Rust library module
+	RustLibraryInterface() bool
+
 	// BaseModuleName returns the android.ModuleBase.BaseModuleName() value for this module.
 	BaseModuleName() string
 
diff --git a/cc/lto.go b/cc/lto.go
index 8d6e3e7..878c21f 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -46,12 +46,12 @@
 		Thin  *bool `android:"arch_variant"`
 	} `android:"arch_variant"`
 
+	LtoEnabled bool `blueprint:"mutated"`
+
 	// Dep properties indicate that this module needs to be built with LTO
 	// since it is an object dependency of an LTO module.
-	ThinEnabled  bool `blueprint:"mutated"`
-	NoLtoEnabled bool `blueprint:"mutated"`
-	ThinDep      bool `blueprint:"mutated"`
-	NoLtoDep     bool `blueprint:"mutated"`
+	LtoDep   bool `blueprint:"mutated"`
+	NoLtoDep bool `blueprint:"mutated"`
 
 	// Use -fwhole-program-vtables cflag.
 	Whole_program_vtables *bool
@@ -66,19 +66,16 @@
 }
 
 func (lto *lto) begin(ctx BaseModuleContext) {
-	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
-		lto.Properties.NoLtoEnabled = true
-	}
+	lto.Properties.LtoEnabled = lto.LTO(ctx)
 }
 
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
-	// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
-	// LTO breaks fuzzer builds.
-	if ctx.isFuzzer() {
+	// TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
+	// This has be checked late because these properties can be mutated.
+	if ctx.isCfi() || ctx.isFuzzer() {
 		return flags
 	}
-
-	if lto.LTO(ctx) {
+	if lto.Properties.LtoEnabled {
 		var ltoCFlag string
 		var ltoLdFlag string
 		if lto.ThinLTO() {
@@ -97,7 +94,7 @@
 			flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
 		}
 
-		if (lto.DefaultThinLTO(ctx) || lto.ThinLTO()) && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
+		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
 			// Set appropriate ThinLTO cache policy
 			cacheDirFormat := "-Wl,--thinlto-cache-dir="
 			cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
@@ -120,30 +117,40 @@
 	return flags
 }
 
+// Determine which LTO mode to use for the given module.
 func (lto *lto) LTO(ctx BaseModuleContext) bool {
-	return lto.ThinLTO() || lto.DefaultThinLTO(ctx)
-}
-
-func (lto *lto) DefaultThinLTO(ctx BaseModuleContext) bool {
+	if lto.Never() {
+		return false
+	}
+	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
+		return false
+	}
+	// Module explicitly requests for LTO.
+	if lto.ThinLTO() {
+		return true
+	}
 	// LP32 has many subtle issues and less test coverage.
-	lib32 := ctx.Arch().ArchType.Multilib == "lib32"
-	// CFI adds LTO flags by itself.
-	cfi := ctx.isCfi()
+	if ctx.Arch().ArchType.Multilib == "lib32" {
+		return false
+	}
 	// Performance and binary size are less important for host binaries and tests.
-	host := ctx.Host()
-	test := ctx.testBinary() || ctx.testLibrary()
+	if ctx.Host() || ctx.testBinary() || ctx.testLibrary() {
+		return false
+	}
 	// FIXME: ThinLTO for VNDK produces different output.
 	// b/169217596
-	vndk := ctx.isVndk()
-	return GlobalThinLTO(ctx) && !lto.Never() && !lib32 && !cfi && !host && !test && !vndk
+	if ctx.isVndk() {
+		return false
+	}
+	return GlobalThinLTO(ctx)
 }
 
 func (lto *lto) ThinLTO() bool {
-	return lto != nil && (proptools.Bool(lto.Properties.Lto.Thin) || lto.Properties.ThinEnabled)
+	return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
 }
 
 func (lto *lto) Never() bool {
-	return lto != nil && (proptools.Bool(lto.Properties.Lto.Never) || lto.Properties.NoLtoEnabled)
+	return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
 }
 
 func GlobalThinLTO(ctx android.BaseModuleContext) bool {
@@ -152,11 +159,12 @@
 
 // Propagate lto requirements down from binaries
 func ltoDepsMutator(mctx android.TopDownMutatorContext) {
-	globalThinLTO := GlobalThinLTO(mctx)
+	defaultLTOMode := GlobalThinLTO(mctx)
 
 	if m, ok := mctx.Module().(*Module); ok {
-		thin := m.lto.ThinLTO()
-		never := m.lto.Never()
+		if m.lto == nil || m.lto.Properties.LtoEnabled == defaultLTOMode {
+			return
+		}
 
 		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
 			tag := mctx.OtherModuleDependencyTag(dep)
@@ -174,10 +182,9 @@
 			}
 
 			if dep, ok := dep.(*Module); ok {
-				if !globalThinLTO && thin && !dep.lto.ThinLTO() {
-					dep.lto.Properties.ThinDep = true
-				}
-				if globalThinLTO && never && !dep.lto.Never() {
+				if m.lto.Properties.LtoEnabled {
+					dep.lto.Properties.LtoDep = true
+				} else {
 					dep.lto.Properties.NoLtoDep = true
 				}
 			}
@@ -196,22 +203,19 @@
 		// Create variations for LTO types required as static
 		// dependencies
 		variationNames := []string{""}
-		if !globalThinLTO && m.lto.Properties.ThinDep && !m.lto.ThinLTO() {
+		if m.lto.Properties.LtoDep {
 			variationNames = append(variationNames, "lto-thin")
 		}
-		if globalThinLTO && m.lto.Properties.NoLtoDep && !m.lto.Never() {
+		if m.lto.Properties.NoLtoDep {
 			variationNames = append(variationNames, "lto-none")
 		}
 
-		// Use correct dependencies if LTO property is explicitly set
-		// (mutually exclusive)
-		if !globalThinLTO && m.lto.ThinLTO() {
-			mctx.SetDependencyVariation("lto-thin")
-		}
-		// Never must be the last, it overrides Thin.
-		if globalThinLTO && m.lto.Never() {
+		if globalThinLTO && !m.lto.Properties.LtoEnabled {
 			mctx.SetDependencyVariation("lto-none")
 		}
+		if !globalThinLTO && m.lto.Properties.LtoEnabled {
+			mctx.SetDependencyVariation("lto-thin")
+		}
 
 		if len(variationNames) > 1 {
 			modules := mctx.CreateVariations(variationNames...)
@@ -226,14 +230,14 @@
 
 				// LTO properties for dependencies
 				if name == "lto-thin" {
-					variation.lto.Properties.ThinEnabled = true
+					variation.lto.Properties.LtoEnabled = true
 				}
 				if name == "lto-none" {
-					variation.lto.Properties.NoLtoEnabled = true
+					variation.lto.Properties.LtoEnabled = false
 				}
 				variation.Properties.PreventInstall = true
 				variation.Properties.HideFromMake = true
-				variation.lto.Properties.ThinDep = false
+				variation.lto.Properties.LtoDep = false
 				variation.lto.Properties.NoLtoDep = false
 			}
 		}
diff --git a/cc/lto_test.go b/cc/lto_test.go
index 4220f32..e0afd4a 100644
--- a/cc/lto_test.go
+++ b/cc/lto_test.go
@@ -23,6 +23,12 @@
 	"github.com/google/blueprint"
 )
 
+var NoGlobalThinLTOPreparer = android.GroupFixturePreparers(
+	prepareForCcTest,
+	android.FixtureModifyEnv(func(env map[string]string) {
+		env["GLOBAL_THINLTO"] = "false"
+	}))
+
 func TestThinLtoDeps(t *testing.T) {
 	t.Parallel()
 	bp := `
@@ -57,9 +63,7 @@
 	}
 `
 
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).RunTestWithBp(t, bp)
+	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
 
 	libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module()
 
@@ -137,9 +141,7 @@
 	}
 `
 
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).RunTestWithBp(t, bp)
+	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
 
 	libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module()
 	libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module()
@@ -197,9 +199,7 @@
 			},
 		},
 	}`
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).RunTestWithBp(t, bp)
+	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
 
 	libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
 	libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
@@ -227,9 +227,7 @@
 		},
 	}`
 
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).RunTestWithBp(t, bp)
+	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
 
 	libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
 	libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld")
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 1cc58a2..eab6d25 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -64,12 +64,14 @@
 		"-dom-tree-reachability-max-bbs-to-explore=128",
 	}
 
+	sanitizeIgnorelistPrefix = "-fsanitize-ignorelist="
+
 	cfiBlocklistPath     = "external/compiler-rt/lib/cfi"
 	cfiBlocklistFilename = "cfi_blocklist.txt"
 	cfiEnableFlag        = "-fsanitize=cfi"
 	cfiCrossDsoFlag      = "-fsanitize-cfi-cross-dso"
 	cfiCflags            = []string{"-flto", cfiCrossDsoFlag,
-		"-fsanitize-ignorelist=" + cfiBlocklistPath + "/" + cfiBlocklistFilename}
+		sanitizeIgnorelistPrefix + cfiBlocklistPath + "/" + cfiBlocklistFilename}
 	// -flto and -fvisibility are required by clang when -fsanitize=cfi is
 	// used, but have no effect on assembly files
 	cfiAsflags = []string{"-flto", "-fvisibility=default"}
@@ -403,6 +405,7 @@
 	exportedVars.ExportStringList("CfiLdFlags", cfiLdflags[2:])
 	exportedVars.ExportStringList("CfiAsFlags", cfiAsflags[1:])
 
+	exportedVars.ExportString("SanitizeIgnorelistPrefix", sanitizeIgnorelistPrefix)
 	exportedVars.ExportString("CfiCrossDsoFlag", cfiCrossDsoFlag)
 	exportedVars.ExportString("CfiBlocklistPath", cfiBlocklistPath)
 	exportedVars.ExportString("CfiBlocklistFilename", cfiBlocklistFilename)
@@ -967,7 +970,7 @@
 
 	blocklist := android.OptionalPathForModuleSrc(ctx, s.Properties.Sanitize.Blocklist)
 	if blocklist.Valid() {
-		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-ignorelist="+blocklist.String())
+		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeIgnorelistPrefix+blocklist.String())
 		flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
 	}
 
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 0212075..b897bb5 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -50,7 +50,6 @@
 
 var bazelMode = flag.Bool("bazel-mode", false, "use bazel for analysis of certain modules")
 var bazelModeStaging = flag.Bool("bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
-var bazelModeDev = flag.Bool("bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
 
 var onlyConfig = flag.Bool("only-config", false, "Only run product config (not Soong or Kati)")
 var onlySoong = flag.Bool("only-soong", false, "Only run product config and Soong (not Kati)")
@@ -229,10 +228,6 @@
 		count++
 		str = "--bazel-mode-staging"
 	}
-	if *bazelModeDev {
-		count++
-		str = "--bazel-mode-dev"
-	}
 
 	if count > 1 {
 		// Can't set more than one
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 2e6b6d4..10a5762 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -21,6 +21,7 @@
 	"fmt"
 	"os"
 	"path/filepath"
+	"regexp"
 	"strings"
 	"time"
 
@@ -85,7 +86,6 @@
 	flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
 	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
 	flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
-	flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
 	flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
 	flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files")
 	flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
@@ -124,7 +124,8 @@
 		return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
 	}
 	ctx.SetBeforePrepareBuildActionsHook(bazelHook)
-	ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args, bootstrap.DoEverything, ctx.Context, ctx.Config())
+	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args, bootstrap.DoEverything, ctx.Context, ctx.Config())
+	maybeQuit(err, "")
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
 	bazelPaths, err := readFileLines(ctx.Config().Getenv("BAZEL_DEPS_FILE"))
@@ -185,10 +186,11 @@
 	}
 
 	// Run the loading and analysis phase
-	ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args,
+	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args,
 		bootstrap.StopBeforePrepareBuildActions,
 		ctx.Context,
 		ctx.Config())
+	maybeQuit(err, "")
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
 	// Add the globbed dependencies
@@ -218,7 +220,7 @@
 	// }
 	//
 	// If we don't generate f/b/api/BUILD, foo.contribution will be unbuildable.
-	err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir, true)
+	err = createBazelWorkspace(codegenContext, absoluteApiBp2buildDir, true)
 	maybeQuit(err, "")
 	ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
 
@@ -412,12 +414,13 @@
 	defer ctx.EventHandler.End("globs_ninja_file")
 
 	globDir := bootstrap.GlobDirectory(ctx.Config().SoongOutDir(), globListDir)
-	bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
+	err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
 		GlobLister: ctx.Globs,
 		GlobFile:   globFile,
 		GlobDir:    globDir,
 		SrcDir:     ctx.SrcDir(),
 	}, ctx.Config())
+	maybeQuit(err, "")
 	return bootstrap.GlobFileListFiles(globDir)
 }
 
@@ -444,7 +447,8 @@
 		stopBefore = bootstrap.DoEverything
 	}
 
-	ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args, stopBefore, ctx.Context, ctx.Config())
+	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args, stopBefore, ctx.Context, ctx.Config())
+	maybeQuit(err, "")
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
 	globListFiles := writeBuildGlobsNinjaFile(ctx)
@@ -531,8 +535,6 @@
 
 	var finalOutputFile string
 
-	writeSymlink := false
-
 	// Run Soong for a specific activity, like bp2build, queryview
 	// or the actual Soong build for the build.ninja file.
 	switch configuration.BuildMode {
@@ -555,13 +557,8 @@
 					maybeQuit(err, "")
 				}
 			}
-			writeSymlink = true
 		} else {
 			finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
-
-			if configuration.BuildMode == android.AnalysisNoBazel {
-				writeSymlink = true
-			}
 		}
 		writeMetrics(configuration, ctx.EventHandler, metricsDir)
 	}
@@ -578,24 +575,6 @@
 	// are ninja inputs to the main output file, then ninja would superfluously
 	// rebuild this output file on the next build invocation.
 	touch(shared.JoinPath(topDir, finalOutputFile))
-
-	// TODO(b/277029044): Remove this function once build.<product>.ninja lands
-	if writeSymlink {
-		writeBuildNinjaSymlink(configuration, finalOutputFile)
-	}
-}
-
-// TODO(b/277029044): Remove this function once build.<product>.ninja lands
-func writeBuildNinjaSymlink(config android.Config, source string) {
-	targetPath := shared.JoinPath(topDir, config.SoongOutDir(), "build.ninja")
-	sourcePath := shared.JoinPath(topDir, source)
-
-	if targetPath == sourcePath {
-		return
-	}
-
-	os.Remove(targetPath)
-	os.Symlink(sourcePath, targetPath)
 }
 
 func writeUsedEnvironmentFile(configuration android.Config) {
@@ -762,6 +741,43 @@
 	return excluded
 }
 
+// buildTargetsByPackage parses Bazel BUILD.bazel and BUILD files under
+// the workspace, and returns a map containing names of Bazel targets defined in
+// these BUILD files.
+// For example, maps "//foo/bar" to ["baz", "qux"] if `//foo/bar:{baz,qux}` exist.
+func buildTargetsByPackage(ctx *android.Context) map[string][]string {
+	existingBazelFiles, err := getExistingBazelRelatedFiles(topDir)
+	maybeQuit(err, "Error determining existing Bazel-related files")
+
+	result := map[string][]string{}
+
+	// Search for instances of `name = "$NAME"` (with arbitrary spacing).
+	targetNameRegex := regexp.MustCompile(`(?m)^\s*name\s*=\s*\"([^\"]+)\"`)
+
+	for _, path := range existingBazelFiles {
+		if !ctx.Config().Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(filepath.Dir(path)) {
+			continue
+		}
+		fullPath := shared.JoinPath(topDir, path)
+		sourceDir := filepath.Dir(path)
+		fileInfo, err := os.Stat(fullPath)
+		maybeQuit(err, "Error accessing Bazel file '%s'", fullPath)
+
+		if !fileInfo.IsDir() &&
+			(fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") {
+			// Process this BUILD file.
+			buildFileContent, err := os.ReadFile(fullPath)
+			maybeQuit(err, "Error reading Bazel file '%s'", fullPath)
+
+			matches := targetNameRegex.FindAllStringSubmatch(string(buildFileContent), -1)
+			for _, match := range matches {
+				result[sourceDir] = append(result[sourceDir], match[1])
+			}
+		}
+	}
+	return result
+}
+
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
@@ -769,12 +785,19 @@
 	var codegenMetrics *bp2build.CodegenMetrics
 	ctx.EventHandler.Do("bp2build", func() {
 
+		ctx.EventHandler.Do("read_build", func() {
+			ctx.Config().SetBazelBuildFileTargets(buildTargetsByPackage(ctx))
+		})
+
 		// Propagate "allow misssing dependencies" bit. This is normally set in
 		// newContext(), but we create ctx without calling that method.
 		ctx.SetAllowMissingDependencies(ctx.Config().AllowMissingDependencies())
 		ctx.SetNameInterface(newNameResolver(ctx.Config()))
 		ctx.RegisterForBazelConversion()
 		ctx.SetModuleListFile(cmdlineArgs.ModuleListFile)
+		// Skip cloning modules during bp2build's blueprint run. Some mutators set
+		// bp2build-related module values which should be preserved during codegen.
+		ctx.SkipCloneModulesAfterMutators = true
 
 		var ninjaDeps []string
 		ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
@@ -784,8 +807,9 @@
 		// from the regular Modules.
 		ctx.EventHandler.Do("bootstrap", func() {
 			blueprintArgs := cmdlineArgs
-			bootstrapDeps := bootstrap.RunBlueprint(blueprintArgs.Args,
+			bootstrapDeps, err := bootstrap.RunBlueprint(blueprintArgs.Args,
 				bootstrap.StopBeforePrepareBuildActions, ctx.Context, ctx.Config())
+			maybeQuit(err, "")
 			ninjaDeps = append(ninjaDeps, bootstrapDeps...)
 		})
 
diff --git a/cmd/zipsync/zipsync.go b/cmd/zipsync/zipsync.go
index aecdc3d..b3e78d0 100644
--- a/cmd/zipsync/zipsync.go
+++ b/cmd/zipsync/zipsync.go
@@ -29,10 +29,14 @@
 var (
 	outputDir  = flag.String("d", "", "output dir")
 	outputFile = flag.String("l", "", "output list file")
-	filter     = flag.String("f", "", "optional filter pattern")
 	zipPrefix  = flag.String("zip-prefix", "", "optional prefix within the zip file to extract, stripping the prefix")
+	filter     multiFlag
 )
 
+func init() {
+	flag.Var(&filter, "f", "optional filter pattern")
+}
+
 func must(err error) {
 	if err != nil {
 		log.Fatal(err)
@@ -107,13 +111,15 @@
 				}
 				name = strings.TrimPrefix(name, *zipPrefix)
 			}
-			if *filter != "" {
-				if match, err := filepath.Match(*filter, filepath.Base(name)); err != nil {
+
+			if filter != nil {
+				if match, err := filter.Match(filepath.Base(name)); err != nil {
 					log.Fatal(err)
 				} else if !match {
 					continue
 				}
 			}
+
 			if filepath.IsAbs(name) {
 				log.Fatalf("%q in %q is an absolute path", name, input)
 			}
@@ -151,3 +157,28 @@
 		must(ioutil.WriteFile(*outputFile, []byte(data), 0666))
 	}
 }
+
+type multiFlag []string
+
+func (m *multiFlag) String() string {
+	return strings.Join(*m, " ")
+}
+
+func (m *multiFlag) Set(s string) error {
+	*m = append(*m, s)
+	return nil
+}
+
+func (m *multiFlag) Match(s string) (bool, error) {
+	if m == nil {
+		return false, nil
+	}
+	for _, f := range *m {
+		if match, err := filepath.Match(f, s); err != nil {
+			return false, err
+		} else if match {
+			return true, nil
+		}
+	}
+	return false, nil
+}
diff --git a/device_config/Android.bp b/device_config/Android.bp
index 360b389..6c44454 100644
--- a/device_config/Android.bp
+++ b/device_config/Android.bp
@@ -12,19 +12,21 @@
         "soong",
         "soong-android",
         "soong-bazel",
-        "soong-shared",
+        "soong-android",
+        "soong-java",
     ],
     srcs: [
         "device_config_definitions.go",
         "device_config_values.go",
         "device_config_value_set.go",
         "init.go",
-        //"testing.go"
+        "java_device_config_definitions_library.go",
+        "testing.go",
     ],
-    /*
     testSrcs: [
-        "device_config_test.go",
+        "device_config_definitions_test.go",
+        "device_config_values_test.go",
+        "device_config_value_set_test.go",
     ],
-    */
     pluginFor: ["soong_build"],
 }
diff --git a/device_config/device_config_definitions.go b/device_config/device_config_definitions.go
index c565766..ab2e4f7 100644
--- a/device_config/device_config_definitions.go
+++ b/device_config/device_config_definitions.go
@@ -38,7 +38,6 @@
 	}
 
 	intermediatePath android.WritablePath
-	srcJarPath       android.WritablePath
 }
 
 func DefinitionsFactory() android.Module {
@@ -78,8 +77,6 @@
 
 func (module *DefinitionsModule) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
-	case ".srcjar":
-		return []android.Path{module.srcJarPath}, nil
 	case "":
 		// The default output of this module is the intermediates format, which is
 		// not installable and in a private format that no other rules can handle
@@ -99,6 +96,14 @@
 	return sb.String()
 }
 
+// Provider published by device_config_value_set
+type definitionsProviderData struct {
+	namespace        string
+	intermediatePath android.WritablePath
+}
+
+var definitionsProviderKey = blueprint.NewProvider(definitionsProviderData{})
+
 func (module *DefinitionsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// Get the values that came from the global RELEASE_DEVICE_CONFIG_VALUE_SETS flag
 	ctx.VisitDirectDeps(func(dep android.Module) {
@@ -117,11 +122,11 @@
 
 	// Intermediate format
 	inputFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
-	module.intermediatePath = android.PathForModuleOut(ctx, "intermediate.json")
+	intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aconfigRule,
 		Inputs:      inputFiles,
-		Output:      module.intermediatePath,
+		Output:      intermediatePath,
 		Description: "device_config_definitions",
 		Args: map[string]string{
 			"release_version": ctx.Config().ReleaseVersion(),
@@ -130,21 +135,9 @@
 		},
 	})
 
-	// Generated java inside a srcjar
-	module.srcJarPath = android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        srcJarRule,
-		Input:       module.intermediatePath,
-		Output:      module.srcJarPath,
-		Description: "device_config.srcjar",
+	ctx.SetProvider(definitionsProviderKey, definitionsProviderData{
+		namespace:        module.properties.Namespace,
+		intermediatePath: intermediatePath,
 	})
 
-	// TODO: C++
-
-	// Phony target for debugging convenience
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   blueprint.Phony,
-		Output: android.PathForPhony(ctx, ctx.ModuleName()),
-		Inputs: []android.Path{module.srcJarPath}, // TODO: C++
-	})
 }
diff --git a/device_config/device_config_definitions_test.go b/device_config/device_config_definitions_test.go
new file mode 100644
index 0000000..6bc6eaa
--- /dev/null
+++ b/device_config/device_config_definitions_test.go
@@ -0,0 +1,42 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package device_config
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestDeviceConfigDefinitions(t *testing.T) {
+	bp := `
+		device_config_definitions {
+			name: "module_name",
+			namespace: "com.example.package",
+			srcs: ["foo.aconfig"],
+		}
+	`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "").Module().(*DefinitionsModule)
+
+	// Check that the provider has the right contents
+	depData := result.ModuleProvider(module, definitionsProviderKey).(definitionsProviderData)
+	android.AssertStringEquals(t, "namespace", depData.namespace, "com.example.package")
+	if !strings.HasSuffix(depData.intermediatePath.String(), "/intermediate.pb") {
+		t.Errorf("Missing intermediates path in provider: %s", depData.intermediatePath.String())
+	}
+}
diff --git a/device_config/device_config_test.go b/device_config/device_config_test.go
deleted file mode 100644
index 91a06a7..0000000
--- a/device_config/device_config_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package device_config
-
-import (
-	"os"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func TestMain(m *testing.M) {
-	os.Exit(m.Run())
-}
-
-func test(t *testing.T, bp string) *android.TestResult {
-	t.Helper()
-
-	mockFS := android.MockFS{
-		"config.aconfig": nil,
-	}
-
-	result := android.GroupFixturePreparers(
-		java.PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithSyspropBuildComponents,
-		// TODO: Consider values files, although maybe in its own test
-		// android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		//	variables.ReleaseConfigValuesBasePaths = ...
-		//})
-		mockFS.AddToFixture(),
-		android.FixtureWithRootAndroidBp(bp),
-	).RunTest(t)
-
-	return result
-}
-
-func TestOutputs(t *testing.T) {
-	/*result := */ test(t, `
-        device_config {
-            name: "my_device_config",
-            srcs: ["config.aconfig"],
-        }
-	`)
-
-	// TODO: Make sure it exports a .srcjar, which is used by java libraries
-	// TODO: Make sure it exports an intermediates file
-	// TODO: Make sure the intermediates file is propagated to the Android.mk file
-}
diff --git a/device_config/device_config_value_set_test.go b/device_config/device_config_value_set_test.go
new file mode 100644
index 0000000..f9e7c38
--- /dev/null
+++ b/device_config/device_config_value_set_test.go
@@ -0,0 +1,43 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package device_config
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestDeviceConfigValueSet(t *testing.T) {
+	bp := `
+				device_config_values {
+					name: "one",
+					srcs: [ "blah.aconfig_values" ],
+					namespace: "foo.namespace"
+				}
+
+				device_config_value_set {
+					name: "module_name",
+          values: [ "one" ],
+				}
+			`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "").Module().(*ValueSetModule)
+
+	// Check that the provider has the right contents
+	depData := result.ModuleProvider(module, valueSetProviderKey).(valueSetProviderData)
+	android.AssertStringEquals(t, "AvailableNamespaces", "blah.aconfig_values", depData.AvailableNamespaces["foo.namespace"][0].String())
+}
diff --git a/device_config/device_config_values_test.go b/device_config/device_config_values_test.go
new file mode 100644
index 0000000..64c57eb
--- /dev/null
+++ b/device_config/device_config_values_test.go
@@ -0,0 +1,39 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package device_config
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestDeviceConfigValues(t *testing.T) {
+	bp := `
+				device_config_values {
+					name: "module_name",
+					srcs: [ "blah.aconfig_values" ],
+					namespace: "foo.namespace"
+				}
+			`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "").Module().(*ValuesModule)
+
+	// Check that the provider has the right contents
+	depData := result.ModuleProvider(module, valuesProviderKey).(valuesProviderData)
+	android.AssertStringEquals(t, "namespace", "foo.namespace", depData.Namespace)
+	android.AssertPathsEndWith(t, "srcs", []string{"blah.aconfig_values"}, depData.Values)
+}
diff --git a/device_config/init.go b/device_config/init.go
index 0a4645b..04bbab6 100644
--- a/device_config/init.go
+++ b/device_config/init.go
@@ -23,11 +23,10 @@
 	pctx = android.NewPackageContext("android/soong/device_config")
 
 	// For device_config_definitions: Generate cache file
-	// TODO: Restat
 	aconfigRule = pctx.AndroidStaticRule("aconfig",
 		blueprint.RuleParams{
 			Command: `${aconfig} create-cache` +
-				` --namespace ${namespace}` +
+				` --package ${namespace}` +
 				` --declarations ${in}` +
 				` ${values}` +
 				` --cache ${out}.tmp` +
@@ -39,7 +38,7 @@
 			Restat: true,
 		}, "release_version", "namespace", "values")
 
-	// For device_config_definitions: Generate java file
+	// For java_device_config_definitions_library: Generate java file
 	srcJarRule = pctx.AndroidStaticRule("aconfig_srcjar",
 		blueprint.RuleParams{
 			Command: `rm -rf ${out}.tmp` +
@@ -59,12 +58,13 @@
 
 func init() {
 	registerBuildComponents(android.InitRegistrationContext)
+	pctx.HostBinToolVariable("aconfig", "aconfig")
+	pctx.HostBinToolVariable("soong_zip", "soong_zip")
 }
 
 func registerBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("device_config_definitions", DefinitionsFactory)
 	ctx.RegisterModuleType("device_config_values", ValuesFactory)
 	ctx.RegisterModuleType("device_config_value_set", ValueSetFactory)
-	pctx.HostBinToolVariable("aconfig", "aconfig")
-	pctx.HostBinToolVariable("soong_zip", "soong_zip")
+	ctx.RegisterModuleType("java_device_config_definitions_library", JavaDefinitionsLibraryFactory)
 }
diff --git a/device_config/java_device_config_definitions_library.go b/device_config/java_device_config_definitions_library.go
new file mode 100644
index 0000000..6e48ece
--- /dev/null
+++ b/device_config/java_device_config_definitions_library.go
@@ -0,0 +1,71 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package device_config
+
+import (
+	"android/soong/android"
+	"android/soong/java"
+	"fmt"
+	"github.com/google/blueprint"
+)
+
+type definitionsTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var definitionsTag = definitionsTagType{}
+
+type JavaDeviceConfigDefinitionsLibraryProperties struct {
+	// name of the device_config_definitions module to generate a library for
+	Device_config_definitions string
+}
+
+type JavaDeviceConfigDefinitionsLibraryCallbacks struct {
+	properties JavaDeviceConfigDefinitionsLibraryProperties
+}
+
+func JavaDefinitionsLibraryFactory() android.Module {
+	callbacks := &JavaDeviceConfigDefinitionsLibraryCallbacks{}
+	return java.GeneratedJavaLibraryModuleFactory("java_device_config_definitions_library", callbacks, &callbacks.properties)
+}
+
+func (callbacks *JavaDeviceConfigDefinitionsLibraryCallbacks) DepsMutator(module *java.GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
+	definitions := callbacks.properties.Device_config_definitions
+	if len(definitions) == 0 {
+		// TODO: Add test for this case
+		ctx.PropertyErrorf("device_config_definitions", "device_config_definitions property required")
+	} else {
+		ctx.AddDependency(ctx.Module(), definitionsTag, definitions)
+	}
+}
+
+func (callbacks *JavaDeviceConfigDefinitionsLibraryCallbacks) GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path {
+	// Get the values that came from the global RELEASE_DEVICE_CONFIG_VALUE_SETS flag
+	definitionsModules := ctx.GetDirectDepsWithTag(definitionsTag)
+	if len(definitionsModules) != 1 {
+		panic(fmt.Errorf("Exactly one device_config_definitions property required"))
+	}
+	definitions := ctx.OtherModuleProvider(definitionsModules[0], definitionsProviderKey).(definitionsProviderData)
+
+	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        srcJarRule,
+		Input:       definitions.intermediatePath,
+		Output:      srcJarPath,
+		Description: "device_config.srcjar",
+	})
+
+	return srcJarPath
+}
diff --git a/device_config/testing.go b/device_config/testing.go
index f054476..284a7fa 100644
--- a/device_config/testing.go
+++ b/device_config/testing.go
@@ -14,6 +14,16 @@
 
 package device_config
 
-import "android/soong/android"
+import (
+	"testing"
 
-var PrepareForTestWithSyspropBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents)
+	"android/soong/android"
+)
+
+var PrepareForTestWithDeviceConfigBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents)
+
+func runTest(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
+	return android.GroupFixturePreparers(PrepareForTestWithDeviceConfigBuildComponents).
+		ExtendWithErrorHandler(errorHandler).
+		RunTestWithBp(t, bp)
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 3e1bbde..370a423 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -38,6 +38,7 @@
 
 	"android/soong/android"
 	"android/soong/bazel"
+	"android/soong/bazel/cquery"
 	"android/soong/snapshot"
 )
 
@@ -329,7 +330,6 @@
 		ctx.PropertyErrorf("src", "missing prebuilt source file")
 		return
 	}
-	p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
 
 	if strings.Contains(filename, "/") {
 		ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
@@ -349,21 +349,42 @@
 	}
 	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
 
-	// This ensures that outputFilePath has the correct name for others to
-	// use, as the source file may have a different name.
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   android.Cp,
-		Output: p.outputFilePath,
-		Input:  p.sourceFilePath,
-	})
+	// Call InstallFile even when uninstallable to make the module included in the package
+	ip := installProperties{
+		installable:    p.Installable(),
+		filename:       filename,
+		sourceFilePath: p.sourceFilePath,
+		symlinks:       p.properties.Symlinks,
+	}
+	p.addInstallRules(ctx, ip)
+}
 
-	if !p.Installable() {
+type installProperties struct {
+	installable    bool
+	filename       string
+	sourceFilePath android.Path
+	symlinks       []string
+}
+
+// utility function to add install rules to the build graph.
+// Reduces code duplication between Soong and Mixed build analysis
+func (p *PrebuiltEtc) addInstallRules(ctx android.ModuleContext, ip installProperties) {
+	if !ip.installable {
 		p.SkipInstall()
 	}
 
-	// Call InstallFile even when uninstallable to make the module included in the package
-	installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath)
-	for _, sl := range p.properties.Symlinks {
+	// Copy the file from src to a location in out/ with the correct `filename`
+	// This ensures that outputFilePath has the correct name for others to
+	// use, as the source file may have a different name.
+	p.outputFilePath = android.PathForModuleOut(ctx, ip.filename).OutputPath
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Output: p.outputFilePath,
+		Input:  ip.sourceFilePath,
+	})
+
+	installPath := ctx.InstallFile(p.installDirPath, ip.filename, p.outputFilePath)
+	for _, sl := range ip.symlinks {
 		ctx.InstallSymlink(p.installDirPath, sl, installPath)
 	}
 }
@@ -781,3 +802,38 @@
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
 }
+
+var _ android.MixedBuildBuildable = (*PrebuiltEtc)(nil)
+
+func (pe *PrebuiltEtc) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
+	return true
+}
+
+func (pe *PrebuiltEtc) QueueBazelCall(ctx android.BaseModuleContext) {
+	ctx.Config().BazelContext.QueueBazelRequest(
+		pe.GetBazelLabel(ctx, pe),
+		cquery.GetPrebuiltFileInfo,
+		android.GetConfigKey(ctx),
+	)
+}
+
+func (pe *PrebuiltEtc) ProcessBazelQueryResponse(ctx android.ModuleContext) {
+	bazelCtx := ctx.Config().BazelContext
+	pfi, err := bazelCtx.GetPrebuiltFileInfo(pe.GetBazelLabel(ctx, pe), android.GetConfigKey(ctx))
+	if err != nil {
+		ctx.ModuleErrorf(err.Error())
+		return
+	}
+
+	// Set properties for androidmk
+	pe.installDirPath = android.PathForModuleInstall(ctx, pfi.Dir)
+
+	// Installation rules
+	ip := installProperties{
+		installable:    pfi.Installable,
+		filename:       pfi.Filename,
+		sourceFilePath: android.PathForSource(ctx, pfi.Src),
+		// symlinks: pe.properties.Symlinks, // TODO: b/207489266 - Fully support all properties in prebuilt_file
+	}
+	pe.addInstallRules(ctx, ip)
+}
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 0d44c31..df7664d 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -23,6 +23,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel/cquery"
 	"android/soong/snapshot"
 )
 
@@ -494,3 +495,41 @@
 		checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect")
 	})
 }
+
+func TestPrebuiltEtcAndroidMkEntriesWithBazel(t *testing.T) {
+	t.Parallel()
+	bp := `
+prebuilt_etc {
+	name: "myetc",
+	src: "prebuilt_etc.rc", // filename in src tree
+	filename: "init.rc", // target filename on device
+	sub_dir: "subdir", // relative subdir for installation
+	bazel_module: { label: "//foo/bar:myetc" },
+}
+`
+	res := android.GroupFixturePreparers(
+		prepareForPrebuiltEtcTest,
+		android.FixtureModifyConfig(func(cfg android.Config) {
+			cfg.BazelContext = android.MockBazelContext{
+				LabelToPrebuiltFileInfo: map[string]cquery.PrebuiltFileInfo{
+					"//foo/bar:myetc": cquery.PrebuiltFileInfo{
+						Src:         "foo/bar/prebuilt_etc.rc",
+						Dir:         "etc/subdir",
+						Filename:    "init.rc",
+						Installable: true,
+					},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp)
+	ctx := res.ModuleForTests("myetc", "android_arm64_armv8-a")
+	mod := ctx.Module()
+	entries := android.AndroidMkEntriesForTest(t, res.TestContext, mod)[0]
+	// verify androidmk entries
+	android.AssertStringDoesContain(t, "LOCAL_MODULE_PATH should contain", entries.EntryMap["LOCAL_MODULE_PATH"][0], "etc/subdir")
+	android.AssertStringEquals(t, "LOCAL_INSTALLED_MODULE_STEM is incorrect", "init.rc", entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"][0])
+	// verify installation rules
+	install := ctx.Description("install")
+	android.AssertStringEquals(t, "Source location of prebuilt_etc installation", "out/soong/.intermediates/myetc/android_arm64_armv8-a/init.rc", install.Input.String())
+	android.AssertStringEquals(t, "Target location of prebuilt_etc installation", "out/soong/target/product/test_device/system/etc/subdir/init.rc", install.Output.String())
+}
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 2954f8b..495bc19 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -47,7 +47,6 @@
 	}
 
 	SandboxingDenyModuleList = []string{
-		"framework-javastream-protos",
 		"RsBalls-rscript",
 		"CtsRsBlasTestCases-rscript",
 		"pvmfw_fdt_template_rs",
@@ -57,7 +56,6 @@
 		"ImageProcessingJB-rscript",
 		"RSTest-rscript",
 		"BluetoothGeneratedDumpsysBinarySchema_bfbs",
-		"WmediumdServerProto_h",
 		"TracingVMProtoStub_h",
 		"FrontendStub_h",
 		"VehicleServerProtoStub_cc",
@@ -87,8 +85,6 @@
 		"ltp_config_x86_64",
 		"vm-tests-tf-lib",
 		"hidl_cpp_impl_test_gen-headers",
-		"pandora_experimental-python-gen-src",
-		"framework-cppstream-protos",
 		"Refocus-rscript",
 		"RSTest_v11-rscript",
 		"RSTest_v16-rscript",
@@ -107,7 +103,6 @@
 		"FrontendStub_cc",
 		"OpenwrtControlServerProto_cc",
 		"OpenwrtControlServerProto_h",
-		"WmediumdServerProto_cc",
 		"c2hal_test_genc++",
 		"c2hal_test_genc++_headers",
 		"hidl2aidl_test_gen_aidl",
@@ -124,7 +119,6 @@
 		"nos_app_weaver_service_genc++_headers",
 		"nos_app_weaver_service_genc++_mock",
 		"nos_generator_test_service_genc++",
-		"pandora-python-gen-src",
 	}
 
 	SandboxingDenyPathList = []string{
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 4992625..b29e2c9 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -24,7 +24,6 @@
 	"path/filepath"
 	"strconv"
 	"strings"
-	"sync"
 
 	"android/soong/bazel/cquery"
 
@@ -61,12 +60,6 @@
 	PrepareForTestWithGenRuleBuildComponents,
 )
 
-var DepfileAllowSet map[string]bool
-var SandboxingDenyModuleSet map[string]bool
-var SandboxingDenyPathSet map[string]bool
-var SandboxingDenyModuleSetLock sync.Mutex
-var DepfileAllowSetLock sync.Mutex
-
 func RegisterGenruleBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("genrule_defaults", defaultsFactory)
 
@@ -203,12 +196,13 @@
 type taskFunc func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask
 
 type generateTask struct {
-	in         android.Paths
-	out        android.WritablePaths
-	depFile    android.WritablePath
-	copyTo     android.WritablePaths // For gensrcs to set on gensrcsMerge rule.
-	genDir     android.WritablePath
-	extraTools android.Paths // dependencies on tools used by the generator
+	in          android.Paths
+	out         android.WritablePaths
+	depFile     android.WritablePath
+	copyTo      android.WritablePaths // For gensrcs to set on gensrcsMerge rule.
+	genDir      android.WritablePath
+	extraTools  android.Paths // dependencies on tools used by the generator
+	extraInputs map[string][]string
 
 	cmd string
 	// For gensrsc sharding.
@@ -402,30 +396,35 @@
 		addLocationLabel(toolFile, toolLocation{paths})
 	}
 
-	includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
-	var srcFiles android.Paths
-	for _, in := range g.properties.Srcs {
-		paths, missingDeps := android.PathsAndMissingDepsRelativeToModuleSourceDir(android.SourceInput{
-			Context: ctx, Paths: []string{in}, ExcludePaths: g.properties.Exclude_srcs, IncludeDirs: includeDirInPaths,
-		})
-		if len(missingDeps) > 0 {
-			if !ctx.Config().AllowMissingDependencies() {
-				panic(fmt.Errorf("should never get here, the missing dependencies %q should have been reported in DepsMutator",
-					missingDeps))
-			}
+	addLabelsForInputs := func(propName string, include, exclude []string) android.Paths {
 
-			// If AllowMissingDependencies is enabled, the build will not have stopped when
-			// the dependency was added on a missing SourceFileProducer module, which will result in nonsensical
-			// "cmd: label ":..." has no files" errors later.  Add a placeholder file to the local label.
-			// The command that uses this placeholder file will never be executed because the rule will be
-			// replaced with an android.Error rule reporting the missing dependencies.
-			ctx.AddMissingDependencies(missingDeps)
-			addLocationLabel(in, errorLocation{"***missing srcs " + in + "***"})
-		} else {
-			srcFiles = append(srcFiles, paths...)
-			addLocationLabel(in, inputLocation{paths})
+		includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
+		var srcFiles android.Paths
+		for _, in := range include {
+			paths, missingDeps := android.PathsAndMissingDepsRelativeToModuleSourceDir(android.SourceInput{
+				Context: ctx, Paths: []string{in}, ExcludePaths: exclude, IncludeDirs: includeDirInPaths,
+			})
+			if len(missingDeps) > 0 {
+				if !ctx.Config().AllowMissingDependencies() {
+					panic(fmt.Errorf("should never get here, the missing dependencies %q should have been reported in DepsMutator",
+						missingDeps))
+				}
+
+				// If AllowMissingDependencies is enabled, the build will not have stopped when
+				// the dependency was added on a missing SourceFileProducer module, which will result in nonsensical
+				// "cmd: label ":..." has no files" errors later.  Add a placeholder file to the local label.
+				// The command that uses this placeholder file will never be executed because the rule will be
+				// replaced with an android.Error rule reporting the missing dependencies.
+				ctx.AddMissingDependencies(missingDeps)
+				addLocationLabel(in, errorLocation{"***missing " + propName + " " + in + "***"})
+			} else {
+				srcFiles = append(srcFiles, paths...)
+				addLocationLabel(in, inputLocation{paths})
+			}
 		}
+		return srcFiles
 	}
+	srcFiles := addLabelsForInputs("srcs", g.properties.Srcs, g.properties.Exclude_srcs)
 
 	var copyFrom android.Paths
 	var outputFiles android.WritablePaths
@@ -437,12 +436,20 @@
 	}
 
 	// Generate tasks, either from genrule or gensrcs.
-	for _, task := range g.taskGenerator(ctx, cmd, srcFiles) {
+	for i, task := range g.taskGenerator(ctx, cmd, srcFiles) {
 		if len(task.out) == 0 {
 			ctx.ModuleErrorf("must have at least one output file")
 			return
 		}
 
+		var extraInputs android.Paths
+		// Only handle extra inputs once as these currently are the same across all tasks
+		if i == 0 {
+			for name, values := range task.extraInputs {
+				extraInputs = append(extraInputs, addLabelsForInputs(name, values, []string{})...)
+			}
+		}
+
 		// Pick a unique path outside the task.genDir for the sbox manifest textproto,
 		// a unique rule name, and the user-visible description.
 		manifestName := "genrule.sbox.textproto"
@@ -551,6 +558,8 @@
 		g.rawCommands = append(g.rawCommands, rawCommand)
 
 		cmd.Text(rawCommand)
+		cmd.Implicits(srcFiles) // need to be able to reference other srcs
+		cmd.Implicits(extraInputs)
 		cmd.ImplicitOutputs(task.out)
 		cmd.Implicits(task.in)
 		cmd.ImplicitTools(tools)
@@ -602,15 +611,10 @@
 	// Allowlist genrule to use depfile until we have a solution to remove it.
 	// TODO(b/235582219): Remove allowlist for genrule
 	if Bool(g.properties.Depfile) {
-		if DepfileAllowSet == nil {
-			DepfileAllowSetLock.Lock()
-			defer DepfileAllowSetLock.Unlock()
-			DepfileAllowSet = map[string]bool{}
-			android.AddToStringSet(DepfileAllowSet, DepfileAllowList)
-		}
+		sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
 		// TODO(b/283852474): Checking the GenruleSandboxing flag is temporary in
 		// order to pass the presubmit before internal master is updated.
-		if ctx.DeviceConfig().GenruleSandboxing() && !DepfileAllowSet[g.Name()] {
+		if ctx.DeviceConfig().GenruleSandboxing() && !sandboxingAllowlistSets.depfileAllowSet[g.Name()] {
 			ctx.PropertyErrorf(
 				"depfile",
 				"Deprecated to ensure the module type is convertible to Bazel. "+
@@ -820,6 +824,9 @@
 				shard:      i,
 				shards:     len(shards),
 				extraTools: extraTools,
+				extraInputs: map[string][]string{
+					"data": properties.Data,
+				},
 			})
 		}
 
@@ -844,6 +851,9 @@
 
 	// maximum number of files that will be passed on a single command line.
 	Shard_size *int64
+
+	// Additional files needed for build that are not tooling related.
+	Data []string `android:"path"`
 }
 
 type bazelGensrcsAttributes struct {
@@ -851,6 +861,7 @@
 	Output_extension *string
 	Tools            bazel.LabelListAttribute
 	Cmd              string
+	Data             bazel.LabelListAttribute
 }
 
 const defaultShardSize = 50
@@ -930,6 +941,23 @@
 	allReplacements.Append(tools.Value)
 	allReplacements.Append(bazel.FirstUniqueBazelLabelList(srcs_labels))
 
+	// The Output_extension prop is not in an immediately accessible field
+	// in the Module struct, so use GetProperties and cast it
+	// to the known struct prop.
+	var outputExtension *string
+	var data bazel.LabelListAttribute
+	if ctx.ModuleType() == "gensrcs" {
+		for _, propIntf := range m.GetProperties() {
+			if props, ok := propIntf.(*genSrcsProperties); ok {
+				outputExtension = props.Output_extension
+				dataFiles := android.BazelLabelForModuleSrc(ctx, props.Data)
+				allReplacements.Append(bazel.FirstUniqueBazelLabelList(dataFiles))
+				data = bazel.MakeLabelListAttribute(dataFiles)
+				break
+			}
+		}
+	}
+
 	// Replace in and out variables with $< and $@
 	var cmd string
 	if m.properties.Cmd != nil {
@@ -958,16 +986,6 @@
 	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 
 	if ctx.ModuleType() == "gensrcs" {
-		// The Output_extension prop is not in an immediately accessible field
-		// in the Module struct, so use GetProperties and cast it
-		// to the known struct prop.
-		var outputExtension *string
-		for _, propIntf := range m.GetProperties() {
-			if props, ok := propIntf.(*genSrcsProperties); ok {
-				outputExtension = props.Output_extension
-				break
-			}
-		}
 		props := bazel.BazelTargetModuleProperties{
 			Rule_class:        "gensrcs",
 			Bzl_load_location: "//build/bazel/rules:gensrcs.bzl",
@@ -977,6 +995,7 @@
 			Output_extension: outputExtension,
 			Cmd:              cmd,
 			Tools:            tools,
+			Data:             data,
 		}
 		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
 			Name: m.Name(),
@@ -993,6 +1012,17 @@
 				break
 			}
 		}
+		bazelName := m.Name()
+		for _, out := range outs {
+			if out == bazelName {
+				// This is a workaround to circumvent a Bazel warning where a genrule's
+				// out may not have the same name as the target itself. This makes no
+				// difference for reverse dependencies, because they may depend on the
+				// out file by name.
+				bazelName = bazelName + "-gen"
+				break
+			}
+		}
 		attrs := &bazelGenruleAttributes{
 			Srcs:  srcs,
 			Outs:  outs,
@@ -1003,7 +1033,7 @@
 			Rule_class: "genrule",
 		}
 		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-			Name: m.Name(),
+			Name: bazelName,
 			Tags: tags,
 		}, attrs)
 	}
@@ -1036,20 +1066,37 @@
 	return module
 }
 
+var sandboxingAllowlistKey = android.NewOnceKey("genruleSandboxingAllowlistKey")
+
+type sandboxingAllowlistSets struct {
+	sandboxingDenyModuleSet map[string]bool
+	sandboxingDenyPathSet   map[string]bool
+	depfileAllowSet         map[string]bool
+}
+
+func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSets {
+	return ctx.Config().Once(sandboxingAllowlistKey, func() interface{} {
+		sandboxingDenyModuleSet := map[string]bool{}
+		sandboxingDenyPathSet := map[string]bool{}
+		depfileAllowSet := map[string]bool{}
+
+		android.AddToStringSet(sandboxingDenyModuleSet, append(DepfileAllowList, SandboxingDenyModuleList...))
+		android.AddToStringSet(sandboxingDenyPathSet, SandboxingDenyPathList)
+		android.AddToStringSet(depfileAllowSet, DepfileAllowList)
+		return &sandboxingAllowlistSets{
+			sandboxingDenyModuleSet: sandboxingDenyModuleSet,
+			sandboxingDenyPathSet:   sandboxingDenyPathSet,
+			depfileAllowSet:         depfileAllowSet,
+		}
+	}).(*sandboxingAllowlistSets)
+}
 func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
 	if !ctx.DeviceConfig().GenruleSandboxing() {
 		return r.SandboxTools()
 	}
-	if SandboxingDenyModuleSet == nil {
-		SandboxingDenyModuleSetLock.Lock()
-		defer SandboxingDenyModuleSetLock.Unlock()
-		SandboxingDenyModuleSet = map[string]bool{}
-		SandboxingDenyPathSet = map[string]bool{}
-		android.AddToStringSet(SandboxingDenyModuleSet, append(DepfileAllowList, SandboxingDenyModuleList...))
-		android.AddToStringSet(SandboxingDenyPathSet, SandboxingDenyPathList)
-	}
-
-	if SandboxingDenyPathSet[ctx.ModuleDir()] || SandboxingDenyModuleSet[ctx.ModuleName()] {
+	sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
+	if sandboxingAllowlistSets.sandboxingDenyPathSet[ctx.ModuleDir()] ||
+		sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
 		return r.SandboxTools()
 	}
 	return r.SandboxInputs()
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 370fe3d..7c17db1 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -604,6 +604,30 @@
 				"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
 			},
 		},
+		{
+			name: "data",
+			prop: `
+				tools: ["tool"],
+				srcs: ["in1.txt", "in2.txt", "in3.txt"],
+				cmd: "$(location) $(in) --extra_input=$(location baz.txt) > $(out)",
+				data: ["baz.txt"],
+				shard_size: 2,
+			`,
+			cmds: []string{
+				"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
+				"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
+			},
+			deps: []string{
+				"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
+			},
+			files: []string{
+				"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
+			},
+		},
 	}
 
 	for _, test := range testcases {
diff --git a/java/Android.bp b/java/Android.bp
index 4af2a14..e079869 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -48,6 +48,7 @@
         "droidstubs.go",
         "fuzz.go",
         "gen.go",
+        "generated_java_library.go",
         "genrule.go",
         "hiddenapi.go",
         "hiddenapi_modular.go",
@@ -92,6 +93,7 @@
         "droidstubs_test.go",
         "fuzz_test.go",
         "genrule_test.go",
+        "generated_java_library_test.go",
         "hiddenapi_singleton_test.go",
         "jacoco_test.go",
         "java_test.go",
diff --git a/java/base.go b/java/base.go
index ed61e12..f9c9e1e 100644
--- a/java/base.go
+++ b/java/base.go
@@ -20,6 +20,7 @@
 	"strconv"
 	"strings"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 
@@ -187,6 +188,9 @@
 
 	// A list of java_library instances that provide additional hiddenapi annotations for the library.
 	Hiddenapi_additional_annotations []string
+
+	// Additional srcJars tacked in by GeneratedJavaLibraryModule
+	Generated_srcjars []android.Path `android:"mutated"`
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -1041,6 +1045,10 @@
 
 }
 
+func (module *Module) addGeneratedSrcJars(path android.Path) {
+	module.properties.Generated_srcjars = append(module.properties.Generated_srcjars, path)
+}
+
 func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
@@ -1082,6 +1090,7 @@
 	if aaptSrcJar != nil {
 		srcJars = append(srcJars, aaptSrcJar)
 	}
+	srcJars = append(srcJars, j.properties.Generated_srcjars...)
 	srcFiles = srcFiles.FilterOutByExt(".srcjar")
 
 	if j.properties.Jarjar_rules != nil {
@@ -1377,12 +1386,20 @@
 		// prebuilt dependencies until we support modules in the platform build, so there shouldn't be
 		// any if len(jars) == 1.
 
+		// moduleStubLinkType determines if the module is the TopLevelStubLibrary generated
+		// from sdk_library. The TopLevelStubLibrary contains only one static lib,
+		// either with .from-source or .from-text suffix.
+		// outputFile should be agnostic to the build configuration,
+		// thus "combine" the single static lib in order to prevent the static lib from being exposed
+		// to the copy rules.
+		stub, _ := moduleStubLinkType(ctx.ModuleName())
+
 		// Transform the single path to the jar into an OutputPath as that is required by the following
 		// code.
-		if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok {
+		if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok && !stub {
 			// The path contains an embedded OutputPath so reuse that.
 			outputFile = moduleOutPath.OutputPath
-		} else if outputPath, ok := jars[0].(android.OutputPath); ok {
+		} else if outputPath, ok := jars[0].(android.OutputPath); ok && !stub {
 			// The path is an OutputPath so reuse it directly.
 			outputFile = outputPath
 		} else {
@@ -2197,5 +2214,7 @@
 		if testHost, ok := ctx.Module().(*TestHost); ok {
 			javaTestHostBp2Build(ctx, testHost)
 		}
+	default:
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
 	}
 }
diff --git a/java/builder.go b/java/builder.go
index 0c57738..c4395e9 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -305,6 +305,12 @@
 	proto android.ProtoFlags
 }
 
+func DefaultJavaBuilderFlags() javaBuilderFlags {
+	return javaBuilderFlags{
+		javaVersion: JAVA_VERSION_8,
+	}
+}
+
 func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int,
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags, deps android.Paths) {
 
diff --git a/java/droiddoc.go b/java/droiddoc.go
index dbe021d..d4ead12 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -608,6 +608,11 @@
 		FlagWithArg("-Xmaxerrs ", "10").
 		FlagWithArg("-Xmaxwarns ", "10").
 		Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.formats.html=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED").
 		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED").
 		FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile).
 		FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `)
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
new file mode 100644
index 0000000..1b3de9f
--- /dev/null
+++ b/java/generated_java_library.go
@@ -0,0 +1,94 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"android/soong/android"
+)
+
+type GeneratedJavaLibraryModule struct {
+	Library
+	callbacks  GeneratedJavaLibraryCallbacks
+	moduleName string
+}
+
+type GeneratedJavaLibraryCallbacks interface {
+	// Called from inside DepsMutator, gives a chance to AddDependencies
+	DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext)
+
+	// Called from inside GenerateAndroidBuildActions. Add the build rules to
+	// make the srcjar, and return the path to it.
+	GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path
+}
+
+// GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated
+// source code, including ones outside the java package to build jar files
+// from that generated source.
+//
+// To use GeneratedJavaLibraryModule, call GeneratedJavaLibraryModuleFactory with
+// a callback interface and a properties object to add to the module.
+//
+// These modules will have some properties blocked, and it will be an error if
+// modules attempt to set them. See the list of property names in GeneratedAndroidBuildActions
+// for the list of those properties.
+func GeneratedJavaLibraryModuleFactory(moduleName string, callbacks GeneratedJavaLibraryCallbacks, properties interface{}) android.Module {
+	module := &GeneratedJavaLibraryModule{
+		callbacks:  callbacks,
+		moduleName: moduleName,
+	}
+	module.addHostAndDeviceProperties()
+	module.initModuleAndImport(module)
+	android.InitApexModule(module)
+	android.InitBazelModule(module)
+	InitJavaModule(module, android.HostAndDeviceSupported)
+	if properties != nil {
+		module.AddProperties(properties)
+	}
+	return module
+}
+
+func (module *GeneratedJavaLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	module.callbacks.DepsMutator(module, ctx)
+	module.Library.DepsMutator(ctx)
+}
+
+func checkPropertyEmpty(ctx android.ModuleContext, module *GeneratedJavaLibraryModule, name string, value []string) {
+	if len(value) != 0 {
+		ctx.PropertyErrorf(name, "%s not allowed on %s", name, module.moduleName)
+	}
+}
+
+func (module *GeneratedJavaLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// These modules are all-generated, so disallow these properties to keep it simple.
+	// No additional sources
+	checkPropertyEmpty(ctx, module, "srcs", module.Library.properties.Srcs)
+	checkPropertyEmpty(ctx, module, "common_srcs", module.Library.properties.Common_srcs)
+	checkPropertyEmpty(ctx, module, "exclude_srcs", module.Library.properties.Exclude_srcs)
+	checkPropertyEmpty(ctx, module, "java_resource_dirs", module.Library.properties.Java_resource_dirs)
+	checkPropertyEmpty(ctx, module, "exclude_java_resource_dirs", module.Library.properties.Exclude_java_resource_dirs)
+	// No additional libraries. The generator should add anything necessary automatically
+	// by returning something from ____ (TODO: Additional libraries aren't needed now, so
+	// these are just blocked).
+	checkPropertyEmpty(ctx, module, "libs", module.Library.properties.Libs)
+	checkPropertyEmpty(ctx, module, "static_libs", module.Library.properties.Static_libs)
+	// Restrict these for no good reason other than to limit the surface area. If there's a
+	// good use case put them back.
+	checkPropertyEmpty(ctx, module, "plugins", module.Library.properties.Plugins)
+	checkPropertyEmpty(ctx, module, "exported_plugins", module.Library.properties.Exported_plugins)
+
+	srcJarPath := module.callbacks.GenerateSourceJarBuildActions(ctx)
+	module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
+	module.Library.GenerateAndroidBuildActions(ctx)
+}
diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go
new file mode 100644
index 0000000..68f1f7e
--- /dev/null
+++ b/java/generated_java_library_test.go
@@ -0,0 +1,65 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func JavaGenLibTestFactory() android.Module {
+	callbacks := &JavaGenLibTestCallbacks{}
+	return GeneratedJavaLibraryModuleFactory("test_java_gen_lib", callbacks, &callbacks.properties)
+}
+
+type JavaGenLibTestProperties struct {
+	Foo string
+}
+
+type JavaGenLibTestCallbacks struct {
+	properties JavaGenLibTestProperties
+}
+
+func (callbacks *JavaGenLibTestCallbacks) DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
+}
+
+func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path {
+	return android.PathForOutput(ctx, "blah.srcjar")
+}
+
+func testGenLib(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
+	return android.GroupFixturePreparers(
+		PrepareForIntegrationTestWithJava,
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			ctx.RegisterModuleType("test_java_gen_lib", JavaGenLibTestFactory)
+		}),
+	).
+		ExtendWithErrorHandler(errorHandler).
+		RunTestWithBp(t, bp)
+}
+
+func TestGenLib(t *testing.T) {
+	bp := `
+				test_java_gen_lib {
+					name: "javagenlibtest",
+                    foo: "bar",  // Note: This won't parse if the property didn't get added
+				}
+			`
+	result := testGenLib(t, android.FixtureExpectsNoErrors, bp)
+
+	javagenlibtest := result.ModuleForTests("javagenlibtest", "android_common").Module().(*GeneratedJavaLibraryModule)
+	android.AssertPathsEndWith(t, "Generated_srcjars", []string{"/blah.srcjar"}, javagenlibtest.Library.properties.Generated_srcjars)
+}
diff --git a/java/java.go b/java/java.go
index a8793fe..a026610 100644
--- a/java/java.go
+++ b/java/java.go
@@ -273,6 +273,8 @@
 	// JacocoReportClassesFile is the path to a jar containing uninstrumented classes that will be
 	// instrumented by jacoco.
 	JacocoReportClassesFile android.Path
+
+	// TODO: Add device config declarations here?
 }
 
 var JavaInfoProvider = blueprint.NewProvider(JavaInfo{})
@@ -3104,24 +3106,15 @@
 	// Attribute jvm_flags
 	var jvmFlags bazel.StringListAttribute
 	if m.binaryProperties.Jni_libs != nil {
-		jniLibPackages := map[string]bool{}
-		for _, jniLibLabel := range android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs).Includes {
-			jniLibPackage := jniLibLabel.Label
-			indexOfColon := strings.Index(jniLibLabel.Label, ":")
-			if indexOfColon > 0 {
-				// JNI lib from other package
-				jniLibPackage = jniLibLabel.Label[2:indexOfColon]
-			} else if indexOfColon == 0 {
-				// JNI lib in the same package of java_binary
-				packageOfCurrentModule := m.GetBazelLabel(ctx, m)
-				jniLibPackage = packageOfCurrentModule[2:strings.Index(packageOfCurrentModule, ":")]
-			}
-			if _, inMap := jniLibPackages[jniLibPackage]; !inMap {
-				jniLibPackages[jniLibPackage] = true
+		jniLibPackages := []string{}
+		for _, jniLib := range m.binaryProperties.Jni_libs {
+			if jniLibModule, exists := ctx.ModuleFromName(jniLib); exists {
+				otherDir := ctx.OtherModuleDir(jniLibModule)
+				jniLibPackages = append(jniLibPackages, filepath.Join(otherDir, jniLib))
 			}
 		}
 		jniLibPaths := []string{}
-		for jniLibPackage, _ := range jniLibPackages {
+		for _, jniLibPackage := range jniLibPackages {
 			// See cs/f:.*/third_party/bazel/.*java_stub_template.txt for the use of RUNPATH
 			jniLibPaths = append(jniLibPaths, "$${RUNPATH}"+jniLibPackage)
 		}
@@ -3145,9 +3138,9 @@
 	}
 
 	libInfo := libraryCreationInfo{
-		deps: deps,
-		attrs: commonAttrs,
-		baseName: m.Name(),
+		deps:      deps,
+		attrs:     commonAttrs,
+		baseName:  m.Name(),
 		hasKotlin: bp2BuildInfo.hasKotlin,
 	}
 	libName := createLibraryTarget(ctx, libInfo)
@@ -3189,9 +3182,9 @@
 	}
 
 	libInfo := libraryCreationInfo{
-		deps: deps,
-		attrs: commonAttrs,
-		baseName: m.Name(),
+		deps:      deps,
+		attrs:     commonAttrs,
+		baseName:  m.Name(),
 		hasKotlin: bp2BuildInfo.hasKotlin,
 	}
 	libName := createLibraryTarget(ctx, libInfo)
@@ -3204,9 +3197,9 @@
 // libraryCreationInfo encapsulates the info needed to create java_library target from
 // java_binary_host or java_test_host.
 type libraryCreationInfo struct {
-	deps bazel.LabelListAttribute
-	attrs *javaCommonAttributes
-	baseName string
+	deps      bazel.LabelListAttribute
+	attrs     *javaCommonAttributes
+	baseName  string
 	hasKotlin bool
 }
 
diff --git a/java/kotlin.go b/java/kotlin.go
index 9bff5ea..f28d6c7 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -30,7 +30,7 @@
 	blueprint.RuleParams{
 		Command: `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
 			`mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` +
-			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
+			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` +
 			`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
 			` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
 			` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 89da19a..3de8238 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -24,6 +24,7 @@
 	"strings"
 	"sync"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -236,6 +237,10 @@
 	return scope.stubsLibraryModuleName(baseName) + ".from-text"
 }
 
+func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string {
+	return scope.stubsLibraryModuleName(baseName) + ".from-source"
+}
+
 func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
 	return baseName + scope.stubsLibraryModuleNameSuffix()
 }
@@ -861,6 +866,13 @@
 	return c.namingScheme.apiLibraryModuleName(apiScope, baseName)
 }
 
+// Name of the java_library module that compiles the stubs
+// generated from source Java files.
+func (c *commonToSdkLibraryAndImport) sourceStubLibraryModuleName(apiScope *apiScope) string {
+	baseName := c.module.BaseModuleName()
+	return c.namingScheme.sourceStubLibraryModuleName(apiScope, baseName)
+}
+
 // The component names for different outputs of the java_sdk_library.
 //
 // They are similar to the names used for the child modules it creates
@@ -1287,10 +1299,7 @@
 	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
 		// Add dependencies to the stubs library
 		stubModuleName := module.stubsLibraryModuleName(apiScope)
-		// Use JavaApiLibraryName function to be redirected to stubs generated from .txt if applicable
-		if module.contributesToApiSurface(ctx.Config()) {
-			stubModuleName = android.JavaApiLibraryName(ctx.Config(), stubModuleName)
-		}
+
 		ctx.AddVariationDependencies(nil, apiScope.stubsTag, stubModuleName)
 
 		// Add a dependency on the stubs source in order to access both stubs source and api information.
@@ -1582,7 +1591,7 @@
 		}
 	}{}
 
-	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+	props.Name = proptools.StringPtr(module.sourceStubLibraryModuleName(apiScope))
 	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
 	// sources are generated from the droiddoc
 	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
@@ -1604,21 +1613,6 @@
 	// interop with older developer tools that don't support 1.9.
 	props.Java_version = proptools.StringPtr("1.8")
 
-	// The imports need to be compiled to dex if the java_sdk_library requests it.
-	compileDex := module.dexProperties.Compile_dex
-	if module.stubLibrariesCompiledForDex() {
-		compileDex = proptools.BoolPtr(true)
-	}
-	props.Compile_dex = compileDex
-
-	// Dist the class jar artifact for sdk builds.
-	if !Bool(module.sdkLibraryProperties.No_dist) {
-		props.Dist.Targets = []string{"sdk", "win_sdk"}
-		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
-		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
-		props.Dist.Tag = proptools.StringPtr(".jar")
-	}
-
 	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
@@ -1824,6 +1818,53 @@
 	mctx.CreateModule(ApiLibraryFactory, &props)
 }
 
+func (module *SdkLibrary) createTopLevelStubsLibrary(
+	mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) {
+	props := struct {
+		Name           *string
+		Visibility     []string
+		Sdk_version    *string
+		Static_libs    []string
+		System_modules *string
+		Dist           struct {
+			Targets []string
+			Dest    *string
+			Dir     *string
+			Tag     *string
+		}
+		Compile_dex *bool
+	}{}
+	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
+	props.Sdk_version = proptools.StringPtr(sdkVersion)
+
+	// Add the stub compiling java_library/java_api_library as static lib based on build config
+	staticLib := module.sourceStubLibraryModuleName(apiScope)
+	if mctx.Config().BuildFromTextStub() && contributesToApiSurface {
+		staticLib = module.apiLibraryModuleName(apiScope)
+	}
+	props.Static_libs = append(props.Static_libs, staticLib)
+	props.System_modules = module.deviceProperties.System_modules
+
+	// Dist the class jar artifact for sdk builds.
+	if !Bool(module.sdkLibraryProperties.No_dist) {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
+		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
+		props.Dist.Tag = proptools.StringPtr(".jar")
+	}
+
+	// The imports need to be compiled to dex if the java_sdk_library requests it.
+	compileDex := module.dexProperties.Compile_dex
+	if module.stubLibrariesCompiledForDex() {
+		compileDex = proptools.BoolPtr(true)
+	}
+	props.Compile_dex = compileDex
+
+	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
 func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
 	return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api)
 }
@@ -2021,9 +2062,12 @@
 
 		module.createStubsLibrary(mctx, scope)
 
-		if module.contributesToApiSurface(mctx.Config()) {
+		contributesToApiSurface := module.contributesToApiSurface(mctx.Config())
+		if contributesToApiSurface {
 			module.createApiLibrary(mctx, scope)
 		}
+
+		module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface)
 	}
 
 	if module.requiresRuntimeImplementationLibrary() {
@@ -2078,6 +2122,8 @@
 	stubsSourceModuleName(scope *apiScope, baseName string) string
 
 	apiLibraryModuleName(scope *apiScope, baseName string) string
+
+	sourceStubLibraryModuleName(scope *apiScope, baseName string) string
 }
 
 type defaultNamingScheme struct {
@@ -2095,9 +2141,15 @@
 	return scope.apiLibraryModuleName(baseName)
 }
 
+func (s *defaultNamingScheme) sourceStubLibraryModuleName(scope *apiScope, baseName string) string {
+	return scope.sourceStubLibraryModuleName(baseName)
+}
+
 var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
 
 func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
+	name = strings.TrimSuffix(name, ".from-source")
+
 	// This suffix-based approach is fragile and could potentially mis-trigger.
 	// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
 	if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) {
@@ -2116,6 +2168,9 @@
 	if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) {
 		return true, javaSystem
 	}
+	if strings.HasSuffix(name, apiScopeSystemServer.stubsLibraryModuleNameSuffix()) {
+		return true, javaSystemServer
+	}
 	return false, javaPlatform
 }
 
@@ -2178,6 +2233,7 @@
 // java_sdk_library bp2build converter
 func (module *SdkLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	if ctx.ModuleType() != "java_sdk_library" {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
 		return
 	}
 
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 141e16b..7ba1f6d 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -411,10 +411,9 @@
 		android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined)
 	}
 	for _, expectation := range expectations {
-		verify("sdklib", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
 		verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
 
-		stubName := apiScopePublic.stubsLibraryModuleName("sdklib")
+		stubName := apiScopePublic.sourceStubLibraryModuleName("sdklib")
 		verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined)
 	}
 }
diff --git a/licenses/Android.bp b/licenses/Android.bp
index dee72ed..d045725 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -1027,42 +1027,42 @@
 
 license_kind {
     name: "SPDX-license-identifier-OFL",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.0",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.0.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.0-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.0-RFN.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.0-no-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.0-no-RFN.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.1",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.1.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.1-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.1-RFN.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.1-no-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.1-no-RFN.html",
 }
 
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 412a23b..165697d 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -19,6 +19,7 @@
 	"sort"
 	"strings"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -109,6 +110,7 @@
 func (l *linkerConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	if l.properties.Src == nil {
 		ctx.PropertyErrorf("src", "empty src is not supported")
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
 		return
 	}
 	src := android.BazelLabelForModuleSrcSingle(ctx, *l.properties.Src)
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index c0ae0c0..8225df6 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -870,7 +870,7 @@
 	}
 
 	// Safeguard against $(call inherit-product,$(PRODUCT_PATH))
-	const maxMatchingFiles = 155 // temporarily increased to 155 for b/284854738
+	const maxMatchingFiles = 150
 	if len(matchingPaths) > maxMatchingFiles {
 		return []starlarkNode{ctx.newBadNode(v, "there are >%d files matching the pattern, please rewrite it", maxMatchingFiles)}
 	}
diff --git a/rust/builder.go b/rust/builder.go
index 0dfaef4..bf009a5 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -324,6 +324,7 @@
 			envVars = append(envVars, "CARGO_BIN_NAME="+strings.TrimSuffix(outputFile.Base(), outputFile.Ext()))
 		}
 		envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
+		envVars = append(envVars, "CARGO_PKG_NAME="+ctx.RustModule().CrateName())
 		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
 		if pkgVersion != "" {
 			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
diff --git a/rust/config/global.go b/rust/config/global.go
index 60acc6e..f838d0e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var pctx = android.NewPackageContext("android/soong/rust/config")
 
 var (
-	RustDefaultVersion = "1.69.0"
+	RustDefaultVersion = "1.70.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 7fa9f5c..0aecf61 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -19,6 +19,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 func TestRustFuzz(t *testing.T) {
@@ -59,3 +60,68 @@
 		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 }
+
+func TestRustFuzzDepBundling(t *testing.T) {
+	ctx := testRust(t, `
+			cc_library {
+				name: "libcc_transitive_dep",
+			}
+			cc_library {
+				name: "libcc_direct_dep",
+			}
+			rust_library {
+				name: "libtest_fuzzing",
+				crate_name: "test_fuzzing",
+				srcs: ["foo.rs"],
+				shared_libs: ["libcc_transitive_dep"],
+			}
+			rust_fuzz {
+				name: "fuzz_libtest",
+				srcs: ["foo.rs"],
+				rustlibs: ["libtest_fuzzing"],
+				shared_libs: ["libcc_direct_dep"],
+			}
+	`)
+
+	fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module)
+
+	if !strings.Contains(fuzz_libtest.FuzzSharedLibraries().String(), ":libcc_direct_dep.so") {
+		t.Errorf("rust_fuzz does not contain the expected bundled direct shared libs ('libcc_direct_dep'): %#v", fuzz_libtest.FuzzSharedLibraries().String())
+	}
+	if !strings.Contains(fuzz_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
+		t.Errorf("rust_fuzz does not contain the expected bundled transitive shared libs ('libcc_transitive_dep'): %#v", fuzz_libtest.FuzzSharedLibraries().String())
+	}
+}
+
+func TestCCFuzzDepBundling(t *testing.T) {
+	ctx := testRust(t, `
+			cc_library {
+				name: "libcc_transitive_dep",
+			}
+			rust_ffi {
+				name: "libtest_fuzzing",
+				crate_name: "test_fuzzing",
+				srcs: ["foo.rs"],
+				shared_libs: ["libcc_transitive_dep"],
+			}
+			cc_fuzz {
+				name: "fuzz_shared_libtest",
+				shared_libs: ["libtest_fuzzing"],
+			}
+			cc_fuzz {
+				name: "fuzz_static_libtest",
+				static_libs: ["libtest_fuzzing"],
+			}
+
+	`)
+
+	fuzz_shared_libtest := ctx.ModuleForTests("fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
+	fuzz_static_libtest := ctx.ModuleForTests("fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
+
+	if !strings.Contains(fuzz_shared_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
+		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_shared ('libcc_transitive_dep'): %#v", fuzz_shared_libtest.FuzzSharedLibraries().String())
+	}
+	if !strings.Contains(fuzz_static_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
+		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_static_libtest.FuzzSharedLibraries().String())
+	}
+}
diff --git a/rust/library.go b/rust/library.go
index a3a5672..ca5ad14 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -25,8 +25,7 @@
 )
 
 var (
-	DylibStdlibSuffix = ".dylib-std"
-	RlibStdlibSuffix  = ".rlib-std"
+	RlibStdlibSuffix = ".rlib-std"
 )
 
 func init() {
@@ -756,7 +755,6 @@
 					dylib.Disable()
 				}
 				rlib.Properties.RustSubName += RlibStdlibSuffix
-				dylib.Properties.RustSubName += DylibStdlibSuffix
 			}
 		}
 	}
diff --git a/rust/library_test.go b/rust/library_test.go
index d4b525f..add7173 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -247,10 +247,10 @@
 		if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
 			t.Errorf("libbar not present as dynamic dependency in dynamic lib")
 		}
-		if android.InList("libbar.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
+		if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
 			t.Errorf("libbar present as rlib dependency in dynamic lib")
 		}
-		if !android.InList("librlib_only.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
+		if !android.InList("librlib_only", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
 			t.Errorf("librlib_only should be selected by rustlibs as an rlib.")
 		}
 	}
diff --git a/rust/rust.go b/rust/rust.go
index 4324ecb..e524c9f 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -631,6 +631,15 @@
 	return false
 }
 
+func (mod *Module) RustLibraryInterface() bool {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(libraryInterface); ok {
+			return true
+		}
+	}
+	return false
+}
+
 func (mod *Module) IsFuzzModule() bool {
 	if _, ok := mod.compiler.(*fuzzDecorator); ok {
 		return true
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 2a38b89..64f90b6 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -377,11 +377,11 @@
 
 	// Check that our bindings are picked up as crate dependencies as well
 	libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
-	if !android.InList("libbindings.dylib-std", libfooMod.Properties.AndroidMkRlibs) {
+	if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) {
 		t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
 	}
 	fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module)
-	if !android.InList("libbindings.dylib-std", fizzBuzzMod.Properties.AndroidMkRlibs) {
+	if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) {
 		t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
 	}
 	libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module)
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 83cf055..0f7cf6e 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -62,8 +62,7 @@
 	"-C llvm-args=-sanitizer-coverage-level=3",
 	"-C llvm-args=-sanitizer-coverage-trace-compares",
 	"-C llvm-args=-sanitizer-coverage-inline-8bit-counters",
-	"-C llvm-args=-sanitizer-coverage-trace-geps",
-	"-C llvm-args=-sanitizer-coverage-prune-blocks=0",
+	"-C llvm-args=-sanitizer-coverage-pc-table",
 
 	// See https://github.com/rust-fuzz/cargo-fuzz/pull/193
 	"-C link-dead-code",
diff --git a/scripts/unpack-prebuilt-apex.sh b/scripts/unpack-prebuilt-apex.sh
index b244f79..2a20e45 100755
--- a/scripts/unpack-prebuilt-apex.sh
+++ b/scripts/unpack-prebuilt-apex.sh
@@ -18,17 +18,16 @@
 
 # Tool to unpack an apex file and verify that the required files were extracted.
 if [ $# -lt 7 ]; then
-  echo "usage: $0 <deapaxer_path> <debugfs_path> <blkid_path> <fsck.erofs_path> <apex file> <output_dir> <required_files>+" >&2
+  echo "usage: $0 <deapaxer_path> <debugfs_path> <fsck.erofs_path> <apex file> <output_dir> <required_files>+" >&2
   exit 1
 fi
 
 DEAPEXER_PATH=$1
 DEBUGFS_PATH=$2
-BLKID_PATH=$3
-FSCK_EROFS_PATH=$4
-APEX_FILE=$5
-OUTPUT_DIR=$6
-shift 6
+FSCK_EROFS_PATH=$3
+APEX_FILE=$4
+OUTPUT_DIR=$5
+shift 5
 REQUIRED_PATHS=$@
 
 rm -fr $OUTPUT_DIR
@@ -36,7 +35,6 @@
 
 # Unpack the apex file contents.
 $DEAPEXER_PATH --debugfs_path $DEBUGFS_PATH \
-               --blkid_path $BLKID_PATH \
                --fsckerofs_path $FSCK_EROFS_PATH \
                extract $APEX_FILE $OUTPUT_DIR
 
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index bef82d6..894109a 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -489,13 +489,13 @@
 .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
 .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/android_common/combined/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
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs/android_common/combined/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
 .intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
 .intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
 `)
@@ -509,13 +509,13 @@
 .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
 .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/android_common/combined/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
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs/android_common/combined/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
 .intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
 .intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
 `
@@ -963,10 +963,10 @@
 .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
 .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/android_common/combined/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
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
 `),
@@ -1095,7 +1095,7 @@
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/stub-flags.csv -> hiddenapi/stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
 `
@@ -1173,10 +1173,10 @@
 .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
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mynewsdklibrary.stubs/android_common/javac/mynewsdklibrary.stubs.jar -> sdk_library/public/mynewsdklibrary-stubs.jar
+.intermediates/mynewsdklibrary.stubs/android_common/combined/mynewsdklibrary.stubs.jar -> sdk_library/public/mynewsdklibrary-stubs.jar
 .intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_api.txt -> sdk_library/public/mynewsdklibrary.txt
 .intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_removed.txt -> sdk_library/public/mynewsdklibrary-removed.txt
 `
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 6159ea9..c018671 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -696,7 +696,7 @@
 		checkAllCopyRules(`
 .intermediates/exported-system-module/android_common/turbine-combined/exported-system-module.jar -> java/exported-system-module.jar
 .intermediates/system-module/android_common/turbine-combined/system-module.jar -> java/system-module.jar
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
@@ -941,13 +941,13 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.system/android_common/combined/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
 .intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.test/android_common/javac/myjavalib.stubs.test.jar -> sdk_library/test/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.test/android_common/combined/myjavalib.stubs.test.jar -> sdk_library/test/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.test/android_common/metalava/myjavalib.stubs.source.test_api.txt -> sdk_library/test/myjavalib.txt
 .intermediates/myjavalib.stubs.source.test/android_common/metalava/myjavalib.stubs.source.test_removed.txt -> sdk_library/test/myjavalib-removed.txt
 `),
@@ -999,7 +999,7 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib-foo.stubs/android_common/javac/myjavalib-foo.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib-foo.stubs/android_common/combined/myjavalib-foo.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
@@ -1052,7 +1052,7 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source-stubs.srcjar -> sdk_library/public/myjavalib.srcjar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
@@ -1100,7 +1100,7 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_annotations.zip -> sdk_library/public/myjavalib_annotations.zip
@@ -1153,7 +1153,7 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 		`),
@@ -1270,7 +1270,7 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
@@ -1318,7 +1318,7 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
@@ -1376,10 +1376,10 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.system/android_common/combined/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
 .intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
 `),
@@ -1448,13 +1448,13 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.system/android_common/combined/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
 .intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.module_lib/android_common/combined/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.module_lib/android_common/metalava/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
 .intermediates/myjavalib.stubs.source.module_lib/android_common/metalava/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
 `),
@@ -1514,10 +1514,10 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system_server/android_common/javac/myjavalib.stubs.system_server.jar -> sdk_library/system-server/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.system_server/android_common/combined/myjavalib.stubs.system_server.jar -> sdk_library/system-server/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.system_server/android_common/metalava/myjavalib.stubs.source.system_server_api.txt -> sdk_library/system-server/myjavalib.txt
 .intermediates/myjavalib.stubs.source.system_server/android_common/metalava/myjavalib.stubs.source.system_server_removed.txt -> sdk_library/system-server/myjavalib-removed.txt
 `),
@@ -1568,7 +1568,7 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
@@ -1625,7 +1625,7 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
 .intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 docs/known_doctags -> doctags/docs/known_doctags
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 108a664..5a25146 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -487,7 +487,7 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
 `),
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 71e6af0..090114b 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -232,6 +232,63 @@
   eval "${_save_trap}"
 }
 
+function test_build_files_take_precedence {
+  _save_trap=$(trap -p EXIT)
+  trap '[[ $? -ne 0 ]] && echo Are you running this locally? Try changing --sandbox_tmpfs_path to something other than /tmp/ in build/bazel/linux.bazelrc.' EXIT
+  _build_files_take_precedence
+  eval "${_save_trap}"
+}
+
+function _build_files_take_precedence {
+  setup
+
+  # This specific directory is hardcoded in bp2build as being one
+  # where the BUILD file should be intentionally kept.
+  mkdir -p testpkg/keep_build_file
+  cat > testpkg/keep_build_file/Android.bp <<'EOF'
+genrule {
+    name: "print_origin",
+    cmd: "echo 'from_soong' > $(out)",
+    out: [
+        "origin.txt",
+    ],
+    bazel_module: {
+        bp2build_available: true,
+    },
+  }
+EOF
+
+  run_soong bp2build
+  run_bazel build --config=android --config=bp2build --config=ci //testpkg/keep_build_file:print_origin
+
+  local -r output_file="$(find -L bazel-out -name origin.txt)"
+  if [[ ! -f "${output_file}" ]]; then
+    fail "Expected origin.txt to be generated, but was missing"
+  fi
+  if ! grep from_soong "${output_file}"; then
+    fail "Expected to find 'from_soong' in '${output_file}'"
+  fi
+
+  cat > testpkg/keep_build_file/BUILD.bazel <<'EOF'
+genrule(
+    name = "print_origin",
+    outs = ["origin.txt"],
+    cmd = "echo 'from_bazel' > $@",
+)
+EOF
+
+  # Clean the workspace. There is a test infrastructure bug where run_bazel
+  # will symlink Android.bp files in the source directory again and thus
+  # pollute the workspace.
+  # TODO: b/286059878 - Remove this clean after the underlying bug is fixed.
+  run_soong clean
+  run_soong bp2build
+  run_bazel build --config=android --config=bp2build --config=ci //testpkg/keep_build_file:print_origin
+  if ! grep from_bazel "${output_file}"; then
+    fail "Expected to find 'from_bazel' in '${output_file}'"
+  fi
+}
+
 function test_bp2build_symlinks_files {
   setup
   mkdir -p foo
@@ -382,4 +439,39 @@
   run_bazel build --config=android --config=api_bp2build //foo:libfoo.contribution
 }
 
+function test_bazel_standalone_output_paths_contain_product_name {
+  setup
+  mkdir -p a
+  cat > a/Android.bp <<EOF
+cc_object {
+  name: "qq",
+  srcs: ["qq.cc"],
+  bazel_module: {
+    bp2build_available: true,
+  },
+  stl: "none",
+  system_shared_libs: [],
+}
+EOF
+
+  cat > a/qq.cc <<EOF
+#include "qq.h"
+int qq() {
+  return QQ;
+}
+EOF
+
+  cat > a/qq.h <<EOF
+#define QQ 1
+EOF
+
+  export TARGET_PRODUCT=aosp_arm; run_soong bp2build
+  local -r output=$(run_bazel cquery //a:qq --output=files --config=android --config=bp2build --config=ci)
+  if [[ ! $(echo ${output} | grep "bazel-out/aosp_arm") ]]; then
+    fail "Did not find the product name '${TARGET_PRODUCT}' in the output path. This can cause " \
+      "unnecessary rebuilds when toggling between products as bazel outputs for different products will " \
+      "clobber each other. Output paths are: \n${output}"
+  fi
+}
+
 scan_and_run_tests
diff --git a/tests/genrule_sandbox_test.py b/tests/genrule_sandbox_test.py
new file mode 100755
index 0000000..a9f0c9b
--- /dev/null
+++ b/tests/genrule_sandbox_test.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2023 The Android Open Source Project
+#
+# 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.
+
+import argparse
+import collections
+import json
+import os.path
+import subprocess
+import tempfile
+
+SRC_ROOT_DIR = os.path.abspath(__file__ + "/../../../..")
+
+
+def _module_graph_path(out_dir):
+  return os.path.join(SRC_ROOT_DIR, out_dir, "soong", "module-actions.json")
+
+
+def _build_with_soong(targets, target_product, out_dir, extra_env={}):
+  env = {
+      "TARGET_PRODUCT": target_product,
+      "TARGET_BUILD_VARIANT": "userdebug",
+  }
+  env.update(os.environ)
+  env.update(extra_env)
+  args = [
+      "build/soong/soong_ui.bash",
+      "--make-mode",
+      "--skip-soong-tests",
+  ]
+  args.extend(targets)
+  try:
+    out = subprocess.check_output(
+        args,
+        cwd=SRC_ROOT_DIR,
+        env=env,
+    )
+  except subprocess.CalledProcessError as e:
+    print(e)
+    print(e.stdout)
+    print(e.stderr)
+    exit(1)
+
+
+def _find_outputs_for_modules(modules, out_dir, target_product):
+  module_path = os.path.join(
+      SRC_ROOT_DIR, out_dir, "soong", "module-actions.json"
+  )
+
+  if not os.path.exists(module_path):
+    _build_with_soong(["json-module-graph"], target_product, out_dir)
+
+  action_graph = json.load(open(_module_graph_path(out_dir)))
+
+  module_to_outs = collections.defaultdict(set)
+  for mod in action_graph:
+    name = mod["Name"]
+    if name in modules:
+      for act in mod["Module"]["Actions"]:
+        if "}generate" in act["Desc"]:
+          module_to_outs[name].update(act["Outputs"])
+  return module_to_outs
+
+
+def _store_outputs_to_tmp(output_files):
+  try:
+    tempdir = tempfile.TemporaryDirectory()
+    for f in output_files:
+      out = subprocess.check_output(
+          ["cp", "--parents", f, tempdir.name],
+          cwd=SRC_ROOT_DIR,
+      )
+    return tempdir
+  except subprocess.CalledProcessError as e:
+    print(e)
+    print(e.stdout)
+    print(e.stderr)
+
+
+def _diff_outs(file1, file2, show_diff):
+  output = None
+  base_args = ["diff"]
+  if not show_diff:
+    base_args.append("--brief")
+  try:
+    args = base_args + [file1, file2]
+    output = subprocess.check_output(
+        args,
+        cwd=SRC_ROOT_DIR,
+    )
+  except subprocess.CalledProcessError as e:
+    if e.returncode == 1:
+      if show_diff:
+        return output
+      return True
+  return None
+
+
+def _compare_outputs(module_to_outs, tempdir, show_diff):
+  different_modules = collections.defaultdict(list)
+  for module, outs in module_to_outs.items():
+    for out in outs:
+      output = None
+      diff = _diff_outs(os.path.join(tempdir.name, out), out, show_diff)
+      if diff:
+        different_modules[module].append(diff)
+
+  tempdir.cleanup()
+  return different_modules
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      "--target_product",
+      "-t",
+      default="aosp_cf_arm64_phone",
+      help="optional, target product, always runs as eng",
+  )
+  parser.add_argument(
+      "modules",
+      nargs="+",
+      help="modules to compare builds with genrule sandboxing enabled/not",
+  )
+  parser.add_argument(
+      "--show-diff",
+      "-d",
+      action="store_true",
+      required=False,
+      help="whether to display differing files",
+  )
+  parser.add_argument(
+      "--output-paths-only",
+      "-o",
+      action="store_true",
+      required=False,
+      help="Whether to only return the output paths per module",
+  )
+  args = parser.parse_args()
+
+  out_dir = os.environ.get("OUT_DIR", "out")
+  target_product = args.target_product
+  modules = set(args.modules)
+
+  module_to_outs = _find_outputs_for_modules(modules, out_dir, target_product)
+  if not module_to_outs:
+    print("No outputs found")
+    exit(1)
+
+  if args.output_paths_only:
+    for m, o in module_to_outs.items():
+      print(f"{m} outputs: {o}")
+    exit(0)
+
+  all_outs = set()
+  for outs in module_to_outs.values():
+    all_outs.update(outs)
+  print("build without sandboxing")
+  _build_with_soong(list(all_outs), target_product, out_dir)
+  tempdir = _store_outputs_to_tmp(all_outs)
+  print("build with sandboxing")
+  _build_with_soong(
+      list(all_outs),
+      target_product,
+      out_dir,
+      extra_env={"GENRULE_SANDBOXING": "true"},
+  )
+  diffs = _compare_outputs(module_to_outs, tempdir, args.show_diff)
+  if len(diffs) == 0:
+    print("All modules are correct")
+  elif args.show_diff:
+    for m, d in diffs.items():
+      print(f"Module {m} has diffs {d}")
+  else:
+    print(f"Modules {list(diffs.keys())} have diffs")
+
+
+if __name__ == "__main__":
+  main()
diff --git a/tests/genrule_sandbox_test.sh b/tests/genrule_sandbox_test.sh
deleted file mode 100755
index 21b476b..0000000
--- a/tests/genrule_sandbox_test.sh
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2023 The Android Open Source Project
-#
-# 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.
-
-set -e
-
-# Build the given genrule modules with GENRULE_SANDBOXING enabled and disabled,
-# then compare the output of the modules and report result.
-
-function die() { format=$1; shift; printf >&2 "$format\n" $@; exit 1; }
-
-function usage() {
-  die "usage: ${0##*/} <-t lunch_target> [module]..."
-}
-
-if [ ! -e "build/make/core/Makefile" ]; then
-  die "$0 must be run from the top of the Android source tree."
-fi
-
-declare TARGET=
-while getopts "t:" opt; do
-  case $opt in
-    t)
-      TARGET=$OPTARG ;;
-    *) usage ;;
-  esac
-done
-
-shift $((OPTIND-1))
-MODULES="$@"
-
-source build/envsetup.sh
-
-if [[ -n $TARGET ]]; then
-  lunch $TARGET
-fi
-
-if [[ -z ${OUT_DIR+x} ]]; then
-  OUT_DIR="out"
-fi
-
-OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
-PASS=true
-
-function cleanup {
-  if [ $PASS = true ]; then
-    rm -rf "${OUTPUT_DIR}"
-  fi
-}
-trap cleanup EXIT
-
-declare -A GEN_PATH_MAP
-
-function find_gen_paths() {
-  for module in $MODULES; do
-    module_path=$(pathmod "$module")
-    package_path=${module_path#$ANDROID_BUILD_TOP}
-    gen_path=$OUT_DIR/soong/.intermediates$package_path/$module
-    GEN_PATH_MAP[$module]=$gen_path
-  done
-}
-
-function store_outputs() {
-  local dir=$1; shift
-
-  for module in $MODULES; do
-    dest_dir=$dir/${module}
-    mkdir -p $dest_dir
-    gen_path=${GEN_PATH_MAP[$module]}
-    cp -r $gen_path $dest_dir
-  done
-}
-
-function cmp_outputs() {
-  local dir1=$1; shift
-  local dir2=$1; shift
-
-  for module in $MODULES; do
-    if ! diff -rq --exclude=genrule.sbox.textproto $dir1/$module $dir2/$module; then
-      PASS=false
-      echo "$module differ"
-    fi
-  done
-  if [ $PASS = true ]; then
-    echo "Test passed"
-  fi
-}
-
-if [ ! -f "$ANDROID_PRODUCT_OUT/module-info.json" ]; then
-  refreshmod
-fi
-
-find_gen_paths
-m --skip-soong-tests GENRULE_SANDBOXING=true "${MODULES[@]}"
-store_outputs "$OUTPUT_DIR/sandbox"
-m --skip-soong-tests GENRULE_SANDBOXING=false "${MODULES[@]}"
-store_outputs "$OUTPUT_DIR/non_sandbox"
-
-cmp_outputs "$OUTPUT_DIR/non_sandbox" "$OUTPUT_DIR/sandbox"
diff --git a/tests/lib.sh b/tests/lib.sh
index 7f3970e..b5dea99 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -101,6 +101,19 @@
   symlink_directory external/spdx-tools
   symlink_directory libcore
 
+  # TODO: b/286872909 - Remove these when the blocking bug is completed
+  symlink_directory external/libavc
+  symlink_directory external/libaom
+  symlink_directory external/libvpx
+  symlink_directory frameworks/base/libs/androidfw
+  symlink_directory external/libhevc
+  symlink_directory external/libexif
+  symlink_directory external/libopus
+  symlink_directory external/libmpeg2
+  symlink_directory external/expat
+  symlink_directory external/flac
+  symlink_directory system/extras/toolchain-extras
+
   touch "$MOCK_TOP/Android.bp"
 }
 
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index c77b903..43a9f0f 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -9,6 +9,7 @@
 "$TOP/build/soong/tests/bp2build_bazel_test.sh"
 "$TOP/build/soong/tests/persistent_bazel_test.sh"
 "$TOP/build/soong/tests/soong_test.sh"
+"$TOP/build/soong/tests/stale_metrics_files_test.sh"
 "$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug
 
 # The following tests build against the full source tree and don't rely on the
diff --git a/tests/stale_metrics_files_test.sh b/tests/stale_metrics_files_test.sh
new file mode 100755
index 0000000..0da89c3
--- /dev/null
+++ b/tests/stale_metrics_files_test.sh
@@ -0,0 +1,47 @@
+#!/bin/bash -e
+
+# This test ensures that stale metrics files are deleted after each run
+
+# Run bazel
+# Note - bp2build metrics are present after clean runs, only
+build/soong/soong_ui.bash --make-mode clean
+build/bazel/bin/b build libcore:all
+soong_build_metrics_files=("out/soong_build_metrics.pb" "out/build_progress.pb" "out/soong_metrics" "out/bp2build_metrics.pb")
+bazel_build_metrics_files=("out/bazel_metrics.pb" "out/build_progress.pb" "out/soong_metrics" "out/bp2build_metrics.pb")
+
+# Ensure bazel metrics files are present
+for i in ${!bazel_build_metrics_files[@]};
+do
+  file=${bazel_build_metrics_files[$i]}
+  if [[ ! -f $file ]]; then
+     echo "Missing metrics file for Bazel build " $file
+     exit 1
+  fi
+done
+
+
+# Run a soong build
+build/soong/soong_ui.bash --make-mode nothing
+
+for i in ${!soong_build_metrics_files[@]};
+do
+  file=${soong_build_metrics_files[$i]}
+  if [[ ! -f $file ]]; then
+     echo "Missing metrics file for Soong build " $file
+     exit 1
+  fi
+done
+
+# Ensure that bazel_metrics.pb is deleted
+if [[ -f out/bazel_metrics.pb ]]; then
+   echo "Stale out/bazel_metrics.pb file detected"
+   exit 1
+fi
+
+# Run bazel again - to make sure that soong_build_metrics.pb gets deleted
+build/bazel/bin/b build libcore:all
+
+if [[ -f out/soong_build_metrics.pb ]]; then
+   echo "Stale out/soong_build_metrics.pb file detected"
+   exit 1
+fi
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 3c55c51..ddd0a80 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -167,7 +167,6 @@
 	for _, c := range options.OptionsForAutogenerated {
 		configs = append(configs, c)
 	}
-	testRunnerConfigs := append([]Option{}, options.TestRunnerOptions...)
 	name := options.Name
 	if name == "" {
 		name = ctx.ModuleName()
@@ -176,15 +175,15 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, options.TestConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+			autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+				autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 			} else {
 				if Bool(options.UnitTest) {
-					autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+					autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 				} else {
-					autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+					autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 				}
 			}
 		}
diff --git a/ui/build/bazel_metrics.go b/ui/build/bazel_metrics.go
index c0690c1..3f9fbb1 100644
--- a/ui/build/bazel_metrics.go
+++ b/ui/build/bazel_metrics.go
@@ -121,6 +121,7 @@
 			}
 		}
 		bazelMetrics.PhaseTimings = phaseTimings
+		bazelMetrics.BesId = proto.String(config.besId)
 
 		return bazelMetrics
 	}
diff --git a/ui/build/build.go b/ui/build/build.go
index 6874ef7..14d23a7 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -114,15 +114,12 @@
 	if config.bazelProdMode {
 		count++
 	}
-	if config.bazelDevMode {
-		count++
-	}
 	if config.bazelStagingMode {
 		count++
 	}
 	if count > 1 {
 		ctx.Fatalln("Conflicting bazel mode.\n" +
-			"Do not specify more than one of --bazel-mode and --bazel-mode-dev and --bazel-mode-staging ")
+			"Do not specify more than one of --bazel-mode and --bazel-mode-staging ")
 	}
 }
 
diff --git a/ui/build/config.go b/ui/build/config.go
index bc0ab33..80038f5 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -42,7 +42,7 @@
 	jsonSuffix   = "json"
 
 	configFetcher         = "vendor/google/tools/soong/expconfigfetcher"
-	envConfigFetchTimeout = 10 * time.Second
+	envConfigFetchTimeout = 20 * time.Second
 )
 
 var (
@@ -90,8 +90,9 @@
 	skipMetricsUpload        bool
 	buildStartedTime         int64 // For metrics-upload-only - manually specify a build-started time
 	buildFromTextStub        bool
-	ensureAllowlistIntegrity bool  // For CI builds - make sure modules are mixed-built
-	bazelExitCode            int32 // For b-runs - necessary for updating NonZeroExit
+	ensureAllowlistIntegrity bool   // For CI builds - make sure modules are mixed-built
+	bazelExitCode            int32  // For b runs - necessary for updating NonZeroExit
+	besId                    string // For b runs, to identify the BuildEventService logs
 
 	// From the product config
 	katiArgs        []string
@@ -111,7 +112,6 @@
 	pathReplaced bool
 
 	bazelProdMode    bool
-	bazelDevMode     bool
 	bazelStagingMode bool
 
 	// Set by multiproduct_kati
@@ -853,8 +853,6 @@
 			c.multitreeBuild = true
 		} else if arg == "--bazel-mode" {
 			c.bazelProdMode = true
-		} else if arg == "--bazel-mode-dev" {
-			c.bazelDevMode = true
 		} else if arg == "--bazel-mode-staging" {
 			c.bazelStagingMode = true
 		} else if arg == "--search-api-dir" {
@@ -911,6 +909,8 @@
 			} else {
 				ctx.Fatalf("Error parsing bazel-exit-code", err)
 			}
+		} else if strings.HasPrefix(arg, "--bes-id=") {
+			c.besId = strings.TrimPrefix(arg, "--bes-id=")
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -960,7 +960,7 @@
 			c.arguments = append(c.arguments, arg)
 		}
 	}
-	if (!c.bazelProdMode) && (!c.bazelDevMode) && (!c.bazelStagingMode) {
+	if (!c.bazelProdMode) && (!c.bazelStagingMode) {
 		c.bazelProdMode = defaultBazelProdMode(c)
 	}
 }
@@ -1124,6 +1124,9 @@
 }
 
 func (c *configImpl) UsedEnvFile(tag string) string {
+	if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
+		return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+"."+tag)
+	}
 	return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag)
 }
 
@@ -1382,7 +1385,7 @@
 }
 
 func (c *configImpl) BazelBuildEnabled() bool {
-	return c.bazelProdMode || c.bazelDevMode || c.bazelStagingMode
+	return c.bazelProdMode || c.bazelStagingMode
 }
 
 func (c *configImpl) StartRBE() bool {
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index a1eccf0..545f727 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -1018,7 +1018,6 @@
 		environ             Environment
 		arguments           []string
 		useBazel            bool
-		bazelDevMode        bool
 		bazelProdMode       bool
 		bazelStagingMode    bool
 		expectedBuildConfig *smpb.BuildConfig
@@ -1097,19 +1096,6 @@
 			},
 		},
 		{
-			name:         "bazel mixed build from dev mode",
-			environ:      Environment{},
-			bazelDevMode: true,
-			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(true),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
-			},
-		},
-		{
 			name:          "bazel mixed build from prod mode",
 			environ:       Environment{},
 			bazelProdMode: true,
@@ -1158,8 +1144,8 @@
 				"USE_RBE=1",
 				"BUILD_BROKEN_DISABLE_BAZEL=1",
 			},
-			useBazel:     true,
-			bazelDevMode: true,
+			useBazel:      true,
+			bazelProdMode: true,
 			expectedBuildConfig: &smpb.BuildConfig{
 				ForceUseGoma:                proto.Bool(true),
 				UseGoma:                     proto.Bool(true),
@@ -1176,7 +1162,6 @@
 		t.Run(tc.name, func(t *testing.T) {
 			c := &configImpl{
 				environ:          &tc.environ,
-				bazelDevMode:     tc.bazelDevMode,
 				bazelProdMode:    tc.bazelProdMode,
 				bazelStagingMode: tc.bazelStagingMode,
 				arguments:        tc.arguments,
diff --git a/ui/build/soong.go b/ui/build/soong.go
index b14208e..07d6188 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -272,9 +272,6 @@
 	if config.bazelProdMode {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode")
 	}
-	if config.bazelDevMode {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-dev")
-	}
 	if config.bazelStagingMode {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-staging")
 	}
@@ -448,7 +445,10 @@
 
 	// since `bootstrap.ninja` is regenerated unconditionally, we ignore the deps, i.e. little
 	// reason to write a `bootstrap.ninja.d` file
-	_ = bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
+	_, err := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
+	if err != nil {
+		ctx.Fatal(err)
+	}
 }
 
 func checkEnvironmentFile(ctx Context, currentEnv *Environment, envFile string) {
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
index bf5e80b..8b97b83 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
@@ -42,6 +42,7 @@
 	PhaseTimings []*PhaseTiming `protobuf:"bytes,1,rep,name=phase_timings,json=phaseTimings,proto3" json:"phase_timings,omitempty"`
 	Total        *int64         `protobuf:"varint,2,opt,name=total,proto3,oneof" json:"total,omitempty"`
 	ExitCode     *int32         `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"`
+	BesId        *string        `protobuf:"bytes,4,opt,name=bes_id,json=besId,proto3,oneof" json:"bes_id,omitempty"`
 }
 
 func (x *BazelMetrics) Reset() {
@@ -97,6 +98,13 @@
 	return 0
 }
 
+func (x *BazelMetrics) GetBesId() string {
+	if x != nil && x.BesId != nil {
+		return *x.BesId
+	}
+	return ""
+}
+
 type PhaseTiming struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -169,7 +177,7 @@
 	0x0a, 0x13, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
 	0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x22, 0xb0, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x22, 0xd7, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
 	0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e,
 	0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
 	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74,
@@ -178,25 +186,28 @@
 	0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
 	0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x78, 0x69,
 	0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x08,
-	0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f,
-	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63,
-	0x6f, 0x64, 0x65, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
-	0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
-	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65,
-	0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74,
-	0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48,
-	0x01, 0x52, 0x0d, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73,
-	0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x15, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f,
-	0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x05, 0x48, 0x02, 0x52, 0x12, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x66, 0x42,
-	0x75, 0x69, 0x6c, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f,
-	0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64,
-	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x42, 0x18, 0x0a,
-	0x16, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69,
-	0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x2e, 0x5a, 0x2c, 0x61, 0x6e, 0x64, 0x72, 0x6f,
-	0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x2f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
-	0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x06, 0x62,
+	0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x62,
+	0x65, 0x73, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f, 0x74, 0x61,
+	0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x42,
+	0x09, 0x0a, 0x07, 0x5f, 0x62, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50,
+	0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68,
+	0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
+	0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a,
+	0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x0d, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x15, 0x70, 0x6f,
+	0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74,
+	0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, 0x12, 0x70, 0x6f, 0x72,
+	0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x66, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x88,
+	0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
+	0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e,
+	0x61, 0x6e, 0x6f, 0x73, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e,
+	0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x2e,
+	0x5a, 0x2c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f,
+	0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x62, 0x61, 0x7a, 0x65, 0x6c,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
index 9073080..e45d2bf 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
@@ -21,6 +21,7 @@
   repeated PhaseTiming phase_timings = 1;
   optional int64 total = 2;
   optional int32 exit_code = 3;
+  optional string bes_id = 4;
 }
 
 message PhaseTiming {
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
index 4821043..b34c2b6 100644
--- a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
@@ -14,8 +14,8 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.0
-// 	protoc        v3.21.7
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
 // source: bp2build_metrics.proto
 
 package bp2build_metrics_proto
@@ -34,6 +34,78 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
+type UnconvertedReasonType int32
+
+const (
+	// Bp2build does not know how to convert this specific module for some reason
+	// not covered by other reason types. The reason detail should explain the
+	// specific issue.
+	UnconvertedReasonType_UNSUPPORTED UnconvertedReasonType = 0
+	// The module was already defined in a BUILD file available in the source tree.
+	UnconvertedReasonType_DEFINED_IN_BUILD_FILE UnconvertedReasonType = 1
+	// The module was explicitly denylisted by name.
+	UnconvertedReasonType_DENYLISTED UnconvertedReasonType = 2
+	// The module's type has no bp2build implementation.
+	UnconvertedReasonType_TYPE_UNSUPPORTED UnconvertedReasonType = 3
+	// The module has a property not yet supported. The detail field should
+	// name the unsupported property name.
+	UnconvertedReasonType_PROPERTY_UNSUPPORTED UnconvertedReasonType = 4
+	// The module has an unconverted dependency. The detail should consist of
+	// the name of the unconverted module.
+	UnconvertedReasonType_UNCONVERTED_DEP UnconvertedReasonType = 5
+	// The module has a source file with the same name as the module itself.
+	UnconvertedReasonType_SRC_NAME_COLLISION UnconvertedReasonType = 6
+)
+
+// Enum value maps for UnconvertedReasonType.
+var (
+	UnconvertedReasonType_name = map[int32]string{
+		0: "UNSUPPORTED",
+		1: "DEFINED_IN_BUILD_FILE",
+		2: "DENYLISTED",
+		3: "TYPE_UNSUPPORTED",
+		4: "PROPERTY_UNSUPPORTED",
+		5: "UNCONVERTED_DEP",
+		6: "SRC_NAME_COLLISION",
+	}
+	UnconvertedReasonType_value = map[string]int32{
+		"UNSUPPORTED":           0,
+		"DEFINED_IN_BUILD_FILE": 1,
+		"DENYLISTED":            2,
+		"TYPE_UNSUPPORTED":      3,
+		"PROPERTY_UNSUPPORTED":  4,
+		"UNCONVERTED_DEP":       5,
+		"SRC_NAME_COLLISION":    6,
+	}
+)
+
+func (x UnconvertedReasonType) Enum() *UnconvertedReasonType {
+	p := new(UnconvertedReasonType)
+	*p = x
+	return p
+}
+
+func (x UnconvertedReasonType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UnconvertedReasonType) Descriptor() protoreflect.EnumDescriptor {
+	return file_bp2build_metrics_proto_enumTypes[0].Descriptor()
+}
+
+func (UnconvertedReasonType) Type() protoreflect.EnumType {
+	return &file_bp2build_metrics_proto_enumTypes[0]
+}
+
+func (x UnconvertedReasonType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UnconvertedReasonType.Descriptor instead.
+func (UnconvertedReasonType) EnumDescriptor() ([]byte, []int) {
+	return file_bp2build_metrics_proto_rawDescGZIP(), []int{0}
+}
+
 type Bp2BuildMetrics struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -53,6 +125,8 @@
 	RuleClassCount map[string]uint64 `protobuf:"bytes,4,rep,name=ruleClassCount,proto3" json:"ruleClassCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
 	// List of converted modules
 	ConvertedModules []string `protobuf:"bytes,5,rep,name=convertedModules,proto3" json:"convertedModules,omitempty"`
+	// Unconverted modules, mapped to the reason the module was not converted.
+	UnconvertedModules map[string]*UnconvertedReason `protobuf:"bytes,11,rep,name=unconvertedModules,proto3" json:"unconvertedModules,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	// Counts of converted modules by module type.
 	ConvertedModuleTypeCount map[string]uint64 `protobuf:"bytes,6,rep,name=convertedModuleTypeCount,proto3" json:"convertedModuleTypeCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
 	// Counts of total modules by module type.
@@ -143,6 +217,13 @@
 	return nil
 }
 
+func (x *Bp2BuildMetrics) GetUnconvertedModules() map[string]*UnconvertedReason {
+	if x != nil {
+		return x.UnconvertedModules
+	}
+	return nil
+}
+
 func (x *Bp2BuildMetrics) GetConvertedModuleTypeCount() map[string]uint64 {
 	if x != nil {
 		return x.ConvertedModuleTypeCount
@@ -233,13 +314,72 @@
 	return 0
 }
 
+type UnconvertedReason struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The type of reason that the module could not be converted.
+	Type UnconvertedReasonType `protobuf:"varint,1,opt,name=type,proto3,enum=soong_build_bp2build_metrics.UnconvertedReasonType" json:"type,omitempty"`
+	// Descriptive details describing why the module could not be converted.
+	// This detail should be kept very short and should be in the context of
+	// the type. (Otherwise, this would significantly bloat metrics.)
+	Detail string `protobuf:"bytes,2,opt,name=detail,proto3" json:"detail,omitempty"`
+}
+
+func (x *UnconvertedReason) Reset() {
+	*x = UnconvertedReason{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_bp2build_metrics_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UnconvertedReason) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnconvertedReason) ProtoMessage() {}
+
+func (x *UnconvertedReason) ProtoReflect() protoreflect.Message {
+	mi := &file_bp2build_metrics_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnconvertedReason.ProtoReflect.Descriptor instead.
+func (*UnconvertedReason) Descriptor() ([]byte, []int) {
+	return file_bp2build_metrics_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *UnconvertedReason) GetType() UnconvertedReasonType {
+	if x != nil {
+		return x.Type
+	}
+	return UnconvertedReasonType_UNSUPPORTED
+}
+
+func (x *UnconvertedReason) GetDetail() string {
+	if x != nil {
+		return x.Detail
+	}
+	return ""
+}
+
 var File_bp2build_metrics_proto protoreflect.FileDescriptor
 
 var file_bp2build_metrics_proto_rawDesc = []byte{
 	0x0a, 0x16, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
 	0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
 	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
-	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xd1, 0x07, 0x0a, 0x0f, 0x42, 0x70, 0x32, 0x42, 0x75,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xc0, 0x09, 0x0a, 0x0f, 0x42, 0x70, 0x32, 0x42, 0x75,
 	0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x67, 0x65,
 	0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75,
 	0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
@@ -266,50 +406,84 @@
 	0x79, 0x52, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e,
 	0x74, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f,
 	0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e,
-	0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x87, 0x01,
-	0x0a, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x4b, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62,
-	0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
-	0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
-	0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54,
-	0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x18, 0x63,
-	0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79,
-	0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x7b, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c,
-	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18,
-	0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+	0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x75, 0x0a,
+	0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
+	0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c,
+	0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65,
+	0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64,
+	0x75, 0x6c, 0x65, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
+	0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e,
+	0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
+	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x52, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x7b,
+	0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
+	0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75,
+	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42,
+	0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x6f, 0x74, 0x61,
+	0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x65,
+	0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x6f,
+	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
+	0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x52, 0x75, 0x6c, 0x65,
+	0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+	0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x76, 0x0a, 0x17, 0x55,
+	0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
+	0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
+	0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+	0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
+	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
+	0x1a, 0x47, 0x0a, 0x19, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54,
+	0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x57, 0x0a, 0x05, 0x45, 0x76, 0x65,
+	0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f,
+	0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72,
+	0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69,
+	0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69,
+	0x6d, 0x65, 0x22, 0x74, 0x0a, 0x11, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65,
+	0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
 	0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14,
-	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43,
-	0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x08,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
-	0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
-	0x73, 0x1a, 0x41, 0x0a, 0x13, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f,
-	0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
-	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
-	0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65,
-	0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
-	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
-	0x01, 0x1a, 0x47, 0x0a, 0x19, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
-	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
-	0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x57, 0x0a, 0x05, 0x45, 0x76,
-	0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74,
-	0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61,
-	0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74,
-	0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54,
-	0x69, 0x6d, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73,
-	0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f,
-	0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
+	0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x2a, 0xb0, 0x01, 0x0a, 0x15, 0x55, 0x6e, 0x63,
+	0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x54, 0x79,
+	0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45,
+	0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x5f, 0x49,
+	0x4e, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0e,
+	0x0a, 0x0a, 0x44, 0x45, 0x4e, 0x59, 0x4c, 0x49, 0x53, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x14,
+	0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54,
+	0x45, 0x44, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x50, 0x45, 0x52, 0x54, 0x59,
+	0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x13,
+	0x0a, 0x0f, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x44, 0x45,
+	0x50, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x52, 0x43, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x5f,
+	0x43, 0x4f, 0x4c, 0x4c, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x06, 0x42, 0x31, 0x5a, 0x2f, 0x61,
+	0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f,
+	0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -324,24 +498,31 @@
 	return file_bp2build_metrics_proto_rawDescData
 }
 
-var file_bp2build_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_bp2build_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_bp2build_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
 var file_bp2build_metrics_proto_goTypes = []interface{}{
-	(*Bp2BuildMetrics)(nil), // 0: soong_build_bp2build_metrics.Bp2BuildMetrics
-	(*Event)(nil),           // 1: soong_build_bp2build_metrics.Event
-	nil,                     // 2: soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
-	nil,                     // 3: soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
-	nil,                     // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
+	(UnconvertedReasonType)(0), // 0: soong_build_bp2build_metrics.UnconvertedReasonType
+	(*Bp2BuildMetrics)(nil),    // 1: soong_build_bp2build_metrics.Bp2BuildMetrics
+	(*Event)(nil),              // 2: soong_build_bp2build_metrics.Event
+	(*UnconvertedReason)(nil),  // 3: soong_build_bp2build_metrics.UnconvertedReason
+	nil,                        // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+	nil,                        // 5: soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry
+	nil,                        // 6: soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
+	nil,                        // 7: soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
 }
 var file_bp2build_metrics_proto_depIdxs = []int32{
-	2, // 0: soong_build_bp2build_metrics.Bp2BuildMetrics.ruleClassCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
-	3, // 1: soong_build_bp2build_metrics.Bp2BuildMetrics.convertedModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
-	4, // 2: soong_build_bp2build_metrics.Bp2BuildMetrics.totalModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
-	1, // 3: soong_build_bp2build_metrics.Bp2BuildMetrics.events:type_name -> soong_build_bp2build_metrics.Event
-	4, // [4:4] is the sub-list for method output_type
-	4, // [4:4] is the sub-list for method input_type
-	4, // [4:4] is the sub-list for extension type_name
-	4, // [4:4] is the sub-list for extension extendee
-	0, // [0:4] is the sub-list for field type_name
+	4, // 0: soong_build_bp2build_metrics.Bp2BuildMetrics.ruleClassCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+	5, // 1: soong_build_bp2build_metrics.Bp2BuildMetrics.unconvertedModules:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry
+	6, // 2: soong_build_bp2build_metrics.Bp2BuildMetrics.convertedModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
+	7, // 3: soong_build_bp2build_metrics.Bp2BuildMetrics.totalModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
+	2, // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.events:type_name -> soong_build_bp2build_metrics.Event
+	0, // 5: soong_build_bp2build_metrics.UnconvertedReason.type:type_name -> soong_build_bp2build_metrics.UnconvertedReasonType
+	3, // 6: soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry.value:type_name -> soong_build_bp2build_metrics.UnconvertedReason
+	7, // [7:7] is the sub-list for method output_type
+	7, // [7:7] is the sub-list for method input_type
+	7, // [7:7] is the sub-list for extension type_name
+	7, // [7:7] is the sub-list for extension extendee
+	0, // [0:7] is the sub-list for field type_name
 }
 
 func init() { file_bp2build_metrics_proto_init() }
@@ -374,19 +555,32 @@
 				return nil
 			}
 		}
+		file_bp2build_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UnconvertedReason); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_bp2build_metrics_proto_rawDesc,
-			NumEnums:      0,
-			NumMessages:   5,
+			NumEnums:      1,
+			NumMessages:   7,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
 		GoTypes:           file_bp2build_metrics_proto_goTypes,
 		DependencyIndexes: file_bp2build_metrics_proto_depIdxs,
+		EnumInfos:         file_bp2build_metrics_proto_enumTypes,
 		MessageInfos:      file_bp2build_metrics_proto_msgTypes,
 	}.Build()
 	File_bp2build_metrics_proto = out.File
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
index 9ff4ae2..49cb2b4 100644
--- a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
@@ -39,6 +39,9 @@
   // List of converted modules
   repeated string convertedModules = 5;
 
+  // Unconverted modules, mapped to the reason the module was not converted.
+  map<string, UnconvertedReason> unconvertedModules = 11;
+
   // Counts of converted modules by module type.
   map<string, uint64> convertedModuleTypeCount = 6;
 
@@ -63,3 +66,40 @@
   // The number of nanoseconds elapsed since start_time.
   uint64 real_time = 3;
 }
+
+message UnconvertedReason {
+  // The type of reason that the module could not be converted.
+  UnconvertedReasonType type = 1;
+
+  // Descriptive details describing why the module could not be converted.
+  // This detail should be kept very short and should be in the context of
+  // the type. (Otherwise, this would significantly bloat metrics.)
+  string detail = 2;
+}
+
+enum UnconvertedReasonType {
+  // Bp2build does not know how to convert this specific module for some reason
+  // not covered by other reason types. The reason detail should explain the
+  // specific issue.
+  UNSUPPORTED = 0;
+
+  // The module was already defined in a BUILD file available in the source tree.
+  DEFINED_IN_BUILD_FILE = 1;
+
+  // The module was explicitly denylisted by name.
+  DENYLISTED = 2;
+
+  // The module's type has no bp2build implementation.
+  TYPE_UNSUPPORTED = 3;
+
+  // The module has a property not yet supported. The detail field should
+  // name the unsupported property name.
+  PROPERTY_UNSUPPORTED = 4;
+
+  // The module has an unconverted dependency. The detail should consist of
+  // the name of the unconverted module.
+  UNCONVERTED_DEP = 5;
+
+  // The module has a source file with the same name as the module itself.
+  SRC_NAME_COLLISION = 6;
+}
\ No newline at end of file