Merge "Revert "Added new framework-pdf jar inside MediaProvider module"" into main
diff --git a/README.md b/README.md
index 22daa95..5e9e04a 100644
--- a/README.md
+++ b/README.md
@@ -648,8 +648,8 @@
 SOONG_DELVE=2345 SOONG_DELVE_STEPS='build,modulegraph' m
 ```
 results in only `build` (main build step) and `modulegraph` being run in the debugger.
-The allowed step names are `api_bp2build`, `bp2build_files`, `bp2build_workspace`,
-`build`, `modulegraph`, `queryview`, `soong_docs`.
+The allowed step names are `bp2build_files`, `bp2build_workspace`, `build`,
+`modulegraph`, `queryview`, `soong_docs`.
 
 Note setting or unsetting `SOONG_DELVE` causes a recompilation of `soong_build`. This
 is because in order to debug the binary, it needs to be built with debug
diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go
index 4db0ef7..48cfb76 100644
--- a/aconfig/java_aconfig_library.go
+++ b/aconfig/java_aconfig_library.go
@@ -15,10 +15,13 @@
 package aconfig
 
 import (
-	"android/soong/android"
-	"android/soong/java"
 	"fmt"
+
+	"android/soong/android"
+	"android/soong/bazel"
+	"android/soong/java"
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 type declarationsTagType struct {
@@ -32,7 +35,7 @@
 	Aconfig_declarations string
 
 	// whether to generate test mode version of the library
-	Test bool
+	Test *bool
 }
 
 type JavaAconfigDeclarationsLibraryCallbacks struct {
@@ -68,7 +71,7 @@
 	// Generate the action to build the srcjar
 	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
 	var mode string
-	if callbacks.properties.Test {
+	if proptools.Bool(callbacks.properties.Test) {
 		mode = "test"
 	} else {
 		mode = "production"
@@ -89,3 +92,39 @@
 
 	return srcJarPath
 }
+
+type bazelJavaAconfigLibraryAttributes struct {
+	Aconfig_declarations bazel.LabelAttribute
+	Test                 *bool
+	Sdk_version          *string
+}
+
+func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) Bp2build(ctx android.Bp2buildMutatorContext, module *java.GeneratedJavaLibraryModule) {
+	if ctx.ModuleType() != "java_aconfig_library" {
+		return
+	}
+
+	// By default, soong builds the aconfig java library with private_current, however
+	// bazel currently doesn't support it so we default it to system_current. One reason
+	// is that the dependency of all java_aconfig_library aconfig-annotations-lib is
+	// built with system_current. For the java aconfig library itself it doesn't really
+	// matter whether it uses private API or system API because the only module it uses
+	// is DeviceConfig which is in system, and the rdeps of the java aconfig library
+	// won't change its sdk version either, so this should be fine.
+	// Ideally we should only use the default value if it is not set by the user, but
+	// bazel only supports a limited sdk versions, for example, the java_aconfig_library
+	// modules in framework/base use core_platform which is not supported by bazel yet.
+	// TODO(b/302148527): change soong to default to system_current as well.
+	sdkVersion := "system_current"
+	attrs := bazelJavaAconfigLibraryAttributes{
+		Aconfig_declarations: *bazel.MakeLabelAttribute(android.BazelLabelForModuleDepSingle(ctx, callbacks.properties.Aconfig_declarations).Label),
+		Test:                 callbacks.properties.Test,
+		Sdk_version:          &sdkVersion,
+	}
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "java_aconfig_library",
+		Bzl_load_location: "//build/bazel/rules/java:java_aconfig_library.bzl",
+	}
+
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: ctx.ModuleName()}, &attrs)
+}
diff --git a/aconfig/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go
index 90b09c8..17385c3 100644
--- a/aconfig/rust_aconfig_library_test.go
+++ b/aconfig/rust_aconfig_library_test.go
@@ -50,11 +50,11 @@
 	}
 
 	for _, variant := range variants {
-		android.AssertStringListContains(
+		android.AssertStringEquals(
 			t,
 			"dylib variant builds from generated rust code",
-			variant.Rule("rustc").Implicits.RelativeToTop().Strings(),
 			"out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs",
+			variant.Rule("rustc").Inputs[0].RelativeToTop().String(),
 		)
 	}
 }
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 5c8e5e3..7077f56 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -75,14 +75,17 @@
 		"build/soong/cc/libbuildversion":     Bp2BuildDefaultTrue, // Skip tests subdir
 		"build/soong/cc/ndkstubgen":          Bp2BuildDefaultTrue,
 		"build/soong/cc/symbolfile":          Bp2BuildDefaultTrue,
+		"build/soong/jar":                    Bp2BuildDefaultTrue,
 		"build/soong/licenses":               Bp2BuildDefaultTrue,
 		"build/soong/linkerconfig":           Bp2BuildDefaultTrueRecursively,
+		"build/soong/response":               Bp2BuildDefaultTrue,
 		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
+		"build/soong/third_party/zip":        Bp2BuildDefaultTrue,
 
 		"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
-		"cts/libs/json":                          Bp2BuildDefaultTrueRecursively,
-		"cts/tests/tests/gesture":                Bp2BuildDefaultTrueRecursively,
-		"platform_testing/libraries/annotations": Bp2BuildDefaultTrueRecursively,
+		"cts/flags/cc_tests":                          Bp2BuildDefaultTrueRecursively,
+		"cts/libs/json":                               Bp2BuildDefaultTrueRecursively,
+		"cts/tests/tests/gesture":                     Bp2BuildDefaultTrueRecursively,
 
 		"dalvik/tools/dexdeps": Bp2BuildDefaultTrueRecursively,
 
@@ -139,6 +142,7 @@
 		"external/bzip2":                         Bp2BuildDefaultTrueRecursively,
 		"external/clang/lib":                     Bp2BuildDefaultTrue,
 		"external/conscrypt":                     Bp2BuildDefaultTrue,
+		"external/dexmaker":                      Bp2BuildDefaultTrueRecursively,
 		"external/e2fsprogs":                     Bp2BuildDefaultTrueRecursively,
 		"external/eigen":                         Bp2BuildDefaultTrueRecursively,
 		"external/erofs-utils":                   Bp2BuildDefaultTrueRecursively,
@@ -191,6 +195,7 @@
 		"external/lzma/C":                        Bp2BuildDefaultTrueRecursively,
 		"external/mdnsresponder":                 Bp2BuildDefaultTrueRecursively,
 		"external/minijail":                      Bp2BuildDefaultTrueRecursively,
+		"external/mockito":                       Bp2BuildDefaultTrueRecursively,
 		"external/musl":                          Bp2BuildDefaultTrueRecursively,
 		"external/objenesis":                     Bp2BuildDefaultTrueRecursively,
 		"external/openscreen":                    Bp2BuildDefaultTrueRecursively,
@@ -213,6 +218,7 @@
 		"external/tinyalsa":                      Bp2BuildDefaultTrueRecursively,
 		"external/tinyalsa_new":                  Bp2BuildDefaultTrueRecursively,
 		"external/toybox":                        Bp2BuildDefaultTrueRecursively,
+		"external/xz-java":                       Bp2BuildDefaultTrueRecursively,
 		"external/zlib":                          Bp2BuildDefaultTrueRecursively,
 		"external/zopfli":                        Bp2BuildDefaultTrueRecursively,
 		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
@@ -230,9 +236,11 @@
 		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/apex/jobscheduler/service/jni":      Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/core/java":                          Bp2BuildDefaultTrue,
+		"frameworks/base/core/res":                           Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
 		"frameworks/base/libs/services":                      Bp2BuildDefaultTrue,
 		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
+		"frameworks/base/mime":                               Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/proto":                              Bp2BuildDefaultTrue,
 		"frameworks/base/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
 		"frameworks/base/startop/apps/test":                  Bp2BuildDefaultTrue,
@@ -242,6 +250,8 @@
 		"frameworks/base/tools/codegen":                      Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/tools/locked_region_code_injection": Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/tools/streaming_proto":              Bp2BuildDefaultTrueRecursively,
+		"frameworks/hardware/interfaces":                     Bp2BuildDefaultTrue,
+		"frameworks/hardware/interfaces/displayservice":      Bp2BuildDefaultTrueRecursively,
 		"frameworks/hardware/interfaces/stats/aidl":          Bp2BuildDefaultTrue,
 		"frameworks/libs/modules-utils/build":                Bp2BuildDefaultTrueRecursively,
 		"frameworks/libs/modules-utils/java":                 Bp2BuildDefaultTrue,
@@ -275,6 +285,7 @@
 		"hardware/interfaces/configstore/1.0":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/1.1":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/utils":                   Bp2BuildDefaultTrue,
+		"hardware/interfaces/contexthub/aidl":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/2.0":              Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/3.0":              Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/4.0":              Bp2BuildDefaultTrue,
@@ -307,35 +318,41 @@
 		"hardware/interfaces/neuralnetworks/1.2/vts":              Bp2BuildDefaultFalseRecursively,
 		"hardware/interfaces/neuralnetworks/1.3/vts":              Bp2BuildDefaultFalseRecursively,
 		"hardware/interfaces/neuralnetworks/1.4/vts":              Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/tests":                               Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/tests/extension":                     Bp2BuildDefaultFalseRecursively, // missing deps
+		"hardware/interfaces/tests/msgq":                          Bp2BuildDefaultFalseRecursively, // missing deps
 
 		"libnativehelper": Bp2BuildDefaultTrueRecursively,
 
-		"packages/apps/DevCamera":                            Bp2BuildDefaultTrue,
-		"packages/apps/HTMLViewer":                           Bp2BuildDefaultTrue,
-		"packages/apps/Protips":                              Bp2BuildDefaultTrue,
-		"packages/apps/SafetyRegulatoryInfo":                 Bp2BuildDefaultTrue,
-		"packages/apps/WallpaperPicker":                      Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/driver/cache":       Bp2BuildDefaultTrueRecursively,
-		"packages/modules/StatsD/lib/libstatssocket":         Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb":                               Bp2BuildDefaultTrue,
-		"packages/modules/adb/apex":                          Bp2BuildDefaultTrue,
-		"packages/modules/adb/fastdeploy":                    Bp2BuildDefaultTrue,
-		"packages/modules/adb/crypto":                        Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/libs":                          Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_auth":                  Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_connection":            Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/proto":                         Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/tls":                           Bp2BuildDefaultTrueRecursively,
-		"packages/modules/Connectivity/staticlibs/native":    Bp2BuildDefaultTrueRecursively,
-		"packages/modules/Gki/libkver":                       Bp2BuildDefaultTrue,
-		"packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex":               Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex/testing":       Bp2BuildDefaultTrue,
-		"packages/providers/MediaProvider/tools/dialogs":     Bp2BuildDefaultFalse, // TODO(b/242834374)
-		"packages/screensavers/Basic":                        Bp2BuildDefaultTrue,
-		"packages/services/Car/tests/SampleRearViewCamera":   Bp2BuildDefaultFalse, // TODO(b/242834321)
+		"packages/apps/DevCamera":                                    Bp2BuildDefaultTrue,
+		"packages/apps/HTMLViewer":                                   Bp2BuildDefaultTrue,
+		"packages/apps/Protips":                                      Bp2BuildDefaultTrue,
+		"packages/apps/SafetyRegulatoryInfo":                         Bp2BuildDefaultTrue,
+		"packages/apps/WallpaperPicker":                              Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/driver/cache":               Bp2BuildDefaultTrueRecursively,
+		"packages/modules/StatsD/lib/libstatssocket":                 Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb":                                       Bp2BuildDefaultTrue,
+		"packages/modules/adb/apex":                                  Bp2BuildDefaultTrue,
+		"packages/modules/adb/fastdeploy":                            Bp2BuildDefaultTrue,
+		"packages/modules/adb/crypto":                                Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/libs":                                  Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/pairing_auth":                          Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/pairing_connection":                    Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/proto":                                 Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/tls":                                   Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/staticlibs/native":            Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/staticlibs/netd/libnetdutils": Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Gki/libkver":                               Bp2BuildDefaultTrue,
+		"packages/modules/NetworkStack/common/captiveportal":         Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/apex":                       Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/apex/testing":               Bp2BuildDefaultTrue,
+		"packages/providers/MediaProvider/tools/dialogs":             Bp2BuildDefaultFalse, // TODO(b/242834374)
+		"packages/screensavers/Basic":                                Bp2BuildDefaultTrue,
+		"packages/services/Car/tests/SampleRearViewCamera":           Bp2BuildDefaultFalse, // TODO(b/242834321)
 
-		"platform_testing/tests/example": Bp2BuildDefaultTrueRecursively,
+		"platform_testing/libraries/annotations":              Bp2BuildDefaultTrueRecursively,
+		"platform_testing/libraries/flag-helpers/libflagtest": Bp2BuildDefaultTrueRecursively,
+		"platform_testing/tests/example":                      Bp2BuildDefaultTrueRecursively,
 
 		"prebuilts/clang/host/linux-x86":                   Bp2BuildDefaultTrueRecursively,
 		"prebuilts/gradle-plugin":                          Bp2BuildDefaultTrueRecursively,
@@ -373,6 +390,7 @@
 		"system/core/libprocessgroup/cgrouprc":                   Bp2BuildDefaultTrue,
 		"system/core/libprocessgroup/cgrouprc_format":            Bp2BuildDefaultTrue,
 		"system/core/libsparse":                                  Bp2BuildDefaultTrueRecursively,
+		"system/core/libstats/expresslog":                        Bp2BuildDefaultTrueRecursively,
 		"system/core/libsuspend":                                 Bp2BuildDefaultTrue,
 		"system/core/libsystem":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/libsysutils":                                Bp2BuildDefaultTrueRecursively,
@@ -398,8 +416,7 @@
 		"system/libhidl/transport/manager/1.0":                   Bp2BuildDefaultTrue,
 		"system/libhidl/transport/manager/1.1":                   Bp2BuildDefaultTrue,
 		"system/libhidl/transport/manager/1.2":                   Bp2BuildDefaultTrue,
-		"system/libhidl/transport/memory/1.0":                    Bp2BuildDefaultTrue,
-		"system/libhidl/transport/memory/token/1.0":              Bp2BuildDefaultTrue,
+		"system/libhidl/transport/memory":                        Bp2BuildDefaultTrueRecursively,
 		"system/libhidl/transport/safe_union/1.0":                Bp2BuildDefaultTrue,
 		"system/libhidl/transport/token/1.0":                     Bp2BuildDefaultTrue,
 		"system/libhidl/transport/token/1.0/utils":               Bp2BuildDefaultTrue,
@@ -409,14 +426,14 @@
 		"system/libziparchive":                                   Bp2BuildDefaultTrueRecursively,
 		"system/logging":                                         Bp2BuildDefaultTrueRecursively,
 		"system/media":                                           Bp2BuildDefaultTrue,
-		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
 		"system/media/alsa_utils":                                Bp2BuildDefaultTrueRecursively,
+		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
 		"system/media/audio_utils":                               Bp2BuildDefaultTrueRecursively,
 		"system/media/camera":                                    Bp2BuildDefaultTrueRecursively,
 		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
 		"system/memory/libmemunreachable":                        Bp2BuildDefaultTrueRecursively,
-		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/security/fsverity":                               Bp2BuildDefaultTrueRecursively,
+		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/testing/gtest_extras":                            Bp2BuildDefaultTrueRecursively,
 		"system/timezone/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/timezone/output_data":                            Bp2BuildDefaultTrueRecursively,
@@ -424,13 +441,14 @@
 		"system/timezone/testing":                                Bp2BuildDefaultTrueRecursively,
 		"system/tools/aidl/build/tests_bp2build":                 Bp2BuildDefaultTrue,
 		"system/tools/aidl/metadata":                             Bp2BuildDefaultTrue,
-		"system/tools/hidl/metadata":                             Bp2BuildDefaultTrue,
-		"system/tools/hidl/utils":                                Bp2BuildDefaultTrue,
+		"system/tools/hidl":                                      Bp2BuildDefaultTrueRecursively,
 		"system/tools/mkbootimg":                                 Bp2BuildDefaultTrueRecursively,
 		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/tools/xsdc/utils":                                Bp2BuildDefaultTrueRecursively,
 		"system/unwinding/libunwindstack":                        Bp2BuildDefaultTrueRecursively,
 
+		"test/vts/vts_hal_hidl_target": Bp2BuildDefaultTrueRecursively,
+
 		"tools/apifinder":                             Bp2BuildDefaultTrue,
 		"tools/apksig":                                Bp2BuildDefaultTrue,
 		"tools/dexter/slicer":                         Bp2BuildDefaultTrueRecursively,
@@ -438,6 +456,7 @@
 		"tools/metalava":                              Bp2BuildDefaultTrueRecursively,
 		"tools/platform-compat/java/android/compat":   Bp2BuildDefaultTrueRecursively,
 		"tools/platform-compat/java/androidprocessor": Bp2BuildDefaultTrueRecursively,
+		"tools/tradefederation/core/util_apps":        Bp2BuildDefaultTrueRecursively,
 		"tools/tradefederation/prebuilts/filegroups":  Bp2BuildDefaultTrueRecursively,
 	}
 
@@ -463,6 +482,7 @@
 		"external/bazelbuild-rules_go":/* recursive = */ true,
 		"external/bazelbuild-rules_python":/* recursive = */ true,
 		"external/bazelbuild-rules_rust":/* recursive = */ true,
+		"external/bazelbuild-rules_testing":/* recursive = */ true,
 		"external/bazelbuild-kotlin-rules":/* recursive = */ true,
 		"external/bazel-skylib":/* recursive = */ true,
 		"external/protobuf":/* recursive = */ false,
@@ -484,6 +504,7 @@
 		"prebuilts/clang-tools":/* recursive = */ true,
 		"prebuilts/gcc":/* recursive = */ true,
 		"prebuilts/build-tools":/* recursive = */ true,
+		"prebuilts/jdk/jdk8":/* recursive = */ true,
 		"prebuilts/jdk/jdk17":/* recursive = */ true,
 		"prebuilts/misc":/* recursive = */ false, // not recursive because we need bp2build converted build files in prebuilts/misc/common/asm
 		"prebuilts/sdk":/* recursive = */ false,
@@ -556,13 +577,8 @@
 		// ext
 		"tagsoup",
 
-		// framework-res
-		"remote-color-resources-compile-public",
-		"remote-color-resources-compile-colors",
-
 		// framework-minus-apex
 		"ImmutabilityAnnotationProcessor",
-		"android.mime.types.minimized",
 		"debian.mime.types.minimized",
 		"framework-javastream-protos",
 		"libview-inspector-annotation-processor",
@@ -571,7 +587,6 @@
 		"apache-commons-math",
 		"cbor-java",
 		"icu4j_calendar_astronomer",
-		"remote-color-resources-compile-public",
 		"statslog-art-java-gen",
 
 		"AndroidCommonLint",
@@ -619,7 +634,6 @@
 		"libneuralnetworks",
 		"libneuralnetworks_static",
 		"libgraphicsenv",
-		"libhardware",
 		"libhardware_headers",
 		"libnativeloader-headers",
 		"libnativewindow_headers",
@@ -755,6 +769,7 @@
 		//system/core/fs_mgr
 		"libfs_mgr",
 
+		"libcodec2_aidl",
 		"libcodec2_hidl@1.0",
 		"libcodec2_hidl@1.1",
 		"libcodec2_hidl@1.2",
@@ -894,7 +909,6 @@
 		"libRSDispatch",
 
 		// hal_unit_tests and deps
-		"android.hardware.contexthub_interface", // created implicitly by android.hardware.contexthub
 		"chre_flatbuffers",
 		"event_logger",
 		"hal_unit_tests",
@@ -922,11 +936,10 @@
 		"androidx.test.annotation-nodeps",
 
 		// jni deps of an internal android_test (b/297405812)
-		"libdexmakerjvmtiagent",
 		"libopenjdkjvmti_headers",
-		"libstaticjvmtiagent",
 
 		// tradefed deps
+		"apache-commons-compress",
 		"tradefed-protos",
 		"grpc-java",
 		"grpc-java-api",
@@ -947,6 +960,40 @@
 		"gson",
 		"GsonBuildConfig.java",
 		"gson_version_generator",
+		"lab-resource-grpc",
+		"blueprint-deptools",
+		"protoc-gen-grpc-java-plugin",
+		"perfetto_trace-full",
+		"tf-remote-client",
+		"truth",
+		"tradefed-lite",
+		"tradefed-isolation-protos",
+		"snakeyaml_patched_src_files",
+		"asuite_proto_java",
+		"tradefed-service-grpc-lib",
+		"tradefed-invocation-grpc",
+		"tradefed-external-dependencies",
+		"tradefed-dynamic-sharding-grpc",
+		"tradefed-device-manager-grpc",
+		"statsd_internal_protos",
+		"snakeyaml",
+		"loganalysis",
+		"junit-params",
+		"grpc-java-testing",
+		"grpc-java-netty-shaded",
+		"aoa-helper",
+		"test-services.apk",
+		"test-composers",
+		"py3-stdlib-prebuilt-srcs",
+		"platformprotos",
+		"perfetto_metrics-full",
+		"test-services-normalized.apk",
+		"tradefed-common-util",
+		"tradefed-clearcut-client",
+		"tradefed-result-interfaces",
+		"tradefed-device-build-interfaces",
+		"tradefed-invocation-interfaces",
+		"tradefed-lib-core",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -963,15 +1010,17 @@
 		"cc_prebuilt_library_static",
 		"combined_apis",
 		"droiddoc_exported_dir",
+		"java_aconfig_library",
 		"java_import",
 		"java_import_host",
 		"java_sdk_library",
 		"java_sdk_library_import",
 		"license",
 		"linker_config",
-		"ndk_library",
 		"ndk_headers",
+		"ndk_library",
 		"sysprop_library",
+		"versioned_ndk_headers",
 		"xsd_config",
 		// go/keep-sorted end
 	}
@@ -998,6 +1047,8 @@
 		"libfsverity_rs",
 		"libtombstoned_client_rust",
 
+		"libhardware", //Depends on unconverted libapexsupport
+
 		// TODO(b/263326760): Failed already.
 		"minijail_compiler_unittest",
 		"minijail_parser_unittest",
@@ -1060,20 +1111,22 @@
 		"libtombstoned_client_rust_bridge_code", "libtombstoned_client_wrapper", // rust conversions are not supported
 
 		// unconverted deps
-		"CarHTMLViewer",                                              // depends on unconverted modules android.car-stubs, car-ui-lib
-		"adb",                                                        // depends on unconverted modules: AdbWinApi, libandroidfw, libopenscreen-discovery, libopenscreen-platform-impl, libusb, bin2c_fastdeployagent, AdbWinUsbApi
-		"android_icu4j_srcgen",                                       // depends on unconverted modules: currysrc
-		"android_icu4j_srcgen_binary",                                // depends on unconverted modules: android_icu4j_srcgen, currysrc
-		"apex_compression_test",                                      // depends on unconverted modules: soong_zip, com.android.example.apex
-		"apex_manifest_proto_java",                                   // b/210751803, depends on libprotobuf-java-full
-		"apexer_with_DCLA_preprocessing_test",                        // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex
-		"art-script",                                                 // depends on unconverted modules: dalvikvm, dex2oat
-		"bin2c_fastdeployagent",                                      // depends on unconverted modules: deployagent
-		"com.android.runtime",                                        // depends on unconverted modules: bionic-linker-config, linkerconfig
-		"currysrc",                                                   // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
-		"dex2oat-script",                                             // depends on unconverted modules: dex2oat
-		"generated_android_icu4j_resources",                          // depends on unconverted modules: android_icu4j_srcgen_binary
-		"generated_android_icu4j_test_resources",                     // depends on unconverted modules: android_icu4j_srcgen_binary
+		"CarHTMLViewer",                          // depends on unconverted modules android.car-stubs, car-ui-lib
+		"adb",                                    // depends on unconverted modules: AdbWinApi, libandroidfw, libopenscreen-discovery, libopenscreen-platform-impl, libusb, bin2c_fastdeployagent, AdbWinUsbApi
+		"android_icu4j_srcgen",                   // depends on unconverted modules: currysrc
+		"android_icu4j_srcgen_binary",            // depends on unconverted modules: android_icu4j_srcgen, currysrc
+		"apex_compression_test",                  // depends on unconverted modules: soong_zip, com.android.example.apex
+		"apex_manifest_proto_java",               // b/210751803, depends on libprotobuf-java-full
+		"apexer_with_DCLA_preprocessing_test",    // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex
+		"art-script",                             // depends on unconverted modules: dalvikvm, dex2oat
+		"bin2c_fastdeployagent",                  // depends on unconverted modules: deployagent
+		"com.android.runtime",                    // depends on unconverted modules: bionic-linker-config, linkerconfig
+		"currysrc",                               // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
+		"dex2oat-script",                         // depends on unconverted modules: dex2oat
+		"generated_android_icu4j_resources",      // depends on unconverted modules: android_icu4j_srcgen_binary
+		"generated_android_icu4j_test_resources", // depends on unconverted modules: android_icu4j_srcgen_binary
+		"hidl_system_api_test",
+		"hidl_test_java",
 		"host-libprotobuf-java-nano",                                 // b/220869005, depends on libprotobuf-java-nano
 		"jacoco-stubs",                                               // b/245767077, depends on droidstubs
 		"libapexutil",                                                // depends on unconverted modules: apex-info-list-tinyxml
@@ -1656,6 +1709,7 @@
 
 		// python_test_host with test data
 		"sbom_writers_test",
+		"hidl_test",
 
 		// TODO(B/283193845): tradefed and its java_test_host dependents
 		"tradefed",
@@ -1713,6 +1767,13 @@
 		"NanoAndroidTest",
 		"MtsLibnativehelperTestCases",
 
+		// Depends on androidx.test.rules
+		"DexmakerTests",
+		"dexmaker-tests-lib",
+		"dexmaker-mockmaker-tests",
+		"dexmaker-inline-mockmaker-tests",
+		"dexmaker-extended-mockmaker-tests",
+
 		// android_test_helper_app from allowlisted packages, but with unconverted deps
 		"SharedLibraryInfoTestApp",
 	}
@@ -1777,18 +1838,4 @@
 		"art_":        DEFAULT_PRIORITIZED_WEIGHT,
 		"ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
 	}
-
-	BazelSandwichTargets = []struct {
-		Label string
-		Host  bool
-	}{
-		{
-			Label: "//build/bazel/examples/partitions:system_image",
-			Host:  false,
-		},
-		{
-			Label: "//build/bazel/examples/partitions:run_test",
-			Host:  false,
-		},
-	}
 )
diff --git a/android/apex.go b/android/apex.go
index d84499b..c6d9940 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -482,7 +482,9 @@
 	}
 	return InList(what, apex_available) ||
 		(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
-		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available))
+		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available)) ||
+		(what == "com.google.mainline.primary.libs") || // TODO b/248601389
+		(what == "com.google.mainline.go.primary.libs") // TODO b/248601389
 }
 
 // Implements ApexModule
diff --git a/android/api_domain.go b/android/api_domain.go
index 587ceae..0a66c3d 100644
--- a/android/api_domain.go
+++ b/android/api_domain.go
@@ -14,20 +14,6 @@
 
 package android
 
-import (
-	"github.com/google/blueprint"
-
-	"android/soong/bazel"
-)
-
-func init() {
-	RegisterApiDomainBuildComponents(InitRegistrationContext)
-}
-
-func RegisterApiDomainBuildComponents(ctx RegistrationContext) {
-	ctx.RegisterModuleType("api_domain", ApiDomainFactory)
-}
-
 type ApiSurface int
 
 // TODO(b/246656800): Reconcile with android.SdkKind
@@ -50,81 +36,3 @@
 		return "invalid"
 	}
 }
-
-type apiDomain struct {
-	ModuleBase
-	BazelModuleBase
-
-	properties apiDomainProperties
-}
-
-type apiDomainProperties struct {
-	// cc library contributions (.h files/.map.txt) of this API domain
-	// This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
-	// will provide a `CcApiContributionInfo` provider
-	Cc_api_contributions []string
-
-	// java library contributions (as .txt) of this API domain
-	// This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
-	// will provide a `JavaApiContributionInfo` provider
-	Java_api_contributions []string
-}
-
-func ApiDomainFactory() Module {
-	m := &apiDomain{}
-	m.AddProperties(&m.properties)
-	InitAndroidArchModule(m, DeviceSupported, MultilibBoth)
-	return m
-}
-
-// Do not create any dependency edges in Soong for now to skip visibility checks for some systemapi libraries.
-// Currently, all api_domain modules reside in build/orchestrator/apis/Android.bp
-// However, cc libraries like libsigchain (com.android.art) restrict their visibility to art/*
-// When the api_domain module types are collocated with their contributions, this dependency edge can be restored
-func (a *apiDomain) DepsMutator(ctx BottomUpMutatorContext) {
-}
-
-// API domain does not have any builld actions yet
-func (a *apiDomain) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
-
-const (
-	apiContributionSuffix = ".contribution"
-)
-
-// ApiContributionTargetName returns the name of the bp2build target (e.g. cc_api_contribution)  of contribution modules (e.g. ndk_library)
-// A suffix is necessary to prevent a name collision with the base target in the same bp2build bazel package
-func ApiContributionTargetName(moduleName string) string {
-	return moduleName + apiContributionSuffix
-}
-
-// For each contributing cc_library, format the name to its corresponding contribution bazel target in the bp2build workspace
-func contributionBazelAttributes(ctx TopDownMutatorContext, contributions []string) bazel.LabelListAttribute {
-	addSuffix := func(ctx BazelConversionPathContext, module blueprint.Module) string {
-		baseLabel := BazelModuleLabel(ctx, module)
-		return ApiContributionTargetName(baseLabel)
-	}
-	bazelLabels := BazelLabelForModuleDepsWithFn(ctx, contributions, addSuffix)
-	return bazel.MakeLabelListAttribute(bazelLabels)
-}
-
-type bazelApiDomainAttributes struct {
-	Cc_api_contributions   bazel.LabelListAttribute
-	Java_api_contributions bazel.LabelListAttribute
-}
-
-var _ ApiProvider = (*apiDomain)(nil)
-
-func (a *apiDomain) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "api_domain",
-		Bzl_load_location: "//build/bazel/rules/apis:api_domain.bzl",
-	}
-	attrs := &bazelApiDomainAttributes{
-		Cc_api_contributions:   contributionBazelAttributes(ctx, a.properties.Cc_api_contributions),
-		Java_api_contributions: contributionBazelAttributes(ctx, a.properties.Java_api_contributions),
-	}
-	ctx.CreateBazelTargetModule(props, CommonAttributes{
-		Name: ctx.ModuleName(),
-	}, attrs)
-}
diff --git a/android/bazel.go b/android/bazel.go
index 8634dab..b4e7ae5 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -218,6 +218,28 @@
 	module.bazelProps().Bazel_module.CanConvertToBazel = true
 }
 
+// BazelHandcraftedHook is a load hook to possibly register the current module as
+// a "handcrafted" Bazel target of a given name. If the current module should be
+// registered in this way, the hook function should return the target name. If
+// it should not be registered in this way, this function should return the empty string.
+type BazelHandcraftedHook func(ctx LoadHookContext) string
+
+// AddBazelHandcraftedHook adds a load hook to (maybe) mark the given module so that
+// it is treated by bp2build as if it has a handcrafted Bazel target.
+func AddBazelHandcraftedHook(module BazelModule, hook BazelHandcraftedHook) {
+	AddLoadHook(module, func(ctx LoadHookContext) {
+		var targetName string = hook(ctx)
+		if len(targetName) > 0 {
+			moduleDir := ctx.ModuleDir()
+			if moduleDir == Bp2BuildTopLevel {
+				moduleDir = ""
+			}
+			label := fmt.Sprintf("//%s:%s", moduleDir, targetName)
+			module.bazelProps().Bazel_module.Label = &label
+		}
+	})
+}
+
 // bazelProps returns the Bazel properties for the given BazelModuleBase.
 func (b *BazelModuleBase) bazelProps() *properties {
 	return &b.bazelProperties
@@ -600,17 +622,21 @@
 }
 
 func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("bp2build_conversion", bp2buildConversionMutator).Parallel()
+	ctx.BottomUp("bp2build_conversion", bp2buildConversionMutator).Parallel()
 }
 
-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, "")
+func registerBp2buildDepsMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("bp2build_deps", bp2buildDepsMutator).Parallel()
+}
+
+func bp2buildConversionMutator(ctx BottomUpMutatorContext) {
+	// If an existing BUILD file in the module directory has a target defined
+	// with this same name as this module, assume that this is an existing
+	// definition for this target.
+	if ctx.Config().HasBazelBuildTargetInSource(ctx.ModuleDir(), ctx.ModuleName()) {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, ctx.ModuleName())
 		return
 	}
-
 	bModule, ok := ctx.Module().(Bazelable)
 	if !ok {
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
@@ -634,24 +660,63 @@
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
 		return
 	}
+	if ctx.Module().base().GetUnconvertedReason() != nil {
+		return
+	}
+
 	bModule.ConvertWithBp2build(ctx)
 
-	if !ctx.Module().base().IsConvertedByBp2build() && ctx.Module().base().GetUnconvertedReason() == nil {
+	if len(ctx.Module().base().Bp2buildTargets()) == 0 && 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) {
-	ctx.TopDown("apiBp2build_conversion", convertWithApiBp2build).Parallel()
-}
-
-// Generate API contribution targets if the Soong module provides APIs
-func convertWithApiBp2build(ctx TopDownMutatorContext) {
-	if m, ok := ctx.Module().(ApiProvider); ok {
-		m.ConvertWithApiBp2build(ctx)
+	// If an existing BUILD file in the module directory has a target defined
+	// with the same name as any target generated by this module, assume that this
+	// is an existing definition for this target. (These generated target names
+	// may be different than the module name, as checked at the beginning of this function!)
+	for _, targetInfo := range ctx.Module().base().Bp2buildTargets() {
+		if ctx.Config().HasBazelBuildTargetInSource(targetInfo.TargetPackage(), targetInfo.TargetName()) {
+			// 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, targetInfo.TargetName())
+			return
+		}
 	}
 }
 
+// TODO: b/285631638 - Add this as a new mutator to the bp2build conversion mutators.
+// Currently, this only exists to prepare test coverage for the launch of this feature.
+func bp2buildDepsMutator(ctx BottomUpMutatorContext) {
+	if ctx.Module().base().GetUnconvertedReason() != nil {
+		return
+	}
+
+	if len(ctx.Module().GetMissingBp2buildDeps()) > 0 {
+		exampleDep := ctx.Module().GetMissingBp2buildDeps()[0]
+		ctx.MarkBp2buildUnconvertible(
+			bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, exampleDep)
+	}
+
+	// Transitively mark modules unconvertible with the following set of conditions.
+	ctx.VisitDirectDeps(func(dep Module) {
+		if dep.base().GetUnconvertedReason() == nil {
+			return
+		}
+
+		if dep.base().GetUnconvertedReason().ReasonType ==
+			int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) {
+			return
+		}
+
+		if ctx.OtherModuleDependencyTag(dep) != Bp2buildDepTag {
+			return
+		}
+
+		ctx.MarkBp2buildUnconvertible(
+			bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, dep.Name())
+	})
+}
+
 // GetMainClassInManifest scans the manifest file specified in filepath and returns
 // the value of attribute Main-Class in the manifest file if it exists, or returns error.
 // WARNING: this is for bp2build converters of java_* modules only.
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 56ec17d..51ce3c9 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -33,10 +33,10 @@
 	"android/soong/shared"
 	"android/soong/starlark_import"
 
+	"android/soong/bazel"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/metrics"
-
-	"android/soong/bazel"
 )
 
 var (
@@ -1048,39 +1048,46 @@
 	allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
 )
 
+// This can't be part of bp2build_product_config.go because it would create a circular go package dependency
+func getLabelsForBazelSandwichPartitions(variables *ProductVariables) []string {
+	targetProduct := "unknown"
+	if variables.DeviceProduct != nil {
+		targetProduct = *variables.DeviceProduct
+	}
+	currentProductFolder := fmt.Sprintf("build/bazel/products/%s", targetProduct)
+	if len(variables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory) > 0 {
+		currentProductFolder = fmt.Sprintf("%s%s", variables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory, targetProduct)
+	}
+	var ret []string
+	if variables.PartitionVarsForBazelMigrationOnlyDoNotUse.PartitionQualifiedVariables["system"].BuildingImage {
+		ret = append(ret, "@//"+currentProductFolder+":system_image")
+		ret = append(ret, "@//"+currentProductFolder+":run_system_image_test")
+	}
+	return ret
+}
+
 func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) {
-	result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets))
+	partitionLabels := getLabelsForBazelSandwichPartitions(&config.productVariables)
+	result := make([]cqueryKey, 0, len(partitionLabels))
 	labelRegex := regexp.MustCompile("^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$")
 	// Note that bazel "targets" are different from soong "targets", the bazel targets are
 	// synonymous with soong modules, and soong targets are a configuration a module is built in.
-	for _, target := range allowlists.BazelSandwichTargets {
-		match := labelRegex.FindStringSubmatch(target.Label)
+	for _, target := range partitionLabels {
+		match := labelRegex.FindStringSubmatch(target)
 		if match == nil {
-			return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target.Label)
-		}
-		if _, err := os.Stat(absolutePath(match[1])); err != nil {
-			if os.IsNotExist(err) {
-				// Ignore bazel sandwich targets that don't exist.
-				continue
-			} else {
-				return nil, err
-			}
+			return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target)
 		}
 
-		var soongTarget Target
-		if target.Host {
-			soongTarget = config.BuildOSTarget
-		} else {
-			soongTarget = config.AndroidCommonTarget
-			if soongTarget.Os.Class != Device {
-				// kernel-build-tools seems to set the AndroidCommonTarget to a linux host
-				// target for some reason, disable device builds in that case.
-				continue
-			}
+		// change this to config.BuildOSTarget if we add host targets
+		soongTarget := config.AndroidCommonTarget
+		if soongTarget.Os.Class != Device {
+			// kernel-build-tools seems to set the AndroidCommonTarget to a linux host
+			// target for some reason, disable device builds in that case.
+			continue
 		}
 
 		result = append(result, cqueryKey{
-			label:       target.Label,
+			label:       target,
 			requestType: cquery.GetOutputFiles,
 			configKey: configKey{
 				arch:   soongTarget.Arch.String(),
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 4ac5840..d272ec2 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -101,8 +102,8 @@
 // BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>"
 // or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the
 // module within the given ctx.
-func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
-	return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel)
+func BazelLabelForModuleDeps(ctx Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel, /*markAsDeps=*/true)
 }
 
 // BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in
@@ -111,15 +112,16 @@
 // list which corresponds to dependencies on the module within the given ctx, and the excluded
 // dependencies.  Prebuilt dependencies will be appended with _alwayslink so they can be handled as
 // whole static libraries.
-func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func BazelLabelForModuleDepsExcludes(ctx Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, BazelModuleLabel)
 }
 
 // BazelLabelForModuleDepsWithFn expects a list of reference to other modules, ("<module>"
 // or ":<module>") and applies moduleToLabelFn to determine and return a Bazel-compatible label
 // which corresponds to dependencies on the module within the given ctx.
-func BazelLabelForModuleDepsWithFn(ctx BazelConversionPathContext, modules []string,
-	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
+func BazelLabelForModuleDepsWithFn(ctx Bp2buildMutatorContext, modules []string,
+	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string,
+	markAsDeps bool) bazel.LabelList {
 	var labels bazel.LabelList
 	// In some cases, a nil string list is different than an explicitly empty list.
 	if len(modules) == 0 && modules != nil {
@@ -133,7 +135,7 @@
 			module = ":" + module
 		}
 		if m, t := SrcIsModuleWithTag(module); m != "" {
-			l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn)
+			l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn, markAsDeps)
 			if l != nil {
 				l.OriginalModuleName = bpText
 				labels.Includes = append(labels.Includes, *l)
@@ -150,27 +152,27 @@
 // to other modules, ("<module>" or ":<module>"). It applies moduleToLabelFn to determine and return a
 // Bazel-compatible label list which corresponds to dependencies on the module within the given ctx, and
 // the excluded dependencies.
-func BazelLabelForModuleDepsExcludesWithFn(ctx BazelConversionPathContext, modules, excludes []string,
+func BazelLabelForModuleDepsExcludesWithFn(ctx Bp2buildMutatorContext, modules, excludes []string,
 	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
-	moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn)
+	moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn, /*markAsDeps=*/true)
 	if len(excludes) == 0 {
 		return moduleLabels
 	}
-	excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn)
+	excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn, /*markAsDeps=*/false)
 	return bazel.LabelList{
 		Includes: moduleLabels.Includes,
 		Excludes: excludeLabels.Includes,
 	}
 }
 
-func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label {
+func BazelLabelForModuleSrcSingle(ctx Bp2buildMutatorContext, path string) bazel.Label {
 	if srcs := BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
 		return srcs[0]
 	}
 	return bazel.Label{}
 }
 
-func BazelLabelForModuleDepSingle(ctx BazelConversionPathContext, path string) bazel.Label {
+func BazelLabelForModuleDepSingle(ctx Bp2buildMutatorContext, path string) bazel.Label {
 	if srcs := BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
 		return srcs[0]
 	}
@@ -183,7 +185,7 @@
 // relative if within the same package).
 // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
 // will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
+func BazelLabelForModuleSrc(ctx Bp2buildMutatorContext, paths []string) bazel.LabelList {
 	return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
 }
 
@@ -193,13 +195,13 @@
 // (absolute if in a different package or relative if within the same package).
 // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
 // will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
-	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
+func BazelLabelForModuleSrcExcludes(ctx Bp2buildMutatorContext, paths, excludes []string) bazel.LabelList {
+	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil), false)
 	excluded := make([]string, 0, len(excludeLabels.Includes))
 	for _, e := range excludeLabels.Includes {
 		excluded = append(excluded, e.Label)
 	}
-	labels := expandSrcsForBazel(ctx, paths, excluded)
+	labels := expandSrcsForBazel(ctx, paths, excluded, true)
 	labels.Excludes = excludeLabels.Includes
 	labels = TransformSubpackagePaths(ctx.Config(), ctx.ModuleDir(), labels)
 	return labels
@@ -228,10 +230,18 @@
 //  2. An Android.bp doesn't exist, but a checked-in BUILD/BUILD.bazel file exists, and that file
 //     is allowlisted by the bp2build configuration to be merged into the symlink forest workspace.
 func isPackageBoundary(config Config, prefix string, components []string, componentIndex int) bool {
+	isSymlink := func(c Config, path string) bool {
+		f, err := c.fs.Lstat(path)
+		if err != nil {
+			// The file does not exist
+			return false
+		}
+		return f.Mode()&os.ModeSymlink == os.ModeSymlink
+	}
 	prefix = filepath.Join(prefix, filepath.Join(components[:componentIndex+1]...))
 	if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "Android.bp")); exists {
 		return true
-	} else if config.Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(prefix) {
+	} else if config.Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(prefix) || isSymlink(config, prefix) {
 		if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD")); exists {
 			return true
 		} else if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD.bazel")); exists {
@@ -352,6 +362,12 @@
 	return newPaths
 }
 
+var Bp2buildDepTag bp2buildDepTag
+
+type bp2buildDepTag struct {
+	blueprint.BaseDependencyTag
+}
+
 // expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source
 // directory and Bazel target labels, excluding those included in the excludes argument (which
 // should already be expanded to resolve references to Soong-modules). Valid elements of paths
@@ -374,7 +390,7 @@
 // Properties passed as the paths or excludes argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on other modules will have already been handled by the
 // pathdeps mutator.
-func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
+func expandSrcsForBazel(ctx Bp2buildMutatorContext, paths, expandedExcludes []string, markAsDeps bool) bazel.LabelList {
 	if paths == nil {
 		return bazel.LabelList{}
 	}
@@ -391,7 +407,7 @@
 
 	for _, p := range paths {
 		if m, tag := SrcIsModuleWithTag(p); m != "" {
-			l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel)
+			l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel, markAsDeps)
 			if l != nil && !InList(l.Label, expandedExcludes) {
 				if strings.HasPrefix(m, "//") {
 					// this is a module in a soong namespace
@@ -423,8 +439,9 @@
 // getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the
 // module. The label will be relative to the current directory if appropriate. The dependency must
 // already be resolved by either deps mutator or path deps mutator.
-func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string,
-	labelFromModule func(BazelConversionPathContext, blueprint.Module) string) *bazel.Label {
+func getOtherModuleLabel(ctx Bp2buildMutatorContext, dep, tag string,
+	labelFromModule func(BazelConversionPathContext, blueprint.Module) string,
+	markAsDep bool) *bazel.Label {
 	m, _ := ctx.ModuleFromName(dep)
 	// The module was not found in an Android.bp file, this is often due to:
 	//		* a limited manifest
@@ -435,6 +452,35 @@
 			Label: ":" + dep + "__BP2BUILD__MISSING__DEP",
 		}
 	}
+	// Returns true if a dependency from the current module to the target module
+	// should be skipped; doing so is a hack to circumvent certain problematic
+	// scenarios that will be addressed in the future.
+	shouldSkipDep := func(dep string) bool {
+		// Don't count dependencies of "libc". This is a hack to circumvent the
+		// fact that, in a variantless build graph, "libc" has a dependency on itself.
+		if ctx.ModuleName() == "libc" {
+			return true
+		}
+
+		// TODO: b/303307672: Dependencies on this module happen to "work" because
+		// there is a source file with the same name as this module in the
+		// same directory. We should remove this hack and enforce the underlying
+		// module of this name is the actual one used.
+		if dep == "mke2fs.conf" {
+			return true
+		}
+
+		// TODO: b/303310285: Remove this special-casing once all dependencies of
+		// crtbegin_dynamic are convertible
+		if ctx.ModuleName() == "crtbegin_dynamic" {
+			return true
+		}
+
+		return false
+	}
+	if markAsDep && !shouldSkipDep(dep) {
+		ctx.AddDependency(ctx.Module(), Bp2buildDepTag, dep)
+	}
 	if !convertedToBazel(ctx, m) {
 		ctx.AddUnconvertedBp2buildDep(dep)
 	}
@@ -442,6 +488,10 @@
 	otherLabel := labelFromModule(ctx, m)
 
 	// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
+	if (tag != "" && m.Name() == "framework-res") ||
+		(tag == ".generated_srcjars" && ctx.OtherModuleType(m) == "java_aconfig_library") {
+		otherLabel += tag
+	}
 
 	if samePackage(label, otherLabel) {
 		otherLabel = bazelShortLabel(otherLabel)
diff --git a/android/config.go b/android/config.go
index df282ec..8da97b2 100644
--- a/android/config.go
+++ b/android/config.go
@@ -297,6 +297,9 @@
 	// in tests when a path doesn't exist.
 	TestAllowNonExistentPaths bool
 
+	// If true, register the "bp2build_deps" mutator in the mutator pipeline.
+	Bp2buildDepsMutator bool
+
 	// The list of files that when changed, must invalidate soong_build to
 	// regenerate build.ninja.
 	ninjaFileDepsSet sync.Map
@@ -1434,10 +1437,6 @@
 	return String(c.config.productVariables.Platform_vndk_version)
 }
 
-func (c *deviceConfig) ProductVndkVersion() string {
-	return String(c.config.productVariables.ProductVndkVersion)
-}
-
 func (c *deviceConfig) ExtraVndkVersions() []string {
 	return c.config.productVariables.ExtraVndkVersions
 }
@@ -2022,10 +2021,9 @@
 	}
 }
 
-func (c *config) HasBazelBuildTargetInSource(ctx BaseModuleContext) bool {
-	moduleName := ctx.Module().Name()
-	for _, buildTarget := range c.bazelTargetsByDir[ctx.ModuleDir()] {
-		if moduleName == buildTarget {
+func (c *config) HasBazelBuildTargetInSource(dir string, target string) bool {
+	for _, existingTarget := range c.bazelTargetsByDir[dir] {
+		if target == existingTarget {
 			return true
 		}
 	}
@@ -2081,3 +2079,15 @@
 func (c *deviceConfig) CheckVendorSeappViolations() bool {
 	return Bool(c.config.productVariables.CheckVendorSeappViolations)
 }
+
+func (c *deviceConfig) NextReleaseHideFlaggedApi() bool {
+	return Bool(c.config.productVariables.NextReleaseHideFlaggedApi)
+}
+
+func (c *deviceConfig) ReleaseExposeFlaggedApi() bool {
+	return Bool(c.config.productVariables.Release_expose_flagged_api)
+}
+
+func (c *deviceConfig) HideFlaggedApis() bool {
+	return c.NextReleaseHideFlaggedApi() && !c.ReleaseExposeFlaggedApi()
+}
diff --git a/android/depset_generic.go b/android/depset_generic.go
index 9f07596..45c1937 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -95,12 +95,6 @@
 	}
 }
 
-// AddDirectToDepSet returns a new DepSet with additional elements added to its direct set.
-// The transitive sets remain untouched.
-func AddDirectToDepSet[T depSettableType](d *DepSet[T], direct ...T) *DepSet[T] {
-	return NewDepSet[T](d.order, Concat(d.direct, direct), d.transitive)
-}
-
 // DepSetBuilder is used to create an immutable DepSet.
 type DepSetBuilder[T depSettableType] struct {
 	order      DepSetOrder
@@ -194,14 +188,3 @@
 	}
 	return list
 }
-
-// ToListDirect returns the direct elements of a DepSet flattened to a list.
-func (d *DepSet[T]) ToListDirect() []T {
-	if d == nil {
-		return nil
-	}
-	list := make([]T, len(d.direct))
-	copy(list, d.direct)
-	list = firstUniqueInPlace(list)
-	return list
-}
diff --git a/android/filegroup.go b/android/filegroup.go
index a4bbcae..856c50e 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -22,7 +22,6 @@
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -51,7 +50,7 @@
 	// ignoring case, checks for proto or protos as an independent word in the name, whether at the
 	// beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
 	filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
-	filegroupLikelyAidlPattern  = regexp.MustCompile("(?i)(^|[^a-z])aidl([^a-z]|$)")
+	filegroupLikelyAidlPattern  = regexp.MustCompile("(?i)(^|[^a-z])aidl(s)?([^a-z]|$)")
 
 	ProtoSrcLabelPartition = bazel.LabelPartition{
 		Extensions:  []string{".proto"},
@@ -86,12 +85,6 @@
 	Strip_import_prefix *string
 }
 
-// api srcs can be contained in filegroups.
-// this should be generated in api_bp2build workspace as well.
-func (fg *fileGroup) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
-	fg.ConvertWithBp2build(ctx)
-}
-
 // ConvertWithBp2build performs bp2build conversion of filegroup
 func (fg *fileGroup) ConvertWithBp2build(ctx Bp2buildMutatorContext) {
 	srcs := bazel.MakeLabelListAttribute(
@@ -112,8 +105,10 @@
 		if f.Label == fg.Name() {
 			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, "")
+			} else {
+				panic("This situation should have been handled by FileGroupFactory's call to InitBazelModuleAsHandcrafted")
 			}
-			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_SRC_NAME_COLLISION, "")
 			return
 		}
 	}
@@ -259,6 +254,16 @@
 	module.AddProperties(&module.properties)
 	InitAndroidModule(module)
 	InitBazelModule(module)
+	AddBazelHandcraftedHook(module, func(ctx LoadHookContext) string {
+		// If there is a single src with the same name as the filegroup module name,
+		// then don't generate this filegroup. It will be OK for other targets
+		// to depend on this source file by name directly.
+		fg := ctx.Module().(*fileGroup)
+		if len(fg.properties.Srcs) == 1 && fg.Name() == fg.properties.Srcs[0] {
+			return fg.Name()
+		}
+		return ""
+	})
 	InitDefaultableModule(module)
 	return module
 }
diff --git a/android/module.go b/android/module.go
index f48af4a..74b8cb8 100644
--- a/android/module.go
+++ b/android/module.go
@@ -565,8 +565,8 @@
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
 
-	// IsConvertedByBp2build returns whether this module was converted via bp2build
-	IsConvertedByBp2build() bool
+	// If this module should not have bazel BUILD definitions generated by bp2build,
+	// GetUnconvertedReason returns a reason this is the case.
 	GetUnconvertedReason() *UnconvertedReason
 
 	// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module
@@ -1272,7 +1272,7 @@
 	m.base().commonProperties.CreateCommonOSVariant = true
 }
 
-func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext,
+func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *bottomUpMutatorContext,
 	enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes {
 
 	mod := ctx.Module().base()
@@ -1430,7 +1430,7 @@
 // If compile_mulitilib is set to
 // 1. 32: Add an incompatibility constraint for non-32 arches
 // 1. 64: Add an incompatibility constraint for non-64 arches
-func addCompatibilityConstraintForCompileMultilib(ctx *topDownMutatorContext, enabled *bazel.LabelListAttribute) {
+func addCompatibilityConstraintForCompileMultilib(ctx *bottomUpMutatorContext, enabled *bazel.LabelListAttribute) {
 	mod := ctx.Module().base()
 	multilib, _ := decodeMultilib(mod, mod.commonProperties.CompileOS, ctx.Config().IgnorePrefer32OnDevice())
 
@@ -1456,7 +1456,7 @@
 
 // Check product variables for `enabled: true` flag override.
 // Returns a list of the constraint_value targets who enable this override.
-func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute {
+func productVariableConfigEnableAttribute(ctx *bottomUpMutatorContext) bazel.LabelListAttribute {
 	result := bazel.LabelListAttribute{}
 	productVariableProps, errs := ProductVariableProperties(ctx, ctx.Module())
 	for _, err := range errs {
@@ -1639,35 +1639,16 @@
 }
 
 func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
-	reason := m.commonProperties.BazelConversionStatus.UnconvertedReason
-	if reason != nil {
-		panic(fmt.Errorf("bp2build: internal error trying to convert module '%s' marked unconvertible. Reason type %d: %s",
-			m.Name(),
-			reason.ReasonType,
-			reason.Detail))
-	}
 	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 {
-		fmt.Println(m.commonProperties.BazelConversionStatus.Bp2buildInfo)
-		panic(fmt.Errorf("bp2build: internal error trying to mark converted module '%s' as unconvertible. Reason type %d: %s",
-			m.Name(),
-			reasonType,
-			detail))
-	}
 	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
 }
diff --git a/android/mutator.go b/android/mutator.go
index 336f8f7..3d59655 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -35,13 +35,9 @@
 // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
 func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
 	bp2buildMutators := append(preArchMutators, registerBp2buildConversionMutator)
-	registerMutatorsForBazelConversion(ctx, bp2buildMutators)
-}
-
-// RegisterMutatorsForApiBazelConversion is an alternate registration pipeline for api_bp2build
-// This pipeline restricts generation of Bazel targets to Soong modules that contribute APIs
-func RegisterMutatorsForApiBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
-	bp2buildMutators := append(preArchMutators, registerApiBp2buildConversionMutator)
+	if ctx.config.Bp2buildDepsMutator {
+		bp2buildMutators = append(bp2buildMutators, registerBp2buildDepsMutator)
+	}
 	registerMutatorsForBazelConversion(ctx, bp2buildMutators)
 }
 
@@ -233,6 +229,15 @@
 	BazelConversionPathContext
 	BaseMutatorContext
 
+	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
+	// dependency (some entries may be nil).
+	//
+	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
+	// new dependencies have had the current mutator called on them.  If the mutator is not
+	// parallel this method does not affect the ordering of the current mutator pass, but will
+	// be ordered correctly for all future mutator passes.
+	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
+
 	// CreateBazelTargetModule creates a BazelTargetModule by calling the
 	// factory method, just like in CreateModule, but also requires
 	// BazelTargetModuleProperties containing additional metadata for the
@@ -284,7 +289,6 @@
 
 type TopDownMutatorContext interface {
 	BaseMutatorContext
-	Bp2buildMutatorContext
 
 	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
 	// the specified property structs to it as if the properties were set in a blueprint file.
@@ -300,15 +304,7 @@
 
 type BottomUpMutatorContext interface {
 	BaseMutatorContext
-
-	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
-	// dependency (some entries may be nil).
-	//
-	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
-	// new dependencies have had the current mutator called on them.  If the mutator is not
-	// parallel this method does not affect the ordering of the current mutator pass, but will
-	// be ordered correctly for all future mutator passes.
-	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
+	Bp2buildMutatorContext
 
 	// AddReverseDependency adds a dependency from the destination to the given module.
 	// Does not affect the ordering of the current mutator pass, but will be ordered
@@ -711,14 +707,14 @@
 	ctx.BottomUp("deps", depsMutator).Parallel()
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetModule(
+func (t *bottomUpMutatorContext) CreateBazelTargetModule(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{}) {
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, bazel.BoolAttribute{})
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetModuleWithRestrictions(
+func (t *bottomUpMutatorContext) CreateBazelTargetModuleWithRestrictions(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{},
@@ -726,7 +722,7 @@
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
 }
 
-func (t *topDownMutatorContext) MarkBp2buildUnconvertible(
+func (t *bottomUpMutatorContext) MarkBp2buildUnconvertible(
 	reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
 	mod := t.Module()
 	mod.base().setBp2buildUnconvertible(reasonType, detail)
@@ -742,7 +738,7 @@
 	Actual *bazel.LabelAttribute
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetAliasInDir(
+func (t *bottomUpMutatorContext) CreateBazelTargetAliasInDir(
 	dir string,
 	name string,
 	actual bazel.Label) {
@@ -763,7 +759,7 @@
 // Returns the directory in which the bazel target will be generated
 // If ca.Dir is not nil, use that
 // Otherwise default to the directory of the soong module
-func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string {
+func dirForBazelTargetGeneration(t *bottomUpMutatorContext, ca *CommonAttributes) string {
 	dir := t.OtherModuleDir(t.Module())
 	if ca.Dir != nil {
 		dir = *ca.Dir
@@ -781,7 +777,7 @@
 	return dir
 }
 
-func (t *topDownMutatorContext) CreateBazelConfigSetting(
+func (t *bottomUpMutatorContext) CreateBazelConfigSetting(
 	csa bazel.ConfigSettingAttributes,
 	ca CommonAttributes,
 	dir string) {
@@ -867,7 +863,7 @@
 	return ConvertApexAvailableToTags(noTestApexes)
 }
 
-func (t *topDownMutatorContext) createBazelTargetModule(
+func (t *bottomUpMutatorContext) createBazelTargetModule(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{},
diff --git a/android/paths.go b/android/paths.go
index d4b1d6e..325a953 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -171,9 +171,6 @@
 	// Base returns the last element of the path
 	Base() string
 
-	// Dir returns a path pointing the directory containing the path
-	Dir() Path
-
 	// Rel returns the portion of the path relative to the directory it was created from.  For
 	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
 	// directory, and OutputPath.Join("foo").Rel() would return "foo".
@@ -1015,12 +1012,6 @@
 	return filepath.Base(p.path)
 }
 
-func (p basePath) Dir() Path {
-	p.path = filepath.Dir(p.path)
-	p.rel = filepath.Dir(p.rel)
-	return p
-}
-
 func (p basePath) Rel() string {
 	if p.rel != "" {
 		return p.rel
@@ -1055,11 +1046,6 @@
 	return p
 }
 
-func (p SourcePath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 // safePathForSource is for paths that we expect are safe -- only for use by go
 // code that is embedding ninja variables in paths
 func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
@@ -1262,12 +1248,6 @@
 	return p
 }
 
-func (p OutputPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	p.fullPath = filepath.Dir(p.fullPath)
-	return p
-}
-
 func (p OutputPath) WithoutRel() OutputPath {
 	p.basePath.rel = filepath.Base(p.basePath.path)
 	return p
@@ -1300,11 +1280,6 @@
 	basePath
 }
 
-func (p toolDepPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (t toolDepPath) RelativeToTop() Path {
 	ensureTestOnly()
 	return t
@@ -1488,11 +1463,6 @@
 	OutputPath
 }
 
-func (p ModuleOutPath) Dir() Path {
-	p.OutputPath = p.OutputPath.Dir().(OutputPath)
-	return p
-}
-
 func (p ModuleOutPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1537,11 +1507,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleGenPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleGenPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1581,11 +1546,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleObjPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleObjPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1610,11 +1570,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleResPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleResPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1651,11 +1606,6 @@
 	makePath bool
 }
 
-func (p InstallPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 // Will panic if called from outside a test environment.
 func ensureTestOnly() {
 	if PrefixInList(os.Args, "-test.") {
@@ -1972,11 +1922,6 @@
 	basePath
 }
 
-func (p PhonyPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (p PhonyPath) writablePath() {}
 
 func (p PhonyPath) getSoongOutDir() string {
@@ -2002,11 +1947,6 @@
 	basePath
 }
 
-func (p testPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (p testPath) RelativeToTop() Path {
 	ensureTestOnly()
 	return p
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index c00b22b..17b3230 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -14,11 +14,7 @@
 
 package android
 
-import (
-	"path/filepath"
-
-	"github.com/google/blueprint"
-)
+import "path/filepath"
 
 func init() {
 	RegisterModuleType("prebuilt_build_tool", NewPrebuiltBuildTool)
@@ -59,13 +55,6 @@
 	}
 }
 
-type PrebuiltBuildToolInfo struct {
-	Src  Path
-	Deps Paths
-}
-
-var PrebuiltBuildToolInfoProvider = blueprint.NewProvider(PrebuiltBuildToolInfo{})
-
 func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) {
 	sourcePath := t.prebuilt.SingleSourcePath(ctx)
 	installedPath := PathForModuleOut(ctx, t.BaseModuleName())
@@ -93,11 +82,6 @@
 	}
 
 	t.toolPath = OptionalPathForPath(installedPath)
-
-	ctx.SetProvider(PrebuiltBuildToolInfoProvider, PrebuiltBuildToolInfo{
-		Src:  sourcePath,
-		Deps: deps,
-	})
 }
 
 func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) {
diff --git a/android/proto.go b/android/proto.go
index fc21d01..c449a87 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -289,7 +289,7 @@
 				attrs.Strip_import_prefix = proptools.StringPtr("")
 			}
 
-			tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
+			tags := ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 
 			moduleDir := ctx.ModuleDir()
 			if !canonicalPathFromRoot {
diff --git a/android/register.go b/android/register.go
index f1c2986..6182159 100644
--- a/android/register.go
+++ b/android/register.go
@@ -181,8 +181,7 @@
 	return ctx
 }
 
-// Helper function to register the module types used in bp2build and
-// api_bp2build.
+// Helper function to register the module types used in bp2build.
 func registerModuleTypes(ctx *Context) {
 	for _, t := range moduleTypes {
 		t.register(ctx)
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 3a2cb1a..c33ade5 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -148,7 +148,7 @@
 		return
 	}
 	if !ok {
-		t.Errorf("%s does not match regular expression %s", s, expectedRex)
+		t.Errorf("%s: %s does not match regular expression %s", message, s, expectedRex)
 	}
 }
 
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
index 71c76c5..6d0eeb7 100644
--- a/android/updatable_modules.go
+++ b/android/updatable_modules.go
@@ -14,9 +14,9 @@
 
 package android
 
-// This file contains branch specific constants for building updatable modules.
-// They are stored in a separate file to minimise the potential of merge
-// conflicts between branches when the code from the package is changed.
+// This file contains branch specific constants. They are stored in a separate
+// file to minimise the potential of merge conflicts between branches when
+// the code from the package is changed.
 
 // The default manifest version for all the modules on this branch.
 // This version code will be used only if there is no version field in the
@@ -33,4 +33,4 @@
 // * AOSP            - xx9990000
 // * x-mainline-prod - xx9990000
 // * master          - 990090000
-const DefaultUpdatableModuleVersion = "339990000"
+const DefaultUpdatableModuleVersion = "340090000"
diff --git a/android/util.go b/android/util.go
index 7f6af2d..5375373 100644
--- a/android/util.go
+++ b/android/util.go
@@ -33,17 +33,12 @@
 	return append([]T{}, s...)
 }
 
-// Concat returns a new slice concatenated from the input slices. It does not change the input
+// Concat returns a new slice concatenated from the two input slices. It does not change the input
 // slices.
-func Concat[T any](slices ...[]T) []T {
-	newLength := 0
-	for _, s := range slices {
-		newLength += len(s)
-	}
-	res := make([]T, 0, newLength)
-	for _, s := range slices {
-		res = append(res, s...)
-	}
+func Concat[T any](s1, s2 []T) []T {
+	res := make([]T, 0, len(s1)+len(s2))
+	res = append(res, s1...)
+	res = append(res, s2...)
 	return res
 }
 
diff --git a/android/variable.go b/android/variable.go
index d33294c..8882e80 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -418,8 +418,6 @@
 	ProductPublicSepolicyDirs  []string `json:",omitempty"`
 	ProductPrivateSepolicyDirs []string `json:",omitempty"`
 
-	ProductVndkVersion *string `json:",omitempty"`
-
 	TargetFSConfigGen []string `json:",omitempty"`
 
 	EnforceProductPartitionInterface *bool `json:",omitempty"`
@@ -485,11 +483,67 @@
 
 	CheckVendorSeappViolations *bool `json:",omitempty"`
 
-	// PartitionsVars are extra variables that are used to define the partition images. They should
-	// not be read from soong modules.
-	PartitionVars struct {
-		ProductDirectory string `json:",omitempty"`
-	} `json:",omitempty"`
+	// PartitionVarsForBazelMigrationOnlyDoNotUse are extra variables that are used to define the
+	// partition images. They should not be read from soong modules.
+	PartitionVarsForBazelMigrationOnlyDoNotUse PartitionVariables `json:",omitempty"`
+
+	NextReleaseHideFlaggedApi *bool `json:",omitempty"`
+
+	Release_expose_flagged_api *bool `json:",omitempty"`
+}
+
+type PartitionVariables struct {
+	ProductDirectory            string `json:",omitempty"`
+	PartitionQualifiedVariables map[string]struct {
+		BuildingImage               bool   `json:",omitempty"`
+		BoardErofsCompressor        string `json:",omitempty"`
+		BoardErofsCompressHints     string `json:",omitempty"`
+		BoardErofsPclusterSize      string `json:",omitempty"`
+		BoardExtfsInodeCount        string `json:",omitempty"`
+		BoardExtfsRsvPct            string `json:",omitempty"`
+		BoardF2fsSloadCompressFlags string `json:",omitempty"`
+		BoardFileSystemCompress     string `json:",omitempty"`
+		BoardFileSystemType         string `json:",omitempty"`
+		BoardJournalSize            string `json:",omitempty"`
+		BoardPartitionReservedSize  string `json:",omitempty"`
+		BoardPartitionSize          string `json:",omitempty"`
+		BoardSquashfsBlockSize      string `json:",omitempty"`
+		BoardSquashfsCompressor     string `json:",omitempty"`
+		BoardSquashfsCompressorOpt  string `json:",omitempty"`
+		BoardSquashfsDisable4kAlign string `json:",omitempty"`
+		ProductBaseFsPath           string `json:",omitempty"`
+		ProductHeadroom             string `json:",omitempty"`
+		ProductVerityPartition      string `json:",omitempty"`
+
+		BoardAvbAddHashtreeFooterArgs string `json:",omitempty"`
+		BoardAvbKeyPath               string `json:",omitempty"`
+		BoardAvbAlgorithm             string `json:",omitempty"`
+		BoardAvbRollbackIndex         string `json:",omitempty"`
+		BoardAvbRollbackIndexLocation string `json:",omitempty"`
+	}
+	TargetUserimagesUseExt2 bool `json:",omitempty"`
+	TargetUserimagesUseExt3 bool `json:",omitempty"`
+	TargetUserimagesUseExt4 bool `json:",omitempty"`
+
+	TargetUserimagesSparseExtDisabled      bool `json:",omitempty"`
+	TargetUserimagesSparseErofsDisabled    bool `json:",omitempty"`
+	TargetUserimagesSparseSquashfsDisabled bool `json:",omitempty"`
+	TargetUserimagesSparseF2fsDisabled     bool `json:",omitempty"`
+
+	BoardErofsCompressor                 string `json:",omitempty"`
+	BoardErofsCompressorHints            string `json:",omitempty"`
+	BoardErofsPclusterSize               string `json:",omitempty"`
+	BoardErofsShareDupBlocks             string `json:",omitempty"`
+	BoardErofsUseLegacyCompression       string `json:",omitempty"`
+	BoardExt4ShareDupBlocks              string `json:",omitempty"`
+	BoardFlashLogicalBlockSize           string `json:",omitempty"`
+	BoardFlashEraseBlockSize             string `json:",omitempty"`
+	BoardUsesRecoveryAsBoot              bool   `json:",omitempty"`
+	BoardBuildGkiBootImageWithoutRamdisk bool   `json:",omitempty"`
+	ProductUseDynamicPartitionSize       bool   `json:",omitempty"`
+	CopyImagesForTargetFilesZip          bool   `json:",omitempty"`
+
+	BoardAvbEnable bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/apex.go b/apex/apex.go
index 090d9c4..f903373 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -736,7 +736,7 @@
 			vndkVersion = deviceConfig.VndkVersion()
 		} else if a.ProductSpecific() {
 			prefix = cc.ProductVariationPrefix
-			vndkVersion = deviceConfig.ProductVndkVersion()
+			vndkVersion = deviceConfig.PlatformVndkVersion()
 		}
 	}
 	if vndkVersion == "current" {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 3a6af1e..e70d3af 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -948,7 +948,7 @@
 	// Ensure that stub dependency from a rust module is not included
 	ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
 	// The rust module is linked to the stub cc library
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").RuleParams.Command
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 
@@ -1024,7 +1024,7 @@
 	mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
 	ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
 	ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").RuleParams.Command
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 }
@@ -3088,10 +3088,7 @@
 			apex_available: ["myapex"],
 			srcs: ["foo.cpp"],
 		}
-	`, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		variables.ProductVndkVersion = proptools.StringPtr("current")
-	}),
-	)
+	`)
 
 	cflags := strings.Fields(
 		ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_myapex").Rule("cc").Args["cFlags"])
@@ -10521,6 +10518,7 @@
 			min_sdk_version: "29",
 			recovery_available: true,
 			vendor_available: true,
+			product_available: true,
 		}
 		api_imports {
 			name: "api_imports",
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 2b86e53..e2aee96 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -115,12 +115,7 @@
 	})
 
 	t.Run("VNDK APEX gathers only vendor variants even if product variants are available", func(t *testing.T) {
-		ctx := testApex(t, bp,
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				// Now product variant is available
-				variables.ProductVndkVersion = proptools.StringPtr("current")
-			}),
-		)
+		ctx := testApex(t, bp)
 
 		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
diff --git a/bazel/aquery.go b/bazel/aquery.go
index c355712..641f16b 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -18,14 +18,16 @@
 	"crypto/sha256"
 	"encoding/base64"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"path/filepath"
-	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 	"reflect"
 	"sort"
 	"strings"
 	"sync"
 
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
 	"github.com/google/blueprint/metrics"
 	"github.com/google/blueprint/proptools"
 	"google.golang.org/protobuf/proto"
@@ -370,13 +372,20 @@
 		defer eventHandler.End("build_statements")
 		wg := sync.WaitGroup{}
 		var errOnce sync.Once
-
+		id2targets := make(map[uint32]string, len(aqueryProto.Targets))
+		for _, t := range aqueryProto.Targets {
+			id2targets[t.GetId()] = t.GetLabel()
+		}
 		for i, actionEntry := range aqueryProto.Actions {
 			wg.Add(1)
 			go func(i int, actionEntry *analysis_v2_proto.Action) {
-				buildStatement, aErr := aqueryHandler.actionToBuildStatement(actionEntry)
-				if aErr != nil {
+				if strings.HasPrefix(id2targets[actionEntry.TargetId], "@bazel_tools//") {
+					// bazel_tools are removed depsets in `populateDepsetMaps()` so skipping
+					// conversion to build statements as well
+					buildStatements[i] = nil
+				} else if buildStatement, aErr := aqueryHandler.actionToBuildStatement(actionEntry); aErr != nil {
 					errOnce.Do(func() {
+						aErr = fmt.Errorf("%s: [%s] [%s]", aErr.Error(), actionEntry.GetMnemonic(), id2targets[actionEntry.TargetId])
 						err = aErr
 					})
 				} else {
@@ -782,7 +791,7 @@
 	}
 
 	if len(actionEntry.Arguments) < 1 {
-		return nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
+		return nil, errors.New("received action with no command")
 	}
 	return a.normalActionBuildStatement(actionEntry)
 
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 32c87a0..cbd2791 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -178,8 +178,8 @@
    { "id": 2, "path_fragment_id": 2 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [1],
    "output_ids": [3],
@@ -198,7 +198,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined outputId 3")
+	assertError(t, err, "undefined outputId 3: [X] []")
 }
 
 func TestInvalidInputDepsetIdFromAction(t *testing.T) {
@@ -209,13 +209,17 @@
    { "id": 2, "path_fragment_id": 2 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [2],
    "output_ids": [1],
    "primary_output_id": 1
  }],
+ "targets": [{
+   "id": 1,
+   "label": "target_x"
+ }],
  "dep_set_of_files": [
    { "id": 1, "direct_artifact_ids": [1, 2] }],
  "path_fragments": [
@@ -229,7 +233,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined (not even empty) input depsetId 2")
+	assertError(t, err, "undefined (not even empty) input depsetId 2: [X] [target_x]")
 }
 
 func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
@@ -383,8 +387,8 @@
    { "id": 4, "path_fragment_id": 4 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [1],
    "output_ids": [2,3,4],
@@ -407,7 +411,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
+	assertError(t, err, `found multiple potential depfiles "two.d", "other.d": [X] []`)
 }
 
 func TestTransitiveInputDepsets(t *testing.T) {
@@ -559,7 +563,7 @@
 	}, actual)
 }
 
-func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
+func TestBazelToolsRemovalFromInputDepsets(t *testing.T) {
 	const inputString = `{
  "artifacts": [
    { "id": 1, "path_fragment_id": 10 },
@@ -637,7 +641,55 @@
 	}
 }
 
-func TestBazelOutRemovalFromTransitiveInputDepsets(t *testing.T) {
+func TestBazelToolsRemovalFromTargets(t *testing.T) {
+	const inputString = `{
+ "artifacts": [{ "id": 1, "path_fragment_id": 10 }],
+ "targets": [
+   { "id": 100, "label": "targetX" },
+   { "id": 200, "label": "@bazel_tools//tool_y" }
+],
+ "actions": [{
+   "target_id": 100,
+   "action_key": "actionX",
+   "arguments": ["bogus", "command"],
+   "mnemonic" : "x",
+   "output_ids": [1]
+ }, {
+   "target_id": 200,
+   "action_key": "y"
+ }],
+ "path_fragments": [{ "id": 10, "label": "outputX"}]
+}`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if len(actualDepsets) != 0 {
+		t.Errorf("expected 0 depset but found %#v", actualDepsets)
+		return
+	}
+	expectedBuildStatement := &BuildStatement{
+		Command:      "bogus command",
+		OutputPaths:  []string{"outputX"},
+		Mnemonic:     "x",
+		SymlinkPaths: []string{},
+	}
+	buildStatementFound := false
+	for _, actualBuildStatement := range actualBuildStatements {
+		if buildStatementEquals(actualBuildStatement, expectedBuildStatement) == "" {
+			buildStatementFound = true
+			break
+		}
+	}
+	if !buildStatementFound {
+		t.Errorf("expected but missing %#v in %#v build statements", expectedBuildStatement, len(actualBuildStatements))
+		return
+	}
+}
+
+func TestBazelToolsRemovalFromTransitiveInputDepsets(t *testing.T) {
 	const inputString = `{
  "artifacts": [
    { "id": 1, "path_fragment_id": 10 },
@@ -939,7 +991,7 @@
    { "id": 3, "path_fragment_id": 3 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
+   "action_key": "action_x",
    "mnemonic": "Symlink",
    "input_dep_set_ids": [1],
    "output_ids": [3],
@@ -958,7 +1010,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
+	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]: [Symlink] []`)
 }
 
 func TestSymlinkMultipleOutputs(t *testing.T) {
@@ -989,7 +1041,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined outputId 2")
+	assertError(t, err, "undefined outputId 2: [Symlink] []")
 }
 
 func TestTemplateExpandActionSubstitutions(t *testing.T) {
@@ -1066,7 +1118,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `Expect 1 output to template expand action, got: output []`)
+	assertError(t, err, `Expect 1 output to template expand action, got: output []: [TemplateExpand] []`)
 }
 
 func TestFileWrite(t *testing.T) {
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 59aacbb..475c2d6 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -21,6 +21,17 @@
 	"android/soong/java"
 )
 
+func runAndroidLibraryImportTestWithRegistrationCtxFunc(t *testing.T, registrationCtxFunc func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "android_library_import"
+	(&tc).ModuleTypeUnderTestFactory = java.AARImportFactory
+	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
+}
+
+func runAndroidLibraryImportTest(t *testing.T, tc Bp2buildTestCase) {
+	runAndroidLibraryImportTestWithRegistrationCtxFunc(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
 func TestConvertAndroidLibrary(t *testing.T) {
 	t.Helper()
 	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
@@ -75,7 +86,7 @@
 func TestConvertAndroidLibraryWithNoSources(t *testing.T) {
 	t.Helper()
 	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library - modules with deps must have sources",
+		Description:                "Android Library - modules will deps when there are no sources",
 		ModuleTypeUnderTest:        "android_library",
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
 		Filesystem: map[string]string{
@@ -91,26 +102,30 @@
 	sdk_version: "current",
 }
 `,
-		ExpectedBazelTargets: []string{},
+		StubbedBuildDefinitions: []string{"lib_dep"},
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget(
+				"android_library",
+				"TestLib",
+				AttrNameToString{
+					"manifest":       `"AndroidManifest.xml"`,
+					"resource_files": `["res/res.png"]`,
+					"sdk_version":    `"current"`, // use as default
+				},
+			),
+			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
+		},
 	})
 }
 
 func TestConvertAndroidLibraryImport(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(
-		t,
+	runAndroidLibraryImportTestWithRegistrationCtxFunc(t,
 		func(ctx android.RegistrationContext) {
 			ctx.RegisterModuleType("android_library", java.AndroidLibraryFactory)
 		},
 		Bp2buildTestCase{
-			Description:                "Android Library Import",
-			ModuleTypeUnderTest:        "android_library_import",
-			ModuleTypeUnderTestFactory: java.AARImportFactory,
-			Filesystem: map[string]string{
-				"import.aar": "",
-				"dep.aar":    "",
-			},
-			StubbedBuildDefinitions: []string{"static_lib_dep", "prebuilt_static_import_dep"},
+			Description:             "Android Library Import",
+			StubbedBuildDefinitions: []string{"static_lib_dep", "static_import_dep", "static_import_dep-neverlink"},
 			// Bazel's aar_import can only export *_import targets, so we expect
 			// only "static_import_dep" in exports, but both "static_lib_dep" and
 			// "static_import_dep" in deps
@@ -122,9 +137,9 @@
     sdk_version: "current",
 }
 
-// TODO: b/301007952 - This dep is needed because android_library_import must have aars set.
 android_library_import {
         name: "static_import_dep",
+        aars: ["import.aar"],
 }
 `,
 			ExpectedBazelTargets: []string{
@@ -219,3 +234,16 @@
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
 }
+
+func TestAarImportFailsToConvertNoAars(t *testing.T) {
+	runAndroidLibraryImportTest(t,
+		Bp2buildTestCase{
+			Description: "Android Library Import with no aars does not convert.",
+			Blueprint: `
+android_library_import {
+        name: "no_aar_import",
+}
+`,
+			ExpectedBazelTargets: []string{},
+		})
+}
diff --git a/bp2build/aconfig_conversion_test.go b/bp2build/aconfig_conversion_test.go
index cbf42ac..9d73ec0 100644
--- a/bp2build/aconfig_conversion_test.go
+++ b/bp2build/aconfig_conversion_test.go
@@ -20,11 +20,13 @@
 	"android/soong/aconfig"
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/java"
 )
 
 func registerAconfigModuleTypes(ctx android.RegistrationContext) {
 	aconfig.RegisterBuildComponents(ctx)
 	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
+	ctx.RegisterModuleType("java_library", java.LibraryFactory)
 }
 
 func TestAconfigDeclarations(t *testing.T) {
@@ -105,7 +107,6 @@
 	cc_library {
 			name: "server_configurable_flags",
 			srcs: ["bar.cc"],
-			bazel_module: { bp2build_available: false },
 	}
 	cc_aconfig_library {
 			name: "foo",
@@ -131,6 +132,105 @@
 			},
 		)}
 	RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		StubbedBuildDefinitions: []string{"server_configurable_flags"},
+	})
+}
+
+func TestJavaAconfigLibrary(t *testing.T) {
+	bp := `
+	aconfig_declarations {
+		name: "foo_aconfig_declarations",
+		srcs: [
+			"foo1.aconfig",
+		],
+		package: "com.android.foo",
+	}
+	java_aconfig_library {
+			name: "foo",
+			aconfig_declarations: "foo_aconfig_declarations",
+			test: true,
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTargetNoRestrictions(
+			"aconfig_declarations",
+			"foo_aconfig_declarations",
+			AttrNameToString{
+				"srcs":    `["foo1.aconfig"]`,
+				"package": `"com.android.foo"`,
+			},
+		),
+		MakeBazelTargetNoRestrictions(
+			"java_aconfig_library",
+			"foo",
+			AttrNameToString{
+				"aconfig_declarations":   `":foo_aconfig_declarations"`,
+				"test":                   `True`,
+				"sdk_version":            `"system_current"`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			},
+		)}
+	RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+	})
+}
+
+func TestJavaAconfigLibraryAsTaggedOutput(t *testing.T) {
+	bp := `
+	aconfig_declarations {
+		name: "foo_aconfig_declarations",
+		srcs: [
+			"foo.aconfig",
+		],
+		package: "com.android.foo",
+	}
+	java_library {
+			name: "foo_library",
+			srcs: [":foo_aconfig_library{.generated_srcjars}"],
+			sdk_version: "current",
+			bazel_module: { bp2build_available: true },
+	}
+	java_aconfig_library {
+			name: "foo_aconfig_library",
+			aconfig_declarations: "foo_aconfig_declarations",
+			test: true,
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTargetNoRestrictions(
+			"aconfig_declarations",
+			"foo_aconfig_declarations",
+			AttrNameToString{
+				"srcs":    `["foo.aconfig"]`,
+				"package": `"com.android.foo"`,
+			},
+		),
+		MakeBazelTargetNoRestrictions(
+			"java_aconfig_library",
+			"foo_aconfig_library",
+			AttrNameToString{
+				"aconfig_declarations":   `":foo_aconfig_declarations"`,
+				"test":                   `True`,
+				"sdk_version":            `"system_current"`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			},
+		),
+		MakeBazelTargetNoRestrictions(
+			"java_library",
+			"foo_library",
+			AttrNameToString{
+				"srcs":                   `[":foo_aconfig_library.generated_srcjars"]`,
+				"sdk_version":            `"current"`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			},
+		),
+		MakeNeverlinkDuplicateTarget("java_library", "foo_library"),
+	}
+
+	RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{
 		Blueprint:            bp,
 		ExpectedBazelTargets: expectedBazelTargets,
 	})
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index 8ec4b35..afe6dcd 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -478,3 +478,41 @@
 			}),
 		}})
 }
+
+func TestFrameworkResConversion(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Framework Res custom conversion",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem: map[string]string{
+			"res/values/attrs.xml": "",
+			"resource_zip.zip":     "",
+		},
+		Blueprint: `
+android_app {
+	name: "framework-res",
+	resource_zips: [
+		"resource_zip.zip",
+	],
+	certificate: "platform",
+}
+
+filegroup {
+	name: "framework-res-package-jar",
+	srcs: [":framework-res{.export-package.apk}"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("framework_resources", "framework-res", AttrNameToString{
+				"certificate_name":       `"platform"`,
+				"manifest":               `"AndroidManifest.xml"`,
+				"resource_files":         `["res/values/attrs.xml"]`,
+				"resource_zips":          `["resource_zip.zip"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			}),
+			MakeBazelTargetNoRestrictions("filegroup", "framework-res-package-jar", AttrNameToString{
+				"srcs": `[":framework-res.export-package.apk"]`,
+			}),
+		}})
+
+}
diff --git a/bp2build/android_test_conversion_test.go b/bp2build/android_test_conversion_test.go
index 52413fa..486f154 100644
--- a/bp2build/android_test_conversion_test.go
+++ b/bp2build/android_test_conversion_test.go
@@ -47,7 +47,40 @@
 		name: "TestApp",
 		srcs: ["app.java"],
 		sdk_version: "current",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_test", "TestApp", AttrNameToString{
+				"srcs":           `["app.java"]`,
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `["res/res.png"]`,
+				"sdk_version":    `"current"`,
+				"assets":         `["assets/asset.png"]`,
+				"assets_dir":     `"assets"`,
+				// no need for optimize = False because it's false for
+				// android_test by default
+			}),
+		}})
+}
+
+func TestAndroidTest_OptimizationEnabled(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android test - simple example",
+		ModuleTypeUnderTest:        "android_test",
+		ModuleTypeUnderTestFactory: java.AndroidTestFactory,
+		Filesystem: map[string]string{
+			"app.java":            "",
+			"res/res.png":         "",
+			"AndroidManifest.xml": "",
+			"assets/asset.png":    "",
+		},
+		Blueprint: `
+android_test {
+		name: "TestApp",
+		srcs: ["app.java"],
+		sdk_version: "current",
 		optimize: {
+			enabled: true,
 			shrink: true,
 			optimize: true,
 			obfuscate: true,
@@ -62,6 +95,9 @@
 				"sdk_version":    `"current"`,
 				"assets":         `["assets/asset.png"]`,
 				"assets_dir":     `"assets"`,
+				// optimize = True because it's false for android_test by
+				// default
+				"optimize": `True`,
 			}),
 		}})
 }
@@ -98,6 +134,45 @@
 				"assets":         `["assets/asset.png"]`,
 				"assets_dir":     `"assets"`,
 				"testonly":       `True`,
+				// no need for optimize = True because it's true for
+				// android_test_helper_app by default
+			}),
+		}})
+}
+
+func TestAndroidTestHelperApp_OptimizationDisabled(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android test helper app - simple example",
+		ModuleTypeUnderTest:        "android_test_helper_app",
+		ModuleTypeUnderTestFactory: java.AndroidTestHelperAppFactory,
+		Filesystem: map[string]string{
+			"app.java":            "",
+			"res/res.png":         "",
+			"AndroidManifest.xml": "",
+			"assets/asset.png":    "",
+		},
+		Blueprint: `
+android_test_helper_app {
+		name: "TestApp",
+		srcs: ["app.java"],
+		sdk_version: "current",
+		optimize: {
+			enabled: false,
+		},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
+				"srcs":           `["app.java"]`,
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `["res/res.png"]`,
+				"sdk_version":    `"current"`,
+				"assets":         `["assets/asset.png"]`,
+				"assets_dir":     `"assets"`,
+				"testonly":       `True`,
+				// optimize = False because it's true for
+				// android_test_helper_app by default
+				"optimize": `False`,
 			}),
 		}})
 }
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 60de28c..5871d59 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -112,7 +112,7 @@
 }
 
 cc_binary { name: "cc_binary_1"}
-sh_binary { name: "sh_binary_2"}
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex {
 	name: "com.android.apogee",
@@ -609,7 +609,7 @@
 }
 
 cc_binary { name: "cc_binary_1" }
-sh_binary { name: "sh_binary_2" }
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex {
 	name: "com.android.apogee",
@@ -736,7 +736,7 @@
 }
 
 cc_binary { name: "cc_binary_1"}
-sh_binary { name: "sh_binary_2"}
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex_test {
 	name: "com.android.apogee",
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index 7c26262..3e00453 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -6,6 +6,7 @@
 	"os"
 	"path/filepath"
 	"reflect"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -22,6 +23,32 @@
 	bp2buildTargets map[string]BazelTargets
 }
 
+type bazelLabel struct {
+	repo   string
+	pkg    string
+	target string
+}
+
+func (l *bazelLabel) Less(other *bazelLabel) bool {
+	if l.repo < other.repo {
+		return true
+	}
+	if l.repo > other.repo {
+		return false
+	}
+	if l.pkg < other.pkg {
+		return true
+	}
+	if l.pkg > other.pkg {
+		return false
+	}
+	return l.target < other.target
+}
+
+func (l *bazelLabel) String() string {
+	return fmt.Sprintf("@%s//%s:%s", l.repo, l.pkg, l.target)
+}
+
 func createProductConfigFiles(
 	ctx *CodegenContext,
 	metrics CodegenMetrics) (createProductConfigFilesResult, error) {
@@ -54,8 +81,8 @@
 	}
 
 	currentProductFolder := fmt.Sprintf("build/bazel/products/%s", targetProduct)
-	if len(productVariables.PartitionVars.ProductDirectory) > 0 {
-		currentProductFolder = fmt.Sprintf("%s%s", productVariables.PartitionVars.ProductDirectory, targetProduct)
+	if len(productVariables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory) > 0 {
+		currentProductFolder = fmt.Sprintf("%s%s", productVariables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory, targetProduct)
 	}
 
 	productReplacer := strings.NewReplacer(
@@ -72,14 +99,22 @@
 		productsForTesting[i] = fmt.Sprintf("  \"@//build/bazel/tests/products:%s\",", productsForTesting[i])
 	}
 
-	productLabelsToVariables := make(map[string]*android.ProductVariables)
-	productLabelsToVariables[productReplacer.Replace("@//{PRODUCT_FOLDER}:{PRODUCT}")] = &productVariables
+	productLabelsToVariables := make(map[bazelLabel]*android.ProductVariables)
+	productLabelsToVariables[bazelLabel{
+		repo:   "",
+		pkg:    currentProductFolder,
+		target: targetProduct,
+	}] = &productVariables
 	for product, productVariablesStarlark := range productsForTestingMap {
 		productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
 		if err != nil {
 			return res, err
 		}
-		productLabelsToVariables["@//build/bazel/tests/products:"+product] = &productVariables
+		productLabelsToVariables[bazelLabel{
+			repo:   "",
+			pkg:    "build/bazel/tests/products",
+			target: product,
+		}] = &productVariables
 	}
 
 	res.bp2buildTargets = make(map[string]BazelTargets)
@@ -194,7 +229,7 @@
 }
 
 func platformMappingContent(
-	productLabelToVariables map[string]*android.ProductVariables,
+	productLabelToVariables map[bazelLabel]*android.ProductVariables,
 	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
 	convertedModulePathMap map[string]string) (string, error) {
 	var result strings.Builder
@@ -211,9 +246,16 @@
 		mergedConvertedModulePathMap[k] = v
 	}
 
+	productLabels := make([]bazelLabel, 0, len(productLabelToVariables))
+	for k := range productLabelToVariables {
+		productLabels = append(productLabels, k)
+	}
+	sort.Slice(productLabels, func(i, j int) bool {
+		return productLabels[i].Less(&productLabels[j])
+	})
 	result.WriteString("platforms:\n")
-	for productLabel, productVariables := range productLabelToVariables {
-		platformMappingSingleProduct(productLabel, productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
+	for _, productLabel := range productLabels {
+		platformMappingSingleProduct(productLabel, productLabelToVariables[productLabel], soongConfigDefinitions, mergedConvertedModulePathMap, &result)
 	}
 	return result.String(), nil
 }
@@ -233,7 +275,7 @@
 }
 
 func platformMappingSingleProduct(
-	label string,
+	label bazelLabel,
 	productVariables *android.ProductVariables,
 	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
 	convertedModulePathMap map[string]string,
@@ -249,11 +291,22 @@
 		defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":generated_android_certificate_directory"
 	}
 
+	// TODO: b/301598690 - commas can't be escaped in a string-list passed in a platform mapping,
+	// so commas are switched for ":" here, and must be back-substituted into commas
+	// wherever the AAPTCharacteristics product config variable is used.
+	AAPTConfig := []string{}
+	for _, conf := range productVariables.AAPTConfig {
+		AAPTConfig = append(AAPTConfig, strings.Replace(conf, ",", ":", -1))
+	}
+
 	for _, suffix := range bazelPlatformSuffixes {
 		result.WriteString("  ")
-		result.WriteString(label)
+		result.WriteString(label.String())
 		result.WriteString(suffix)
 		result.WriteString("\n")
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:aapt_characteristics=%s\n", proptools.String(productVariables.AAPTCharacteristics)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:aapt_config=%s\n", strings.Join(AAPTConfig, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:aapt_preferred_config=%s\n", proptools.String(productVariables.AAPTPreferredConfig)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:arc=%t\n", proptools.Bool(productVariables.Arc)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
@@ -272,7 +325,7 @@
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_page_size_agnostic=%t\n", proptools.Bool(productVariables.DevicePageSizeAgnostic)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_platform=%s\n", label))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_platform=%s\n", label.String()))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte)))
@@ -284,6 +337,8 @@
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_sdk_final=%t\n", proptools.Bool(productVariables.Platform_sdk_final)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_security_patch=%s\n", proptools.String(productVariables.Platform_security_patch)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_version_last_stable=%s\n", proptools.String(productVariables.Platform_version_last_stable)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
@@ -310,8 +365,9 @@
 			}
 		}
 
-		for namespace, namespaceContents := range productVariables.VendorVars {
-			for variable, value := range namespaceContents {
+		for _, namespace := range android.SortedKeys(productVariables.VendorVars) {
+			for _, variable := range android.SortedKeys(productVariables.VendorVars[namespace]) {
+				value := productVariables.VendorVars[namespace][variable]
 				key := namespace + "__" + variable
 				_, hasBool := soongConfigDefinitions.BoolVars[key]
 				_, hasString := soongConfigDefinitions.StringVars[key]
@@ -422,11 +478,15 @@
 	return result, nil
 }
 
-func createTargets(productLabelsToVariables map[string]*android.ProductVariables, res map[string]BazelTargets) {
+func createTargets(productLabelsToVariables map[bazelLabel]*android.ProductVariables, res map[string]BazelTargets) {
 	createGeneratedAndroidCertificateDirectories(productLabelsToVariables, res)
+	createAvbKeyFilegroups(productLabelsToVariables, res)
+	for label, variables := range productLabelsToVariables {
+		createSystemPartition(label, &variables.PartitionVarsForBazelMigrationOnlyDoNotUse, res)
+	}
 }
 
-func createGeneratedAndroidCertificateDirectories(productLabelsToVariables map[string]*android.ProductVariables, targets map[string]BazelTargets) {
+func createGeneratedAndroidCertificateDirectories(productLabelsToVariables map[bazelLabel]*android.ProductVariables, targets map[string]BazelTargets) {
 	var allDefaultAppCertificateDirs []string
 	for _, productVariables := range productLabelsToVariables {
 		if proptools.String(productVariables.DefaultAppCertificate) != "" {
@@ -454,3 +514,311 @@
 		})
 	}
 }
+
+func createAvbKeyFilegroups(productLabelsToVariables map[bazelLabel]*android.ProductVariables, targets map[string]BazelTargets) {
+	var allAvbKeys []string
+	for _, productVariables := range productLabelsToVariables {
+		for _, partitionVariables := range productVariables.PartitionVarsForBazelMigrationOnlyDoNotUse.PartitionQualifiedVariables {
+			if partitionVariables.BoardAvbKeyPath != "" {
+				if !android.InList(partitionVariables.BoardAvbKeyPath, allAvbKeys) {
+					allAvbKeys = append(allAvbKeys, partitionVariables.BoardAvbKeyPath)
+				}
+			}
+		}
+	}
+	for _, key := range allAvbKeys {
+		dir := filepath.Dir(key)
+		name := filepath.Base(key)
+		content := fmt.Sprintf(`filegroup(
+    name = "%s_filegroup",
+    srcs = ["%s"],
+    visibility = ["//visibility:public"],
+)`, name, name)
+		targets[dir] = append(targets[dir], BazelTarget{
+			name:        name + "_filegroup",
+			packageName: dir,
+			content:     content,
+			ruleClass:   "filegroup",
+		})
+	}
+}
+
+func createSystemPartition(platformLabel bazelLabel, variables *android.PartitionVariables, targets map[string]BazelTargets) {
+	if !variables.PartitionQualifiedVariables["system"].BuildingImage {
+		return
+	}
+	qualifiedVariables := variables.PartitionQualifiedVariables["system"]
+
+	imageProps := generateImagePropDictionary(variables, "system")
+	imageProps["skip_fsck"] = "true"
+
+	var properties strings.Builder
+	for _, prop := range android.SortedKeys(imageProps) {
+		properties.WriteString(prop)
+		properties.WriteRune('=')
+		properties.WriteString(imageProps[prop])
+		properties.WriteRune('\n')
+	}
+
+	var extraProperties strings.Builder
+	if variables.BoardAvbEnable {
+		extraProperties.WriteString("    avb_enable = True,\n")
+		extraProperties.WriteString(fmt.Sprintf("    avb_add_hashtree_footer_args = %q,\n", qualifiedVariables.BoardAvbAddHashtreeFooterArgs))
+		keypath := qualifiedVariables.BoardAvbKeyPath
+		if keypath != "" {
+			extraProperties.WriteString(fmt.Sprintf("    avb_key = \"//%s:%s\",\n", filepath.Dir(keypath), filepath.Base(keypath)+"_filegroup"))
+			extraProperties.WriteString(fmt.Sprintf("    avb_algorithm = %q,\n", qualifiedVariables.BoardAvbAlgorithm))
+			extraProperties.WriteString(fmt.Sprintf("    avb_rollback_index = %s,\n", qualifiedVariables.BoardAvbRollbackIndex))
+			extraProperties.WriteString(fmt.Sprintf("    avb_rollback_index_location = %s,\n", qualifiedVariables.BoardAvbRollbackIndexLocation))
+		}
+	}
+
+	targets[platformLabel.pkg] = append(targets[platformLabel.pkg], BazelTarget{
+		name:        "system_image",
+		packageName: platformLabel.pkg,
+		content: fmt.Sprintf(`partition(
+    name = "system_image",
+    base_staging_dir = "//build/bazel/bazel_sandwich:system_staging_dir",
+    base_staging_dir_file_list = "//build/bazel/bazel_sandwich:system_staging_dir_file_list",
+    root_dir = "//build/bazel/bazel_sandwich:root_staging_dir",
+    selinux_file_contexts = "//build/bazel/bazel_sandwich:selinux_file_contexts",
+    image_properties = """
+%s
+""",
+%s
+    type = "system",
+)`, properties.String(), extraProperties.String()),
+		ruleClass: "partition",
+		loads: []BazelLoad{{
+			file: "//build/bazel/rules/partitions:partition.bzl",
+			symbols: []BazelLoadSymbol{{
+				symbol: "partition",
+			}},
+		}},
+	}, BazelTarget{
+		name:        "system_image_test",
+		packageName: platformLabel.pkg,
+		content: `partition_diff_test(
+    name = "system_image_test",
+    partition1 = "//build/bazel/bazel_sandwich:make_system_image",
+    partition2 = ":system_image",
+)`,
+		ruleClass: "partition_diff_test",
+		loads: []BazelLoad{{
+			file: "//build/bazel/rules/partitions/diff:partition_diff.bzl",
+			symbols: []BazelLoadSymbol{{
+				symbol: "partition_diff_test",
+			}},
+		}},
+	}, BazelTarget{
+		name:        "run_system_image_test",
+		packageName: platformLabel.pkg,
+		content: `run_test_in_build(
+    name = "run_system_image_test",
+    test = ":system_image_test",
+)`,
+		ruleClass: "run_test_in_build",
+		loads: []BazelLoad{{
+			file: "//build/bazel/bazel_sandwich:run_test_in_build.bzl",
+			symbols: []BazelLoadSymbol{{
+				symbol: "run_test_in_build",
+			}},
+		}},
+	})
+}
+
+var allPartitionTypes = []string{
+	"system",
+	"vendor",
+	"cache",
+	"userdata",
+	"product",
+	"system_ext",
+	"oem",
+	"odm",
+	"vendor_dlkm",
+	"odm_dlkm",
+	"system_dlkm",
+}
+
+// An equivalent of make's generate-image-prop-dictionary function
+func generateImagePropDictionary(variables *android.PartitionVariables, partitionType string) map[string]string {
+	partitionQualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]
+	if !ok {
+		panic("Unknown partitionType: " + partitionType)
+	}
+	ret := map[string]string{}
+	if partitionType == "system" {
+		if len(variables.PartitionQualifiedVariables["system_other"].BoardPartitionSize) > 0 {
+			ret["system_other_size"] = variables.PartitionQualifiedVariables["system_other"].BoardPartitionSize
+		}
+		if len(partitionQualifiedVariables.ProductHeadroom) > 0 {
+			ret["system_headroom"] = partitionQualifiedVariables.ProductHeadroom
+		}
+		addCommonRoFlagsToImageProps(variables, partitionType, ret)
+	}
+	// TODO: other partition-specific logic
+	if variables.TargetUserimagesUseExt2 {
+		ret["fs_type"] = "ext2"
+	} else if variables.TargetUserimagesUseExt3 {
+		ret["fs_type"] = "ext3"
+	} else if variables.TargetUserimagesUseExt4 {
+		ret["fs_type"] = "ext4"
+	}
+
+	if !variables.TargetUserimagesSparseExtDisabled {
+		ret["extfs_sparse_flag"] = "-s"
+	}
+	if !variables.TargetUserimagesSparseErofsDisabled {
+		ret["erofs_sparse_flag"] = "-s"
+	}
+	if !variables.TargetUserimagesSparseSquashfsDisabled {
+		ret["squashfs_sparse_flag"] = "-s"
+	}
+	if !variables.TargetUserimagesSparseF2fsDisabled {
+		ret["f2fs_sparse_flag"] = "-S"
+	}
+	erofsCompressor := variables.BoardErofsCompressor
+	if len(erofsCompressor) == 0 && hasErofsPartition(variables) {
+		if len(variables.BoardErofsUseLegacyCompression) > 0 {
+			erofsCompressor = "lz4"
+		} else {
+			erofsCompressor = "lz4hc,9"
+		}
+	}
+	if len(erofsCompressor) > 0 {
+		ret["erofs_default_compressor"] = erofsCompressor
+	}
+	if len(variables.BoardErofsCompressorHints) > 0 {
+		ret["erofs_default_compress_hints"] = variables.BoardErofsCompressorHints
+	}
+	if len(variables.BoardErofsCompressorHints) > 0 {
+		ret["erofs_default_compress_hints"] = variables.BoardErofsCompressorHints
+	}
+	if len(variables.BoardErofsPclusterSize) > 0 {
+		ret["erofs_pcluster_size"] = variables.BoardErofsPclusterSize
+	}
+	if len(variables.BoardErofsShareDupBlocks) > 0 {
+		ret["erofs_share_dup_blocks"] = variables.BoardErofsShareDupBlocks
+	}
+	if len(variables.BoardErofsUseLegacyCompression) > 0 {
+		ret["erofs_use_legacy_compression"] = variables.BoardErofsUseLegacyCompression
+	}
+	if len(variables.BoardExt4ShareDupBlocks) > 0 {
+		ret["ext4_share_dup_blocks"] = variables.BoardExt4ShareDupBlocks
+	}
+	if len(variables.BoardFlashLogicalBlockSize) > 0 {
+		ret["flash_logical_block_size"] = variables.BoardFlashLogicalBlockSize
+	}
+	if len(variables.BoardFlashEraseBlockSize) > 0 {
+		ret["flash_erase_block_size"] = variables.BoardFlashEraseBlockSize
+	}
+	if len(variables.BoardExt4ShareDupBlocks) > 0 {
+		ret["ext4_share_dup_blocks"] = variables.BoardExt4ShareDupBlocks
+	}
+	if len(variables.BoardExt4ShareDupBlocks) > 0 {
+		ret["ext4_share_dup_blocks"] = variables.BoardExt4ShareDupBlocks
+	}
+	for _, partitionType := range allPartitionTypes {
+		if qualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]; ok && len(qualifiedVariables.ProductVerityPartition) > 0 {
+			ret[partitionType+"_verity_block_device"] = qualifiedVariables.ProductVerityPartition
+		}
+	}
+	// TODO: Vboot
+	// TODO: AVB
+	if variables.BoardUsesRecoveryAsBoot {
+		ret["recovery_as_boot"] = "true"
+	}
+	if variables.BoardBuildGkiBootImageWithoutRamdisk {
+		ret["gki_boot_image_without_ramdisk"] = "true"
+	}
+	if variables.ProductUseDynamicPartitionSize {
+		ret["use_dynamic_partition_size"] = "true"
+	}
+	if variables.CopyImagesForTargetFilesZip {
+		ret["use_fixed_timestamp"] = "true"
+	}
+	return ret
+}
+
+// Soong equivalent of make's add-common-ro-flags-to-image-props
+func addCommonRoFlagsToImageProps(variables *android.PartitionVariables, partitionType string, ret map[string]string) {
+	partitionQualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]
+	if !ok {
+		panic("Unknown partitionType: " + partitionType)
+	}
+	if len(partitionQualifiedVariables.BoardErofsCompressor) > 0 {
+		ret[partitionType+"_erofs_compressor"] = partitionQualifiedVariables.BoardErofsCompressor
+	}
+	if len(partitionQualifiedVariables.BoardErofsCompressHints) > 0 {
+		ret[partitionType+"_erofs_compress_hints"] = partitionQualifiedVariables.BoardErofsCompressHints
+	}
+	if len(partitionQualifiedVariables.BoardErofsPclusterSize) > 0 {
+		ret[partitionType+"_erofs_pcluster_size"] = partitionQualifiedVariables.BoardErofsPclusterSize
+	}
+	if len(partitionQualifiedVariables.BoardExtfsRsvPct) > 0 {
+		ret[partitionType+"_extfs_rsv_pct"] = partitionQualifiedVariables.BoardExtfsRsvPct
+	}
+	if len(partitionQualifiedVariables.BoardF2fsSloadCompressFlags) > 0 {
+		ret[partitionType+"_f2fs_sldc_flags"] = partitionQualifiedVariables.BoardF2fsSloadCompressFlags
+	}
+	if len(partitionQualifiedVariables.BoardFileSystemCompress) > 0 {
+		ret[partitionType+"_f2fs_compress"] = partitionQualifiedVariables.BoardFileSystemCompress
+	}
+	if len(partitionQualifiedVariables.BoardFileSystemType) > 0 {
+		ret[partitionType+"_fs_type"] = partitionQualifiedVariables.BoardFileSystemType
+	}
+	if len(partitionQualifiedVariables.BoardJournalSize) > 0 {
+		ret[partitionType+"_journal_size"] = partitionQualifiedVariables.BoardJournalSize
+	}
+	if len(partitionQualifiedVariables.BoardPartitionReservedSize) > 0 {
+		ret[partitionType+"_reserved_size"] = partitionQualifiedVariables.BoardPartitionReservedSize
+	}
+	if len(partitionQualifiedVariables.BoardPartitionSize) > 0 {
+		ret[partitionType+"_size"] = partitionQualifiedVariables.BoardPartitionSize
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsBlockSize) > 0 {
+		ret[partitionType+"_squashfs_block_size"] = partitionQualifiedVariables.BoardSquashfsBlockSize
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsCompressor) > 0 {
+		ret[partitionType+"_squashfs_compressor"] = partitionQualifiedVariables.BoardSquashfsCompressor
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsCompressorOpt) > 0 {
+		ret[partitionType+"_squashfs_compressor_opt"] = partitionQualifiedVariables.BoardSquashfsCompressorOpt
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsDisable4kAlign) > 0 {
+		ret[partitionType+"_squashfs_disable_4k_align"] = partitionQualifiedVariables.BoardSquashfsDisable4kAlign
+	}
+	if len(partitionQualifiedVariables.BoardPartitionSize) == 0 && len(partitionQualifiedVariables.BoardPartitionReservedSize) == 0 && len(partitionQualifiedVariables.ProductHeadroom) == 0 {
+		ret[partitionType+"_disable_sparse"] = "true"
+	}
+	addCommonFlagsToImageProps(variables, partitionType, ret)
+}
+
+func hasErofsPartition(variables *android.PartitionVariables) bool {
+	return variables.PartitionQualifiedVariables["product"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["system_ext"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["odm"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["vendor"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["system"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["vendor_dlkm"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["odm_dlkm"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["system_dlkm"].BoardFileSystemType == "erofs"
+}
+
+// Soong equivalent of make's add-common-flags-to-image-props
+func addCommonFlagsToImageProps(variables *android.PartitionVariables, partitionType string, ret map[string]string) {
+	// The selinux_fc will be handled separately
+	partitionQualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]
+	if !ok {
+		panic("Unknown partitionType: " + partitionType)
+	}
+	ret["building_"+partitionType+"_image"] = boolToMakeString(partitionQualifiedVariables.BuildingImage)
+}
+
+func boolToMakeString(b bool) string {
+	if b {
+		return "true"
+	}
+	return ""
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 15b7766..53c37b9 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -287,9 +287,9 @@
 	return r.buildFileToTargets
 }
 
-// struct to store state of go bazel targets
+// struct to store state of b bazel targets (e.g. go targets which do not implement android.Module)
 // this implements bp2buildModule interface and is passed to generateBazelTargets
-type goBazelTarget struct {
+type bTarget struct {
 	targetName            string
 	targetPackage         string
 	bazelRuleClass        string
@@ -297,26 +297,26 @@
 	bazelAttributes       []interface{}
 }
 
-var _ bp2buildModule = (*goBazelTarget)(nil)
+var _ bp2buildModule = (*bTarget)(nil)
 
-func (g goBazelTarget) TargetName() string {
-	return g.targetName
+func (b bTarget) TargetName() string {
+	return b.targetName
 }
 
-func (g goBazelTarget) TargetPackage() string {
-	return g.targetPackage
+func (b bTarget) TargetPackage() string {
+	return b.targetPackage
 }
 
-func (g goBazelTarget) BazelRuleClass() string {
-	return g.bazelRuleClass
+func (b bTarget) BazelRuleClass() string {
+	return b.bazelRuleClass
 }
 
-func (g goBazelTarget) BazelRuleLoadLocation() string {
-	return g.bazelRuleLoadLocation
+func (b bTarget) BazelRuleLoadLocation() string {
+	return b.bazelRuleLoadLocation
 }
 
-func (g goBazelTarget) BazelAttributes() []interface{} {
-	return g.bazelAttributes
+func (b bTarget) BazelAttributes() []interface{} {
+	return b.bazelAttributes
 }
 
 // Creates a target_compatible_with entry that is *not* compatible with android
@@ -421,7 +421,7 @@
 		Target_compatible_with: targetNotCompatibleWithAndroid(),
 	}
 
-	libTest := goBazelTarget{
+	libTest := bTarget{
 		targetName:            gp.name,
 		targetPackage:         gp.dir,
 		bazelRuleClass:        "go_test",
@@ -514,7 +514,7 @@
 		Target_compatible_with: targetNotCompatibleWithAndroid(),
 	}
 
-	lib := goBazelTarget{
+	lib := bTarget{
 		targetName:            g.Name(),
 		targetPackage:         ctx.ModuleDir(g),
 		bazelRuleClass:        "go_library",
@@ -555,23 +555,35 @@
 	Deps []string
 }
 
+type buildConversionMetadata struct {
+	nameToGoLibraryModule nameToGoLibraryModule
+	ndkHeaders            []blueprint.Module
+}
+
 type nameToGoLibraryModule map[string]goLibraryModule
 
-// Visit each module in the graph
+// Visit each module in the graph, and collect metadata about the build graph
 // If a module is of type `bootstrap_go_package`, return a map containing metadata like its dir and deps
-func createGoLibraryModuleMap(ctx *android.Context) nameToGoLibraryModule {
-	ret := nameToGoLibraryModule{}
+// If a module is of type `ndk_headers`, add it to a list and return the list
+func createBuildConversionMetadata(ctx *android.Context) buildConversionMetadata {
+	goMap := nameToGoLibraryModule{}
+	ndkHeaders := []blueprint.Module{}
 	ctx.VisitAllModules(func(m blueprint.Module) {
 		moduleType := ctx.ModuleType(m)
 		// We do not need to store information about blueprint_go_binary since it does not have any rdeps
 		if moduleType == "bootstrap_go_package" {
-			ret[m.Name()] = goLibraryModule{
+			goMap[m.Name()] = goLibraryModule{
 				Dir:  ctx.ModuleDir(m),
 				Deps: m.(*bootstrap.GoPackage).Deps(),
 			}
+		} else if moduleType == "ndk_headers" || moduleType == "versioned_ndk_headers" {
+			ndkHeaders = append(ndkHeaders, m)
 		}
 	})
-	return ret
+	return buildConversionMetadata{
+		nameToGoLibraryModule: goMap,
+		ndkHeaders:            ndkHeaders,
+	}
 }
 
 // Returns the deps in the transitive closure of a go target
@@ -620,7 +632,7 @@
 			Deps:                   goDepLabels(transitiveDeps, goModulesMap),
 			Target_compatible_with: targetNotCompatibleWithAndroid(),
 		}
-		libTestSource := goBazelTarget{
+		libTestSource := bTarget{
 			targetName:            goSource,
 			targetPackage:         ctx.ModuleDir(g),
 			bazelRuleClass:        "go_source",
@@ -669,7 +681,7 @@
 		ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs())
 	}
 
-	bin := goBazelTarget{
+	bin := bTarget{
 		targetName:            g.Name(),
 		targetPackage:         ctx.ModuleDir(g),
 		bazelRuleClass:        "go_binary",
@@ -700,7 +712,9 @@
 
 	// Visit go libraries in a pre-run and store its state in a map
 	// The time complexity remains O(N), and this does not add significant wall time.
-	nameToGoLibMap := createGoLibraryModuleMap(ctx.Context())
+	meta := createBuildConversionMetadata(ctx.Context())
+	nameToGoLibMap := meta.nameToGoLibraryModule
+	ndkHeaders := meta.ndkHeaders
 
 	bpCtx := ctx.Context()
 	bpCtx.VisitAllModules(func(m blueprint.Module) {
@@ -713,27 +727,32 @@
 
 		switch ctx.Mode() {
 		case Bp2Build:
-			// There are two main ways of converting a Soong module to Bazel:
-			// 1) Manually handcrafting a Bazel target and associating the module with its label
-			// 2) Automatically generating with bp2build converters
-			//
-			// bp2build converters are used for the majority of modules.
-			if b, ok := m.(android.Bazelable); ok && b.HasHandcraftedLabel() {
-				if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
-					panic(fmt.Errorf("module %q [%s] [%s] was both converted with bp2build and has a handcrafted label", bpCtx.ModuleName(m), moduleType, dir))
-				}
-				// Handle modules converted to handcrafted targets.
-				//
-				// Since these modules are associated with some handcrafted
-				// target in a BUILD file, we don't autoconvert them.
+			if aModule, ok := m.(android.Module); ok {
+				reason := aModule.GetUnconvertedReason()
+				if reason != nil {
+					// If this module was force-enabled, cause an error.
+					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)
+					}
 
-				// Log the module.
-				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() {
+					// Log the module isn't to be converted by bp2build.
+					// TODO: b/291598248 - Log handcrafted modules differently than other unconverted modules.
+					metrics.AddUnconvertedModule(m, moduleType, dir, *reason)
+					return
+				}
+				if len(aModule.Bp2buildTargets()) == 0 {
+					panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", aModule.Name()))
+				}
+
 				// Handle modules converted to generated targets.
+				targets, targetErrs = generateBazelTargets(bpCtx, aModule)
+				errs = append(errs, targetErrs...)
+				for _, t := range targets {
+					// A module can potentially generate more than 1 Bazel
+					// target, each of a different rule class.
+					metrics.IncrementRuleClassCount(t.ruleClass)
+				}
 
 				// Log the module.
 				metrics.AddConvertedModule(aModule, moduleType, dir)
@@ -761,34 +780,16 @@
 						return
 					}
 				}
-				targets, targetErrs = generateBazelTargets(bpCtx, aModule)
-				errs = append(errs, targetErrs...)
-				for _, t := range targets {
-					// A module can potentially generate more than 1 Bazel
-					// target, each of a different rule class.
-					metrics.IncrementRuleClassCount(t.ruleClass)
-				}
-			} 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 if glib, ok := m.(*bootstrap.GoPackage); ok {
 				targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_library")
-				metrics.AddConvertedModule(glib, "go_library", dir)
+				metrics.IncrementRuleClassCount("bootstrap_go_package")
+				metrics.AddConvertedModule(glib, "bootstrap_go_package", dir)
 			} else if gbin, ok := m.(*bootstrap.GoBinary); ok {
 				targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_binary")
-				metrics.AddConvertedModule(gbin, "go_binary", dir)
+				metrics.IncrementRuleClassCount("blueprint_go_binary")
+				metrics.AddConvertedModule(gbin, "blueprint_go_binary", dir)
 			} else {
 				metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
 					ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
@@ -818,6 +819,39 @@
 		}
 	})
 
+	// Create an ndk_sysroot target that has a dependency edge on every target corresponding to Soong's ndk_headers
+	// This root target will provide headers to sdk variants of jni libraries
+	if ctx.Mode() == Bp2Build {
+		var depLabels bazel.LabelList
+		for _, ndkHeader := range ndkHeaders {
+			depLabel := bazel.Label{
+				Label: "//" + bpCtx.ModuleDir(ndkHeader) + ":" + ndkHeader.Name(),
+			}
+			depLabels.Add(&depLabel)
+		}
+		a := struct {
+			Deps                bazel.LabelListAttribute
+			System_dynamic_deps bazel.LabelListAttribute
+		}{
+			Deps:                bazel.MakeLabelListAttribute(bazel.UniqueSortedBazelLabelList(depLabels)),
+			System_dynamic_deps: bazel.MakeLabelListAttribute(bazel.MakeLabelList([]bazel.Label{})),
+		}
+		ndkSysroot := bTarget{
+			targetName:            "ndk_sysroot",
+			targetPackage:         "build/bazel/rules/cc", // The location is subject to change, use build/bazel for now
+			bazelRuleClass:        "cc_library_headers",
+			bazelRuleLoadLocation: "//build/bazel/rules/cc:cc_library_headers.bzl",
+			bazelAttributes:       []interface{}{&a},
+		}
+
+		if t, err := generateBazelTarget(bpCtx, ndkSysroot); err == nil {
+			dir := ndkSysroot.targetPackage
+			buildFileToTargets[dir] = append(buildFileToTargets[dir], t)
+		} else {
+			errs = append(errs, err)
+		}
+	}
+
 	if len(errs) > 0 {
 		return conversionResults{}, errs
 	}
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 329c907..8e51d98 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -349,19 +349,6 @@
 			},
 		},
 		{
-			Description: "non-existent dep",
-			Blueprint: `custom {
-  name: "has_dep",
-  arch_paths: [":dep"],
-  bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "has_dep", AttrNameToString{
-					"arch_paths": `[":dep__BP2BUILD__MISSING__DEP"]`,
-				}),
-			},
-		},
-		{
 			Description: "arch-variant srcs",
 			Blueprint: `custom {
     name: "arch_paths",
@@ -1994,6 +1981,41 @@
 	})
 }
 
+func TestAlreadyPresentOneToManyBuildTarget(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+    one_to_many_prop: true,
+	}
+	custom {
+		name: "bar",
+	}
+	`
+	alreadyPresentBuildFile :=
+		MakeBazelTarget(
+			"custom",
+			// one_to_many_prop ensures that foo generates "foo_proto_library_deps".
+			"foo_proto_library_deps",
+			AttrNameToString{},
+		)
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		AlreadyExistingBuildContents: alreadyPresentBuildFile,
+		Blueprint:                    bp,
+		ExpectedBazelTargets:         expectedBazelTargets,
+		Description:                  "Not duplicating work for an already-present BUILD target (different generated name)",
+	})
+}
+
 // Verifies that if a module is defined in pkg1/Android.bp, that a target present
 // in pkg2/BUILD.bazel does not result in the module being labeled "already defined
 // in a BUILD file".
@@ -2066,3 +2088,219 @@
 	})
 
 }
+
+func TestBp2buildDepsMutator_missingTransitiveDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	}
+
+	custom {
+		name: "has_deps",
+	  arch_paths: [":has_missing_dep", ":foo"],
+	}
+
+	custom {
+		name: "has_missing_dep",
+	  arch_paths: [":missing"],
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with missing transitive dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_missingDirectDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":exists"],
+	}
+	custom {
+		name: "exists",
+	}
+
+	custom {
+		name: "has_missing_dep",
+	  arch_paths: [":missing"],
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":exists"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"exists",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with missing direct dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_unconvertedDirectDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "has_unconverted_dep",
+	  arch_paths: [":unconvertible"],
+	}
+
+	custom {
+		name: "unconvertible",
+		does_not_convert_to_bazel: true
+	}
+	`
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: []string{},
+		Description:          "Skipping conversion of a target with unconverted direct dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_unconvertedTransitiveDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":has_unconverted_dep", ":bar"],
+	}
+
+	custom {
+		name: "bar",
+	}
+
+	custom {
+		name: "has_unconverted_dep",
+	  arch_paths: [":unconvertible"],
+	}
+
+	custom {
+		name: "unconvertible",
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with unconverted transitive dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_alreadyExistsBuildDeps(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":bar"],
+	}
+	custom {
+		name: "bar",
+	  arch_paths: [":checked_in"],
+	}
+	custom {
+		name: "checked_in",
+	  arch_paths: [":checked_in"],
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":bar"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{"arch_paths": `[":checked_in"]`},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		StubbedBuildDefinitions: []string{"checked_in"},
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		Description:             "Convert target with already-existing build dep",
+		DepsMutator:             true,
+	})
+}
+
+// Tests that deps of libc are always considered valid for libc. This circumvents
+// an issue that, in a variantless graph (such as bp2build's), libc has the
+// unique predicament that it depends on itself.
+func TestBp2buildDepsMutator_depOnLibc(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":libc"],
+	}
+	custom {
+		name: "libc",
+	  arch_paths: [":libc_dep"],
+	}
+	custom {
+		name: "libc_dep",
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":libc"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"libc",
+			AttrNameToString{"arch_paths": `[":libc_dep"]`},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		StubbedBuildDefinitions: []string{"checked_in"},
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		Description:             "Convert target with dep on libc",
+		DepsMutator:             true,
+	})
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 402d4b0..645298f 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -95,6 +95,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -128,6 +129,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -161,6 +163,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 560123e..5ddae68 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -159,6 +159,10 @@
 			"min_sdk_version":    `"29"`,
 			"use_version_lib":    `True`,
 			"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
+			"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 		}),
 	})
 }
@@ -555,8 +559,8 @@
 		ModuleTypeUnderTest:        "cc_library",
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
 		Dir:                        "foo/bar",
-		StubbedBuildDefinitions: []string{"//foo/bar:prebuilt_whole_static_lib_for_shared", "//foo/bar:prebuilt_whole_static_lib_for_static",
-			"//foo/bar:prebuilt_whole_static_lib_for_both"},
+		StubbedBuildDefinitions: []string{"//foo/bar:whole_static_lib_for_shared", "//foo/bar:whole_static_lib_for_static",
+			"//foo/bar:whole_static_lib_for_both"},
 		Filesystem: map[string]string{
 			"foo/bar/Android.bp": `
 cc_library {
@@ -3351,6 +3355,7 @@
 		Description:                "cc_library with target.apex",
 		ModuleTypeUnderTest:        "cc_library",
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		StubbedBuildDefinitions:    []string{"bar", "baz", "buh"},
 		Blueprint: `
 cc_library {
     name: "foo",
@@ -3362,27 +3367,29 @@
             exclude_static_libs: ["buh"],
         }
     }
-}`,
+}` + simpleModule("cc_library_static", "baz") +
+			simpleModule("cc_library_static", "buh") +
+			simpleModule("cc_library_static", "bar"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":buh__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":buh"],
     })`,
-				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_dynamic_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":bar"],
     })`,
 				"local_includes": `["."]`,
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":buh__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":buh"],
     })`,
-				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_dynamic_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":bar"],
     })`,
 				"local_includes": `["."]`,
 			}),
@@ -3408,20 +3415,23 @@
             exclude_static_libs: ["abc"],
         }
     }
-}`,
+}` + simpleModule("cc_library_static", "bar") +
+			simpleModule("cc_library_static", "baz") +
+			simpleModule("cc_library_static", "abc"),
+		StubbedBuildDefinitions: []string{"bar", "baz", "abc"},
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"implementation_dynamic_deps": `select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":bar"],
     })`,
 				"dynamic_deps": `select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":baz__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":baz"],
     })`,
 				"deps": `select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":abc__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":abc"],
     })`,
 				"local_includes": `["."]`,
 			}),
@@ -5157,7 +5167,6 @@
 		Blueprint: `
 cc_library {
 	name: "libfoo",
-	bazel_module: { bp2build_available: false },
 }
 ndk_library {
 	name: "libfoo",
@@ -5165,6 +5174,7 @@
 	symbol_file: "libfoo.map.txt",
 }
 `,
+		StubbedBuildDefinitions: []string{"libfoo"},
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_stub_suite", "libfoo.ndk_stub_libs", AttrNameToString{
 				"api_surface":          `"publicapi"`,
@@ -5210,3 +5220,34 @@
 	}
 	runCcLibraryTestCase(t, tc)
 }
+
+func TestVersionedNdkHeadersConversion(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "versioned_ndk_headers conversion",
+		ModuleTypeUnderTest:        "versioned_ndk_headers",
+		ModuleTypeUnderTestFactory: cc.VersionedNdkHeadersFactory,
+		Blueprint: `
+versioned_ndk_headers {
+	name: "libfoo_headers",
+	from: "from",
+	to: "to",
+}
+`,
+		Filesystem: map[string]string{
+			"from/foo.h":       "",
+			"from/foo_other.h": "",
+		},
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("ndk_headers", "libfoo_headers", AttrNameToString{
+				"strip_import_prefix": `"from"`,
+				"import_prefix":       `"to"`,
+				"hdrs": `[
+        "from/foo.h",
+        "from/foo_other.h",
+    ]`,
+				"run_versioner": "True",
+			}),
+		},
+	}
+	runCcLibraryTestCase(t, tc)
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index fde4c97..5168fe9 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -70,10 +70,6 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description: "cc_library_headers test",
 		Filesystem: map[string]string{
-			"lib-1/lib1a.h":                        "",
-			"lib-1/lib1b.h":                        "",
-			"lib-2/lib2a.h":                        "",
-			"lib-2/lib2b.h":                        "",
 			"dir-1/dir1a.h":                        "",
 			"dir-1/dir1b.h":                        "",
 			"dir-2/dir2a.h":                        "",
@@ -86,7 +82,6 @@
 cc_library_headers {
     name: "foo_headers",
     export_include_dirs: ["dir-1", "dir-2"],
-    header_libs: ["lib-1", "lib-2"],
 
     arch: {
         arm64: {
@@ -118,6 +113,10 @@
     ]`,
 				"sdk_version":     `"current"`,
 				"min_sdk_version": `"29"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
@@ -318,7 +317,7 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers exported_static_lib_headers is reexported",
 		Filesystem:              map[string]string{},
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "foo_no_reexport"},
 		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
@@ -326,7 +325,8 @@
 		static_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModule("cc_library_headers", "foo_export"),
+` + simpleModule("cc_library_headers", "foo_export") +
+			simpleModule("cc_library_headers", "foo_no_reexport"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -339,7 +339,7 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers exported_shared_lib_headers is reexported",
 		Filesystem:              map[string]string{},
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "foo_no_reexport"},
 		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
@@ -347,7 +347,8 @@
 		shared_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModule("cc_library_headers", "foo_export"),
+` + simpleModule("cc_library_headers", "foo_export") +
+			simpleModule("cc_library_headers", "foo_no_reexport"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -360,7 +361,7 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers exported_header_lib_headers is reexported",
 		Filesystem:              map[string]string{},
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "foo_no_reexport"},
 		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
@@ -368,7 +369,8 @@
 		header_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModule("cc_library_headers", "foo_export"),
+` + simpleModule("cc_library_headers", "foo_export") +
+			simpleModule("cc_library_headers", "foo_no_reexport"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -422,7 +424,7 @@
 func TestPrebuiltCcLibraryHeadersPreferredRdepUpdated(t *testing.T) {
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers prebuilt preferred is used as rdep",
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "//foo/bar:foo_headers"},
 		Filesystem: map[string]string{
 			"foo/bar/Android.bp": simpleModule("cc_library_headers", "foo_headers"),
 		},
@@ -454,7 +456,7 @@
 func TestPrebuiltCcLibraryHeadersRdepUpdated(t *testing.T) {
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers not preferred is not used for rdep",
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "//foo/bar:foo_headers"},
 		Filesystem: map[string]string{
 			"foo/bar/Android.bp": simpleModule("cc_library_headers", "foo_headers"),
 		},
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index bdde996..2c5305f 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -175,6 +175,10 @@
     ]`,
 				"sdk_version":     `"current"`,
 				"min_sdk_version": `"29"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
@@ -1595,7 +1599,7 @@
 		Description:                "cc_library_shared stubs",
 		ModuleTypeUnderTest:        "cc_library_shared",
 		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		StubbedBuildDefinitions:    []string{"libNoStubs", "libHasApexStubs", "libHasApexAndNdkStubs"},
+		StubbedBuildDefinitions:    []string{"libNoStubs", "libHasApexStubs", "libHasApexAndNdkStubs", "libHasApexAndNdkStubs.ndk_stub_libs"},
 		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
 	name: "libUsesSdk",
@@ -1621,9 +1625,7 @@
 }
 ndk_library {
 	name: "libHasApexAndNdkStubs",
-	// TODO: b/301321658 - Stub this once existing-build-file handling can deal with
-	// modules that generate targets of a different name.
-	bazel_module: { bp2build_available: false },
+	first_version: "28",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -1644,6 +1646,10 @@
     })`,
 				"local_includes": `["."]`,
 				"sdk_version":    `"current"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 7b97b39..09e40ed 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -203,6 +203,10 @@
     ]`,
 				"sdk_version":     `"current"`,
 				"min_sdk_version": `"29"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 679a364..392a962 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -631,3 +631,23 @@
 		},
 	})
 }
+
+func TestCcTest_UnitTestFalse(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "cc test with test_options.tags converted to tags",
+		blueprint: `
+cc_test {
+    name: "mytest",
+    host_supported: true,
+    srcs: ["test.cpp"],
+    test_options: { unit_test: false },
+}
+` + simpleModule("cc_library_static", "libgtest_main") +
+			simpleModule("cc_library_static", "libgtest"),
+		stubbedBuildDefinitions: []string{
+			"libgtest_main",
+			"libgtest",
+		},
+		targets: []testBazelTarget{},
+	})
+}
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index cb2e207..9c49dac 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -40,7 +40,9 @@
     srcs: ["foo"],
 }
 `,
-		ExpectedBazelTargets: []string{}})
+		ExpectedBazelTargets:       []string{},
+		ExpectedHandcraftedModules: []string{"foo"}},
+	)
 }
 
 func TestFilegroupSameNameAsFile_MultipleFiles(t *testing.T) {
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
index e808340..e9fc61d 100644
--- a/bp2build/gensrcs_conversion_test.go
+++ b/bp2build/gensrcs_conversion_test.go
@@ -15,16 +15,22 @@
 package bp2build
 
 import (
+	"testing"
+
 	"android/soong/android"
 	"android/soong/genrule"
-	"testing"
 )
 
+func registerModulesForGensrcsTests(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+}
+
 func TestGensrcs(t *testing.T) {
 	testcases := []struct {
-		name               string
-		bp                 string
-		expectedBazelAttrs AttrNameToString
+		name                    string
+		bp                      string
+		expectedBazelAttrs      AttrNameToString
+		stubbedBuildDefinitions []string
 	}{
 		{
 			name: "gensrcs with common usage of properties",
@@ -37,18 +43,22 @@
                 data: ["foo/file.txt", ":external_files"],
                 output_extension: "out",
                 bazel_module: { bp2build_available: true },
+			}
+      filegroup {
+                name: "external_files",
 			}`,
+			stubbedBuildDefinitions: []string{"external_files"},
 			expectedBazelAttrs: AttrNameToString{
 				"srcs": `[
         "test/input.txt",
-        ":external_files__BP2BUILD__MISSING__DEP",
+        ":external_files",
     ]`,
 				"tools":            `["program.py"]`,
 				"output_extension": `"out"`,
-				"cmd":              `"$(location program.py) $(SRC) $(OUT) $(location foo/file.txt) $(location :external_files__BP2BUILD__MISSING__DEP)"`,
+				"cmd":              `"$(location program.py) $(SRC) $(OUT) $(location foo/file.txt) $(location :external_files)"`,
 				"data": `[
         "foo/file.txt",
-        ":external_files__BP2BUILD__MISSING__DEP",
+        ":external_files",
     ]`,
 			},
 		},
@@ -73,12 +83,13 @@
 			MakeBazelTargetNoRestrictions("gensrcs", "foo", test.expectedBazelAttrs),
 		}
 		t.Run(test.name, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+			RunBp2BuildTestCase(t, registerModulesForGensrcsTests,
 				Bp2buildTestCase{
 					ModuleTypeUnderTest:        "gensrcs",
 					ModuleTypeUnderTestFactory: genrule.GenSrcsFactory,
 					Blueprint:                  test.bp,
 					ExpectedBazelTargets:       expectedBazelTargets,
+					StubbedBuildDefinitions:    test.stubbedBuildDefinitions,
 				})
 		})
 	}
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 7d8ab63..4271f76 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -114,7 +114,7 @@
 	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
 		Description:             "java_binary_host with srcs, libs.",
 		Filesystem:              testFs,
-		StubbedBuildDefinitions: []string{"prebuilt_java-lib-dep-1"},
+		StubbedBuildDefinitions: []string{"java-lib-dep-1", "java-lib-dep-1-neverlink"},
 		Blueprint: `java_binary_host {
     name: "java-binary-host-libs",
     libs: ["java-lib-dep-1"],
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 7e4e44e..426dffa 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -567,12 +567,20 @@
 		"b.aidl",
 	],
 }
+filegroup {
+	name: "aidls_files",
+	srcs: [
+		"a.aidl",
+		"b.aidl",
+	],
+}
 java_library {
 	name: "example_lib",
 	srcs: [
 		"a.java",
 		"b.java",
 		":aidl_files",
+		":aidls_files",
 		":random_other_files",
 	],
 	sdk_version: "current",
@@ -586,8 +594,18 @@
     ]`,
 				"tags": `["apex_available=//apex_available:anyapex"]`,
 			}),
+			MakeBazelTargetNoRestrictions("aidl_library", "aidls_files", AttrNameToString{
+				"srcs": `[
+        "a.aidl",
+        "b.aidl",
+    ]`,
+				"tags": `["apex_available=//apex_available:anyapex"]`,
+			}),
 			MakeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
-				"deps": `[":aidl_files"]`,
+				"deps": `[
+        ":aidl_files",
+        ":aidls_files",
+    ]`,
 			}),
 			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
 				"deps":    `[":example_lib_java_aidl_library"]`,
@@ -617,7 +635,7 @@
 		Description:                "java_library with non adjacent aidl filegroup",
 		ModuleTypeUnderTest:        "java_library",
 		ModuleTypeUnderTestFactory: java.LibraryFactory,
-		StubbedBuildDefinitions:    []string{"A_aidl"},
+		StubbedBuildDefinitions:    []string{"//path/to/A:A_aidl"},
 		Filesystem: map[string]string{
 			"path/to/A/Android.bp": `
 filegroup {
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index 3d55eb2..cd89978 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -141,17 +141,22 @@
 func TestJavaLibsAndOnlyProtoSrcs(t *testing.T) {
 	runJavaProtoTestCase(t, Bp2buildTestCase{
 		Description:             "java_library that has only proto srcs",
-		StubbedBuildDefinitions: []string{"java-lib"},
+		StubbedBuildDefinitions: []string{"java-lib-1", "java-lib-2"},
 		Blueprint: `java_library_static {
     name: "java-protos",
     srcs: ["a.proto"],
-    libs: ["java-lib"],
+    libs: ["java-lib-1"],
+    static_libs: ["java-lib-2"],
     java_version: "7",
     sdk_version: "current",
 }
 
 java_library_static {
-    name: "java-lib",
+    name: "java-lib-1",
+}
+
+java_library_static {
+    name: "java-lib-2",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -162,12 +167,19 @@
 				"java_lite_proto_library",
 				"java-protos_java_proto_lite",
 				AttrNameToString{
-					"deps":         `[":java-protos_proto"]`,
+					"deps": `[":java-protos_proto"]`,
+					"additional_proto_deps": `[
+        ":java-lib-1-neverlink",
+        ":java-lib-2",
+    ]`,
 					"java_version": `"7"`,
 					"sdk_version":  `"current"`,
 				}),
 			MakeBazelTarget("java_library", "java-protos", AttrNameToString{
-				"exports":      `[":java-protos_java_proto_lite"]`,
+				"exports": `[
+        ":java-lib-2",
+        ":java-protos_java_proto_lite",
+    ]`,
 				"java_version": `"7"`,
 				"sdk_version":  `"current"`,
 			}),
@@ -181,3 +193,46 @@
 		},
 	})
 }
+
+func TestJavaProtoPlugin(t *testing.T) {
+	runJavaProtoTestCase(t, Bp2buildTestCase{
+		Description:             "java_library proto plugin",
+		StubbedBuildDefinitions: []string{"protoc-gen-test-plugin"},
+		Blueprint: `java_library_static {
+    name: "java-protos",
+    srcs: ["a.proto"],
+    proto: {
+        plugin: "test-plugin",
+    },
+    sdk_version: "current",
+}
+
+java_library_static {
+    name: "protoc-gen-test-plugin",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
+				"srcs": `["a.proto"]`,
+			}),
+			MakeBazelTarget(
+				"java_lite_proto_library",
+				"java-protos_java_proto_lite",
+				AttrNameToString{
+					"deps":        `[":java-protos_proto"]`,
+					"plugin":      `":protoc-gen-test-plugin"`,
+					"sdk_version": `"current"`,
+				}),
+			MakeBazelTarget("java_library", "java-protos", AttrNameToString{
+				"exports":     `[":java-protos_java_proto_lite"]`,
+				"sdk_version": `"current"`,
+			}),
+			MakeNeverlinkDuplicateTargetWithAttrs(
+				"java_library",
+				"java-protos",
+				AttrNameToString{
+					"sdk_version": `"current"`,
+				}),
+		},
+	})
+}
diff --git a/bp2build/java_test_host_conversion_test.go b/bp2build/java_test_host_conversion_test.go
index 95c239d..87f35f6 100644
--- a/bp2build/java_test_host_conversion_test.go
+++ b/bp2build/java_test_host_conversion_test.go
@@ -97,14 +97,13 @@
 
 java_library {
     name: "lib_a",
-    bazel_module: { bp2build_available: false },
 }
 
 java_library {
     name: "static_libs_a",
-    bazel_module: { bp2build_available: false },
 }
 `,
+		StubbedBuildDefinitions: []string{"lib_a", "static_libs_a"},
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
 				"runtime_deps": `[
diff --git a/bp2build/rust_protobuf_conversion_test.go b/bp2build/rust_protobuf_conversion_test.go
index cf256aa..bd4f54b 100644
--- a/bp2build/rust_protobuf_conversion_test.go
+++ b/bp2build/rust_protobuf_conversion_test.go
@@ -27,7 +27,7 @@
 
 func registerRustProtobufModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("rust_protobuf_host", rust.RustProtobufHostFactory)
-
+	ctx.RegisterModuleType("rust_protobuf", rust.RustProtobufHostFactory)
 }
 
 func TestRustProtobufHostTestCase(t *testing.T) {
@@ -58,3 +58,32 @@
 	},
 	)
 }
+
+func TestRustProtobufTestCase(t *testing.T) {
+	runRustProtobufTestCase(t, Bp2buildTestCase{
+		Dir:       "external/rust/crates/foo",
+		Blueprint: "",
+		Filesystem: map[string]string{
+			"external/rust/crates/foo/src/lib.rs":    "",
+			"external/rust/crates/foo/src/helper.rs": "",
+			"external/rust/crates/foo/Android.bp": `
+rust_protobuf {
+	name: "libfoo",
+	crate_name: "foo",
+	protos: ["src/foo.proto"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+		},
+		ExpectedBazelTargets: []string{
+			makeBazelTargetHostOrDevice("proto_library", "libfoo_proto", AttrNameToString{
+				"srcs": `["src/foo.proto"]`,
+			}, android.HostSupported),
+			makeBazelTargetHostOrDevice("rust_proto_library", "libfoo", AttrNameToString{
+				"crate_name": `"foo"`,
+				"deps":       `[":libfoo_proto"]`,
+			}, android.HostSupported),
+		},
+	},
+	)
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index a810709..6907487 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -27,6 +27,7 @@
 	"strings"
 	"testing"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -87,6 +88,15 @@
 	// ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
 	// Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
 	ExpectedBazelTargets []string
+	// ExpectedConvertedModules asserts that modules in this list are labeled as "converted
+	// by bp2build" in the metrics reported by bp2build.
+	ExpectedConvertedModules []string
+	// ExpectedHandcraftedModules asserts that modules in this list are labeled as "handcrafted
+	// in build files" in the metrics reported by bp2build. Such modules are either explicitly
+	// defined in a BUILD file (by name), or registered as "otherwise implicitly handled"
+	// by bp2build (for example, by macros owned by other modules).
+	ExpectedHandcraftedModules []string
+
 	// AlreadyExistingBuildContents, if non-empty, simulates an already-present source BUILD file
 	// in the directory under test. The BUILD file has the given contents. This BUILD file
 	// will also be treated as "BUILD file to keep" by the simulated bp2build environment.
@@ -114,15 +124,37 @@
 	// be merged with the generated BUILD file. This allows custom BUILD targets
 	// to be used in tests, or use BUILD files to draw package boundaries.
 	KeepBuildFileForDirs []string
+
+	// If true, the bp2build_deps mutator is used for this test. This is an
+	// experimental mutator that will disable modules which have transitive
+	// dependencies with no bazel definition.
+	// TODO: b/285631638 - Enable this feature by default.
+	DepsMutator bool
+}
+
+func RunBp2BuildTestCaseExtraContext(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), modifyContext func(ctx *android.TestContext), tc Bp2buildTestCase) {
+	t.Helper()
+	preparers := []android.FixturePreparer{
+		android.FixtureRegisterWithContext(registerModuleTypes),
+	}
+	if modifyContext != nil {
+		preparers = append(preparers, android.FixtureModifyContext(modifyContext))
+	}
+	if tc.DepsMutator {
+		preparers = append(preparers, android.FixtureModifyConfig(func(cfg android.Config) {
+			cfg.Bp2buildDepsMutator = true
+		}))
+	}
+	preparers = append(preparers, SetBp2BuildTestRunner)
+	bp2buildSetup := android.GroupFixturePreparers(
+		preparers...,
+	)
+	runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
 }
 
 func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
 	t.Helper()
-	bp2buildSetup := android.GroupFixturePreparers(
-		android.FixtureRegisterWithContext(registerModuleTypes),
-		SetBp2BuildTestRunner,
-	)
-	runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
+	RunBp2BuildTestCaseExtraContext(t, registerModuleTypes, nil, tc)
 }
 
 func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) {
@@ -223,7 +255,7 @@
 		checkDir: tc.ExpectedBazelTargets,
 	}
 
-	result.CompareAllBazelTargets(t, tc.Description, expectedTargets, true)
+	result.CompareAllBazelTargets(t, tc, expectedTargets, true)
 }
 
 // SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
@@ -274,7 +306,7 @@
 // have a corresponding expected BazelTarget.
 //
 // If ignoreUnexpected=true then it will ignore directories for which there are no expected targets.
-func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, description string, expectedTargets map[string][]string, ignoreUnexpected bool) {
+func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, tc Bp2buildTestCase, expectedTargets map[string][]string, ignoreUnexpected bool) {
 	t.Helper()
 	actualTargets := b.buildFileToTargets
 
@@ -301,7 +333,24 @@
 				t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
 			}
 		} else {
-			b.CompareBazelTargets(t, description, expected, actual)
+			b.CompareBazelTargets(t, tc.Description, expected, actual)
+		}
+	}
+
+	for _, module := range tc.ExpectedConvertedModules {
+		if _, found := b.metrics.convertedModulePathMap[module]; !found {
+			t.Errorf("expected %s to be generated by bp2build, but was not. Map of converted modules: %s", module, b.metrics.convertedModulePathMap)
+		}
+	}
+
+	for _, module := range tc.ExpectedHandcraftedModules {
+		if reason, found := b.metrics.serialized.UnconvertedModules[module]; !found {
+			t.Errorf("expected %s to be marked 'unconverted' by bp2build, but was not found. Full list: %s",
+				module, b.metrics.serialized.UnconvertedModules)
+		} else {
+			if reason.Type != bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE {
+				t.Errorf("expected %s to be marked 'handcrafted' by bp2build, but was disabled for another reason: %s", module, reason)
+			}
 		}
 	}
 }
@@ -363,6 +412,10 @@
 	// Prop used to indicate this conversion should be 1 module -> multiple targets
 	One_to_many_prop *bool
 
+	// Prop used to simulate an unsupported property in bp2build conversion. If this
+	// is true, this module should be treated as "unconvertible" via bp2build.
+	Does_not_convert_to_bazel *bool
+
 	Api *string // File describing the APIs of this module
 
 	Test_config_setting *bool // Used to test generation of config_setting targets
@@ -498,6 +551,10 @@
 }
 
 func (m *customModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	if p := m.props.Does_not_convert_to_bazel; p != nil && *p {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "")
+		return
+	}
 	if p := m.props.One_to_many_prop; p != nil && *p {
 		customBp2buildOneToMany(ctx, m)
 		return
@@ -571,23 +628,6 @@
 	)
 }
 
-var _ android.ApiProvider = (*customModule)(nil)
-
-func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "custom_api_contribution",
-	}
-	apiAttribute := bazel.MakeLabelAttribute(
-		android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
-	)
-	attrs := &customBazelModuleAttributes{
-		Api: *apiAttribute,
-	}
-	ctx.CreateBazelTargetModule(props,
-		android.CommonAttributes{Name: c.Name()},
-		attrs)
-}
-
 // A bp2build mutator that uses load statements and creates a 1:M mapping from
 // module to target.
 func customBp2buildOneToMany(ctx android.Bp2buildMutatorContext, m *customModule) {
diff --git a/cc/Android.bp b/cc/Android.bp
index c32d854..8fa0fbe 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -18,6 +18,7 @@
         "soong-genrule",
         "soong-multitree",
         "soong-snapshot",
+        "soong-sysprop-bp2build",
         "soong-tradefed",
     ],
     srcs: [
@@ -49,7 +50,6 @@
         "snapshot_utils.go",
         "stl.go",
         "strip.go",
-        "sysprop.go",
         "tidy.go",
         "util.go",
         "vendor_snapshot.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 569f721..ec5d522 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -99,7 +99,7 @@
 	Tidy_timeout_srcs     bazel.LabelListAttribute
 }
 
-func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) {
+func (m *Module) convertTidyAttributes(ctx android.Bp2buildMutatorContext, moduleAttrs *tidyAttributes) {
 	for _, f := range m.features {
 		if tidy, ok := f.(*tidyFeature); ok {
 			var tidyAttr *string
@@ -223,7 +223,7 @@
 }
 
 // bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
-func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes {
+func bp2BuildParseLibProps(ctx android.Bp2buildMutatorContext, module *Module, isStatic bool) staticOrSharedAttributes {
 	lib, ok := module.compiler.(*libraryDecorator)
 	if !ok {
 		return staticOrSharedAttributes{}
@@ -232,12 +232,12 @@
 }
 
 // bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
-func bp2BuildParseSharedProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes {
+func bp2BuildParseSharedProps(ctx android.Bp2buildMutatorContext, module *Module) staticOrSharedAttributes {
 	return bp2BuildParseLibProps(ctx, module, false)
 }
 
 // bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
-func bp2BuildParseStaticProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes {
+func bp2BuildParseStaticProps(ctx android.Bp2buildMutatorContext, module *Module) staticOrSharedAttributes {
 	return bp2BuildParseLibProps(ctx, module, true)
 }
 
@@ -246,9 +246,9 @@
 	implementation bazel.LabelList
 }
 
-type bazelLabelForDepsFn func(android.BazelConversionPathContext, []string) bazel.LabelList
+type bazelLabelForDepsFn func(android.Bp2buildMutatorContext, []string) bazel.LabelList
 
-func maybePartitionExportedAndImplementationsDeps(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
+func maybePartitionExportedAndImplementationsDeps(ctx android.Bp2buildMutatorContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
 	if !exportsDeps {
 		return depsPartition{
 			implementation: fn(ctx, allDeps),
@@ -263,9 +263,9 @@
 	}
 }
 
-type bazelLabelForDepsExcludesFn func(android.BazelConversionPathContext, []string, []string) bazel.LabelList
+type bazelLabelForDepsExcludesFn func(android.Bp2buildMutatorContext, []string, []string) bazel.LabelList
 
-func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
+func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.Bp2buildMutatorContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
 	if !exportsDeps {
 		return depsPartition{
 			implementation: fn(ctx, allDeps, excludes),
@@ -288,7 +288,7 @@
 }
 
 // Parses properties common to static and shared libraries. Also used for prebuilt libraries.
-func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
+func bp2buildParseStaticOrSharedProps(ctx android.Bp2buildMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
 	attrs := staticOrSharedAttributes{}
 
 	setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
@@ -334,7 +334,7 @@
 	attrs.Srcs_c = partitionedSrcs[cSrcPartition]
 	attrs.Srcs_as = partitionedSrcs[asSrcPartition]
 
-	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), apexAvailable)
+	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx, apexAvailable)
 
 	attrs.Features.Append(convertHiddenVisibilityToFeatureStaticOrShared(ctx, module, isStatic))
 
@@ -352,7 +352,7 @@
 	Enabled bazel.BoolAttribute
 }
 
-func parseSrc(ctx android.BazelConversionPathContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) {
+func parseSrc(ctx android.Bp2buildMutatorContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) {
 	srcFileError := func() {
 		ctx.ModuleErrorf("parseSrc: Expected at most one source file for %s %s\n", axis, config)
 	}
@@ -370,7 +370,7 @@
 }
 
 // NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package
-func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes {
+func Bp2BuildParsePrebuiltLibraryProps(ctx android.Bp2buildMutatorContext, module *Module, isStatic bool) prebuiltAttributes {
 
 	var srcLabelAttribute bazel.LabelAttribute
 	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
@@ -407,7 +407,7 @@
 	}
 }
 
-func bp2BuildParsePrebuiltBinaryProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
+func bp2BuildParsePrebuiltBinaryProps(ctx android.Bp2buildMutatorContext, module *Module) prebuiltAttributes {
 	var srcLabelAttribute bazel.LabelAttribute
 	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		if props, ok := props.(*prebuiltLinkerProperties); ok {
@@ -420,7 +420,7 @@
 	}
 }
 
-func bp2BuildParsePrebuiltObjectProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
+func bp2BuildParsePrebuiltObjectProps(ctx android.Bp2buildMutatorContext, module *Module) prebuiltAttributes {
 	var srcLabelAttribute bazel.LabelAttribute
 	bp2BuildPropParseHelper(ctx, module, &prebuiltObjectProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		if props, ok := props.(*prebuiltObjectProperties); ok {
@@ -555,7 +555,7 @@
 	return result
 }
 
-func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
+func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
 	// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
 	// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
 	srcsList, ok := parseSrcs(ctx, props)
@@ -680,7 +680,7 @@
 }
 
 // Parse srcs from an arch or OS's props value.
-func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
+func parseSrcs(ctx android.Bp2buildMutatorContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
 	anySrcs := false
 	// Add srcs-like dependencies such as generated files.
 	// First create a LabelList containing these dependencies, then merge the values with srcs.
@@ -1143,7 +1143,7 @@
 	compilerAttrs compilerAttributes,
 ) *bazel.LabelAttribute {
 	var aidlLibsFromSrcs, aidlFiles bazel.LabelListAttribute
-	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 
 	if !aidlSrcs.IsEmpty() {
 		aidlLibsFromSrcs, aidlFiles = aidlSrcs.Partition(func(src bazel.Label) bool {
@@ -1265,7 +1265,7 @@
 
 // resolveTargetApex re-adds the shared and static libs in target.apex.exclude_shared|static_libs props to non-apex variant
 // since all libs are already excluded by default
-func (la *linkerAttributes) resolveTargetApexProp(ctx android.BazelConversionPathContext, props *BaseLinkerProperties) {
+func (la *linkerAttributes) resolveTargetApexProp(ctx android.Bp2buildMutatorContext, props *BaseLinkerProperties) {
 	excludeSharedLibs := bazelLabelForSharedDeps(ctx, props.Target.Apex.Exclude_shared_libs)
 	sharedExcludes := bazel.LabelList{Excludes: excludeSharedLibs.Includes}
 	sharedExcludesLabelList := bazel.LabelListAttribute{}
@@ -1283,7 +1283,7 @@
 	la.implementationDeps.Append(staticExcludesLabelList)
 }
 
-func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
+func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutatorContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
 	isBinary := module.Binary()
 	// Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module
 	var axisFeatures []string
@@ -1378,10 +1378,10 @@
 		// having stubs or not, so Bazel select() statement can be used to choose
 		// source/stub variants of them.
 		apexAvailable := module.ApexAvailable()
-		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false)
-		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false)
+		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, &la.deps, 0, false)
+		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, &la.deps, 1, false)
 		if len(systemSharedLibs) > 0 {
-			SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
+			SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, &la.deps, 2, true)
 		}
 	}
 
@@ -1490,7 +1490,7 @@
 // Note that this is an anti-pattern: The config_setting should be created from the apex definition
 // and not from a cc_library.
 // This anti-pattern is needed today since not all apexes have been allowlisted.
-func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
+func createInApexConfigSetting(ctx android.Bp2buildMutatorContext, apexName string) {
 	if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
 		// These correspond to android-non_apex and android-in_apex
 		return
@@ -1587,13 +1587,13 @@
 	return exists && ctx.OtherModuleType(mod) == "ndk_library"
 }
 
-func SetStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
-	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
+func SetStubsForDynamicDeps(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis,
+	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, deps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
 
 	// Create a config_setting for each apex_available.
 	// This will be used to select impl of a dep if dep is available to the same apex.
 	for _, aa := range apexAvailable {
-		createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
+		createInApexConfigSetting(ctx, aa)
 	}
 
 	apiDomainForSelects := []string{}
@@ -1669,9 +1669,21 @@
 			existingValue.Append(bazel.MakeLabelList([]bazel.Label{label}))
 			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue))
 		}
+
+		// Add ndk_sysroot to deps.
+		// ndk_sysroot has a dependency edge on all ndk_headers, and will provide the .h files of _every_ ndk library
+		existingValue := deps.SelectValue(bazel.OsAndInApexAxis, "unbundled_app")
+		existingValue.Append(bazel.MakeLabelList([]bazel.Label{ndkSysrootLabel}))
+		deps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue))
 	}
 }
 
+var (
+	ndkSysrootLabel = bazel.Label{
+		Label: "//build/bazel/rules/cc:ndk_sysroot",
+	}
+)
+
 func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
 	bp2BuildPropParseHelper(ctx, module, &StripProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		if stripProperties, ok := props.(*StripProperties); ok {
@@ -1684,7 +1696,7 @@
 	})
 }
 
-func (la *linkerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) {
+func (la *linkerAttributes) convertProductVariables(ctx android.Bp2buildMutatorContext, productVariableProps android.ProductConfigProperties) {
 
 	type productVarDep struct {
 		// the name of the corresponding excludes field, if one exists
@@ -1692,7 +1704,7 @@
 		// reference to the bazel attribute that should be set for the given product variable config
 		attribute *bazel.LabelListAttribute
 
-		depResolutionFunc func(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList
+		depResolutionFunc func(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList
 	}
 
 	// an intermediate attribute that holds Header_libs info, and will be appended to
@@ -1750,7 +1762,7 @@
 	la.implementationDeps.Append(headerDeps)
 }
 
-func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) {
+func (la *linkerAttributes) finalize(ctx android.Bp2buildMutatorContext) {
 	// if system dynamic deps have the default value, any use of a system dynamic library used will
 	// result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries
 	// from bionic OSes and the no config case as these libraries only build for bionic OSes.
@@ -1891,39 +1903,39 @@
 	return xsd.CppBp2buildTargetName()
 }
 
-func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps)
+func bazelLabelForWholeDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps, /*markAsDeps=*/true)
 }
 
-func bazelLabelForWholeDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForWholeDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticWholeModuleDeps)
 }
 
-func bazelLabelForStaticDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForStaticDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticModule)
 }
 
-func bazelLabelForStaticDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule)
+func bazelLabelForStaticDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule, /*markAsDeps=*/true)
 }
 
-func bazelLabelForSharedDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule)
+func bazelLabelForSharedDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule, /*markAsDeps=*/true)
 }
 
-func bazelLabelForHeaderDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
+func bazelLabelForHeaderDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
 	// This is not elegant, but bp2build's shared library targets only propagate
 	// their header information as part of the normal C++ provider.
 	return bazelLabelForSharedDeps(ctx, modules)
 }
 
-func bazelLabelForHeaderDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForHeaderDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	// This is only used when product_variable header_libs is processed, to follow
 	// the pattern of depResolutionFunc
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
 }
 
-func bazelLabelForSharedDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForSharedDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index 81a6cd6..8c248f9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1895,8 +1895,7 @@
 			// do not add a name suffix because it is a base module.
 			return ""
 		}
-		vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
-		nameSuffix = ProductSuffix
+		return ProductSuffix
 	} else {
 		vndkVersion = ctx.DeviceConfig().VndkVersion()
 		nameSuffix = VendorSuffix
@@ -4273,24 +4272,6 @@
 	}
 }
 
-var _ android.ApiProvider = (*Module)(nil)
-
-func (c *Module) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	if c.IsPrebuilt() {
-		return
-	}
-	switch c.typ() {
-	case fullLibrary:
-		apiContributionBp2Build(ctx, c)
-	case sharedLibrary:
-		apiContributionBp2Build(ctx, c)
-	case headerLibrary:
-		// Aggressively generate api targets for all header modules
-		// This is necessary since the header module does not know if it is a dep of API surface stub library
-		apiLibraryHeadersBp2Build(ctx, c)
-	}
-}
-
 // Defaults
 type Defaults struct {
 	android.ModuleBase
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7ce0f37..f7eb8d2 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -41,7 +41,6 @@
 	PrepareForTestWithCcIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
@@ -104,33 +103,6 @@
 	return result.TestContext
 }
 
-// testCcNoVndk runs tests using the prepareForCcTest
-//
-// See testCc for an explanation as to how to stop using this deprecated method.
-//
-// deprecated
-func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
-	t.Helper()
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	return testCcWithConfig(t, config)
-}
-
-// testCcNoProductVndk runs tests using the prepareForCcTest
-//
-// See testCc for an explanation as to how to stop using this deprecated method.
-//
-// deprecated
-func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext {
-	t.Helper()
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	return testCcWithConfig(t, config)
-}
-
 // testCcErrorWithConfig runs tests using the prepareForCcTest
 //
 // See testCc for an explanation as to how to stop using this deprecated method.
@@ -167,7 +139,6 @@
 	t.Helper()
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	testCcErrorWithConfig(t, pattern, config)
 	return
@@ -523,7 +494,6 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	ctx := testCcWithConfig(t, config)
@@ -889,63 +859,6 @@
 	}
 }
 
-func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
-	t.Parallel()
-	ctx := testCcNoVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvndk-private",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libllndk",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-				export_llndk_headers: ["libllndk_headers"],
-			}
-		}
-
-		cc_library_headers {
-			name: "libllndk_headers",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-			},
-			export_include_dirs: ["include"],
-		}
-	`)
-
-	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
-		"LLNDK: libc.so",
-		"LLNDK: libdl.so",
-		"LLNDK: libft2.so",
-		"LLNDK: libllndk.so",
-		"LLNDK: libm.so",
-		"VNDK-SP: libc++.so",
-		"VNDK-core: libvndk-private.so",
-		"VNDK-core: libvndk.so",
-		"VNDK-private: libft2.so",
-		"VNDK-private: libvndk-private.so",
-		"VNDK-product: libc++.so",
-		"VNDK-product: libvndk-private.so",
-		"VNDK-product: libvndk.so",
-	})
-}
-
 func TestVndkModuleError(t *testing.T) {
 	t.Parallel()
 	// Check the error message for vendor_available and product_available properties.
@@ -1111,6 +1024,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1132,6 +1046,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1153,6 +1068,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1175,6 +1091,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1390,6 +1307,7 @@
 		cc_library {
 			name: "libanothervndksp",
 			vendor_available: true,
+			product_available: true,
 		}
 	`)
 }
@@ -1467,7 +1385,6 @@
 	`
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	ctx := testCcWithConfig(t, config)
@@ -1482,70 +1399,6 @@
 	assertString(t, mod_product.outputFile.Path().Base(), "libvndk2-suffix.so")
 }
 
-func TestVndkExtWithoutBoardVndkVersion(t *testing.T) {
-	t.Parallel()
-	// This test checks the VNDK-Ext properties when BOARD_VNDK_VERSION is not set.
-	ctx := testCcNoVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	// Ensures that the core variant of "libvndk_ext" can be found.
-	mod := ctx.ModuleForTests("libvndk_ext", coreVariant).Module().(*Module)
-	if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
-		t.Errorf("\"libvndk_ext\" must extend from \"libvndk\" but get %q", extends)
-	}
-}
-
-func TestVndkExtWithoutProductVndkVersion(t *testing.T) {
-	t.Parallel()
-	// This test checks the VNDK-Ext properties when PRODUCT_PRODUCT_VNDK_VERSION is not set.
-	ctx := testCcNoProductVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	// Ensures that the core variant of "libvndk_ext_product" can be found.
-	mod := ctx.ModuleForTests("libvndk_ext_product", coreVariant).Module().(*Module)
-	if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
-		t.Errorf("\"libvndk_ext_product\" must extend from \"libvndk\" but get %q", extends)
-	}
-}
-
 func TestVndkExtError(t *testing.T) {
 	t.Parallel()
 	// This test ensures an error is emitted in ill-formed vndk-ext definition.
@@ -1920,7 +1773,6 @@
 	`
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	testCcWithConfig(t, config)
@@ -3034,24 +2886,6 @@
 	checkRuntimeLibs(t, nil, module)
 }
 
-func TestRuntimeLibsNoVndk(t *testing.T) {
-	t.Parallel()
-	ctx := testCcNoVndk(t, runtimeLibAndroidBp)
-
-	// If DeviceVndkVersion is not defined, then runtime_libs are copied as-is.
-
-	variant := "android_arm64_armv8-a_shared"
-
-	module := ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available"}, module)
-
-	module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libvendor1", "libproduct_vendor"}, module)
-
-	module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libproduct1", "libproduct_vendor"}, module)
-}
-
 func checkStaticLibs(t *testing.T, expected []string, module *Module) {
 	t.Helper()
 	actual := module.Properties.AndroidMkStaticLibs
diff --git a/cc/config/global.go b/cc/config/global.go
index a586a3f..62b008b 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -29,83 +29,112 @@
 	// Flags used by lots of devices.  Putting them in package static variables
 	// will save bytes in build.ninja so they aren't repeated for every file
 	commonGlobalCflags = []string{
-		"-DANDROID",
-		"-fmessage-length=0",
-		"-W",
+		// Enable some optimization by default.
+		"-O2",
+
+		// Warnings enabled by default. Reference:
+		// https://clang.llvm.org/docs/DiagnosticsReference.html
 		"-Wall",
-		"-Wno-unused",
+		"-Wextra",
 		"-Winit-self",
 		"-Wpointer-arith",
-		"-Wunreachable-code-loop-increment",
+		"-Wunguarded-availability",
 
-		// Make paths in deps files relative
-		"-no-canonical-prefixes",
+		// Warnings treated as errors by default.
+		// See also noOverrideGlobalCflags for errors that cannot be disabled
+		// from Android.bp files.
 
-		"-DNDEBUG",
-		"-UDEBUG",
-
-		"-fno-exceptions",
-
-		"-O2",
-		"-fdebug-default-version=5",
-
-		"-fno-strict-aliasing",
-
+		// Using __DATE__/__TIME__ causes build nondeterminism.
 		"-Werror=date-time",
+		// Detects forgotten */& that usually cause a crash
+		"-Werror=int-conversion",
+		// Detects unterminated alignment modification pragmas, which often lead
+		// to ABI mismatch between modules and hard-to-debug crashes.
 		"-Werror=pragma-pack",
+		// Same as above, but detects alignment pragmas around a header
+		// inclusion.
 		"-Werror=pragma-pack-suspicious-include",
+		// Detects dividing an array size by itself, which is a common typo that
+		// leads to bugs.
+		"-Werror=sizeof-array-div",
+		// Detects a typo that cuts off a prefix from a string literal.
 		"-Werror=string-plus-int",
+		// Detects for loops that will never execute more than once (for example
+		// due to unconditional break), but have a non-empty loop increment
+		// clause. Often a mistake/bug.
 		"-Werror=unreachable-code-loop-increment",
 
-		// Force deprecation warnings to be warnings for code that compiles with -Werror.
-		// Making deprecated usages an error causes extreme pain when trying to deprecate anything.
-		"-Wno-error=deprecated-declarations",
+		// Warnings that should not be errors even for modules with -Werror.
 
+		// Making deprecated usages an error causes extreme pain when trying to
+		// deprecate anything.
+		"-Wno-error=deprecated-declarations",
+		// This rarely indicates a bug. http://b/145210666
+		"-Wno-error=reorder-init-list",
+
+		// Warnings disabled by default.
+
+		// Designated initializer syntax is recommended by the Google C++ style
+		// and is OK to use even if not formally supported by the chosen C++
+		// version.
+		"-Wno-c99-designator",
+		// Detects uses of a GNU C extension equivalent to a limited form of
+		// constexpr. Enabling this would require replacing many constants with
+		// macros, which is not a good trade-off.
+		"-Wno-gnu-folding-constant",
+		// AIDL generated code redeclares pure virtual methods in each
+		// subsequent version of an interface, so this warning is currently
+		// infeasible to enable.
+		"-Wno-inconsistent-missing-override",
+		// Incompatible with the Google C++ style guidance to use 'int' for loop
+		// indices; poor signal to noise ratio.
+		"-Wno-sign-compare",
+		// Poor signal to noise ratio.
+		"-Wno-unused",
+
+		// Global preprocessor constants.
+
+		"-DANDROID",
+		"-DNDEBUG",
+		"-UDEBUG",
 		"-D__compiler_offsetof=__builtin_offsetof",
+		// Allows the bionic versioning.h to indirectly determine whether the
+		// option -Wunguarded-availability is on or not.
+		"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
+
+		// -f and -g options.
 
 		// Emit address-significance table which allows linker to perform safe ICF. Clang does
 		// not emit the table by default on Android since NDK still uses GNU binutils.
 		"-faddrsig",
 
-		// Help catch common 32/64-bit errors.
-		"-Werror=int-conversion",
+		// Emit debugging data in a modern format (DWARF v5).
+		"-fdebug-default-version=5",
 
 		// Force clang to always output color diagnostics. Ninja will strip the ANSI
 		// color codes if it is not running in a terminal.
 		"-fcolor-diagnostics",
 
-		// -Wno-sign-compare is incompatible with the Google C++ style guidance
-		// to use 'int' for loop indices, and the signal to noise ratio is poor
-		// anyway.
-		"-Wno-sign-compare",
-
-		// AIDL generated code redeclares pure virtual methods in each
-		// subsequent version of an interface, so this is currently infeasible
-		// to enable.
-		"-Wno-inconsistent-missing-override",
-
-		// Designated initializer syntax is recommended by the Google C++ style
-		// guide and should not be a warning, at least by default.
-		"-Wno-c99-designator",
-
-		// Warnings from clang-12
-		"-Wno-gnu-folding-constant",
-
-		// http://b/145210666
-		"-Wno-error=reorder-init-list",
-
-		// Calls to the APIs that are newer than the min sdk version of the caller should be
-		// guarded with __builtin_available.
-		"-Wunguarded-availability",
-		// This macro allows the bionic versioning.h to indirectly determine whether the
-		// option -Wunguarded-availability is on or not.
-		"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
-
 		// Turn off FMA which got enabled by default in clang-r445002 (http://b/218805949)
 		"-ffp-contract=off",
 
+		// Google C++ style does not allow exceptions, turn them off by default.
+		"-fno-exceptions",
+
+		// Disable optimizations based on strict aliasing by default.
+		// The performance benefit of enabling them currently does not outweigh
+		// the risk of hard-to-reproduce bugs.
+		"-fno-strict-aliasing",
+
+		// Disable line wrapping for error messages - it interferes with
+		// displaying logs in web browsers.
+		"-fmessage-length=0",
+
 		// Using simple template names reduces the size of debug builds.
 		"-gsimple-template-names",
+
+		// Make paths in deps files relative.
+		"-no-canonical-prefixes",
 	}
 
 	commonGlobalConlyflags = []string{}
@@ -117,6 +146,7 @@
 		"-fdebug-default-version=4",
 	}
 
+	// Compilation flags for device code; not applied to host code.
 	deviceGlobalCflags = []string{
 		"-ffunction-sections",
 		"-fdata-sections",
@@ -152,6 +182,7 @@
 		"-fvisibility-inlines-hidden",
 	}
 
+	// Linking flags for device code; not applied to host binaries.
 	deviceGlobalLdflags = []string{
 		"-Wl,-z,noexecstack",
 		"-Wl,-z,relro",
@@ -180,8 +211,6 @@
 	hostGlobalLldflags = commonGlobalLldflags
 
 	commonGlobalCppflags = []string{
-		"-Wsign-promo",
-
 		// -Wimplicit-fallthrough is not enabled by -Wall.
 		"-Wimplicit-fallthrough",
 
@@ -194,6 +223,14 @@
 
 	// These flags are appended after the module's cflags, so they cannot be
 	// overridden from Android.bp files.
+	//
+	// NOTE: if you need to disable a warning to unblock a compiler upgrade
+	// and it is only triggered by third party code, add it to
+	// extraExternalCflags (if possible) or noOverrideExternalGlobalCflags
+	// (if the former doesn't work). If the new warning also occurs in first
+	// party code, try adding it to commonGlobalCflags first. Adding it here
+	// should be the last resort, because it prevents all code in Android from
+	// opting into the warning.
 	noOverrideGlobalCflags = []string{
 		"-Werror=bool-operation",
 		"-Werror=format-insufficient-args",
@@ -245,35 +282,9 @@
 
 	noOverride64GlobalCflags = []string{}
 
-	// Similar to noOverrideGlobalCflags, but applies only to third-party code
-	// (anything for which IsThirdPartyPath() in build/soong/android/paths.go
-	// returns true - includes external/, most of vendor/ and most of hardware/)
-	noOverrideExternalGlobalCflags = []string{
-		// http://b/151457797
-		"-fcommon",
-		// http://b/191699019
-		"-Wno-format-insufficient-args",
-		// http://b/296321145
-		// Indicates potential memory or stack corruption, so should be changed
-		// to a hard error. Currently triggered by some vendor code.
-		"-Wno-incompatible-function-pointer-types",
-		// http://b/296321508
-		// Introduced in response to a critical security vulnerability and
-		// should be a hard error - it requires only whitespace changes to fix.
-		"-Wno-misleading-indentation",
-		// Triggered by old LLVM code in external/llvm. Likely not worth
-		// enabling since it's a cosmetic issue.
-		"-Wno-bitwise-instead-of-logical",
-
-		"-Wno-unused-but-set-variable",
-		"-Wno-unused-but-set-parameter",
-		"-Wno-unqualified-std-cast-call",
-		"-Wno-array-parameter",
-		"-Wno-gnu-offsetof-extensions",
-	}
-
-	// Extra cflags for external third-party projects to disable warnings that
-	// are infeasible to fix in all the external projects and their upstream repos.
+	// Extra cflags applied to third-party code (anything for which
+	// IsThirdPartyPath() in build/soong/android/paths.go returns true;
+	// includes external/, most of vendor/ and most of hardware/)
 	extraExternalCflags = []string{
 		"-Wno-enum-compare",
 		"-Wno-enum-compare-switch",
@@ -303,11 +314,41 @@
 		"-Wno-deprecated-non-prototype",
 	}
 
+	// Similar to noOverrideGlobalCflags, but applies only to third-party code
+	// (see extraExternalCflags).
+	// This section can unblock compiler upgrades when a third party module that
+	// enables -Werror and some group of warnings explicitly triggers newly
+	// added warnings.
+	noOverrideExternalGlobalCflags = []string{
+		// http://b/151457797
+		"-fcommon",
+		// http://b/191699019
+		"-Wno-format-insufficient-args",
+		// http://b/296321145
+		// Indicates potential memory or stack corruption, so should be changed
+		// to a hard error. Currently triggered by some vendor code.
+		"-Wno-incompatible-function-pointer-types",
+		// http://b/296321508
+		// Introduced in response to a critical security vulnerability and
+		// should be a hard error - it requires only whitespace changes to fix.
+		"-Wno-misleading-indentation",
+		// Triggered by old LLVM code in external/llvm. Likely not worth
+		// enabling since it's a cosmetic issue.
+		"-Wno-bitwise-instead-of-logical",
+
+		"-Wno-unused-but-set-variable",
+		"-Wno-unused-but-set-parameter",
+		"-Wno-unqualified-std-cast-call",
+		"-Wno-array-parameter",
+		"-Wno-gnu-offsetof-extensions",
+	}
+
 	llvmNextExtraCommonGlobalCflags = []string{
 		// Do not report warnings when testing with the top of trunk LLVM.
 		"-Wno-error",
 	}
 
+	// Flags that must not appear in any command line.
 	IllegalFlags = []string{
 		"-w",
 	}
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index e048622..d5bc760 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -27,6 +27,9 @@
 		"-Werror=implicit-function-declaration",
 		"-fno-emulated-tls",
 		"-march=rv64gcv_zba_zbb_zbs",
+		// Equivalent to "-munaligned-access", but our clang doesn't have that yet.
+		"-Xclang -target-feature -Xclang +unaligned-scalar-mem",
+		"-Xclang -target-feature -Xclang +unaligned-vector-mem",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
@@ -34,6 +37,9 @@
 	riscv64Ldflags = []string{
 		"-Wl,--hash-style=gnu",
 		"-march=rv64gcv_zba_zbb_zbs",
+		// Equivalent to "-munaligned-access", but our clang doesn't have that yet.
+		"-Xclang -target-feature -Xclang +unaligned-scalar-mem",
+		"-Xclang -target-feature -Xclang +unaligned-vector-mem",
 	}
 
 	riscv64Lldflags = append(riscv64Ldflags,
diff --git a/cc/fdo_profile.go b/cc/fdo_profile.go
index 05a8f46..cd3eb1e 100644
--- a/cc/fdo_profile.go
+++ b/cc/fdo_profile.go
@@ -72,7 +72,8 @@
 
 	ctx.CreateBazelTargetModuleWithRestrictions(
 		bazel.BazelTargetModuleProperties{
-			Rule_class: "fdo_profile",
+			Bzl_load_location: "//build/bazel/rules/fdo:fdo_profile.bzl",
+			Rule_class:        "fdo_profile",
 		},
 		android.CommonAttributes{
 			Name: fp.Name(),
diff --git a/cc/gen.go b/cc/gen.go
index b15f164..151f23d 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -20,6 +20,7 @@
 
 	"android/soong/aidl_library"
 	"android/soong/bazel"
+	"android/soong/sysprop/bp2build"
 
 	"github.com/google/blueprint"
 
@@ -240,12 +241,13 @@
 }
 
 func bp2buildCcSysprop(ctx android.Bp2buildMutatorContext, moduleName string, minSdkVersion *string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
-	labels := SyspropLibraryLabels{
-		SyspropLibraryLabel: moduleName + "_sysprop_library",
-		StaticLibraryLabel:  moduleName + "_cc_sysprop_library_static",
+	labels := bp2build.SyspropLibraryLabels{
+		SyspropLibraryLabel:  moduleName + "_sysprop_library",
+		CcStaticLibraryLabel: moduleName + "_cc_sysprop_library_static",
 	}
-	Bp2buildSysprop(ctx, labels, srcs, minSdkVersion)
-	return createLabelAttributeCorrespondingToSrcs(":"+labels.StaticLibraryLabel, srcs)
+	bp2build.Bp2buildBaseSyspropLibrary(ctx, labels.SyspropLibraryLabel, srcs)
+	bp2build.Bp2buildSyspropCc(ctx, labels, minSdkVersion)
+	return createLabelAttributeCorrespondingToSrcs(":"+labels.CcStaticLibraryLabel, srcs)
 }
 
 // Creates a LabelAttribute for a given label where the value is only set for
diff --git a/cc/genrule.go b/cc/genrule.go
index d1c4c2a..63c728c 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -84,7 +84,7 @@
 		return true
 	}
 
-	if ctx.DeviceConfig().ProductVndkVersion() != "" && ctx.ProductSpecific() {
+	if ctx.ProductSpecific() {
 		return false
 	}
 
@@ -134,15 +134,8 @@
 		}
 	}
 
-	if ctx.DeviceConfig().ProductVndkVersion() == "" {
-		return variants
-	}
-
 	if Bool(g.Product_available) || ctx.ProductSpecific() {
 		variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
-		if vndkVersion := ctx.DeviceConfig().ProductVndkVersion(); vndkVersion != "current" {
-			variants = append(variants, ProductVariationPrefix+vndkVersion)
-		}
 	}
 
 	return variants
diff --git a/cc/image.go b/cc/image.go
index f91762a..239f1db 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -427,7 +427,6 @@
 
 	platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
 	boardVndkVersion := mctx.DeviceConfig().VndkVersion()
-	productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
 	recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion()
 	usingRecoverySnapshot := recoverySnapshotVersion != "current" &&
 		recoverySnapshotVersion != ""
@@ -444,9 +443,6 @@
 	if boardVndkVersion == "current" {
 		boardVndkVersion = platformVndkVersion
 	}
-	if productVndkVersion == "current" {
-		productVndkVersion = platformVndkVersion
-	}
 
 	if m.NeedsLlndkVariants() {
 		// This is an LLNDK library.  The implementation of the library will be on /system,
@@ -462,9 +458,6 @@
 		if needVndkVersionVendorVariantForLlndk {
 			vendorVariants = append(vendorVariants, boardVndkVersion)
 		}
-		if productVndkVersion != "" {
-			productVariants = append(productVariants, productVndkVersion)
-		}
 	} else if m.NeedsVendorPublicLibraryVariants() {
 		// A vendor public library has the implementation on /vendor, with stub variants
 		// for system and product.
@@ -473,9 +466,6 @@
 		if platformVndkVersion != "" {
 			productVariants = append(productVariants, platformVndkVersion)
 		}
-		if productVndkVersion != "" {
-			productVariants = append(productVariants, productVndkVersion)
-		}
 	} else if boardVndkVersion == "" {
 		// If the device isn't compiling against the VNDK, we always
 		// use the core mode.
@@ -507,10 +497,6 @@
 		// product_available modules are available to /product.
 		if m.HasProductVariant() {
 			productVariants = append(productVariants, platformVndkVersion)
-			// VNDK is always PLATFORM_VNDK_VERSION
-			if !m.IsVndk() {
-				productVariants = append(productVariants, productVndkVersion)
-			}
 		}
 	} else if vendorSpecific && m.SdkVersion() == "" {
 		// This will be available in /vendor (or /odm) only
@@ -538,17 +524,10 @@
 		coreVariantNeeded = true
 	}
 
-	if boardVndkVersion != "" && productVndkVersion != "" {
-		if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
-			// The module has "product_specific: true" that does not create core variant.
-			coreVariantNeeded = false
-			productVariants = append(productVariants, productVndkVersion)
-		}
-	} else {
-		// Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no
-		// restriction to use system libs.
-		// No product variants defined in this case.
-		productVariants = []string{}
+	if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
+		// The module has "product_specific: true" that does not create core variant.
+		coreVariantNeeded = false
+		productVariants = append(productVariants, platformVndkVersion)
 	}
 
 	if m.RamdiskAvailable() {
diff --git a/cc/library.go b/cc/library.go
index b9dc71b..90d91ca 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -517,70 +517,6 @@
 	}
 }
 
-func apiContributionBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	apiSurfaces := make([]string, 0)
-	apiHeaders := make([]string, 0)
-	// module-libapi for apexes (non-null `stubs` property)
-	if module.HasStubsVariants() {
-		apiSurfaces = append(apiSurfaces, android.ModuleLibApi.String())
-		apiIncludes := getModuleLibApiIncludes(ctx, module)
-		if !apiIncludes.isEmpty() {
-			createApiHeaderTarget(ctx, apiIncludes)
-			apiHeaders = append(apiHeaders, apiIncludes.name)
-		}
-	}
-	// vendorapi (non-null `llndk` property)
-	if module.HasLlndkStubs() {
-		apiSurfaces = append(apiSurfaces, android.VendorApi.String())
-		apiIncludes := getVendorApiIncludes(ctx, module)
-		if !apiIncludes.isEmpty() {
-			createApiHeaderTarget(ctx, apiIncludes)
-			apiHeaders = append(apiHeaders, apiIncludes.name)
-		}
-	}
-	// create a target only if this module contributes to an api surface
-	// TODO: Currently this does not distinguish modulelibapi-only headers and vendrorapi-only headers
-	// TODO: Update so that modulelibapi-only headers do not get exported to vendorapi (and vice-versa)
-	if len(apiSurfaces) > 0 {
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_api_contribution",
-			Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-		}
-		attrs := &bazelCcApiContributionAttributes{
-			Library_name: module.Name(),
-			Api_surfaces: bazel.MakeStringListAttribute(apiSurfaces),
-			Api:          apiLabelAttribute(ctx, module),
-			Hdrs: bazel.MakeLabelListAttribute(
-				bazel.MakeLabelListFromTargetNames(apiHeaders),
-			),
-		}
-		ctx.CreateBazelTargetModule(
-			props,
-			android.CommonAttributes{
-				Name:     android.ApiContributionTargetName(module.Name()),
-				SkipData: proptools.BoolPtr(true),
-			},
-			attrs,
-		)
-	}
-}
-
-// Native apis are versioned in a single .map.txt for all api surfaces
-// Pick any one of the .map.txt files
-func apiLabelAttribute(ctx android.TopDownMutatorContext, module *Module) bazel.LabelAttribute {
-	var apiFile *string
-	linker := module.linker.(*libraryDecorator)
-	if llndkApi := linker.Properties.Llndk.Symbol_file; llndkApi != nil {
-		apiFile = llndkApi
-	} else if moduleLibApi := linker.Properties.Stubs.Symbol_file; moduleLibApi != nil {
-		apiFile = moduleLibApi
-	} else {
-		ctx.ModuleErrorf("API surface library does not have any API file")
-	}
-	apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label
-	return *bazel.MakeLabelAttribute(apiLabel)
-}
-
 // wrapper struct to flatten the arch and os specific export_include_dirs
 // flattening is necessary since we want to export apis of all arches even when we build for x86 (e.g.)
 type bazelCcApiLibraryHeadersAttributes struct {
@@ -611,54 +547,6 @@
 	includes.attrs.Deps.Append(lla)
 }
 
-// includes provided to the module-lib API surface. This API surface is used by apexes.
-func getModuleLibApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
-	flagProps := c.library.(*libraryDecorator).flagExporter.Properties
-	linkProps := c.library.(*libraryDecorator).baseLinker.Properties
-	includes := android.FirstUniqueStrings(flagProps.Export_include_dirs)
-	systemIncludes := android.FirstUniqueStrings(flagProps.Export_system_include_dirs)
-	headerLibs := android.FirstUniqueStrings(linkProps.Export_header_lib_headers)
-	attrs := bazelCcLibraryHeadersAttributes{
-		Export_includes:        bazel.MakeStringListAttribute(includes),
-		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, headerLibs)),
-	}
-
-	return apiIncludes{
-		name: c.Name() + ".module-libapi.headers",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: attrs,
-		},
-	}
-}
-
-func getVendorApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
-	baseProps := c.library.(*libraryDecorator).flagExporter.Properties
-	llndkProps := c.library.(*libraryDecorator).Properties.Llndk
-	includes := baseProps.Export_include_dirs
-	systemIncludes := baseProps.Export_system_include_dirs
-	// LLNDK can override the base includes
-	if llndkIncludes := llndkProps.Override_export_include_dirs; llndkIncludes != nil {
-		includes = llndkIncludes
-	}
-	if proptools.Bool(llndkProps.Export_headers_as_system) {
-		systemIncludes = append(systemIncludes, includes...)
-		includes = nil
-	}
-
-	attrs := bazelCcLibraryHeadersAttributes{
-		Export_includes:        bazel.MakeStringListAttribute(includes),
-		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, llndkProps.Export_llndk_headers)),
-	}
-	return apiIncludes{
-		name: c.Name() + ".vendorapi.headers",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: attrs,
-		},
-	}
-}
-
 // cc_library creates both static and/or shared libraries for a device and/or
 // host. By default, a cc_library has a single variant that targets the device.
 // Specifying `host_supported: true` also creates a library that targets the
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 5eba6ab..4da2b48 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -15,8 +15,6 @@
 package cc
 
 import (
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
@@ -163,118 +161,3 @@
 		Tags: tags,
 	}, attrs)
 }
-
-// Append .contribution suffix to input labels
-func apiBazelTargets(ll bazel.LabelList) bazel.LabelList {
-	labels := make([]bazel.Label, 0)
-	for _, l := range ll.Includes {
-		labels = append(labels, bazel.Label{
-			Label: android.ApiContributionTargetName(l.Label),
-		})
-	}
-	return bazel.MakeLabelList(labels)
-}
-
-func apiLibraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	// cc_api_library_headers have a 1:1 mapping to arch/no-arch
-	// For API export, create a top-level arch-agnostic target and list the arch-specific targets as its deps
-
-	// arch-agnostic includes
-	apiIncludes := getModuleLibApiIncludes(ctx, module)
-	// arch and os specific includes
-	archApiIncludes, androidOsIncludes := archOsSpecificApiIncludes(ctx, module)
-	for _, arch := range allArches { // sorted iteration
-		archApiInclude := archApiIncludes[arch]
-		if !archApiInclude.isEmpty() {
-			createApiHeaderTarget(ctx, archApiInclude)
-			apiIncludes.addDep(archApiInclude.name)
-		}
-	}
-	// os==android includes
-	if !androidOsIncludes.isEmpty() {
-		createApiHeaderTarget(ctx, androidOsIncludes)
-		apiIncludes.addDep(androidOsIncludes.name)
-	}
-
-	if !apiIncludes.isEmpty() {
-		// override the name from <mod>.module-libapi.headers --> <mod>.contribution
-		apiIncludes.name = android.ApiContributionTargetName(module.Name())
-		createApiHeaderTarget(ctx, apiIncludes)
-	}
-}
-
-func createApiHeaderTarget(ctx android.TopDownMutatorContext, includes apiIncludes) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_api_library_headers",
-		Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-	}
-	ctx.CreateBazelTargetModule(
-		props,
-		android.CommonAttributes{
-			Name:     includes.name,
-			SkipData: proptools.BoolPtr(true),
-		},
-		&includes.attrs,
-	)
-}
-
-var (
-	allArches = []string{"arm", "arm64", "x86", "x86_64"}
-)
-
-type archApiIncludes map[string]apiIncludes
-
-func archOsSpecificApiIncludes(ctx android.TopDownMutatorContext, module *Module) (archApiIncludes, apiIncludes) {
-	baseProps := bp2BuildParseBaseProps(ctx, module)
-	i := bp2BuildParseExportedIncludes(ctx, module, &baseProps.includes)
-	archRet := archApiIncludes{}
-	for _, arch := range allArches {
-		includes := i.Includes.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		systemIncludes := i.SystemIncludes.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		deps := baseProps.deps.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		attrs := bazelCcLibraryHeadersAttributes{
-			Export_includes:        bazel.MakeStringListAttribute(includes),
-			Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		}
-		apiDeps := apiBazelTargets(deps)
-		if !apiDeps.IsEmpty() {
-			attrs.Deps = bazel.MakeLabelListAttribute(apiDeps)
-		}
-		apiIncludes := apiIncludes{
-			name: android.ApiContributionTargetName(module.Name()) + "." + arch,
-			attrs: bazelCcApiLibraryHeadersAttributes{
-				bazelCcLibraryHeadersAttributes: attrs,
-				Arch:                            proptools.StringPtr(arch),
-			},
-		}
-		archRet[arch] = apiIncludes
-	}
-
-	// apiIncludes for os == Android
-	androidOsDeps := baseProps.deps.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid)
-	androidOsAttrs := bazelCcLibraryHeadersAttributes{
-		Export_includes: bazel.MakeStringListAttribute(
-			i.Includes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
-		),
-		Export_system_includes: bazel.MakeStringListAttribute(
-			i.SystemIncludes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
-		),
-	}
-	androidOsApiDeps := apiBazelTargets(androidOsDeps)
-	if !androidOsApiDeps.IsEmpty() {
-		androidOsAttrs.Deps = bazel.MakeLabelListAttribute(androidOsApiDeps)
-	}
-	osRet := apiIncludes{
-		name: android.ApiContributionTargetName(module.Name()) + ".androidos",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: androidOsAttrs,
-		},
-	}
-	return archRet, osRet
-}
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index da5db1c..461aa96 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -19,6 +19,7 @@
 	"path/filepath"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -151,6 +152,7 @@
 	Strip_import_prefix *string
 	Import_prefix       *string
 	Hdrs                bazel.LabelListAttribute
+	Run_versioner       *bool
 }
 
 func (h *headerModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
@@ -217,6 +219,7 @@
 // Note that this is really only built to handle bionic/libc/include.
 type versionedHeaderModule struct {
 	android.ModuleBase
+	android.BazelModuleBase
 
 	properties versionedHeaderProperties
 
@@ -255,6 +258,25 @@
 	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
 }
 
+func (h *versionedHeaderModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "ndk_headers",
+		Bzl_load_location: "//build/bazel/rules/cc:ndk_headers.bzl",
+	}
+	globPattern := headerGlobPattern(proptools.String(h.properties.From))
+	attrs := &bazelNdkHeadersAttributes{
+		Strip_import_prefix: h.properties.From,
+		Import_prefix:       h.properties.To,
+		Run_versioner:       proptools.BoolPtr(true),
+		Hdrs:                bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, []string{globPattern})),
+	}
+	ctx.CreateBazelTargetModule(
+		props,
+		android.CommonAttributes{Name: h.Name()},
+		attrs,
+	)
+}
+
 func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
 	srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
 	// The versioner depends on a dependencies directory to simplify determining include paths
@@ -298,12 +320,13 @@
 // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
 // directory level specified in `from` property. This is only used to process
 // the bionic/libc/include directory.
-func versionedNdkHeadersFactory() android.Module {
+func VersionedNdkHeadersFactory() android.Module {
 	module := &versionedHeaderModule{}
 
 	module.AddProperties(&module.properties)
 
 	android.InitAndroidModule(module)
+	android.InitBazelModule(module)
 
 	return module
 }
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index b3bb2da..2064b1b 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -61,7 +61,7 @@
 			// because we don't want to spam the build output with "nothing
 			// changed" messages, so redirect output message to $out, and if
 			// changes were detected print the output and fail.
-			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && false)",
+			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && false; echo 'Run $$ANDROID_BUILD_TOP/development/tools/ndk/update_ndk_abi.sh to update the ABI dumps.')",
 			CommandDeps: []string{"$stgdiff"},
 		}, "args")
 
@@ -386,9 +386,11 @@
 	// level.
 	abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp")
 	prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel)
+	missingPrebuiltErrorTemplate :=
+		"Did not find prebuilt ABI dump for %q (%q). Generate with " +
+			"//development/tools/ndk/update_ndk_abi.sh."
 	missingPrebuiltError := fmt.Sprintf(
-		"Did not find prebuilt ABI dump for %q (%q). Generate with "+
-			"//development/tools/ndk/update_ndk_abi.sh.", this.libraryName(ctx),
+		missingPrebuiltErrorTemplate, this.libraryName(ctx),
 		prebuiltAbiDump.InvalidReason())
 	if !prebuiltAbiDump.Valid() {
 		ctx.Build(pctx, android.BuildParams{
@@ -424,12 +426,15 @@
 		nextAbiDiffPath := android.PathForModuleOut(ctx,
 			"abidiff_next.timestamp")
 		nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel)
+		missingNextPrebuiltError := fmt.Sprintf(
+			missingPrebuiltErrorTemplate, this.libraryName(ctx),
+			nextAbiDump.InvalidReason())
 		if !nextAbiDump.Valid() {
 			ctx.Build(pctx, android.BuildParams{
 				Rule:   android.ErrorRule,
 				Output: nextAbiDiffPath,
 				Args: map[string]string{
-					"error": missingPrebuiltError,
+					"error": missingNextPrebuiltError,
 				},
 			})
 		} else {
@@ -575,15 +580,6 @@
 	Library_name string
 }
 
-// Names of the cc_api_header targets in the bp2build workspace
-func apiHeaderLabels(ctx android.TopDownMutatorContext, hdrLibs []string) bazel.LabelList {
-	addSuffix := func(ctx android.BazelConversionPathContext, module blueprint.Module) string {
-		label := android.BazelModuleLabel(ctx, module)
-		return android.ApiContributionTargetName(label)
-	}
-	return android.BazelLabelForModuleDepsWithFn(ctx, hdrLibs, addSuffix)
-}
-
 func ndkLibraryBp2build(ctx android.Bp2buildMutatorContext, c *Module) {
 	ndk, _ := c.linker.(*stubDecorator)
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 54a2ee2..483d23b 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -64,7 +64,7 @@
 func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
-	ctx.RegisterModuleType("versioned_ndk_headers", versionedNdkHeadersFactory)
+	ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory)
 	ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
 	ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
 }
diff --git a/cc/proto.go b/cc/proto.go
index 0ed4381..4e08a4c 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -246,7 +246,7 @@
 	protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
 
 	name := m.Name() + suffix
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), m)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        rule_class,
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 9ceb1c8..6329e97 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1113,12 +1113,15 @@
 // indirectly (via a mutator) sets the bool ptr to true, and you can't
 // distinguish between the cases. It isn't needed though - both cases can be
 // treated identically.
-func (sanitize *sanitize) isSanitizerEnabled(t SanitizerType) bool {
-	if sanitize == nil {
+func (s *sanitize) isSanitizerEnabled(t SanitizerType) bool {
+	if s == nil {
+		return false
+	}
+	if proptools.Bool(s.Properties.SanitizeMutated.Never) {
 		return false
 	}
 
-	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
+	sanitizerVal := s.getSanitizerBoolPtr(t)
 	return sanitizerVal != nil && *sanitizerVal == true
 }
 
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 49117a0..31e668e 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"runtime"
 	"strings"
 	"testing"
@@ -1273,3 +1274,122 @@
 		t.Errorf("non-CFI variant of baz not expected to contain CFI flags ")
 	}
 }
+
+func TestHwasan(t *testing.T) {
+	t.Parallel()
+
+	bp := `
+	cc_library_shared {
+		name: "shared_with_hwaddress",
+		static_libs: [
+			"static_dep_with_hwaddress",
+			"static_dep_no_hwaddress",
+		],
+		sanitize: {
+			hwaddress: true,
+		},
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+
+	cc_library_static {
+		name: "static_dep_with_hwaddress",
+		sanitize: {
+			hwaddress: true,
+		},
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+
+	cc_library_static {
+		name: "static_dep_no_hwaddress",
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+`
+
+	androidArm := "android_arm_armv7-a-neon"
+	androidArm64 := "android_arm64_armv8-a"
+	androidX86 := "android_x86_silvermont"
+	sharedSuffix := "_shared"
+	hwasanSuffix := "_hwasan"
+	staticSuffix := "_static"
+	sdkSuffix := "_sdk"
+
+	sharedWithHwasanVariant := sharedSuffix + hwasanSuffix
+	sharedWithSdkVariant := sdkSuffix + sharedSuffix
+	staticWithHwasanVariant := staticSuffix + hwasanSuffix
+	staticWithSdkVariant := sdkSuffix + staticSuffix
+
+	testCases := []struct {
+		buildOs          string
+		extraPreparer    android.FixturePreparer
+		expectedVariants map[string][]string
+	}{
+		{
+			buildOs: androidArm64,
+			expectedVariants: map[string][]string{
+				"shared_with_hwaddress": []string{
+					androidArm64 + sharedWithHwasanVariant,
+					androidArm64 + sharedWithSdkVariant,
+					androidArm + sharedSuffix,
+					androidArm + sharedWithSdkVariant,
+				},
+				"static_dep_with_hwaddress": []string{
+					androidArm64 + staticSuffix,
+					androidArm64 + staticWithHwasanVariant,
+					androidArm64 + staticWithSdkVariant,
+					androidArm + staticSuffix,
+					androidArm + staticWithSdkVariant,
+				},
+				"static_dep_no_hwaddress": []string{
+					androidArm64 + staticSuffix,
+					androidArm64 + staticWithHwasanVariant,
+					androidArm64 + staticWithSdkVariant,
+					androidArm + staticSuffix,
+					androidArm + staticWithSdkVariant,
+				},
+			},
+		},
+		{
+			buildOs: androidX86,
+			extraPreparer: android.FixtureModifyConfig(func(config android.Config) {
+				config.Targets[android.Android] = []android.Target{
+					{
+						android.Android,
+						android.Arch{
+							ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, android.NativeBridgeDisabled, "", "", false},
+				}
+			}),
+			expectedVariants: map[string][]string{
+				"shared_with_hwaddress": []string{
+					androidX86 + sharedSuffix,
+					androidX86 + sharedWithSdkVariant,
+				},
+				"static_dep_with_hwaddress": []string{
+					androidX86 + staticSuffix,
+					androidX86 + staticWithSdkVariant,
+				},
+				"static_dep_no_hwaddress": []string{
+					androidX86 + staticSuffix,
+					androidX86 + staticWithSdkVariant,
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			prepareForCcTest,
+			android.OptionalFixturePreparer(tc.extraPreparer),
+		)
+		result := preparer.RunTestWithBp(t, bp)
+
+		for m, v := range tc.expectedVariants {
+			variants := result.ModuleVariantsForTests(m)
+			if !reflect.DeepEqual(variants, v) {
+				t.Errorf("Expected variants of %q to be %q, but got %q", m, v, variants)
+			}
+		}
+	}
+}
diff --git a/cc/sysprop.go b/cc/sysprop.go
deleted file mode 100644
index 7ddd476..0000000
--- a/cc/sysprop.go
+++ /dev/null
@@ -1,77 +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 cc
-
-import (
-	"android/soong/android"
-	"android/soong/bazel"
-)
-
-// TODO(b/240463568): Additional properties will be added for API validation
-type bazelSyspropLibraryAttributes struct {
-	Srcs bazel.LabelListAttribute
-	Tags bazel.StringListAttribute
-}
-
-type bazelCcSyspropLibraryAttributes struct {
-	Dep             bazel.LabelAttribute
-	Min_sdk_version *string
-	Tags            bazel.StringListAttribute
-}
-
-type SyspropLibraryLabels struct {
-	SyspropLibraryLabel string
-	SharedLibraryLabel  string
-	StaticLibraryLabel  string
-}
-
-func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
-	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "sysprop_library",
-			Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
-		},
-		android.CommonAttributes{Name: labels.SyspropLibraryLabel},
-		&bazelSyspropLibraryAttributes{
-			Srcs: srcs,
-			Tags: apexAvailableTags,
-		},
-	)
-
-	attrs := &bazelCcSyspropLibraryAttributes{
-		Dep:             *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
-		Min_sdk_version: minSdkVersion,
-		Tags:            apexAvailableTags,
-	}
-
-	if labels.SharedLibraryLabel != "" {
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "cc_sysprop_library_shared",
-				Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
-			},
-			android.CommonAttributes{Name: labels.SharedLibraryLabel},
-			attrs)
-	}
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_sysprop_library_static",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
-		},
-		android.CommonAttributes{Name: labels.StaticLibraryLabel},
-		attrs)
-}
diff --git a/cc/test.go b/cc/test.go
index 7a6cf1b..f128187 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -25,6 +25,7 @@
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
 	"android/soong/tradefed"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 )
 
 // TestLinkerProperties properties to be registered via the linker
@@ -718,6 +719,13 @@
 				combinedData.Append(android.BazelLabelForModuleDeps(ctx, p.Data_libs))
 				data.SetSelectValue(axis, config, combinedData)
 				tags.SetSelectValue(axis, config, p.Test_options.Tags)
+
+				// TODO: b/300117121 - handle bp2build conversion of non-unit tests
+				// default to true to only handle non-nil falses
+				if !BoolDefault(p.Test_options.Unit_test, true) {
+					ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "Host unit_test = false")
+					return
+				}
 			}
 		}
 	}
@@ -791,7 +799,7 @@
 
 // cc_test that builds using gtest needs some additional deps
 // addImplicitGtestDeps makes these deps explicit in the generated BUILD files
-func addImplicitGtestDeps(ctx android.BazelConversionPathContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
+func addImplicitGtestDeps(ctx android.Bp2buildMutatorContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
 	addDepsAndDedupe := func(lla *bazel.LabelListAttribute, modules []string) {
 		moduleLabels := android.BazelLabelForModuleDeps(ctx, modules)
 		lla.Value.Append(moduleLabels)
diff --git a/cc/testing.go b/cc/testing.go
index 36bc261..71d986b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -68,26 +68,6 @@
 
 func commonDefaultModules() string {
 	return `
-		prebuilt_build_tool {
-			name: "clang++",
-			src: "bin/clang++",
-		}
-		prebuilt_build_tool {
-			name: "clang++.real",
-			src: "bin/clang++.real",
-		}
-		prebuilt_build_tool {
-			name: "lld",
-			src: "bin/lld",
-		}
-		prebuilt_build_tool {
-			name: "ld.lld",
-			src: "bin/ld.lld",
-		}
-		prebuilt_build_tool {
-			name: "llvm-ar",
-			src: "bin/llvm-ar",
-		}
 		cc_defaults {
 			name: "toolchain_libs_defaults",
 			host_supported: true,
@@ -589,12 +569,6 @@
 
 	// Additional files needed in tests that disallow non-existent source.
 	android.MockFS{
-		"defaults/cc/common/bin/clang++":      nil,
-		"defaults/cc/common/bin/clang++.real": nil,
-		"defaults/cc/common/bin/lld":          nil,
-		"defaults/cc/common/bin/ld.lld":       nil,
-		"defaults/cc/common/bin/llvm-ar":      nil,
-
 		"defaults/cc/common/libc.map.txt":      nil,
 		"defaults/cc/common/libdl.map.txt":     nil,
 		"defaults/cc/common/libm.map.txt":      nil,
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 9ea337b..e8e930e 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -98,6 +98,11 @@
 			if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(scs) {
 				return false
 			}
+			// cfi and hwasan cannot be enabled at the same time.
+			// Skip variants that have both cfi and hwasan enabled.
+			if sanitizable.IsSanitizerEnabled(cfi) && sanitizable.IsSanitizerEnabled(Hwasan) {
+				return false
+			}
 			// cfi and hwasan also export both variants. But for static, we capture both.
 			// This is because cfi static libraries can't be linked from non-cfi modules,
 			// and vice versa.
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 2e71fe1..a7308b4 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -76,8 +76,8 @@
 	if err != nil {
 		return nil, err
 	}
-	bytes := make([]byte, tocFile.FileHeader.UncompressedSize64)
-	if _, err := rc.Read(bytes); err != nil && err != io.EOF {
+	bytes, err := io.ReadAll(rc)
+	if err != nil {
 		return nil, err
 	}
 	rc.Close()
diff --git a/docs/clion.md b/docs/clion.md
index d6ae19a..110891b 100644
--- a/docs/clion.md
+++ b/docs/clion.md
@@ -3,6 +3,10 @@
 Soong can generate CLion projects. This is intended for source code editing
 only. Build should still be done via make/m/mm(a)/mmm(a).
 
+Note: alternatively, you can use
+[aidegen to generate a Clion or VSCode project](https://android.googlesource.com/platform/tools/asuite/+/refs/heads/master/aidegen/README.md)
+with a single command, using the `-i c` flag.
+
 CMakeLists.txt project file generation is enabled via environment variable:
 
 ```bash
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index afa52cc..3e92706 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -135,10 +135,125 @@
 		"ltp_config_arm_64_lowmem_hwasan",
 		"ltp_config_x86",
 		"libbssl_sys_src_nostd",
+		"libcore-non-cts-tests-txt",
+		"ControlEnvProxyServerProto_cc",
+		"ControlEnvProxyServerProto_h",
+		"camera-its",
+		"android-cts-verifier",
+		"CtsApkVerityTestDebugFiles",
+		"vm-tests-tf-lib",
+		"egl_extensions_functions_hdr",
+		"egl_functions_hdr",
+		"gles1_core_functions_hdr",
+		"gles1_extensions_functions_hdr",
+		"gles2_core_functions_hdr",
+		"gles2_extensions_functions_hdr",
+		"gles31_only_functions_hdr",
+		"gles3_only_functions_hdr",
+		"angle_commit_id",
+		"deqp_spvtools_update_build_version",
+		"emp_ematch.yacc.c",
+		"emp_ematch.yacc.h",
+		"libchrome-crypto-include",
+		"libchrome-include",
+		"libmojo_jni_headers",
+		"libxml2_schema_fuzz_corpus",
+		"libxml2_xml_fuzz_corpus",
+		"libc_musl_sysroot_bits",
+		"awkgram.tab.h",
+		"openwrt_rootfs_combined_aarch64",
+		"openwrt_rootfs_combined_x86_64",
+		"openwrt_rootfs_customization_aarch64",
+		"openwrt_rootfs_customization_x86_64",
+		"pandora-python-gen-src",
+		"pdl_cxx_canonical_be_src_gen",
+		"pdl_cxx_canonical_be_test_gen",
+		"pdl_cxx_canonical_le_src_gen",
+		"pdl_cxx_canonical_le_test_gen",
+		"pdl_python_generator_be_test_gen",
+		"pdl_python_generator_le_test_gen",
+		"pdl_rust_noalloc_le_test_backend_srcs",
+		"pdl_rust_noalloc_le_test_gen_harness",
+		"swiftshader_spvtools_update_build_version",
+		"uwb_core_artifacts",
+		"futility_cmds",
+		"MultiDexLegacyTestApp_genrule",
+		"com.android.overlaytest.overlaid.pem",
+		"com.android.overlaytest.overlaid.pubkey",
+		"com.android.overlaytest.overlay.pem",
+		"com.android.overlaytest.overlay.pubkey",
+		"wm_shell_protolog_src",
+		"services.core.protologsrc",
+		"PackageManagerServiceServerTests_apks_as_resources",
+		"wmtests.protologsrc",
+		"com.android.apex.apkrollback.test.pem",
+		"com.android.apex.apkrollback.test.pubkey",
+		"UpdatableSystemFontTest_NotoColorEmojiV0.sig",
+		"UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
+		"UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig",
+		"UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
+		"UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig",
+		"UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
+		"temp_layoutlib",
+		"android-support-multidex-instrumentation-version",
+		"android-support-multidex-version",
+		"core-tests-smali-dex",
+		"gd_hci_packets_python3_gen",
+		"gd_smp_packets_python3_gen",
+		"bluetooth_core_rust_packets",
+		"HeadlessBuildTimestamp",
+		"hci_packets_python3_gen",
+		"link_layer_packets_python3_gen",
+		"llcp_packets_python3_gen",
+		"rootcanal_bredr_bb_packets_cxx_gen",
+		"rootcanal_hci_packets_cxx_gen",
+		"rootcanal_link_layer_packets_cxx_gen",
+		"authfs_test_apk_assets",
+		"measure_io_as_jar",
+		"statsd-config-protos",
+		"statsd-config-protos",
+		"sample-profile-text-protos",
+		"sample-profile-text-protos",
+		"lib-test-profile-text-protos",
+		"lib-test-profile-text-protos",
+		"common-profile-text-protos",
+		"common-profile-text-protos",
+		"vndk_abi_dump_zip",
+		"r8retrace-dexdump-sample-app",
+		"gen_key_mismatch_capex",
+		"gen_corrupt_rebootless_apex",
+		"gen_corrupt_superblock_apex",
+		"gen_manifest_mismatch_apex_no_hashtree",
+		"apexer_test_host_tools",
+		"com.android.apex.cts.shim.debug.pem",
+		"com.android.apex.cts.shim.debug.pubkey",
+		"com.android.apex.cts.shim.pem",
+		"com.android.apex.cts.shim.pubkey",
+		"com.android.apex.cts.shim.v2_no_pb",
+		"com.android.apex.cts.shim.v2_signed_bob",
+		"com.android.apex.cts.shim.v2_signed_bob_rot",
+		"com.android.apex.cts.shim.v2_signed_bob_rot_rollback",
+		"com.android.apex.cts.shim.v2_unsigned_apk_container",
+		"com.android.apex.cts.shim.v3_signed_bob",
+		"com.android.apex.cts.shim.v3_signed_bob_rot",
+		"com.android.apex.cts.shim_not_pre_installed.pem",
+		"com.android.apex.cts.shim_not_pre_installed.pubkey",
+		"com.android.apex.rotation.key.bob.pem",
+		"com.android.apex.rotation.key.bob.pk8",
+		"com.android.apex.rotation.key.bob.rot.rollback",
+		"com.android.apex.rotation.key.bob.rot",
+		"com.android.apex.rotation.key.bob.x509.pem",
+		"generate_hash_v1",
+		"ue_unittest_erofs_imgs",
+		"ue_unittest_erofs_imgs",
+		"ue_unittest_erofs_imgs",
+		"vts_vndk_abi_dump_zip",
+		"atest_integration_fake_src",
 	}
 
 	SandboxingDenyPathList = []string{
 		"art/test",
 		"external/perfetto",
+		"external/cronet",
 	}
 )
diff --git a/jar/jar.go b/jar/jar.go
index f164ee1..54eded9 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -166,10 +166,23 @@
 	}
 	s.IsIdentRune = javaIdentRune
 
-	tok := s.Scan()
-	if sErr != nil {
-		return "", sErr
+	var tok rune
+	for {
+		tok = s.Scan()
+		if sErr != nil {
+			return "", sErr
+		}
+		// If the first token is an annotation, it could be annotating a package declaration, so consume them.
+		// Note that this does not support "complex" annotations with attributes, e.g. @Foo(x=y).
+		if tok != '@' {
+			break
+		}
+		tok = s.Scan()
+		if tok != scanner.Ident || sErr != nil {
+			return "", fmt.Errorf("expected annotation identifier, got @%v", tok)
+		}
 	}
+
 	if tok == scanner.Ident {
 		switch s.TokenText() {
 		case "package":
@@ -189,9 +202,6 @@
 		default:
 			return "", fmt.Errorf(`expected first token of java file to be "package", got %q`, s.TokenText())
 		}
-	} else if tok == '@' {
-		// File has no package statement, first token is an annotation
-		return "", nil
 	} else if tok == scanner.EOF {
 		// File no package statement, it has no non-whitespace non-comment tokens
 		return "", nil
diff --git a/jar/jar_test.go b/jar/jar_test.go
index c92011e..61da9bb 100644
--- a/jar/jar_test.go
+++ b/jar/jar_test.go
@@ -61,6 +61,16 @@
 			in:      "package 0foo.bar;",
 			wantErr: true,
 		},
+		{
+			name: "annotations",
+			in:   "@NonNullApi\n@X\npackage foo.bar;",
+			want: "foo.bar",
+		},
+		{
+			name:    "complex annotation",
+			in:      "@Foo(x=y)\n@package foo.bar;",
+			wantErr: true, // Complex annotation not supported yet.
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/java/aar.go b/java/aar.go
index f28d971..44496dc 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -1223,6 +1223,7 @@
 type bazelAapt struct {
 	Manifest       bazel.Label
 	Resource_files bazel.LabelListAttribute
+	Resource_zips  bazel.LabelListAttribute
 	Assets_dir     bazel.StringAttribute
 	Assets         bazel.LabelListAttribute
 }
@@ -1267,15 +1268,30 @@
 		assets = bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir)))
 
 	}
+	var resourceZips bazel.LabelList
+	if len(a.aaptProperties.Resource_zips) > 0 {
+		if ctx.ModuleName() == "framework-res" {
+			resourceZips = android.BazelLabelForModuleSrc(ctx, a.aaptProperties.Resource_zips)
+		} else {
+			//TODO: b/301593550 - Implement support for this
+			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "resource_zips")
+			return &bazelAapt{}, false
+		}
+	}
 	return &bazelAapt{
 		android.BazelLabelForModuleSrcSingle(ctx, manifest),
 		bazel.MakeLabelListAttribute(resourceFiles),
+		bazel.MakeLabelListAttribute(resourceZips),
 		assetsDir,
 		bazel.MakeLabelListAttribute(assets),
 	}, true
 }
 
 func (a *AARImport) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	if len(a.properties.Aars) == 0 {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "aars can't be empty")
+		return
+	}
 	aars := android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Aars, []string{})
 	exportableStaticLibs := []string{}
 	// TODO(b/240716882): investigate and handle static_libs deps that are not imports. They are not supported for export by Bazel.
@@ -1340,10 +1356,12 @@
 	if !commonAttrs.Srcs.IsEmpty() {
 		deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
 	} else if !depLabels.Deps.IsEmpty() {
-		ctx.MarkBp2buildUnconvertible(
-			bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED,
-			"Module has direct dependencies but no sources. Bazel will not allow this.")
-		return
+		// android_library does not accept deps when there are no srcs because
+		// there is no compilation happening, but it accepts exports.
+		// The non-empty deps here are unnecessary as deps on the android_library
+		// since they aren't being propagated to any dependencies.
+		// So we can drop deps here.
+		deps = bazel.LabelListAttribute{}
 	}
 	name := a.Name()
 	props := AndroidLibraryBazelTargetModuleProperties()
@@ -1352,6 +1370,9 @@
 	if !supported {
 		return
 	}
+	if hasJavaResources := aaptAttrs.ConvertJavaResources(ctx, commonAttrs); hasJavaResources {
+		return
+	}
 	ctx.CreateBazelTargetModule(
 		props,
 		android.CommonAttributes{Name: name},
diff --git a/java/app.go b/java/app.go
index dabc319..166c22d 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1638,6 +1638,15 @@
 	Updatable        *bool
 }
 
+func (b bazelAapt) ConvertJavaResources(ctx android.Bp2buildMutatorContext, javaAttrs *javaCommonAttributes) bool {
+	// TODO (b/300470246) bp2build support for java_resources & java_resource_dirs in android rules
+	hasJavaResources := !javaAttrs.javaResourcesAttributes.Resources.IsEmpty()
+	if hasJavaResources {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "(b/300470246) java resources in android_* module")
+	}
+	return hasJavaResources
+}
+
 func convertWithBp2build(ctx android.Bp2buildMutatorContext, a *AndroidApp) (bool, android.CommonAttributes, *bazelAndroidAppAttributes) {
 	aapt, supported := a.convertAaptAttrsWithBp2Build(ctx)
 	if !supported {
@@ -1674,9 +1683,25 @@
 		Updatable:        a.appProperties.Updatable,
 	}
 
-	if !BoolDefault(a.dexProperties.Optimize.Enabled, true) {
-		appAttrs.Optimize = proptools.BoolPtr(false)
-	} else {
+	// As framework-res has no sources, no deps in the Bazel sense, and java compilation, dexing and optimization is skipped by
+	// Soong specifically for it, return early here before any of the conversion work for the above is attempted.
+	if ctx.ModuleName() == "framework-res" {
+		appAttrs.bazelAapt = aapt
+		return true, android.CommonAttributes{Name: a.Name(), SkipData: proptools.BoolPtr(true)}, appAttrs
+	}
+
+	// Optimization is..
+	// - enabled by default for android_app, android_test_helper_app
+	// - disabled by default for android_test
+	//
+	// TODO(b/192032291): Disable android_test_helper_app optimization by
+	// default after auditing downstream usage.
+	if a.dexProperties.Optimize.EnabledByDefault != a.dexer.effectiveOptimizeEnabled() {
+		// Property is explicitly defined by default from default, so emit the Bazel attribute.
+		appAttrs.Optimize = proptools.BoolPtr(a.dexer.effectiveOptimizeEnabled())
+	}
+
+	if a.dexer.effectiveOptimizeEnabled() {
 		handCraftedFlags := ""
 		if Bool(a.dexProperties.Optimize.Ignore_warnings) {
 			handCraftedFlags += "-ignorewarning "
@@ -1712,6 +1737,10 @@
 	if !supported {
 		return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{}
 	}
+	if hasJavaResources := aapt.ConvertJavaResources(ctx, commonAttrs); hasJavaResources {
+		return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{}
+	}
+
 	depLabels := bp2BuildInfo.DepLabels
 
 	deps := depLabels.Deps
@@ -1762,11 +1791,18 @@
 // ConvertWithBp2build is used to convert android_app to Bazel.
 func (a *AndroidApp) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
 	if ok, commonAttrs, appAttrs := convertWithBp2build(ctx, a); ok {
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "android_binary",
-			Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
+		var props bazel.BazelTargetModuleProperties
+		if ctx.ModuleName() == "framework-res" {
+			props = bazel.BazelTargetModuleProperties{
+				Rule_class:        "framework_resources",
+				Bzl_load_location: "//build/bazel/rules/android:framework_resources.bzl",
+			}
+		} else {
+			props = bazel.BazelTargetModuleProperties{
+				Rule_class:        "android_binary",
+				Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
+			}
 		}
-
 		ctx.CreateBazelTargetModule(props, commonAttrs, appAttrs)
 	}
 
@@ -1790,13 +1826,12 @@
 		// an android_test_helper_app is an android_binary with testonly = True
 		commonAttrs.Testonly = proptools.BoolPtr(true)
 
-		// additionally, it sets default values differently to android_app,
+		// android_test_helper_app sets default values differently to android_app,
 		// https://cs.android.com/android/platform/superproject/main/+/main:build/soong/java/app.go;l=1273-1279;drc=e12c083198403ec694af6c625aed11327eb2bf7f
 		//
 		// installable: true (settable prop)
 		// use_embedded_native_libs: true (settable prop)
 		// lint.test: true (settable prop)
-		// optimize EnabledByDefault: true (blueprint mutated prop)
 		// AlwaysPackageNativeLibs: true (blueprint mutated prop)
 		// dexpreopt isTest: true (not prop)
 
diff --git a/java/base.go b/java/base.go
index a110aff..c685fba 100644
--- a/java/base.go
+++ b/java/base.go
@@ -432,6 +432,9 @@
 	srcJarArgs []string
 	srcJarDeps android.Paths
 
+	// the source files of this module and all its static dependencies
+	transitiveSrcFiles *android.DepSet[android.Path]
+
 	// jar file containing implementation classes and resources including static library
 	// dependencies
 	implementationAndResourcesJar android.Path
@@ -638,6 +641,11 @@
 		return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
 	case ".generated_srcjars":
 		return j.properties.Generated_srcjars, nil
+	case ".lint":
+		if j.linter.outputs.xml != nil {
+			return android.Paths{j.linter.outputs.xml}, nil
+		}
+		return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -711,6 +719,10 @@
 	return j.SdkVersion(ctx).ApiLevel
 }
 
+func (j *Module) GetDeviceProperties() *DeviceProperties {
+	return &j.deviceProperties
+}
+
 func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 	if j.deviceProperties.Max_sdk_version != nil {
 		return android.ApiLevelFrom(ctx, *j.deviceProperties.Max_sdk_version)
@@ -1343,10 +1355,17 @@
 					jars = append(jars, classes)
 				}
 			}
+			// Assume approximately 5 sources per srcjar.
+			// For framework-minus-apex in AOSP at the time this was written, there are 266 srcjars, with a mean
+			// of 5.8 sources per srcjar, but a median of 1, a standard deviation of 10, and a max of 48 source files.
 			if len(srcJars) > 0 {
-				classes := j.compileJavaClasses(ctx, jarName, len(shardSrcs),
-					nil, srcJars, flags, extraJarDeps)
-				jars = append(jars, classes)
+				startIdx := len(shardSrcs)
+				shardSrcJarsList := android.ShardPaths(srcJars, shardSize/5)
+				for idx, shardSrcJars := range shardSrcJarsList {
+					classes := j.compileJavaClasses(ctx, jarName, startIdx+idx,
+						nil, shardSrcJars, flags, extraJarDeps)
+					jars = append(jars, classes)
+				}
 			}
 		} else {
 			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
@@ -1687,6 +1706,8 @@
 		j.linter.lint(ctx)
 	}
 
+	j.collectTransitiveSrcFiles(ctx, srcFiles)
+
 	ctx.CheckbuildFile(outputFile)
 
 	j.collectTransitiveAconfigFiles(ctx)
@@ -1701,6 +1722,7 @@
 		AidlIncludeDirs:                j.exportAidlIncludeDirs,
 		SrcJarArgs:                     j.srcJarArgs,
 		SrcJarDeps:                     j.srcJarDeps,
+		TransitiveSrcFiles:             j.transitiveSrcFiles,
 		ExportedPlugins:                j.exportedPluginJars,
 		ExportedPluginClasses:          j.exportedPluginClasses,
 		ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
@@ -2025,6 +2047,21 @@
 	return j.jacocoReportClassesFile
 }
 
+func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) {
+	var fromDeps []*android.DepSet[android.Path]
+	ctx.VisitDirectDeps(func(module android.Module) {
+		tag := ctx.OtherModuleDependencyTag(module)
+		if tag == staticLibTag {
+			depInfo := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+			if depInfo.TransitiveSrcFiles != nil {
+				fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles)
+			}
+		}
+	})
+
+	j.transitiveSrcFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps)
+}
+
 func (j *Module) IsInstallable() bool {
 	return Bool(j.properties.Installable)
 }
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index fc63f4d..e5e187c 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -49,8 +49,5 @@
 		"-J--add-opens=java.base/java.util=ALL-UNNAMED", // https://youtrack.jetbrains.com/issue/KT-43704
 	}, " "))
 
-	pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{
-		// b/222162908: prevent kotlinc from reading /tmp/build.txt
-		"-Didea.plugins.compatible.build=999.SNAPSHOT",
-	}, " "))
+	pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{}, " "))
 }
diff --git a/java/dex.go b/java/dex.go
index c1d51c7..348c939 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -110,7 +110,8 @@
 			`${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
 			`$d8Template${config.D8Cmd} ${config.D8Flags} --output $outDir $d8Flags $tmpJar && ` +
 			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
-			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
+			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
+			`rm -f "$tmpJar" "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
 		CommandDeps: []string{
 			"${config.D8Cmd}",
 			"${config.Zip2ZipCmd}",
@@ -139,9 +140,7 @@
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
 			`rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` +
 			`mkdir -p $$(dirname ${outUsage}) && ` +
-			`mkdir -p $$(dirname $tmpJar) && ` +
-			`${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
-			`$r8Template${config.R8Cmd} ${config.R8Flags} -injars $tmpJar --output $outDir ` +
+			`$r8Template${config.R8Cmd} ${config.R8Flags} -injars $in --output $outDir ` +
 			`--no-data-resources ` +
 			`-printmapping ${outDict} ` +
 			`-printconfiguration ${outConfig} ` +
@@ -152,7 +151,8 @@
 			`${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` +
 			`rm -rf ${outUsageDir} && ` +
 			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
-			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
+			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
+			`rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
 		Depfile: "${out}.d",
 		Deps:    blueprint.DepsGCC,
 		CommandDeps: []string{
@@ -185,7 +185,7 @@
 			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 		},
 	}, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir",
-		"r8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, []string{"implicits"})
+		"r8Flags", "zipFlags", "mergeZipsFlags"}, []string{"implicits"})
 
 func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
 	dexParams *compileDexParams) (flags []string, deps android.Paths) {
@@ -368,7 +368,6 @@
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", dexParams.jarName).OutputPath
 	outDir := android.PathForModuleOut(ctx, "dex")
-	tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", dexParams.jarName)
 
 	zipFlags := "--ignore_missing_files"
 	if proptools.Bool(d.dexProperties.Uncompress_dex) {
@@ -406,7 +405,6 @@
 			"outUsage":       proguardUsage.String(),
 			"outUsageZip":    proguardUsageZip.String(),
 			"outDir":         outDir.String(),
-			"tmpJar":         tmpJar.String(),
 			"mergeZipsFlags": mergeZipsFlags,
 		}
 		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
@@ -426,6 +424,7 @@
 			Args:      args,
 		})
 	} else {
+		tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", dexParams.jarName)
 		d8Flags, d8Deps := d8Flags(dexParams.flags)
 		d8Deps = append(d8Deps, commonDeps...)
 		rule := d8
diff --git a/java/droiddoc.go b/java/droiddoc.go
index d5547d0..87588f3 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -136,6 +136,9 @@
 	// At some point, this might be improved to show more warnings.
 	Todo_file *string `android:"path"`
 
+	// A file containing a baseline for allowed lint errors.
+	Lint_baseline *string `android:"path"`
+
 	// directory under current module source that provide additional resources (images).
 	Resourcesdir *string
 
@@ -665,6 +668,10 @@
 			ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file)))
 	}
 
+	if String(d.properties.Lint_baseline) != "" {
+		cmd.FlagWithInput("-lintbaseline ", android.PathForModuleSrc(ctx, String(d.properties.Lint_baseline)))
+	}
+
 	if String(d.properties.Resourcesdir) != "" {
 		// TODO: should we add files under resourcesDir to the implicits? It seems that
 		// resourcesDir is one sub dir of htmlDir
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 1d5dd76..b059c0a 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -24,7 +24,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/java/config"
 	"android/soong/remoteexec"
 )
@@ -541,6 +540,10 @@
 	// See b/285312164 for more information.
 	cmd.FlagWithArg("--format-defaults ", "overloaded-method-order=source")
 
+	if ctx.DeviceConfig().HideFlaggedApis() {
+		cmd.FlagWithArg("--hide-annotation ", "android.annotation.FlaggedApi")
+	}
+
 	return cmd
 }
 
@@ -855,34 +858,6 @@
 	}
 }
 
-var _ android.ApiProvider = (*Droidstubs)(nil)
-
-type bazelJavaApiContributionAttributes struct {
-	Api         bazel.LabelAttribute
-	Api_surface *string
-}
-
-func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_api_contribution",
-		Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
-	}
-	apiFile := d.properties.Check_api.Current.Api_file
-	// Do not generate a target if check_api is not set
-	if apiFile == nil {
-		return
-	}
-	attrs := &bazelJavaApiContributionAttributes{
-		Api: *bazel.MakeLabelAttribute(
-			android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
-		),
-		Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
-	}
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: android.ApiContributionTargetName(ctx.ModuleName()),
-	}, attrs)
-}
-
 func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
 	api_file := d.properties.Check_api.Current.Api_file
 	api_surface := d.properties.Api_surface
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 7a04d73..e149b98 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -22,6 +22,8 @@
 	"testing"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func TestDroidstubs(t *testing.T) {
@@ -403,3 +405,35 @@
 
 	ctx.ModuleForTests("bar", "android_common")
 }
+
+func TestDroidstubsHideFlaggedApi(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.NextReleaseHideFlaggedApi = proptools.BoolPtr(true)
+			variables.Release_expose_flagged_api = proptools.BoolPtr(false)
+		}),
+		android.FixtureMergeMockFs(map[string][]byte{
+			"a/A.java":      nil,
+			"a/current.txt": nil,
+			"a/removed.txt": nil,
+		}),
+	).RunTestWithBp(t, `
+	droidstubs {
+		name: "foo",
+		srcs: ["a/A.java"],
+		api_surface: "public",
+		check_api: {
+			current: {
+				api_file: "a/current.txt",
+				removed_api_file: "a/removed.txt",
+			}
+		},
+	}
+	`)
+
+	m := result.ModuleForTests("foo", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	cmdline := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command)
+	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "--hide-annotation android.annotation.FlaggedApi")
+}
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index 578237e..930bfd2 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -35,6 +35,8 @@
 	// Called from inside GenerateAndroidBuildActions. Add the build rules to
 	// make the srcjar, and return the path to it.
 	GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path
+
+	Bp2build(ctx android.Bp2buildMutatorContext, module *GeneratedJavaLibraryModule)
 }
 
 // GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated
@@ -108,3 +110,7 @@
 	module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
 	module.Library.GenerateAndroidBuildActions(ctx)
 }
+
+func (module *GeneratedJavaLibraryModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	module.callbacks.Bp2build(ctx, module)
+}
diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go
index 7f52fd1..7fbbfee 100644
--- a/java/generated_java_library_test.go
+++ b/java/generated_java_library_test.go
@@ -41,6 +41,9 @@
 	return android.PathForOutput(ctx, "blah.srcjar")
 }
 
+func (callbacks *JavaGenLibTestCallbacks) Bp2build(ctx android.Bp2buildMutatorContext, module *GeneratedJavaLibraryModule) {
+}
+
 func testGenLib(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
 	return android.GroupFixturePreparers(
 		PrepareForIntegrationTestWithJava,
diff --git a/java/java.go b/java/java.go
index d5aeb7c..cac49a2 100644
--- a/java/java.go
+++ b/java/java.go
@@ -278,6 +278,9 @@
 	// SrcJarDeps is a list of paths to depend on when packaging the sources of this module.
 	SrcJarDeps android.Paths
 
+	// The source files of this module and all its transitive static dependencies.
+	TransitiveSrcFiles *android.DepSet[android.Path]
+
 	// ExportedPlugins is a list of paths that should be used as annotation processors for any
 	// module that depends on this module.
 	ExportedPlugins android.Paths
@@ -1667,11 +1670,6 @@
 	// This is a list of Soong modules
 	Api_contributions []string
 
-	// list of api.txt files relative to this directory that contribute to the
-	// API surface.
-	// This is a list of relative paths
-	Api_files []string `android:"path"`
-
 	// List of flags to be passed to the javac compiler to generate jar file
 	Javacflags []string
 
@@ -1819,37 +1817,22 @@
 	}
 }
 
-// API signature file names sorted from
-// the narrowest api scope to the widest api scope
-var scopeOrderedSourceFileNames = allApiScopes.Strings(
-	func(s *apiScope) string { return s.apiFilePrefix + "current.txt" })
+// Map where key is the api scope name and value is the int value
+// representing the order of the api scope, narrowest to the widest
+var scopeOrderMap = allApiScopes.MapToIndex(
+	func(s *apiScope) string { return s.name })
 
-func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo, apiFiles android.Paths) android.Paths {
-	var sortedSrcFiles android.Paths
-
-	for i, apiScope := range allApiScopes {
-		for _, srcFileInfo := range srcFilesInfo {
-			if srcFileInfo.ApiFile.Base() == scopeOrderedSourceFileNames[i] || srcFileInfo.ApiSurface == apiScope.name {
-				sortedSrcFiles = append(sortedSrcFiles, android.PathForSource(ctx, srcFileInfo.ApiFile.String()))
-			}
-		}
-		// TODO: b/300964421 - Remove when api_files property is removed
-		for _, apiFileName := range apiFiles {
-			if apiFileName.Base() == scopeOrderedSourceFileNames[i] {
-				sortedSrcFiles = append(sortedSrcFiles, apiFileName)
-			}
+func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo {
+	for _, srcFileInfo := range srcFilesInfo {
+		if srcFileInfo.ApiSurface == "" {
+			ctx.ModuleErrorf("Api surface not defined for the associated api file %s", srcFileInfo.ApiFile)
 		}
 	}
+	sort.Slice(srcFilesInfo, func(i, j int) bool {
+		return scopeOrderMap[srcFilesInfo[i].ApiSurface] < scopeOrderMap[srcFilesInfo[j].ApiSurface]
+	})
 
-	if len(srcFilesInfo)+len(apiFiles) != len(sortedSrcFiles) {
-		var srcFiles android.Paths
-		for _, srcFileInfo := range srcFilesInfo {
-			srcFiles = append(srcFiles, srcFileInfo.ApiFile)
-		}
-		ctx.ModuleErrorf("Unrecognizable source file found within %s", append(srcFiles, apiFiles...))
-	}
-
-	return sortedSrcFiles
+	return srcFilesInfo
 }
 
 func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1892,16 +1875,12 @@
 		}
 	})
 
-	// Add the api_files inputs
-	// These are api files in the module subdirectory, which are not provided by
-	// java_api_contribution but provided directly as module property.
-	var apiFiles android.Paths
-	for _, api := range al.properties.Api_files {
-		apiFiles = append(apiFiles, android.PathForModuleSrc(ctx, api))
+	srcFilesInfo = al.sortApiFilesByApiScope(ctx, srcFilesInfo)
+	var srcFiles android.Paths
+	for _, srcFileInfo := range srcFilesInfo {
+		srcFiles = append(srcFiles, android.PathForSource(ctx, srcFileInfo.ApiFile.String()))
 	}
 
-	srcFiles := al.sortApiFilesByApiScope(ctx, srcFilesInfo, apiFiles)
-
 	if srcFiles == nil && !ctx.Config().AllowMissingDependencies() {
 		ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
 	}
@@ -3067,17 +3046,6 @@
 		}
 	}
 
-	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
-	// Soong does not differentiate between a java_library and the Bazel equivalent of
-	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
-	// listed directly in the srcs of a java_library, and the classes produced
-	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
-	// that depend on a java_library with proto sources can link directly to the protobuf API,
-	// and so this should be a static dependency.
-	if protoDepLabel != nil {
-		staticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
-	}
-
 	depLabels := &javaDependencyLabels{}
 	depLabels.Deps = deps
 
@@ -3093,6 +3061,20 @@
 	}
 	depLabels.StaticDeps.Append(staticDeps)
 
+	var additionalProtoDeps bazel.LabelListAttribute
+	additionalProtoDeps.Append(depLabels.Deps)
+	additionalProtoDeps.Append(depLabels.StaticDeps)
+	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition], additionalProtoDeps)
+	// Soong does not differentiate between a java_library and the Bazel equivalent of
+	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
+	// listed directly in the srcs of a java_library, and the classes produced
+	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
+	// that depend on a java_library with proto sources can link directly to the protobuf API,
+	// and so this should be a static dependency.
+	if protoDepLabel != nil {
+		depLabels.StaticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
+	}
+
 	hasKotlin := !kotlinSrcs.IsEmpty()
 	commonAttrs.kotlinAttributes = &kotlinAttributes{
 		Kotlincflags: &m.properties.Kotlincflags,
diff --git a/java/java_test.go b/java/java_test.go
index 2ee05ec..d51604a 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1885,7 +1885,6 @@
 			name: "bar2",
 			api_surface: "system",
 			api_contributions: ["foo1", "foo2"],
-			api_files: ["api1/current.txt", "api2/current.txt"]
 		}
 		`,
 		map[string][]byte{
@@ -1903,7 +1902,7 @@
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -1975,7 +1974,6 @@
 			api_surface: "system",
 			defaults:["baz1", "baz2"],
 			api_contributions: ["foo4"],
-			api_files: ["api1/current.txt", "api2/current.txt"]
 		}
 		`,
 		map[string][]byte{
@@ -2000,7 +1998,7 @@
 		{
 			moduleName: "bar3",
 			// API text files need to be sorted from the narrower api scope to the wider api scope
-			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt", "c/system-current.txt", "d/system-current.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "c/system-current.txt", "d/system-current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -2265,27 +2263,26 @@
 	android.AssertStringDoesContain(t, "Command expected to contain full_api_surface_stub output jar", manifestCommand, "lib1.jar")
 }
 
-func TestJavaApiLibraryFilegroupInput(t *testing.T) {
-	ctx, _ := testJavaWithFS(t, `
-	    filegroup {
-			name: "default_current.txt",
-			srcs: ["current.txt"],
+func TestTransitiveSrcFiles(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "a",
+			srcs: ["a.java"],
 		}
-
-		java_api_library {
-			name: "foo",
-			api_files: [":default_current.txt"],
+		java_library {
+			name: "b",
+			srcs: ["b.java"],
 		}
-		`,
-		map[string][]byte{
-			"current.txt": nil,
-		})
-
-	m := ctx.ModuleForTests("foo", "android_common")
-	outputs := fmt.Sprint(m.AllOutputs())
-	if !strings.Contains(outputs, "foo/foo.jar") {
-		t.Errorf("Module output does not contain expected jar %s", "foo/foo.jar")
-	}
+		java_library {
+			name: "c",
+			srcs: ["c.java"],
+			libs: ["a"],
+			static_libs: ["b"],
+		}
+	`)
+	c := ctx.ModuleForTests("c", "android_common").Module()
+	transitiveSrcFiles := android.Paths(ctx.ModuleProvider(c, JavaInfoProvider).(JavaInfo).TransitiveSrcFiles.ToList())
+	android.AssertArrayString(t, "unexpected jar deps", []string{"b.java", "c.java"}, transitiveSrcFiles.Strings())
 }
 
 func TestTradefedOptions(t *testing.T) {
@@ -2423,3 +2420,30 @@
 	sourceFilesFlag := "--source-files current.txt"
 	android.AssertStringDoesContain(t, "source text files not present", manifestCommand, sourceFilesFlag)
 }
+
+func TestJavaApiLibraryApiFilesSorting(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_api_library {
+			name: "foo",
+			api_contributions: [
+				"system-server-api-stubs-docs-non-updatable.api.contribution",
+				"test-api-stubs-docs-non-updatable.api.contribution",
+				"system-api-stubs-docs-non-updatable.api.contribution",
+				"module-lib-api-stubs-docs-non-updatable.api.contribution",
+				"api-stubs-docs-non-updatable.api.contribution",
+			],
+		}
+	`)
+	m := ctx.ModuleForTests("foo", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
+	manifestCommand := sboxProto.Commands[0].GetCommand()
+
+	// Api files are sorted from the narrowest api scope to the widest api scope.
+	// test api and module lib api surface do not have subset/superset relationship,
+	// but they will never be passed as inputs at the same time.
+	sourceFilesFlag := "--source-files default/java/api/current.txt " +
+		"default/java/api/system-current.txt default/java/api/test-current.txt " +
+		"default/java/api/module-lib-current.txt default/java/api/system-server-current.txt"
+	android.AssertStringDoesContain(t, "source text files not in api scope order", manifestCommand, sourceFilesFlag)
+}
diff --git a/java/lint.go b/java/lint.go
index f84f1c0..34720e5 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -66,6 +66,10 @@
 		// This will be true by default for test module types, false otherwise.
 		// If soong gets support for testonly, this flag should be replaced with that.
 		Test *bool
+
+		// Whether to ignore the exit code of Android lint. This is the --exit_code
+		// option. Defaults to false.
+		Suppress_exit_code *bool
 	}
 }
 
@@ -504,7 +508,8 @@
 	rule.Temporary(lintPaths.projectXML)
 	rule.Temporary(lintPaths.configXML)
 
-	if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" {
+	suppressExitCode := BoolDefault(l.properties.Lint.Suppress_exit_code, false)
+	if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" && !suppressExitCode {
 		cmd.Flag("--exitcode")
 	}
 
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index ade7395..02a2298 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -57,6 +57,9 @@
 
 	// Path to the monolithic hiddenapi-unsupported.csv file.
 	hiddenAPIMetadataCSV android.OutputPath
+
+	// Path to a srcjar containing all the transitive sources of the bootclasspath.
+	srcjar android.OutputPath
 }
 
 type platformBootclasspathProperties struct {
@@ -95,6 +98,8 @@
 		return android.Paths{b.hiddenAPIIndexCSV}, nil
 	case "hiddenapi-metadata.csv":
 		return android.Paths{b.hiddenAPIMetadataCSV}, nil
+	case ".srcjar":
+		return android.Paths{b.srcjar}, nil
 	}
 
 	return nil, fmt.Errorf("unknown tag %s", tag)
@@ -173,6 +178,18 @@
 	allModules = append(allModules, apexModules...)
 	b.configuredModules = allModules
 
+	var transitiveSrcFiles android.Paths
+	for _, module := range allModules {
+		depInfo := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		if depInfo.TransitiveSrcFiles != nil {
+			transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...)
+		}
+	}
+	jarArgs := resourcePathsToJarArgs(transitiveSrcFiles)
+	jarArgs = append(jarArgs, "-srcjar") // Move srcfiles to the right package
+	b.srcjar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar").OutputPath
+	TransformResourcesToJar(ctx, b.srcjar, jarArgs, transitiveSrcFiles)
+
 	// Gather all the fragments dependencies.
 	b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
 
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index ff2da4b..37ff639 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -81,6 +81,15 @@
 			RunTest(t)
 	})
 
+	fooSourceSrc := "source/a.java"
+	barSrc := "a.java"
+
+	checkSrcJarInputs := func(t *testing.T, result *android.TestResult, name string, expected []string) {
+		t.Helper()
+		srcjar := result.ModuleForTests(name, "android_common").Output(name + "-transitive.srcjar")
+		android.AssertStringDoesContain(t, "srcjar arg", srcjar.Args["jarArgs"], "-srcjar")
+		android.AssertArrayString(t, "srcjar inputs", expected, srcjar.Implicits.Strings())
+	}
 	t.Run("source", func(t *testing.T) {
 		result := android.GroupFixturePreparers(
 			preparer,
@@ -91,6 +100,10 @@
 			"platform:foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			fooSourceSrc,
+			barSrc,
+		})
 	})
 
 	t.Run("prebuilt", func(t *testing.T) {
@@ -103,6 +116,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 
 	t.Run("source+prebuilt - source preferred", func(t *testing.T) {
@@ -116,6 +133,10 @@
 			"platform:foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			fooSourceSrc,
+			barSrc,
+		})
 	})
 
 	t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
@@ -129,6 +150,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 
 	t.Run("dex import", func(t *testing.T) {
@@ -146,6 +171,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 }
 
diff --git a/java/proto.go b/java/proto.go
index 2ed7b27..c88d3d7 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -151,11 +151,19 @@
 	// a specific .proto file module explicitly.
 	Transitive_deps bazel.LabelListAttribute
 
+	// This is the libs and the static_libs of the original java_library module.
+	// On the bazel side, after proto sources are generated in java_*_proto_library, a java_library
+	// will compile them. The libs and static_libs from the original java_library module need
+	// to be linked because they are necessary in compile-time classpath.
+	Additional_proto_deps bazel.LabelListAttribute
+
 	Sdk_version  bazel.StringAttribute
 	Java_version bazel.StringAttribute
+
+	Plugin bazel.LabelAttribute
 }
 
-func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) *bazel.Label {
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute, AdditionalProtoDeps bazel.LabelListAttribute) *bazel.Label {
 	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
 	if !ok {
 		return nil
@@ -183,11 +191,18 @@
 		ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
 	}
 
+	plugin := bazel.LabelAttribute{}
+	if m.protoProperties.Proto.Plugin != nil {
+		plugin.SetValue(android.BazelLabelForModuleDepSingle(ctx, "protoc-gen-"+*m.protoProperties.Proto.Plugin))
+	}
+
 	protoAttrs := &protoAttributes{
-		Deps:            bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
-		Transitive_deps: bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
-		Java_version:    bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:     bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		Deps:                  bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
+		Transitive_deps:       bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
+		Additional_proto_deps: AdditionalProtoDeps,
+		Java_version:          bazel.StringAttribute{Value: m.properties.Java_version},
+		Sdk_version:           bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		Plugin:                plugin,
 	}
 
 	name := m.Name() + suffix
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 27f8626..e410a41 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -286,6 +286,17 @@
 	return list
 }
 
+// Method that maps the apiScopes properties to the index of each apiScopes elements.
+// apiScopes property to be used as the key can be specified with the input accessor.
+// Only a string property of apiScope can be used as the key of the map.
+func (scopes apiScopes) MapToIndex(accessor func(*apiScope) string) map[string]int {
+	ret := make(map[string]int)
+	for i, scope := range scopes {
+		ret[accessor(scope)] = i
+	}
+	return ret
+}
+
 var (
 	scopeByName    = make(map[string]*apiScope)
 	allScopeNames  []string
diff --git a/java/testing.go b/java/testing.go
index f2bcccf..98bea7f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -424,30 +424,80 @@
 		`, extra)
 	}
 
-	extraApiLibraryModules := map[string]string{
-		"android_stubs_current.from-text":                  "api/current.txt",
-		"android_system_stubs_current.from-text":           "api/system-current.txt",
-		"android_test_stubs_current.from-text":             "api/test-current.txt",
-		"android_module_lib_stubs_current.from-text":       "api/module-lib-current.txt",
-		"android_module_lib_stubs_current_full.from-text":  "api/module-lib-current.txt",
-		"android_system_server_stubs_current.from-text":    "api/system-server-current.txt",
-		"core.current.stubs.from-text":                     "api/current.txt",
-		"legacy.core.platform.api.stubs.from-text":         "api/current.txt",
-		"stable.core.platform.api.stubs.from-text":         "api/current.txt",
-		"core-lambda-stubs.from-text":                      "api/current.txt",
-		"android-non-updatable.stubs.from-text":            "api/current.txt",
-		"android-non-updatable.stubs.system.from-text":     "api/system-current.txt",
-		"android-non-updatable.stubs.test.from-text":       "api/test-current.txt",
-		"android-non-updatable.stubs.module_lib.from-text": "api/module-lib-current.txt",
+	type apiContributionStruct struct {
+		name       string
+		apiSurface string
+		apiFile    string
 	}
 
-	for libName, apiFile := range extraApiLibraryModules {
+	var publicApiContribution = apiContributionStruct{
+		name:       "api-stubs-docs-non-updatable.api.contribution",
+		apiSurface: "public",
+		apiFile:    "api/current.txt",
+	}
+	var systemApiContribution = apiContributionStruct{
+		name:       "system-api-stubs-docs-non-updatable.api.contribution",
+		apiSurface: "system",
+		apiFile:    "api/system-current.txt",
+	}
+	var testApiContribution = apiContributionStruct{
+		name:       "test-api-stubs-docs-non-updatable.api.contribution",
+		apiSurface: "test",
+		apiFile:    "api/test-current.txt",
+	}
+	var moduleLibApiContribution = apiContributionStruct{
+		name:       "module-lib-api-stubs-docs-non-updatable.api.contribution",
+		apiSurface: "module-lib",
+		apiFile:    "api/module-lib-current.txt",
+	}
+	var systemServerApiContribution = apiContributionStruct{
+		// This module does not exist but is named this way for consistency
+		name:       "system-server-api-stubs-docs-non-updatable.api.contribution",
+		apiSurface: "system-server",
+		apiFile:    "api/system-server-current.txt",
+	}
+	var apiContributionStructs = []apiContributionStruct{
+		publicApiContribution,
+		systemApiContribution,
+		testApiContribution,
+		moduleLibApiContribution,
+		systemServerApiContribution,
+	}
+
+	extraApiLibraryModules := map[string]apiContributionStruct{
+		"android_stubs_current.from-text":                  publicApiContribution,
+		"android_system_stubs_current.from-text":           systemApiContribution,
+		"android_test_stubs_current.from-text":             testApiContribution,
+		"android_module_lib_stubs_current.from-text":       moduleLibApiContribution,
+		"android_module_lib_stubs_current_full.from-text":  moduleLibApiContribution,
+		"android_system_server_stubs_current.from-text":    systemServerApiContribution,
+		"core.current.stubs.from-text":                     publicApiContribution,
+		"legacy.core.platform.api.stubs.from-text":         publicApiContribution,
+		"stable.core.platform.api.stubs.from-text":         publicApiContribution,
+		"core-lambda-stubs.from-text":                      publicApiContribution,
+		"android-non-updatable.stubs.from-text":            publicApiContribution,
+		"android-non-updatable.stubs.system.from-text":     systemApiContribution,
+		"android-non-updatable.stubs.test.from-text":       testApiContribution,
+		"android-non-updatable.stubs.module_lib.from-text": moduleLibApiContribution,
+	}
+
+	for _, apiContribution := range apiContributionStructs {
+		bp += fmt.Sprintf(`
+			java_api_contribution {
+				name: "%s",
+				api_surface: "%s",
+				api_file: "%s",
+			}
+		`, apiContribution.name, apiContribution.apiSurface, apiContribution.apiFile)
+	}
+
+	for libName, apiContribution := range extraApiLibraryModules {
 		bp += fmt.Sprintf(`
             java_api_library {
                 name: "%s",
-                api_files: ["%s"],
+                api_contributions: ["%s"],
             }
-        `, libName, apiFile)
+        `, libName, apiContribution.name)
 	}
 
 	bp += `
diff --git a/rust/afdo_test.go b/rust/afdo_test.go
index 80327af..0cdf704 100644
--- a/rust/afdo_test.go
+++ b/rust/afdo_test.go
@@ -54,8 +54,8 @@
 
 	expectedCFlag := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo.afdo")
 
-	if !strings.Contains(foo.RuleParams.Command, expectedCFlag) {
-		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in command %q", expectedCFlag, foo.RuleParams.Command)
+	if !strings.Contains(foo.Args["rustcFlags"], expectedCFlag) {
+		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", expectedCFlag, foo.Args["rustcFlags"])
 	}
 }
 
@@ -96,17 +96,17 @@
 		rustMockedFiles.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
-	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Description("rustc")
-	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Description("rustc")
+	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Rule("rustc")
+	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
 	expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm.afdo")
 	expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm64.afdo")
 
-	if !strings.Contains(fooArm.RuleParams.Command, expectedCFlagArm) {
-		t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in command %q", expectedCFlagArm, fooArm.RuleParams.Command)
+	if !strings.Contains(fooArm.Args["rustcFlags"], expectedCFlagArm) {
+		t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm, fooArm.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(fooArm64.RuleParams.Command, expectedCFlagArm64) {
-		t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in command %q", expectedCFlagArm64, fooArm.RuleParams.Command)
+	if !strings.Contains(fooArm64.Args["rustcFlags"], expectedCFlagArm64) {
+		t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm64, fooArm64.Args["rustcFlags"])
 	}
 }
diff --git a/rust/binary.go b/rust/binary.go
index 353381d..860dc94 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -77,14 +77,11 @@
 func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = binary.baseCompiler.compilerFlags(ctx, flags)
 
-	if ctx.Os().Linux() {
-		flags.LinkFlags = append(flags.LinkFlags, "-Wl,--gc-sections")
-	}
-
 	if ctx.toolchain().Bionic() {
 		// no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined,
 		// but we can apply this to binaries.
 		flags.LinkFlags = append(flags.LinkFlags,
+			"-Wl,--gc-sections",
 			"-Wl,-z,nocopyreloc",
 			"-Wl,--no-undefined-version")
 
@@ -149,6 +146,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if binary.stripper.NeedsStrip(ctx) {
 		strippedOutputFile := outputFile
@@ -159,7 +157,7 @@
 	}
 	binary.baseCompiler.unstrippedOutputFile = outputFile
 
-	ret.kytheFile = TransformSrcToBinary(ctx, binary, crateRootPath, deps, flags, outputFile).kytheFile
+	ret.kytheFile = TransformSrcToBinary(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	return ret
 }
 
diff --git a/rust/binary_test.go b/rust/binary_test.go
index ab1d2bc..ef93037 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -135,7 +135,7 @@
 
 	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
 
-	flags := fizzBuzz.RuleParams.Command
+	flags := fizzBuzz.Args["rustcFlags"]
 	if strings.Contains(flags, "--test") {
 		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
 	}
@@ -153,8 +153,8 @@
 	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
 	flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
-	if !strings.Contains(foo.RuleParams.Command, flag) {
-		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, command: %#v", flag, foo.RuleParams.Command)
+	if !strings.Contains(foo.Args["linkFlags"], flag) {
+		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, linkFlags: %#v", flag, foo.Args["linkFlags"])
 	}
 }
 
@@ -169,15 +169,16 @@
 	fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
 	fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
 
-	flags := fizzOut.RuleParams.Command
+	flags := fizzOut.Args["rustcFlags"]
+	linkFlags := fizzOut.Args["linkFlags"]
 	if !strings.Contains(flags, "-C relocation-model=static") {
-		t.Errorf("static binary missing '-C relocation-model=static' in command, found: %#v", flags)
+		t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
 	}
 	if !strings.Contains(flags, "-C panic=abort") {
-		t.Errorf("static binary missing '-C panic=abort' in command, found: %#v", flags)
+		t.Errorf("static binary missing '-C panic=abort' in rustcFlags, found: %#v", flags)
 	}
-	if !strings.Contains(flags, "-static") {
-		t.Errorf("static binary missing '-static' in command, found: %#v", flags)
+	if !strings.Contains(linkFlags, "-static") {
+		t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags)
 	}
 
 	if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) {
@@ -200,8 +201,9 @@
 		}`)
 
 	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
-	if !strings.Contains(fizzBuzz.RuleParams.Command, "/libfoo.so") {
-		t.Errorf("missing shared dependency 'libfoo.so' in command: %#v", fizzBuzz.RuleParams.Command)
+	linkFlags := fizzBuzz.Args["linkFlags"]
+	if !strings.Contains(linkFlags, "/libfoo.so") {
+		t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
 	}
 }
 
diff --git a/rust/builder.go b/rust/builder.go
index 0740518..bea8ff7 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -15,7 +15,6 @@
 package rust
 
 import (
-	"fmt"
 	"path/filepath"
 	"strings"
 
@@ -26,6 +25,49 @@
 )
 
 var (
+	_     = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
+	rustc = pctx.AndroidStaticRule("rustc",
+		blueprint.RuleParams{
+			Command: "$envVars $rustcCmd " +
+				"-C linker=${config.RustLinker} " +
+				"-C link-args=\"${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}\" " +
+				"--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
+				" && grep \"^$out:\" $out.d.raw > $out.d",
+			CommandDeps: []string{"$rustcCmd"},
+			// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
+			// Rustc emits unneeded dependency lines for the .d and input .rs files.
+			// Those extra lines cause ninja warning:
+			//     "warning: depfile has multiple output paths"
+			// For ninja, we keep/grep only the dependency rule for the rust $out file.
+			Deps:    blueprint.DepsGCC,
+			Depfile: "$out.d",
+		},
+		"rustcFlags", "earlyLinkFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
+
+	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
+	rustdoc = pctx.AndroidStaticRule("rustdoc",
+		blueprint.RuleParams{
+			Command: "$envVars $rustdocCmd $rustdocFlags $in -o $outDir && " +
+				"touch $out",
+			CommandDeps: []string{"$rustdocCmd"},
+		},
+		"rustdocFlags", "outDir", "envVars")
+
+	_            = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
+	clippyDriver = pctx.AndroidStaticRule("clippy",
+		blueprint.RuleParams{
+			Command: "$envVars $clippyCmd " +
+				// Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
+				// Use the metadata output as it has the smallest footprint.
+				"--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " +
+				"$rustcFlags $clippyFlags" +
+				" && grep \"^$out:\" $out.d.raw > $out.d",
+			CommandDeps: []string{"$clippyCmd"},
+			Deps:        blueprint.DepsGCC,
+			Depfile:     "$out.d",
+		},
+		"rustcFlags", "libFlags", "clippyFlags", "envVars")
+
 	zip = pctx.AndroidStaticRule("zip",
 		blueprint.RuleParams{
 			Command:        "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
@@ -34,7 +76,7 @@
 			RspfileContent: "$in",
 		})
 
-	cpDir = pctx.AndroidStaticRule("cpDir",
+	cp = pctx.AndroidStaticRule("cp",
 		blueprint.RuleParams{
 			Command:        "cp `cat $outDir.rsp` $outDir",
 			Rspfile:        "${outDir}.rsp",
@@ -42,12 +84,6 @@
 		},
 		"outDir")
 
-	cp = pctx.AndroidStaticRule("cp",
-		blueprint.RuleParams{
-			Command:     "rm -f $out && cp $in $out",
-			Description: "cp $out",
-		})
-
 	// Cross-referencing:
 	_ = pctx.SourcePathVariable("rustExtractor",
 		"prebuilts/build-tools/${config.HostPrebuiltTag}/bin/rust_extractor")
@@ -55,6 +91,24 @@
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
 	_ = pctx.VariableFunc("kytheCuEncoding",
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
+	_            = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
+	kytheExtract = pctx.AndroidStaticRule("kythe",
+		blueprint.RuleParams{
+			Command: `KYTHE_CORPUS=${kytheCorpus} ` +
+				`KYTHE_OUTPUT_FILE=$out ` +
+				`KYTHE_VNAMES=$kytheVnames ` +
+				`KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
+				`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
+				`$rustExtractor $envVars ` +
+				`$rustcCmd ` +
+				`-C linker=${config.RustLinker} ` +
+				`-C link-args="${crtBegin} ${linkFlags} ${crtEnd}" ` +
+				`$in ${libFlags} $rustcFlags`,
+			CommandDeps:    []string{"$rustExtractor", "$kytheVnames"},
+			Rspfile:        "${out}.rsp",
+			RspfileContent: "$in",
+		},
+		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 )
 
 type buildOutput struct {
@@ -66,40 +120,40 @@
 	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 }
 
-func TransformSrcToBinary(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
 
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "bin")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin")
 }
 
-func TransformSrctoRlib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "rlib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib")
 }
 
-func TransformSrctoDylib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
 
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "dylib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib")
 }
 
-func TransformSrctoStatic(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "staticlib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib")
 }
 
-func TransformSrctoShared(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "cdylib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib")
 }
 
-func TransformSrctoProcMacro(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps,
+func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
 	flags Flags, outputFile android.WritablePath) buildOutput {
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "proc-macro")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro")
 }
 
 func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -110,46 +164,28 @@
 	return paths
 }
 
-func makeLibFlags(deps PathDeps, ruleCmd *android.RuleBuilderCommand) []string {
+func makeLibFlags(deps PathDeps) []string {
 	var libFlags []string
 
 	// Collect library/crate flags
-	for _, lib := range deps.Rlibs.ToListDirect() {
-		libPath := ruleCmd.PathForInput(lib.Path)
-		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath)
+	for _, lib := range deps.RLibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
 	}
-	for _, lib := range deps.Dylibs.ToListDirect() {
-		libPath := ruleCmd.PathForInput(lib.Path)
-		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath)
+	for _, lib := range deps.DyLibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
 	}
-	for _, procMacro := range deps.ProcMacros.ToListDirect() {
-		procMacroPath := ruleCmd.PathForInput(procMacro.Path)
-		libFlags = append(libFlags, "--extern "+procMacro.CrateName+"="+procMacroPath)
+	for _, proc_macro := range deps.ProcMacros {
+		libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
 	}
 
 	for _, path := range deps.linkDirs {
-		libFlags = append(libFlags, "-L "+ruleCmd.PathForInput(path))
+		libFlags = append(libFlags, "-L "+path)
 	}
 
 	return libFlags
 }
 
-func collectImplicits(deps PathDeps) android.Paths {
-	depPaths := android.Paths{}
-	depPaths = append(depPaths, rustLibsToPaths(deps.Rlibs.ToList())...)
-	depPaths = append(depPaths, rustLibsToPaths(deps.Dylibs.ToList())...)
-	depPaths = append(depPaths, rustLibsToPaths(deps.ProcMacros.ToList())...)
-	depPaths = append(depPaths, deps.AfdoProfiles...)
-	depPaths = append(depPaths, deps.WholeStaticLibs...)
-	depPaths = append(depPaths, deps.SrcDeps...)
-	depPaths = append(depPaths, deps.srcProviderFiles...)
-	depPaths = append(depPaths, deps.LibDeps...)
-	depPaths = append(depPaths, deps.linkObjects...)
-	depPaths = append(depPaths, deps.BuildToolSrcDeps...)
-	return depPaths
-}
-
-func rustEnvVars(ctx ModuleContext, deps PathDeps, cmd *android.RuleBuilderCommand) []string {
+func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
 	var envVars []string
 
 	// libstd requires a specific environment variable to be set. This is
@@ -163,17 +199,15 @@
 		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
 		// We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this)
 		// assumes that paths are relative to the source file.
-		var outDir string
-		if filepath.IsAbs(moduleGenDir.String()) {
-			// If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
-			outDir = moduleGenDir.String()
-		} else if moduleGenDir.Valid() {
+		var outDirPrefix string
+		if !filepath.IsAbs(moduleGenDir.String()) {
 			// If OUT_DIR is not absolute, we use $$PWD to generate an absolute path (os.Getwd() returns '/')
-			outDir = filepath.Join("$$PWD/", cmd.PathForInput(moduleGenDir.Path()))
+			outDirPrefix = "$$PWD/"
 		} else {
-			outDir = "$$PWD/"
+			// If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
+			outDirPrefix = ""
 		}
-		envVars = append(envVars, "OUT_DIR="+outDir)
+		envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String()))
 	} else {
 		// TODO(pcc): Change this to "OUT_DIR=" after fixing crates to not rely on this value.
 		envVars = append(envVars, "OUT_DIR=out")
@@ -204,27 +238,25 @@
 		}
 	}
 
-	envVars = append(envVars, "AR="+cmd.PathForTool(deps.Llvm_ar))
-
-	if ctx.Darwin() {
-		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
-	}
-
 	return envVars
 }
 
-func transformSrctoCrate(ctx ModuleContext, comp compiler, main android.Path, deps PathDeps, flags Flags,
+func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath, crateType string) buildOutput {
 
 	var inputs android.Paths
+	var implicits android.Paths
+	var orderOnly android.Paths
 	var output buildOutput
 	var rustcFlags, linkFlags []string
-	var earlyLinkFlags []string
+	var earlyLinkFlags string
 
 	output.outputFile = outputFile
 	crateName := ctx.RustModule().CrateName()
 	targetTriple := ctx.toolchain().RustTriple()
 
+	envVars := rustEnvVars(ctx, deps)
+
 	inputs = append(inputs, main)
 
 	// Collect rustc flags
@@ -245,6 +277,7 @@
 	// Enable incremental compilation if requested by user
 	if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") {
 		incrementalPath := android.PathForOutput(ctx, "rustc").String()
+
 		rustcFlags = append(rustcFlags, "-Cincremental="+incrementalPath)
 	}
 
@@ -256,16 +289,36 @@
 
 	// Collect linker flags
 	if !ctx.Darwin() {
-		earlyLinkFlags = append(earlyLinkFlags, "-Wl,--as-needed")
+		earlyLinkFlags = "-Wl,--as-needed"
 	}
 
+	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
+	linkFlags = append(linkFlags, flags.LinkFlags...)
+
+	// Check if this module needs to use the bootstrap linker
+	if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
+		dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
+		if ctx.toolchain().Is64Bit() {
+			dynamicLinker += "64"
+		}
+		linkFlags = append(linkFlags, dynamicLinker)
+	}
+
+	libFlags := makeLibFlags(deps)
+
 	// Collect dependencies
-	var linkImplicits android.Paths
-	implicits := collectImplicits(deps)
-	toolImplicits := android.Concat(deps.BuildToolDeps)
-	linkImplicits = append(linkImplicits, deps.CrtBegin...)
-	linkImplicits = append(linkImplicits, deps.CrtEnd...)
-	implicits = append(implicits, comp.compilationSourcesAndData(ctx)...)
+	implicits = append(implicits, rustLibsToPaths(deps.RLibs)...)
+	implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...)
+	implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
+	implicits = append(implicits, deps.StaticLibs...)
+	implicits = append(implicits, deps.SharedLibDeps...)
+	implicits = append(implicits, deps.srcProviderFiles...)
+	implicits = append(implicits, deps.AfdoProfiles...)
+
+	implicits = append(implicits, deps.CrtBegin...)
+	implicits = append(implicits, deps.CrtEnd...)
+
+	orderOnly = append(orderOnly, deps.SharedLibs...)
 
 	if len(deps.SrcDeps) > 0 {
 		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
@@ -280,7 +333,7 @@
 		}
 
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        cpDir,
+			Rule:        cp,
 			Description: "cp " + moduleGenDir.Path().Rel(),
 			Outputs:     outputs,
 			Inputs:      deps.SrcDeps,
@@ -291,177 +344,83 @@
 		implicits = append(implicits, outputs.Paths()...)
 	}
 
-	if flags.Clippy {
-		// TODO(b/298461712) remove this hack to let slim manifest branches build
-		if deps.Clippy_driver == nil {
-			deps.Clippy_driver = config.RustPath(ctx, "bin/clippy-driver")
+	envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
+
+	if ctx.RustModule().compiler.CargoEnvCompat() {
+		if _, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
+			envVars = append(envVars, "CARGO_BIN_NAME="+strings.TrimSuffix(outputFile.Base(), outputFile.Ext()))
 		}
+		envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
+		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
+		if pkgVersion != "" {
+			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+		}
+	}
 
-		clippyRule := getRuleBuilder(ctx, pctx, false, "clippy")
-		clippyCmd := clippyRule.Command()
+	if flags.Clippy {
 		clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
-		clippyDepInfoFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d.raw")
-		clippyDepFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d")
-
-		clippyCmd.
-			Flags(rustEnvVars(ctx, deps, clippyCmd)).
-			Tool(deps.Clippy_driver).
-			Flag("--emit metadata").
-			FlagWithOutput("-o ", clippyFile).
-			FlagWithOutput("--emit dep-info=", clippyDepInfoFile).
-			Inputs(inputs).
-			Flags(makeLibFlags(deps, clippyCmd)).
-			Flags(rustcFlags).
-			Flags(flags.ClippyFlags).
-			ImplicitTools(toolImplicits).
-			Implicits(implicits)
-
-		depfileCreationCmd := clippyRule.Command()
-		depfileCreationCmd.
-			Flag(fmt.Sprintf(
-				`grep "^%s:" %s >`,
-				depfileCreationCmd.PathForOutput(clippyFile),
-				depfileCreationCmd.PathForOutput(clippyDepInfoFile),
-			)).
-			DepFile(clippyDepFile)
-
-		clippyRule.BuildWithUnescapedNinjaVars("clippy", "clippy "+main.Rel())
-
+		ctx.Build(pctx, android.BuildParams{
+			Rule:            clippyDriver,
+			Description:     "clippy " + main.Rel(),
+			Output:          clippyFile,
+			ImplicitOutputs: nil,
+			Inputs:          inputs,
+			Implicits:       implicits,
+			OrderOnly:       orderOnly,
+			Args: map[string]string{
+				"rustcFlags":  strings.Join(rustcFlags, " "),
+				"libFlags":    strings.Join(libFlags, " "),
+				"clippyFlags": strings.Join(flags.ClippyFlags, " "),
+				"envVars":     strings.Join(envVars, " "),
+			},
+		})
 		// Declare the clippy build as an implicit dependency of the original crate.
 		implicits = append(implicits, clippyFile)
 	}
 
-	sboxDirectory := "rustc"
-	rustSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base())
-	depFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d")
-	depInfoFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d.raw")
-	var rustcImplicitOutputs android.WritablePaths
-
-	sandboxedCompilation := comp.crateRoot(ctx) != nil
-	rustcRule := getRuleBuilder(ctx, pctx, sandboxedCompilation, sboxDirectory)
-	rustcCmd := rustcRule.Command()
-
-	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
-	linkFlags = append(linkFlags, flags.LinkFlags...)
-	linkFlags = append(linkFlags, rustcCmd.PathsForInputs(deps.linkObjects)...)
-
-	// Check if this module needs to use the bootstrap linker
-	if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
-		dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
-		if ctx.toolchain().Is64Bit() {
-			dynamicLinker += "64"
-		}
-		linkFlags = append(linkFlags, dynamicLinker)
-	}
-
-	libFlags := makeLibFlags(deps, rustcCmd)
-
-	usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro"
-	if usesLinker {
-		rustSboxOutputFile = android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".rsp")
-		rustcImplicitOutputs = android.WritablePaths{
-			android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".whole.a"),
-			android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".a"),
-		}
-	}
-
-	// TODO(b/298461712) remove this hack to let slim manifest branches build
-	if deps.Rustc == nil {
-		deps.Rustc = config.RustPath(ctx, "bin/rustc")
-	}
-
-	rustcCmd.
-		Flags(rustEnvVars(ctx, deps, rustcCmd)).
-		Tool(deps.Rustc).
-		FlagWithInput("-C linker=", android.PathForSource(ctx, "build", "soong", "scripts", "mkcratersp.py")).
-		Flag("--emit link").
-		Flag("-o").
-		Output(rustSboxOutputFile).
-		FlagWithOutput("--emit dep-info=", depInfoFile).
-		Inputs(inputs).
-		Flags(libFlags).
-		ImplicitTools(toolImplicits).
-		Implicits(implicits).
-		Flags(rustcFlags).
-		ImplicitOutputs(rustcImplicitOutputs)
-
-	depfileCreationCmd := rustcRule.Command()
-	depfileCreationCmd.
-		Flag(fmt.Sprintf(
-			`grep "^%s:" %s >`,
-			depfileCreationCmd.PathForOutput(rustSboxOutputFile),
-			depfileCreationCmd.PathForOutput(depInfoFile),
-		)).
-		DepFile(depFile)
-
-	if !usesLinker {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   cp,
-			Input:  rustSboxOutputFile,
-			Output: outputFile,
-		})
-	} else {
-		// TODO: delmerico - separate rustLink into its own rule
-		// mkcratersp.py hardcodes paths to files within the sandbox, so
-		// those need to be renamed/symlinked to something in the rustLink sandbox
-		// if we want to separate the rules
-		linkerSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base())
-		rustLinkCmd := rustcRule.Command()
-		rustLinkCmd.
-			Tool(deps.Clang).
-			Flag("-o").
-			Output(linkerSboxOutputFile).
-			Inputs(deps.CrtBegin).
-			Flags(earlyLinkFlags).
-			FlagWithInput("@", rustSboxOutputFile).
-			Flags(linkFlags).
-			Inputs(deps.CrtEnd).
-			ImplicitTools(toolImplicits).
-			Implicits(rustcImplicitOutputs.Paths()).
-			Implicits(implicits).
-			Implicits(linkImplicits)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   cp,
-			Input:  linkerSboxOutputFile,
-			Output: outputFile,
-		})
-	}
-
-	rustcRule.BuildWithUnescapedNinjaVars("rustc", "rustc "+main.Rel())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        rustc,
+		Description: "rustc " + main.Rel(),
+		Output:      outputFile,
+		Inputs:      inputs,
+		Implicits:   implicits,
+		OrderOnly:   orderOnly,
+		Args: map[string]string{
+			"rustcFlags":     strings.Join(rustcFlags, " "),
+			"earlyLinkFlags": earlyLinkFlags,
+			"linkFlags":      strings.Join(linkFlags, " "),
+			"libFlags":       strings.Join(libFlags, " "),
+			"crtBegin":       strings.Join(deps.CrtBegin.Strings(), " "),
+			"crtEnd":         strings.Join(deps.CrtEnd.Strings(), " "),
+			"envVars":        strings.Join(envVars, " "),
+		},
+	})
 
 	if flags.EmitXrefs {
-		kytheRule := getRuleBuilder(ctx, pctx, false, "kythe")
-		kytheCmd := kytheRule.Command()
 		kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
-		kytheCmd.
-			Flag("KYTHE_CORPUS=${kytheCorpus}").
-			FlagWithOutput("KYTHE_OUTPUT_FILE=", kytheFile).
-			FlagWithInput("KYTHE_VNAMES=", android.PathForSource(ctx, "build", "soong", "vnames.json")).
-			Flag("KYTHE_KZIP_ENCODING=${kytheCuEncoding}").
-			Flag("KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative").
-			Tool(ctx.Config().PrebuiltBuildTool(ctx, "rust_extractor")).
-			Flags(rustEnvVars(ctx, deps, kytheCmd)).
-			Tool(deps.Rustc).
-			Flag("-C linker=true").
-			Inputs(inputs).
-			Flags(makeLibFlags(deps, kytheCmd)).
-			Flags(rustcFlags).
-			ImplicitTools(toolImplicits).
-			Implicits(implicits)
-		kytheRule.BuildWithUnescapedNinjaVars("kythe", "Xref Rust extractor "+main.Rel())
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        kytheExtract,
+			Description: "Xref Rust extractor " + main.Rel(),
+			Output:      kytheFile,
+			Inputs:      inputs,
+			Implicits:   implicits,
+			OrderOnly:   orderOnly,
+			Args: map[string]string{
+				"rustcFlags": strings.Join(rustcFlags, " "),
+				"linkFlags":  strings.Join(linkFlags, " "),
+				"libFlags":   strings.Join(libFlags, " "),
+				"crtBegin":   strings.Join(deps.CrtBegin.Strings(), " "),
+				"crtEnd":     strings.Join(deps.CrtEnd.Strings(), " "),
+				"envVars":    strings.Join(envVars, " "),
+			},
+		})
 		output.kytheFile = kytheFile
 	}
 	return output
 }
 
-func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags) android.ModuleOutPath {
-	// TODO(b/298461712) remove this hack to let slim manifest branches build
-	if deps.Rustdoc == nil {
-		deps.Rustdoc = config.RustPath(ctx, "bin/rustdoc")
-	}
-
-	rustdocRule := getRuleBuilder(ctx, pctx, false, "rustdoc")
-	rustdocCmd := rustdocRule.Command()
+func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps,
+	flags Flags) android.ModuleOutPath {
 
 	rustdocFlags := append([]string{}, flags.RustdocFlags...)
 	rustdocFlags = append(rustdocFlags, "--sysroot=/dev/null")
@@ -480,7 +439,7 @@
 	crateName := ctx.RustModule().CrateName()
 	rustdocFlags = append(rustdocFlags, "--crate-name "+crateName)
 
-	rustdocFlags = append(rustdocFlags, makeLibFlags(deps, rustdocCmd)...)
+	rustdocFlags = append(rustdocFlags, makeLibFlags(deps)...)
 	docTimestampFile := android.PathForModuleOut(ctx, "rustdoc.timestamp")
 
 	// Silence warnings about renamed lints for third-party crates
@@ -496,26 +455,18 @@
 	// https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/write_shared.rs#L144-L146
 	docDir := android.PathForOutput(ctx, "rustdoc")
 
-	rustdocCmd.
-		Flags(rustEnvVars(ctx, deps, rustdocCmd)).
-		Tool(deps.Rustdoc).
-		Flags(rustdocFlags).
-		Input(main).
-		Flag("-o "+docDir.String()).
-		FlagWithOutput("&& touch ", docTimestampFile).
-		Implicit(ctx.RustModule().UnstrippedOutputFile())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        rustdoc,
+		Description: "rustdoc " + main.Rel(),
+		Output:      docTimestampFile,
+		Input:       main,
+		Implicit:    ctx.RustModule().UnstrippedOutputFile(),
+		Args: map[string]string{
+			"rustdocFlags": strings.Join(rustdocFlags, " "),
+			"outDir":       docDir.String(),
+			"envVars":      strings.Join(rustEnvVars(ctx, deps), " "),
+		},
+	})
 
-	rustdocRule.BuildWithUnescapedNinjaVars("rustdoc", "rustdoc "+main.Rel())
 	return docTimestampFile
 }
-
-func getRuleBuilder(ctx android.ModuleContext, pctx android.PackageContext, sbox bool, sboxDirectory string) *android.RuleBuilder {
-	r := android.NewRuleBuilder(pctx, ctx)
-	if sbox {
-		r = r.Sbox(
-			android.PathForModuleOut(ctx, sboxDirectory),
-			android.PathForModuleOut(ctx, sboxDirectory+".sbox.textproto"),
-		).SandboxInputs()
-	}
-	return r
-}
diff --git a/rust/builder_test.go b/rust/builder_test.go
index 5c11cb7..639f6d4 100644
--- a/rust/builder_test.go
+++ b/rust/builder_test.go
@@ -14,7 +14,11 @@
 
 package rust
 
-import "testing"
+import (
+	"android/soong/android"
+	"sort"
+	"testing"
+)
 
 func TestSourceProviderCollision(t *testing.T) {
 	testRustError(t, "multiple source providers generate the same filename output: bindings.rs", `
@@ -40,3 +44,113 @@
 		}
 	`)
 }
+
+func TestCompilationOutputFiles(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library {
+			name: "libfizz_buzz",
+			crate_name:"fizz_buzz",
+			srcs: ["lib.rs"],
+		}
+		rust_binary {
+			name: "fizz_buzz",
+			crate_name:"fizz_buzz",
+			srcs: ["lib.rs"],
+		}
+		rust_ffi {
+			name: "librust_ffi",
+			crate_name: "rust_ffi",
+			srcs: ["lib.rs"],
+		}
+	`)
+	testcases := []struct {
+		testName      string
+		moduleName    string
+		variant       string
+		expectedFiles []string
+	}{
+		{
+			testName:   "dylib",
+			moduleName: "libfizz_buzz",
+			variant:    "android_arm64_armv8-a_dylib",
+			expectedFiles: []string{
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/unstripped/libfizz_buzz.dylib.so",
+				"out/soong/target/product/test_device/system/lib64/libfizz_buzz.dylib.so",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/meta_lic",
+			},
+		},
+		{
+			testName:   "rlib dylib-std",
+			moduleName: "libfizz_buzz",
+			variant:    "android_arm64_armv8-a_rlib_dylib-std",
+			expectedFiles: []string{
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/libfizz_buzz.rlib",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/libfizz_buzz.rlib.clippy",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/meta_lic",
+			},
+		},
+		{
+			testName:   "rlib rlib-std",
+			moduleName: "libfizz_buzz",
+			variant:    "android_arm64_armv8-a_rlib_rlib-std",
+			expectedFiles: []string{
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib.clippy",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/meta_lic",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/rustdoc.timestamp",
+			},
+		},
+		{
+			testName:   "rust_binary",
+			moduleName: "fizz_buzz",
+			variant:    "android_arm64_armv8-a",
+			expectedFiles: []string{
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz",
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy",
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/unstripped/fizz_buzz",
+				"out/soong/target/product/test_device/system/bin/fizz_buzz",
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/meta_lic",
+			},
+		},
+		{
+			testName:   "rust_ffi static",
+			moduleName: "librust_ffi",
+			variant:    "android_arm64_armv8-a_static",
+			expectedFiles: []string{
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a.clippy",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/meta_lic",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/rustdoc.timestamp",
+			},
+		},
+		{
+			testName:   "rust_ffi shared",
+			moduleName: "librust_ffi",
+			variant:    "android_arm64_armv8-a_shared",
+			expectedFiles: []string{
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.clippy",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so.toc",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/meta_lic",
+				"out/soong/target/product/test_device/system/lib64/librust_ffi.so",
+			},
+		},
+	}
+	for _, tc := range testcases {
+		t.Run(tc.testName, func(t *testing.T) {
+			modOutputs := ctx.ModuleForTests(tc.moduleName, tc.variant).AllOutputs()
+			sort.Strings(tc.expectedFiles)
+			sort.Strings(modOutputs)
+			android.AssertStringPathsRelativeToTopEquals(
+				t,
+				"incorrect outputs from rust module",
+				ctx.Config(),
+				tc.expectedFiles,
+				modOutputs,
+			)
+		})
+	}
+}
diff --git a/rust/clippy_test.go b/rust/clippy_test.go
index 2703a1c..bd3bfb1 100644
--- a/rust/clippy_test.go
+++ b/rust/clippy_test.go
@@ -63,14 +63,14 @@
 			).RunTest(t)
 
 			r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
-			android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags)
+			android.AssertStringEquals(t, "libfoo flags", tc.fooFlags, r.Args["clippyFlags"])
 
 			r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
-			android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.ClippyDefaultLints}")
+			android.AssertStringEquals(t, "libbar flags", "${config.ClippyDefaultLints}", r.Args["clippyFlags"])
 
 			r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
 			if r.Rule != nil {
-				t.Errorf("libfoobar is setup to use clippy when explicitly disabled: command=%q", r.RuleParams.Command)
+				t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"])
 			}
 		})
 	}
diff --git a/rust/compiler.go b/rust/compiler.go
index 3fa3ccd..b3f574d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -82,9 +82,6 @@
 	//          not directly used as source files.
 	Crate_root *string `android:"path,arch_variant"`
 
-	// Additional data files that are used during compilation only. These are not accessible at runtime.
-	Compile_data []string `android:"path,arch_variant"`
-
 	// name of the lint set that should be used to validate this module.
 	//
 	// Possible values are "default" (for using a sensible set of lints
@@ -330,10 +327,15 @@
 		flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
 	}
 
-	if !ctx.toolchain().Bionic() && ctx.Os() != android.LinuxMusl && !ctx.Windows() {
-		// Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device
-		// builds. This is irrelevant for the Windows target as these are Posix specific.
+	if ctx.Os() == android.Linux {
+		// Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match
+		// the default behavior of device builds.
+		flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...)
+	} else if ctx.Os() == android.Darwin {
+		// Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default
+		// behavior of device builds.
 		flags.LinkFlags = append(flags.LinkFlags,
+			"-lc",
 			"-ldl",
 			"-lpthread",
 			"-lm",
@@ -346,23 +348,6 @@
 	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
 }
 
-func (compile *baseCompiler) crateRoot(ctx ModuleContext) android.Path {
-	if compile.Properties.Crate_root != nil {
-		return android.PathForModuleSrc(ctx, *compile.Properties.Crate_root)
-	}
-	return nil
-}
-
-// compilationSourcesAndData returns a list of files necessary to complete the compilation.
-// This includes the rust source files as well as any other data files that
-// are referenced during the build.
-func (compile *baseCompiler) compilationSourcesAndData(ctx ModuleContext) android.Paths {
-	return android.PathsForModuleSrc(ctx, android.Concat(
-		compile.Properties.Srcs,
-		compile.Properties.Compile_data,
-	))
-}
-
 func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags,
 	deps PathDeps) android.OptionalPath {
 
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index e5cc888..ec6829a 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -36,9 +36,9 @@
 
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"fizz\"'") ||
-		!strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"buzz\"'") {
-		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, command: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") ||
+		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") {
+		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -57,9 +57,9 @@
 
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'std'") ||
-		!strings.Contains(libfooDylib.RuleParams.Command, "cfg 'cfg1=\"one\"'") {
-		t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") ||
+		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") {
+		t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -146,14 +146,14 @@
 
 	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
 
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_BIN_NAME=fizz") {
-		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") {
+		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_CRATE_NAME=foo") {
-		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") {
+		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_PKG_VERSION=1.0.0") {
-		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") {
+		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
 }
 
@@ -230,13 +230,13 @@
 			).RunTest(t)
 
 			r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags)
+			android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags)
 
 			r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.RustDefaultLints}")
+			android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}")
 
 			r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libfoobar flags", r.RuleParams.Command, "${config.RustAllowAllLints}")
+			android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}")
 		})
 	}
 }
diff --git a/rust/config/global.go b/rust/config/global.go
index 0ddc116..c37ac4e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -52,11 +52,22 @@
 		"-C force-unwind-tables=yes",
 		// Use v0 mangling to distinguish from C++ symbols
 		"-C symbol-mangling-version=v0",
-		"--color always",
+		// This flag requires to have no space so that when it's exported to bazel
+		// it can be removed. See aosp/2768339
+		"--color=always",
 		"-Zdylib-lto",
 		"-Z link-native-libraries=no",
 	}
 
+	LinuxHostGlobalLinkFlags = []string{
+		"-lc",
+		"-lrt",
+		"-ldl",
+		"-lpthread",
+		"-lm",
+		"-lgcc_s",
+	}
+
 	deviceGlobalRustFlags = []string{
 		"-C panic=abort",
 		// Generate additional debug info for AutoFDO
@@ -101,6 +112,8 @@
 	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
 
 	exportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
+	exportedVars.ExportStringListStaticVariable("GLOBAL_RUSTC_FLAGS", GlobalRustFlags)
+	exportedVars.ExportStringListStaticVariable("LINUX_HOST_GLOBAL_LINK_FLAGS", LinuxHostGlobalLinkFlags)
 }
 
 func HostPrebuiltTag(config android.Config) string {
@@ -126,27 +139,3 @@
 func BazelRustToolchainVars(config android.Config) string {
 	return android.BazelToolchainVars(config, exportedVars)
 }
-
-func RustPath(ctx android.PathContext, file string) android.SourcePath {
-	type rustToolKey string
-	key := android.NewCustomOnceKey(rustToolKey(file))
-	return ctx.Config().OnceSourcePath(key, func() android.SourcePath {
-		return rustPath(ctx).Join(ctx, file)
-	})
-}
-
-var rustPathKey = android.NewOnceKey("clangPath")
-
-func rustPath(ctx android.PathContext) android.SourcePath {
-	return ctx.Config().OnceSourcePath(rustPathKey, func() android.SourcePath {
-		rustBase := RustDefaultBase
-		if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
-			rustBase = override
-		}
-		rustVersion := RustDefaultVersion
-		if override := ctx.Config().Getenv("RUST_DEFAULT_VERSION"); override != "" {
-			rustVersion = override
-		}
-		return android.PathForSource(ctx, rustBase, ctx.Config().PrebuiltOS(), rustVersion)
-	})
-}
diff --git a/rust/coverage.go b/rust/coverage.go
index b312194..bc6504d 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -17,7 +17,6 @@
 import (
 	"github.com/google/blueprint"
 
-	"android/soong/android"
 	"android/soong/cc"
 )
 
@@ -66,15 +65,12 @@
 			"-C instrument-coverage", "-g")
 		flags.LinkFlags = append(flags.LinkFlags,
 			profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
-		deps.LibDeps = append(deps.LibDeps, coverage.OutputFile().Path())
+		deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
 
 		// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
 		if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
 			profiler_builtins := ctx.GetDirectDepWithTag(ProfilerBuiltins, rlibDepTag).(*Module)
-			deps.Rlibs = android.AddDirectToDepSet[RustLibrary](deps.Rlibs, RustLibrary{
-				Path:      profiler_builtins.OutputFile().Path(),
-				CrateName: profiler_builtins.CrateName(),
-			})
+			deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile().Path(), CrateName: profiler_builtins.CrateName()})
 		}
 
 		if cc.EnableContinuousCoverage(ctx) {
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 1466e0c..0f599d7 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -55,27 +55,23 @@
 	libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
 	fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
 	buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
-	libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc")
-	libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
-	fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
-	buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
 
 	rustcCoverageFlags := []string{"-C instrument-coverage", " -g "}
 	for _, flag := range rustcCoverageFlags {
 		missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
 
-		if !strings.Contains(fizzCov.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.RuleParams.Command)
+		if !strings.Contains(fizzCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["rustcFlags"])
 		}
-		if !strings.Contains(libfooCov.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.RuleParams.Command)
+		if !strings.Contains(libfooCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["rustcFlags"])
 		}
-		if strings.Contains(buzzNoCov.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.RuleParams.Command)
+		if strings.Contains(buzzNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["rustcFlags"])
 		}
-		if strings.Contains(libbarNoCov.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.RuleParams.Command)
+		if strings.Contains(libbarNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["rustcFlags"])
 		}
 	}
 
@@ -84,17 +80,17 @@
 		missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
 
-		if !strings.Contains(fizzCovLink.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.RuleParams.Command)
+		if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
 		}
-		if !strings.Contains(libfooCovLink.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.RuleParams.Command)
+		if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
 		}
-		if strings.Contains(buzzNoCovLink.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.RuleParams.Command)
+		if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
 		}
-		if strings.Contains(libbarNoCovLink.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.RuleParams.Command)
+		if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
 		}
 	}
 
@@ -108,7 +104,7 @@
 		}`)
 
 	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
-	if !strings.Contains(fizz.RuleParams.Command, "libprofile-clang-extras.a") {
-		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") {
+		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
 	}
 }
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index ea35905..ee28c6d 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -51,23 +51,23 @@
 
 	// Check that compiler flags are set appropriately .
 	fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
-	if !strings.Contains(fuzz_libtest.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(fuzz_libtest.RuleParams.Command, "--cfg fuzzing") {
+	if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
 		t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 
 	// Check that host modules support fuzzing.
 	host_fuzzer := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
-	if !strings.Contains(host_fuzzer.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(host_fuzzer.RuleParams.Command, "--cfg fuzzing") {
+	if !strings.Contains(host_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(host_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
 		t.Errorf("rust_fuzz_host module does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 
 	// Check that dependencies have 'fuzzer' variants produced for them as well.
-	libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Rule("rustc")
-	if !strings.Contains(libtest_fuzzer.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(libtest_fuzzer.RuleParams.Command, "--cfg fuzzing") {
-		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing). command: %q", libtest_fuzzer.RuleParams.Command)
+	libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
+	if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
+		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 }
 
diff --git a/rust/image_test.go b/rust/image_test.go
index 813c5bc..fb4d9c1 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -59,36 +59,36 @@
 
 	vendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_static").Rule("rustc")
 
-	if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
-	if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
-	if strings.Contains(vendor.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
 
 	product := ctx.ModuleForTests("libfoo", "android_product.29_arm64_armv8-a_static").Rule("rustc")
-	if !strings.Contains(product.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
-	if strings.Contains(product.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
-	if !strings.Contains(product.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
 
 	system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Rule("rustc")
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
 	}
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
 	}
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
 
 }
diff --git a/rust/library.go b/rust/library.go
index 7bb82bc..c598473 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -485,23 +485,6 @@
 	return flags
 }
 
-func (library *libraryDecorator) compilationSourcesAndData(ctx ModuleContext) android.Paths {
-	var extraSrcs android.Paths
-	if library.rlib() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Rlib.Srcs)
-	} else if library.dylib() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Dylib.Srcs)
-	} else if library.static() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
-	} else if library.shared() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
-	}
-	return android.Concat(
-		library.baseCompiler.compilationSourcesAndData(ctx),
-		extraSrcs,
-	)
-}
-
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	var outputFile android.ModuleOutPath
 	var ret buildOutput
@@ -542,6 +525,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if library.dylib() {
 		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -552,19 +536,18 @@
 
 	// Call the appropriate builder for this library type
 	if library.rlib() {
-		ret.kytheFile = TransformSrctoRlib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.dylib() {
-		ret.kytheFile = TransformSrctoDylib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.static() {
-		ret.kytheFile = TransformSrctoStatic(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.shared() {
-		ret.kytheFile = TransformSrctoShared(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	}
 
 	if library.rlib() || library.dylib() {
 		library.flagExporter.exportLinkDirs(deps.linkDirs...)
 		library.flagExporter.exportLinkObjects(deps.linkObjects...)
-		library.flagExporter.exportLibDeps(deps.LibDeps...)
 	}
 
 	if library.static() || library.shared() {
diff --git a/rust/library_test.go b/rust/library_test.go
index dab9381..e03074d 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -48,23 +48,23 @@
 	staticCrateType := "staticlib"
 
 	// Test crate type for rlib is correct.
-	if !strings.Contains(libfooRlib.RuleParams.Command, "crate-type="+rlibCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.RuleParams.Command)
+	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"])
 	}
 
 	// Test crate type for dylib is correct.
-	if !strings.Contains(libfooDylib.RuleParams.Command, "crate-type="+dylibCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"])
 	}
 
 	// Test crate type for C static libraries is correct.
-	if !strings.Contains(libfooStatic.RuleParams.Command, "crate-type="+staticCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.RuleParams.Command)
+	if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
 	}
 
 	// Test crate type for C shared libraries is correct.
-	if !strings.Contains(libfooShared.RuleParams.Command, "crate-type="+sharedCrateType) {
-		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.RuleParams.Command)
+	if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
+		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
 	}
 
 }
@@ -78,10 +78,10 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "prefer-dynamic") {
-		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
+		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -94,10 +94,10 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "--cfg 'android_dylib'") {
-		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
+		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -149,9 +149,9 @@
 	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
 
 	libfooOutput := libfoo.Rule("rustc")
-	if !strings.Contains(libfooOutput.RuleParams.Command, "-Wl,-soname=libfoo.so") {
+	if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
 		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
-			libfooOutput.RuleParams.Command)
+			libfooOutput.Args["linkFlags"])
 	}
 
 	if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
@@ -237,21 +237,19 @@
 	// The build system assumes the  cc deps will be at the final linkage (either a shared library or binary)
 	// Hence, these flags are no-op
 	// TODO: We could consider removing these flags
-	expectedSharedFlag := "-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared"
-	expectedStaticFlag := "-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static"
 	for _, module := range modules {
-		if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedSharedFlag) {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared/") {
 			t.Errorf(
-				"expected to find shared library linkdir flag %q, rustcFlags: %#v",
-				expectedSharedFlag,
-				rustRlibRlibStd.Rule("rustc").RuleParams.Command,
+				"missing -L flag for shared_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
 			)
 		}
-		if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedStaticFlag) {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static/") {
 			t.Errorf(
-				"expected to find static library linkdir flag %q, rustcFlags: %#v",
-				expectedStaticFlag,
-				rustRlibRlibStd.Rule("rustc").RuleParams.Command,
+				"missing -L flag for static_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
 			)
 		}
 	}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index d012680..fe9d0b5 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -146,10 +146,7 @@
 }
 
 func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
-	deps.linkDirs = append(deps.linkDirs, android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...)
-	prebuilt.flagExporter.exportLinkDirs(deps.linkDirs...)
-	prebuilt.flagExporter.exportLinkObjects(deps.linkObjects...)
-	prebuilt.flagExporter.exportLibDeps(deps.LibDeps...)
+	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
@@ -206,7 +203,7 @@
 }
 
 func (prebuilt *prebuiltProcMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
-	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...)
+	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 3f0d17a..b93b24f 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -80,7 +80,7 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 
 	srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
-	ret := TransformSrctoProcMacro(ctx, procMacro, srcPath, deps, flags, outputFile)
+	ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
 	procMacro.baseCompiler.unstrippedOutputFile = outputFile
 	return ret
 }
diff --git a/rust/proc_macro_test.go b/rust/proc_macro_test.go
index a547926..cc81938 100644
--- a/rust/proc_macro_test.go
+++ b/rust/proc_macro_test.go
@@ -30,7 +30,7 @@
 
 	libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc")
 
-	if !strings.Contains(libprocmacro.RuleParams.Command, "--extern proc_macro") {
-		t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.RuleParams.Command)
+	if !strings.Contains(libprocmacro.Args["rustcFlags"], "--extern proc_macro") {
+		t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.Args["rustcFlags"])
 	}
 }
diff --git a/rust/protobuf.go b/rust/protobuf.go
index c8d2bda..2982efd 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -20,6 +20,7 @@
 
 	"android/soong/android"
 	"android/soong/bazel"
+	"android/soong/cc"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -59,14 +60,18 @@
 	// Use protobuf version 3.x. This will be deleted once we migrate all current users
 	// of protobuf off of 2.x.
 	Use_protobuf3 *bool
+
+	// List of exported include paths containing proto files for dependent rust_protobuf modules.
+	Exported_include_dirs []string
 }
 
 type protobufDecorator struct {
 	*BaseSourceProvider
 
-	Properties ProtobufProperties
-	protoNames []string
-	grpcNames  []string
+	Properties       ProtobufProperties
+	protoNames       []string
+	additionalCrates []string
+	grpcNames        []string
 
 	grpcProtoFlags android.ProtoFlags
 	protoFlags     android.ProtoFlags
@@ -184,6 +189,10 @@
 	// stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
 	proto.BaseSourceProvider.OutputFiles = append(android.Paths{stemFile}, outputs.Paths()...)
 
+	ctx.SetProvider(cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
+		IncludeDirs: android.PathsForModuleSrc(ctx, proto.Properties.Exported_include_dirs),
+	})
+
 	// mod_stem.rs is the entry-point for our library modules, so this is what we return.
 	return stemFile
 }
@@ -192,10 +201,16 @@
 	lines := []string{
 		"// @Soong generated Source",
 	}
+
 	for _, protoName := range proto.protoNames {
 		lines = append(lines, fmt.Sprintf("pub mod %s;", protoName))
 	}
 
+	for _, crate := range proto.additionalCrates {
+		lines = append(lines, fmt.Sprintf("pub use %s::*;", crate))
+
+	}
+
 	for _, grpcName := range proto.grpcNames {
 		lines = append(lines, fmt.Sprintf("pub mod %s;", grpcName))
 		lines = append(lines, fmt.Sprintf("pub mod %s%s;", grpcName, grpcSuffix))
@@ -305,7 +320,11 @@
 		},
 	}
 
-	ctx.CreateBazelTargetModule(
+	// TODO(b/295918553): Remove androidRestriction after rust toolchain for android is checked in.
+	var androidRestriction bazel.BoolAttribute
+	androidRestriction.SetSelectValue(bazel.OsConfigurationAxis, "android", proptools.BoolPtr(false))
+
+	ctx.CreateBazelTargetModuleWithRestrictions(
 		bazel.BazelTargetModuleProperties{
 			Rule_class: "proto_library",
 		},
@@ -317,9 +336,10 @@
 				android.BazelLabelForModuleSrc(ctx, protoFiles),
 			),
 		},
+		androidRestriction,
 	)
 
-	ctx.CreateBazelTargetModule(
+	ctx.CreateBazelTargetModuleWithRestrictions(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        "rust_proto_library",
 			Bzl_load_location: "@rules_rust//proto/protobuf:defs.bzl",
@@ -333,5 +353,6 @@
 			},
 			Deps: protoDeps,
 		},
+		androidRestriction,
 	)
 }
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index b723f3f..9dca029 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -118,6 +118,58 @@
 	}
 }
 
+func TestRustProtobufInclude(t *testing.T) {
+	ctx := testRust(t, `
+		rust_protobuf {
+			name: "librust_proto",
+			protos: ["proto.proto"],
+			crate_name: "rust_proto",
+			source_stem: "proto",
+			use_protobuf3: true,
+			rustlibs: ["librust_exported_proto", "libfoo"],
+		}
+		rust_protobuf {
+			name: "librust_exported_proto",
+			protos: ["proto.proto"],
+			crate_name: "rust_exported_proto",
+			source_stem: "exported_proto",
+			use_protobuf3: true,
+			exported_include_dirs: ["proto"]
+		}
+		rust_library {
+			name: "libfoo",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+		}
+	`)
+	// Check that librust_exported_proto is added as additional crate to generate source.
+	librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Module().(*Module).sourceProvider.(*protobufDecorator)
+	if !android.InList("rust_exported_proto", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should have librust_exported_proto included as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+
+	// Make sure the default crates aren't being included.
+	if android.InList("std", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should not have included libstd as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+	if android.InList("protobuf", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should not have included libprotobuf as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+
+	// And make sure that non-protobuf crates aren't getting included either.
+	if android.InList("foo", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should not have included libfoo as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+
+	// Check librust_proto args includes -Iproto
+	librust_proto_rule := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("proto.rs")
+	cmd := librust_proto_rule.RuleParams.Command
+	if w := "-Iproto"; !strings.Contains(cmd, w) {
+		t.Errorf("expected %q in %q", w, cmd)
+	}
+
+}
+
 func TestRustGrpc(t *testing.T) {
 	ctx := testRust(t, `
 		rust_protobuf {
diff --git a/rust/rust.go b/rust/rust.go
index 6d6b55e..ba63613 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -267,6 +267,15 @@
 	return false
 }
 
+func (mod *Module) Source() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok && mod.sourceProvider != nil {
+			return library.source()
+		}
+	}
+	return false
+}
+
 func (mod *Module) RlibStd() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok && library.rlib() {
@@ -438,18 +447,13 @@
 }
 
 type PathDeps struct {
-	Dylibs          *android.DepSet[RustLibrary]
-	Rlibs           *android.DepSet[RustLibrary]
-	ProcMacros      *android.DepSet[RustLibrary]
-	LibDeps         android.Paths
-	WholeStaticLibs android.Paths
-	AfdoProfiles    android.Paths
-	// These paths are files needed to run the build tools and will be located under
-	// __SBOX_SANDBOX_DIR__/tools/...
-	BuildToolDeps android.Paths
-	// These paths are files needed to run the build tools and will be located under
-	// __SBOX_SANDBOX_DIR__/...
-	BuildToolSrcDeps android.Paths
+	DyLibs        RustLibraries
+	RLibs         RustLibraries
+	SharedLibs    android.Paths
+	SharedLibDeps android.Paths
+	StaticLibs    android.Paths
+	ProcMacros    RustLibraries
+	AfdoProfiles  android.Paths
 
 	// depFlags and depLinkFlags are rustc and linker (clang) flags.
 	depFlags     []string
@@ -457,8 +461,8 @@
 
 	// linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker.
 	// Both of these are exported and propagate to dependencies.
-	linkDirs    android.Paths
-	linkObjects android.Paths
+	linkDirs    []string
+	linkObjects []string
 
 	// Used by bindgen modules which call clang
 	depClangFlags         []string
@@ -472,13 +476,6 @@
 	// Paths to generated source files
 	SrcDeps          android.Paths
 	srcProviderFiles android.Paths
-
-	// Paths to specific build tools
-	Rustc         android.Path
-	Clang         android.Path
-	Llvm_ar       android.Path
-	Clippy_driver android.Path
-	Rustdoc       android.Path
 }
 
 type RustLibraries []RustLibrary
@@ -498,8 +495,6 @@
 	compilerDeps(ctx DepsContext, deps Deps) Deps
 	crateName() string
 	rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
-	crateRoot(ctx ModuleContext) android.Path
-	compilationSourcesAndData(ctx ModuleContext) android.Paths
 
 	// Output directory in which source-generated code from dependencies is
 	// copied. This is equivalent to Cargo's OUT_DIR variable.
@@ -529,8 +524,8 @@
 }
 
 type exportedFlagsProducer interface {
-	exportLinkDirs(...android.Path)
-	exportLinkObjects(...android.Path)
+	exportLinkDirs(...string)
+	exportLinkObjects(...string)
 }
 
 type xref interface {
@@ -538,28 +533,22 @@
 }
 
 type flagExporter struct {
-	linkDirs    android.Paths
-	linkObjects android.Paths
-	libDeps     android.Paths
+	linkDirs    []string
+	linkObjects []string
 }
 
-func (flagExporter *flagExporter) exportLinkDirs(dirs ...android.Path) {
-	flagExporter.linkDirs = android.FirstUniquePaths(append(flagExporter.linkDirs, dirs...))
+func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
+	flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
 }
 
-func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) {
-	flagExporter.linkObjects = android.FirstUniquePaths(append(flagExporter.linkObjects, flags...))
-}
-
-func (flagExporter *flagExporter) exportLibDeps(paths ...android.Path) {
-	flagExporter.libDeps = android.FirstUniquePaths(append(flagExporter.libDeps, paths...))
+func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
+	flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
 }
 
 func (flagExporter *flagExporter) setProvider(ctx ModuleContext) {
 	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
 		LinkDirs:    flagExporter.linkDirs,
 		LinkObjects: flagExporter.linkObjects,
-		LibDeps:     flagExporter.libDeps,
 	})
 }
 
@@ -571,9 +560,8 @@
 
 type FlagExporterInfo struct {
 	Flags       []string
-	LinkDirs    android.Paths
-	LinkObjects android.Paths
-	LibDeps     android.Paths
+	LinkDirs    []string // TODO: this should be android.Paths
+	LinkObjects []string // TODO: this should be android.Paths
 }
 
 var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
@@ -941,14 +929,6 @@
 func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 }
 
-type RustInfo struct {
-	TransitiveRlibs      *android.DepSet[RustLibrary]
-	TransitiveDylibs     *android.DepSet[RustLibrary]
-	TransitiveProcMacros *android.DepSet[RustLibrary]
-}
-
-var RustInfoProvider = blueprint.NewProvider(RustInfo{})
-
 func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
 	ctx := &moduleContext{
 		ModuleContext: actx,
@@ -1058,12 +1038,6 @@
 
 		ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
 	}
-
-	ctx.SetProvider(RustInfoProvider, RustInfo{
-		TransitiveRlibs:      deps.Rlibs,
-		TransitiveDylibs:     deps.Dylibs,
-		TransitiveProcMacros: deps.ProcMacros,
-	})
 }
 
 func (mod *Module) deps(ctx DepsContext) Deps {
@@ -1122,7 +1096,6 @@
 var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
 
 var (
-	buildToolDepTag     = dependencyTag{name: "buildToolTag"}
 	customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
 	rlibDepTag          = dependencyTag{name: "rlibTag", library: true}
 	dylibDepTag         = dependencyTag{name: "dylib", library: true, dynamic: true}
@@ -1186,6 +1159,13 @@
 	return cc.MakeLibName(ctx, c, dep, depName)
 }
 
+func collectIncludedProtos(mod *Module, dep *Module) {
+	if protoMod, ok := mod.sourceProvider.(*protobufDecorator); ok {
+		if _, ok := dep.sourceProvider.(*protobufDecorator); ok {
+			protoMod.additionalCrates = append(protoMod.additionalCrates, dep.CrateName())
+		}
+	}
+}
 func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
@@ -1256,9 +1236,7 @@
 
 	var transitiveAndroidMkSharedLibs []*android.DepSet[string]
 	var directAndroidMkSharedLibs []string
-	transitiveRlibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
-	transitiveDylibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
-	transitiveProcMacros := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1271,17 +1249,6 @@
 			return
 		}
 
-		rustInfo := ctx.OtherModuleProvider(dep, RustInfoProvider).(RustInfo)
-		if rustInfo.TransitiveDylibs != nil {
-			transitiveDylibs.Transitive(rustInfo.TransitiveDylibs)
-		}
-		if rustInfo.TransitiveRlibs != nil {
-			transitiveRlibs.Transitive(rustInfo.TransitiveRlibs)
-		}
-		if rustInfo.TransitiveProcMacros != nil {
-			transitiveProcMacros.Transitive(rustInfo.TransitiveProcMacros)
-		}
-
 		if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
 			//Handle Rust Modules
 			makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
@@ -1296,12 +1263,9 @@
 				directDylibDeps = append(directDylibDeps, rustDep)
 				mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
 				mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName))
-				transitiveDylibs.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
 
 			case rlibDepTag:
+
 				rlib, ok := rustDep.compiler.(libraryInterface)
 				if !ok || !rlib.rlib() {
 					ctx.ModuleErrorf("mod %q not an rlib library", makeLibName)
@@ -1310,18 +1274,15 @@
 				directRlibDeps = append(directRlibDeps, rustDep)
 				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
 				mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName))
-				transitiveRlibs.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
 
 			case procMacroDepTag:
 				directProcMacroDeps = append(directProcMacroDeps, rustDep)
 				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
-				transitiveProcMacros.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
+
+			case sourceDepTag:
+				if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
+					collectIncludedProtos(mod, rustDep)
+				}
 			}
 
 			transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs)
@@ -1352,16 +1313,23 @@
 				depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
 				depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
 				depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
-				depPaths.LibDeps = append(depPaths.LibDeps, exportedInfo.LibDeps...)
 			}
 
 			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
 				linkFile := rustDep.UnstrippedOutputFile()
+				linkDir := linkPathFromFilePath(linkFile)
 				if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
-					lib.exportLinkDirs(linkFile.Dir())
+					lib.exportLinkDirs(linkDir)
 				}
 			}
-
+			if depTag == sourceDepTag {
+				if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() {
+					if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok {
+						exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+						depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
+					}
+				}
+			}
 		} else if ccDep, ok := dep.(cc.LinkableInterface); ok {
 			//Handle C dependencies
 			makeLibName := cc.MakeLibName(ctx, mod, ccDep, depName)
@@ -1385,7 +1353,7 @@
 				return
 			}
 
-			linkPath := linkObject.Path().Dir()
+			linkPath := linkPathFromFilePath(linkObject.Path())
 
 			exportDep := false
 			switch {
@@ -1400,7 +1368,6 @@
 						depPaths.depLinkFlags = append(depPaths.depLinkFlags, []string{"-Wl,--whole-archive", linkObject.Path().String(), "-Wl,--no-whole-archive"}...)
 					} else if libName, ok := libNameFromFilePath(linkObject.Path()); ok {
 						depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName)
-						depPaths.WholeStaticLibs = append(depPaths.WholeStaticLibs, linkObject.Path())
 					} else {
 						ctx.ModuleErrorf("'%q' cannot be listed as a whole_static_library in Rust modules unless the output is prefixed by 'lib'", depName, ctx.ModuleName())
 					}
@@ -1408,7 +1375,7 @@
 
 				// Add this to linkObjects to pass the library directly to the linker as well. This propagates
 				// to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant.
-				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 
 				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
@@ -1439,10 +1406,10 @@
 					}
 					return
 				}
-				linkPath = linkObject.Path().Dir()
+				linkPath = linkPathFromFilePath(linkObject.Path())
 
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
-				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
 				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
 				depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
@@ -1468,31 +1435,10 @@
 			// Make sure these dependencies are propagated
 			if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
 				lib.exportLinkDirs(linkPath)
-				if linkObject.Valid() {
-					lib.exportLinkObjects(linkObject.Path())
-				}
+				lib.exportLinkObjects(linkObject.String())
 			}
 		} else {
 			switch {
-			case depTag == buildToolDepTag:
-				buildTool := ctx.OtherModuleProvider(dep, android.PrebuiltBuildToolInfoProvider).(android.PrebuiltBuildToolInfo)
-				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Src)
-				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Deps...)
-				switch android.RemoveOptionalPrebuiltPrefix(dep.Name()) {
-				case "rustc":
-					depPaths.Rustc = buildTool.Src
-					// rustc expects the standard cc toolchain libraries (libdl, libm, libc, etc.)
-					// not to be under the __SBOX_SANDBOX_DIR__/ directory
-					depPaths.BuildToolSrcDeps = append(depPaths.BuildToolSrcDeps, buildTool.Deps...)
-				case "clang++":
-					depPaths.Clang = buildTool.Src
-				case "llvm-ar":
-					depPaths.Llvm_ar = buildTool.Src
-				case "clippy-driver":
-					depPaths.Clippy_driver = buildTool.Src
-				case "rustdoc":
-					depPaths.Rustdoc = buildTool.Src
-				}
 			case depTag == cc.CrtBeginDepTag:
 				depPaths.CrtBegin = append(depPaths.CrtBegin, android.OutputFileForModule(ctx, dep, ""))
 			case depTag == cc.CrtEndDepTag:
@@ -1508,16 +1454,34 @@
 		}
 	})
 
-	var libDepFiles android.Paths
-	for _, dep := range directStaticLibDeps {
-		libDepFiles = append(libDepFiles, dep.OutputFile().Path())
+	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
+
+	var rlibDepFiles RustLibraries
+	for _, dep := range directRlibDeps {
+		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+	}
+	var dylibDepFiles RustLibraries
+	for _, dep := range directDylibDeps {
+		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+	}
+	var procMacroDepFiles RustLibraries
+	for _, dep := range directProcMacroDeps {
+		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
 	}
 
+	var staticLibDepFiles android.Paths
+	for _, dep := range directStaticLibDeps {
+		staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
+	}
+
+	var sharedLibFiles android.Paths
+	var sharedLibDepFiles android.Paths
 	for _, dep := range directSharedLibDeps {
+		sharedLibFiles = append(sharedLibFiles, dep.SharedLibrary)
 		if dep.TableOfContents.Valid() {
-			libDepFiles = append(libDepFiles, dep.TableOfContents.Path())
+			sharedLibDepFiles = append(sharedLibDepFiles, dep.TableOfContents.Path())
 		} else {
-			libDepFiles = append(libDepFiles, dep.SharedLibrary)
+			sharedLibDepFiles = append(sharedLibDepFiles, dep.SharedLibrary)
 		}
 	}
 
@@ -1531,22 +1495,22 @@
 		srcProviderDepFiles = append(srcProviderDepFiles, srcs...)
 	}
 
-	depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...)
+	depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
+	depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
+	depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibFiles...)
+	depPaths.SharedLibDeps = append(depPaths.SharedLibDeps, sharedLibDepFiles...)
+	depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
+	depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
 	depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...)
 
 	// Dedup exported flags from dependencies
-	depPaths.linkDirs = android.FirstUniquePaths(depPaths.linkDirs)
-	depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects)
+	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
+	depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects)
 	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
 	depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
 	depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
 	depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths)
 
-	depPaths.Rlibs = transitiveRlibs.Build()
-	depPaths.Dylibs = transitiveDylibs.Build()
-	depPaths.ProcMacros = transitiveProcMacros.Build()
-	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
-
 	return depPaths
 }
 
@@ -1569,6 +1533,10 @@
 	return mod.InRecovery()
 }
 
+func linkPathFromFilePath(filepath android.Path) string {
+	return strings.Split(filepath.String(), filepath.Base())[0]
+}
+
 // usePublicApi returns true if the rust variant should link against NDK (publicapi)
 func (r *Module) usePublicApi() bool {
 	return r.Device() && r.UseSdk()
@@ -1611,15 +1579,6 @@
 			blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage})
 	}
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustc")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clippy-driver")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustdoc")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++.real")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "lld")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "ld.lld")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "llvm-ar")
-
 	// rlibs
 	rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation})
 	for _, lib := range deps.Rlibs {
@@ -1636,30 +1595,43 @@
 	}
 
 	// rustlibs
-	if deps.Rustlibs != nil && !mod.compiler.Disabled() {
-		autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
-		for _, lib := range deps.Rustlibs {
-			if autoDep.depTag == rlibDepTag {
-				// Handle the rlib deptag case
-				addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations)
-			} else {
-				// autoDep.depTag is a dylib depTag. Not all rustlibs may be available as a dylib however.
-				// Check for the existence of the dylib deptag variant. Select it if available,
-				// otherwise select the rlib variant.
-				autoDepVariations := append(commonDepVariations,
-					blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation})
-
-				replacementLib := cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Dylibs)
-
-				if actx.OtherModuleDependencyVariantExists(autoDepVariations, replacementLib) {
-					addDylibDependency(actx, lib, mod, &snapshotInfo, autoDepVariations, autoDep.depTag)
-				} else {
-					// If there's no dylib dependency available, try to add the rlib dependency instead.
+	if deps.Rustlibs != nil {
+		if !mod.compiler.Disabled() {
+			for _, lib := range deps.Rustlibs {
+				autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
+				if autoDep.depTag == rlibDepTag {
+					// Handle the rlib deptag case
 					addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations)
+				} else {
+					// autoDep.depTag is a dylib depTag. Not all rustlibs may be available as a dylib however.
+					// Check for the existence of the dylib deptag variant. Select it if available,
+					// otherwise select the rlib variant.
+					autoDepVariations := append(commonDepVariations,
+						blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation})
+
+					replacementLib := cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Dylibs)
+
+					if actx.OtherModuleDependencyVariantExists(autoDepVariations, replacementLib) {
+						addDylibDependency(actx, lib, mod, &snapshotInfo, autoDepVariations, autoDep.depTag)
+					} else {
+						// If there's no dylib dependency available, try to add the rlib dependency instead.
+						addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations)
+					}
+				}
+			}
+		} else if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
+			for _, lib := range deps.Rustlibs {
+				replacementLib := cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Dylibs)
+				srcProviderVariations := append(commonDepVariations,
+					blueprint.Variation{Mutator: "rust_libraries", Variation: "source"})
+
+				if actx.OtherModuleDependencyVariantExists(srcProviderVariations, replacementLib) {
+					actx.AddVariationDependencies(srcProviderVariations, sourceDepTag, lib)
 				}
 			}
 		}
 	}
+
 	// stdlibs
 	if deps.Stdlibs != nil {
 		if mod.compiler.stdLinkage(ctx) == RlibLinkage {
@@ -1917,7 +1889,7 @@
 		procMacroBp2build(ctx, m)
 	} else if ctx.ModuleType() == "rust_binary_host" {
 		binaryBp2build(ctx, m)
-	} else if ctx.ModuleType() == "rust_protobuf_host" {
+	} else if ctx.ModuleType() == "rust_protobuf_host" || ctx.ModuleType() == "rust_protobuf" {
 		protoLibraryBp2build(ctx, m)
 	} else {
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 576209d..d609c2f 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -15,17 +15,14 @@
 package rust
 
 import (
-	"fmt"
 	"os"
 	"runtime"
 	"strings"
 	"testing"
 
 	"github.com/google/blueprint/proptools"
-	"google.golang.org/protobuf/encoding/prototext"
 
 	"android/soong/android"
-	"android/soong/cmd/sbox/sbox_proto"
 	"android/soong/genrule"
 )
 
@@ -43,7 +40,6 @@
 	PrepareForTestWithRustIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
@@ -67,14 +63,11 @@
 
 // testRust returns a TestContext in which a basic environment has been setup.
 // This environment contains a few mocked files. See rustMockedFiles for the list of these files.
-func testRust(t *testing.T, bp string, preparers ...android.FixturePreparer) *android.TestContext {
+func testRust(t *testing.T, bp string) *android.TestContext {
 	skipTestIfOsNotSupported(t)
 	result := android.GroupFixturePreparers(
 		prepareForRustTest,
 		rustMockedFiles.AddToFixture(),
-		android.GroupFixturePreparers(
-			preparers...,
-		),
 	).
 		RunTestWithBp(t, bp)
 	return result.TestContext
@@ -111,7 +104,6 @@
 		android.FixtureModifyProductVariables(
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr(device_version)
-				variables.ProductVndkVersion = StringPtr(product_version)
 				variables.Platform_vndk_version = StringPtr(vndk_version)
 			},
 		),
@@ -179,7 +171,6 @@
 		android.FixtureModifyProductVariables(
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr("current")
-				variables.ProductVndkVersion = StringPtr("current")
 				variables.Platform_vndk_version = StringPtr("VER")
 			},
 		),
@@ -208,11 +199,11 @@
 // Test that we can extract the link path from a lib path.
 func TestLinkPathFromFilePath(t *testing.T) {
 	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
-	libName := barPath.Dir()
-	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared"
+	libName := linkPathFromFilePath(barPath)
+	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
 
-	if libName.String() != expectedResult {
-		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName.String())
+	if libName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
 	}
 }
 
@@ -262,7 +253,6 @@
 	`)
 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
 	rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
-	rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
 	if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
@@ -281,20 +271,20 @@
 		t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
 	}
 
-	if !strings.Contains(rustc.RuleParams.Command, "-lstatic=wholestatic") {
-		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.RuleParams.Command)
+	if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") {
+		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(rustLink.RuleParams.Command, "cc_stubs_dep.so") {
-		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.RuleParams.Command)
+	if !strings.Contains(rustc.Args["linkFlags"], "cc_stubs_dep.so") {
+		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustc.Args["linkFlags"])
 	}
 
-	if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so") {
-		t.Errorf("shared cc dep not being passed as implicit to rustc %#v", rustLink.OrderOnly.Strings())
+	if !android.SuffixInList(rustc.OrderOnly.Strings(), "cc_stubs_dep.so") {
+		t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustc.OrderOnly.Strings())
 	}
 
-	if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") {
-		t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustLink.Implicits.Strings())
+	if !android.SuffixInList(rustc.Implicits.Strings(), "cc_stubs_dep.so.toc") {
+		t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustc.Implicits.Strings())
 	}
 }
 
@@ -433,7 +423,7 @@
 	`)
 	rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
 
-	if !strings.Contains(rustc.RuleParams.Command, "libbar/linux_glibc_x86_64") {
+	if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
 		t.Errorf("Proc_macro is not using host variant of dependent modules.")
 	}
 }
@@ -486,396 +476,3 @@
 		t.Errorf("expected %q got %q", expected, got)
 	}
 }
-
-var (
-	sboxCompilationFiles = []string{
-		"out/soong/.intermediates/defaults/rust/libaddr2line/android_arm64_armv8-a_rlib/libaddr2line.rlib",
-		"out/soong/.intermediates/defaults/rust/libadler/android_arm64_armv8-a_rlib/libadler.rlib",
-		"out/soong/.intermediates/defaults/rust/liballoc/android_arm64_armv8-a_rlib/liballoc.rlib",
-		"out/soong/.intermediates/defaults/rust/libcfg_if/android_arm64_armv8-a_rlib/libcfg_if.rlib",
-		"out/soong/.intermediates/defaults/rust/libcompiler_builtins/android_arm64_armv8-a_rlib/libcompiler_builtins.rlib",
-		"out/soong/.intermediates/defaults/rust/libcore/android_arm64_armv8-a_rlib/libcore.rlib",
-		"out/soong/.intermediates/defaults/rust/libgimli/android_arm64_armv8-a_rlib/libgimli.rlib",
-		"out/soong/.intermediates/defaults/rust/libhashbrown/android_arm64_armv8-a_rlib/libhashbrown.rlib",
-		"out/soong/.intermediates/defaults/rust/liblibc/android_arm64_armv8-a_rlib/liblibc.rlib",
-		"out/soong/.intermediates/defaults/rust/libmemchr/android_arm64_armv8-a_rlib/libmemchr.rlib",
-		"out/soong/.intermediates/defaults/rust/libminiz_oxide/android_arm64_armv8-a_rlib/libminiz_oxide.rlib",
-		"out/soong/.intermediates/defaults/rust/libobject/android_arm64_armv8-a_rlib/libobject.rlib",
-		"out/soong/.intermediates/defaults/rust/libpanic_unwind/android_arm64_armv8-a_rlib/libpanic_unwind.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_demangle/android_arm64_armv8-a_rlib/librustc_demangle.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_std_workspace_alloc/android_arm64_armv8-a_rlib/librustc_std_workspace_alloc.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_std_workspace_core/android_arm64_armv8-a_rlib/librustc_std_workspace_core.rlib",
-		"out/soong/.intermediates/defaults/rust/libstd_detect/android_arm64_armv8-a_rlib/libstd_detect.rlib",
-		"build/soong/scripts/mkcratersp.py",
-		"defaults/rust/linux-x86/1.69.0/bin/rustc",
-		"defaults/rust/linux-x86/1.69.0/lib/libstd.so",
-		"defaults/rust/linux-x86/1.69.0/lib64/libc++.so.1",
-	}
-	sboxCompilationFilesWithCc = []string{
-		"defaults/cc/common",
-		"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so",
-		"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc",
-		"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so",
-		"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc",
-		"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so",
-		"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc",
-		"out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so",
-		"out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so.toc",
-	}
-)
-
-func TestSandboxCompilation(t *testing.T) {
-	ctx := testRust(t, `
-		filegroup {
-			name: "libsrcs1",
-			srcs: ["src_filegroup1.rs"],
-		}
-		filegroup {
-			name: "libsrcs2",
-			srcs: ["src_filegroup2.rs"],
-		}
-		rust_library {
-			name: "libfizz_buzz",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: [
-				"src_lib*.rs",
-				":libsrcs1",
-				":libsrcs2",
-			],
-			compile_data: [
-				"compile_data1.txt",
-				"compile_data2.txt",
-			],
-			dylib: {
-				srcs: ["dylib_only.rs"],
-			},
-			rlib: {
-				srcs: ["rlib_only.rs"],
-			},
-		}
-		rust_binary {
-			name: "fizz_buzz",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: [
-				"src_lib*.rs",
-				":libsrcs1",
-				":libsrcs2",
-			],
-		}
-		rust_ffi {
-			name: "librust_ffi",
-			crate_name: "rust_ffi",
-			crate_root: "foo.rs",
-			static: {
-				srcs: ["static_only.rs"],
-			},
-			shared: {
-				srcs: ["shared_only.rs"],
-			},
-			srcs: ["src1.rs"],
-		}
-		cc_library_static {
-			name: "cc_dep_static",
-		}
-		cc_library_shared {
-			name: "cc_dep_shared",
-		}
-		rust_library {
-			name: "libfizz_buzz_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			shared_libs: ["cc_dep_shared"],
-			static_libs: ["cc_dep_static"],
-		}
-		rust_library {
-			name: "libfizz_buzz_intermediate_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			rustlibs: ["libfizz_buzz_cc_deps"],
-		}
-		rust_library {
-			name: "libfizz_buzz_transitive_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			rustlibs: ["libfizz_buzz_intermediate_cc_deps"],
-		}
-	`,
-		android.FixtureMergeMockFs(android.MockFS{
-			"src_lib1.rs":       nil,
-			"src_lib2.rs":       nil,
-			"src_lib3.rs":       nil,
-			"src_lib4.rs":       nil,
-			"src_filegroup1.rs": nil,
-			"src_filegroup2.rs": nil,
-			"static_only.rs":    nil,
-			"shared_only.rs":    nil,
-		}),
-	)
-
-	testcases := []struct {
-		name                     string
-		moduleName               string
-		variant                  string
-		rustcExpectedFilesToCopy []string
-		expectedFlags            []string
-	}{
-		{
-			name:       "rust_library (dylib)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"compile_data1.txt",
-				"compile_data2.txt",
-				"dylib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup2.rs",
-
-				"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so",
-				"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc",
-				"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so",
-				"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc",
-				"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so",
-				"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy",
-			}),
-			expectedFlags: []string{
-				"-C linker=build/soong/scripts/mkcratersp.py",
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.rsp",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library (rlib dylib-std)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"rlib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup2.rs",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library (rlib rlib-std)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"rlib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup2.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib.clippy",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_binary",
-			moduleName: "fizz_buzz",
-			variant:    "android_arm64_armv8-a",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup1.rs",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup2.rs",
-
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_dynamic/android_arm64_armv8-a/crtbegin_dynamic.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_android/android_arm64_armv8-a/crtend_android.o",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/fizz_buzz",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/fizz_buzz.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_ffi static lib variant",
-			moduleName: "librust_ffi",
-			variant:    "android_arm64_armv8-a_static",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src1.rs",
-				"static_only.rs",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a.clippy",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/librust_ffi.a",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.a.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_ffi shared lib variant",
-			moduleName: "librust_ffi",
-			variant:    "android_arm64_armv8-a_shared",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src1.rs",
-				"shared_only.rs",
-
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.clippy",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/librust_ffi.so",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.so.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library with cc deps (dylib)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with cc deps (rlib rlib-std)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with cc deps (rlib dylib-std)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (dylib)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (rlib rlib-std)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (rlib dylib-std)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-	}
-
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			writeFile := ctx.ModuleForTests(tc.moduleName, tc.variant).Rule("unescapedWriteFile")
-			contents := writeFile.BuildParams.Args["content"]
-			manifestProto := sbox_proto.Manifest{}
-			err := prototext.Unmarshal([]byte(contents), &manifestProto)
-			if err != nil {
-				t.Errorf("expected no errors unmarshaling manifest proto; got %v", err)
-			}
-
-			if len(manifestProto.Commands) != 1 {
-				t.Errorf("expected 1 command; got %v", len(manifestProto.Commands))
-			}
-
-			// check that sandbox contains correct files
-			rustc := manifestProto.Commands[0]
-			actualFilesToCopy := []string{}
-			for _, copy := range rustc.CopyBefore {
-				actualFilesToCopy = append(actualFilesToCopy, copy.GetFrom())
-			}
-			_, expectedFilesNotCopied, _ := android.ListSetDifference(tc.rustcExpectedFilesToCopy, actualFilesToCopy)
-			if len(expectedFilesNotCopied) > 0 {
-				t.Errorf("did not copy expected files to sbox: %v;\n files copied: %v", expectedFilesNotCopied, actualFilesToCopy)
-			}
-
-			rustcCmd := proptools.String(rustc.Command)
-			for _, flag := range tc.expectedFlags {
-				android.AssertStringDoesContain(
-					t,
-					fmt.Sprintf(
-						"missing flag in rustc invocation; expected to find substring %q; got %q",
-						flag,
-						rustcCmd,
-					),
-					rustcCmd,
-					flag,
-				)
-			}
-		})
-	}
-}
diff --git a/rust/testing.go b/rust/testing.go
index 9951937..3fe751e 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -52,22 +52,6 @@
 
 func GatherRequiredDepsForTest() string {
 	bp := `
-		prebuilt_build_tool {
-			name: "rustc",
-			src: "linux-x86/1.69.0/bin/rustc",
-			deps: [
-				"linux-x86/1.69.0/lib/libstd.so",
-				"linux-x86/1.69.0/lib64/libc++.so.1",
-			],
-		}
-		prebuilt_build_tool {
-			name: "clippy-driver",
-			src: "linux-x86/1.69.0/bin/clippy-driver",
-		}
-		prebuilt_build_tool {
-			name: "rustdoc",
-			src: "linux-x86/1.69.0/bin/rustdoc",
-		}
 		rust_prebuilt_library {
 				name: "libstd",
 				crate_name: "std",
@@ -79,25 +63,6 @@
 				},
 				host_supported: true,
 				sysroot: true,
-			rlibs: [
-			    "libaddr2line",
-			    "libadler",
-			    "liballoc",
-			    "libcfg_if",
-			    "libcompiler_builtins",
-			    "libcore",
-			    "libgimli",
-			    "libhashbrown",
-			    "liblibc",
-			    "libmemchr",
-			    "libminiz_oxide",
-			    "libobject",
-			    "libpanic_unwind",
-			    "librustc_demangle",
-			    "librustc_std_workspace_alloc",
-			    "librustc_std_workspace_core",
-			    "libstd_detect",
-			],
 		}
 		//////////////////////////////
 		// Device module requirements
@@ -134,278 +99,6 @@
 			nocrt: true,
 			system_shared_libs: [],
 		}
-		rust_library_rlib {
-			name: "libaddr2line",
-			crate_name: "addr2line",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libadler",
-			crate_name: "adler",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "liballoc",
-			crate_name: "alloc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcfg_if",
-			crate_name: "cfg_if",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcompiler_builtins",
-			crate_name: "compiler_builtins",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcore",
-			crate_name: "core",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libgimli",
-			crate_name: "gimli",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libhashbrown",
-			crate_name: "hashbrown",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "liblibc",
-			crate_name: "libc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libmemchr",
-			crate_name: "memchr",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libminiz_oxide",
-			crate_name: "miniz_oxide",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libobject",
-			crate_name: "object",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libpanic_unwind",
-			crate_name: "panic_unwind",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_demangle",
-			crate_name: "rustc_demangle",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_std_workspace_alloc",
-			crate_name: "rustc_std_workspace_alloc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_std_workspace_core",
-			crate_name: "rustc_std_workspace_core",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libstd_detect",
-			crate_name: "std_detect",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
 		rust_library {
 			name: "libstd",
 			crate_name: "std",
@@ -420,25 +113,6 @@
 			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
 			min_sdk_version: "29",
-			rlibs: [
-			    "libaddr2line",
-			    "libadler",
-			    "liballoc",
-			    "libcfg_if",
-			    "libcompiler_builtins",
-			    "libcore",
-			    "libgimli",
-			    "libhashbrown",
-			    "liblibc",
-			    "libmemchr",
-			    "libminiz_oxide",
-			    "libobject",
-			    "libpanic_unwind",
-			    "librustc_demangle",
-			    "librustc_std_workspace_alloc",
-			    "librustc_std_workspace_core",
-			    "libstd_detect",
-			],
 		}
 		rust_library {
 			name: "libtest",
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
index cb345a4..054104c 100644
--- a/rust/toolchain_library.go
+++ b/rust/toolchain_library.go
@@ -89,7 +89,7 @@
 
 func rustSetToolchainSource(ctx android.LoadHookContext) {
 	if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
-		prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx))
+		prefix := filepath.Join("linux-x86", GetRustPrebuiltVersion(ctx))
 		versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_crate_root))
 		versionedSrcs := make([]string, len(toolchainLib.Properties.Toolchain_srcs))
 		for i, src := range toolchainLib.Properties.Toolchain_srcs {
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 621a724..4f45799 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -1051,7 +1051,7 @@
 	ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31")
 
 	// libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
-	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").RuleParams.Command
+	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").Args["linkFlags"]
 	for _, input := range [][]string{
 		[]string{sharedVariant, "libvndk.vndk.30.arm64"},
 		[]string{staticVariant, "libvendor.vendor_static.30.arm64"},
@@ -1119,7 +1119,7 @@
 		t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkDylibName, expectedRustVendorSnapshotName)
 	}
 
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").RuleParams.Command
+	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").Args["linkFlags"]
 	libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
 	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
 		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index c6aa3d0..c6e6e30 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -62,8 +62,8 @@
     if args.source:
         for input in args.source.split(':'):
             pb.MergeFrom(LoadJsonMessage(input))
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Print(args):
@@ -90,8 +90,8 @@
     for item in installed_libraries:
         if item not in getattr(pb, 'provideLibs'):
             getattr(pb, 'provideLibs').append(item)
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Append(args):
@@ -106,8 +106,8 @@
     else:
         setattr(pb, args.key, args.value)
 
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+    ValidateAndWriteAsPbFile(pb, args.output)
+
 
 
 def Merge(args):
@@ -116,8 +116,7 @@
         with open(other, 'rb') as f:
             pb.MergeFromString(f.read())
 
-    with open(args.out, 'wb') as f:
-        f.write(pb.SerializeToString())
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Validate(args):
@@ -151,6 +150,29 @@
         sys.exit(f'Unknown type: {args.type}')
 
 
+def ValidateAndWriteAsPbFile(pb, output_path):
+    ValidateConfiguration(pb)
+    with open(output_path, 'wb') as f:
+        f.write(pb.SerializeToString())
+
+
+def ValidateConfiguration(pb):
+    """
+    Validate if the configuration is valid to be used as linker configuration
+    """
+
+    # Validate if provideLibs and requireLibs have common module
+    provideLibs = set(getattr(pb, 'provideLibs'))
+    requireLibs = set(getattr(pb, 'requireLibs'))
+
+    intersectLibs = provideLibs.intersection(requireLibs)
+
+    if intersectLibs:
+        for lib in intersectLibs:
+            print(f'{lib} exists both in requireLibs and provideLibs', file=sys.stderr)
+        sys.exit(1)
+
+
 def GetArgParser():
     parser = argparse.ArgumentParser()
     subparsers = parser.add_subparsers()
diff --git a/scripts/mkcratersp.py b/scripts/mkcratersp.py
deleted file mode 100755
index 6ef01eb..0000000
--- a/scripts/mkcratersp.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/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.
-#
-
-"""
-This script is used as a replacement for the Rust linker. It converts a linker
-command line into a rspfile that can be used during the link phase.
-"""
-
-import os
-import shutil
-import subprocess
-import sys
-
-def create_archive(out, objects, archives):
-  mricmd = f'create {out}\n'
-  for o in objects:
-    mricmd += f'addmod {o}\n'
-  for a in archives:
-    mricmd += f'addlib {a}\n'
-  mricmd += 'save\nend\n'
-  subprocess.run([os.getenv('AR'), '-M'], encoding='utf-8', input=mricmd, check=True)
-
-objects = []
-archives = []
-linkdirs = []
-libs = []
-temp_archives = []
-version_script = None
-
-for i, arg in enumerate(sys.argv):
-  if arg == '-o':
-    out = sys.argv[i+1]
-  if arg == '-L':
-    linkdirs.append(sys.argv[i+1])
-  if arg.startswith('-l') or arg == '-shared':
-    libs.append(arg)
-  if os.getenv('ANDROID_RUST_DARWIN') and (arg == '-dylib' or arg == '-dynamiclib'):
-    libs.append(arg)
-  if arg.startswith('-Wl,--version-script='):
-    version_script = arg[21:]
-  if arg[0] == '-':
-    continue
-  if arg.endswith('.o') or arg.endswith('.rmeta'):
-    objects.append(arg)
-  if arg.endswith('.rlib'):
-    if arg.startswith(os.getenv('TMPDIR')):
-      temp_archives.append(arg)
-    else:
-      archives.append(arg)
-
-create_archive(f'{out}.whole.a', objects, [])
-create_archive(f'{out}.a', [], temp_archives)
-
-with open(out, 'w') as f:
-  if os.getenv("ANDROID_RUST_DARWIN"):
-    print(f'-force_load', file=f)
-    print(f'{out}.whole.a', file=f)
-  else:
-    print(f'-Wl,--whole-archive', file=f)
-    print(f'{out}.whole.a', file=f)
-    print(f'-Wl,--no-whole-archive', file=f)
-  print(f'{out}.a', file=f)
-  for a in archives:
-    print(a, file=f)
-  for linkdir in linkdirs:
-    print(f'-L{linkdir}', file=f)
-  for l in libs:
-    print(l, file=f)
-  if version_script:
-    shutil.copyfile(version_script, f'{out}.version_script')
-    print(f'-Wl,--version-script={out}.version_script', file=f)
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index e5263fe..7f51000 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -12,6 +12,7 @@
         "soong-bp2build",
         "soong-cc",
         "soong-java",
+        "soong-sysprop-bp2build",
     ],
     srcs: [
         "sysprop_library.go",
diff --git a/sysprop/bp2build/Android.bp b/sysprop/bp2build/Android.bp
new file mode 100644
index 0000000..1b9eda8
--- /dev/null
+++ b/sysprop/bp2build/Android.bp
@@ -0,0 +1,16 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-sysprop-bp2build",
+    pkgPath: "android/soong/sysprop/bp2build",
+    deps: [
+        "soong-android",
+        "soong-bazel",
+    ],
+    srcs: [
+        "bp2build.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/sysprop/bp2build/bp2build.go b/sysprop/bp2build/bp2build.go
new file mode 100644
index 0000000..18991de
--- /dev/null
+++ b/sysprop/bp2build/bp2build.go
@@ -0,0 +1,106 @@
+// 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 bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/bazel"
+)
+
+type SyspropLibraryLabels struct {
+	SyspropLibraryLabel  string
+	CcSharedLibraryLabel string
+	CcStaticLibraryLabel string
+	JavaLibraryLabel     string
+}
+
+// TODO(b/240463568): Additional properties will be added for API validation
+type bazelSyspropLibraryAttributes struct {
+	Srcs bazel.LabelListAttribute
+	Tags bazel.StringListAttribute
+}
+
+func Bp2buildBaseSyspropLibrary(ctx android.Bp2buildMutatorContext, name string, srcs bazel.LabelListAttribute) {
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "sysprop_library",
+			Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
+		},
+		android.CommonAttributes{Name: name},
+		&bazelSyspropLibraryAttributes{
+			Srcs: srcs,
+			Tags: apexAvailableTags,
+		},
+	)
+}
+
+type bazelCcSyspropLibraryAttributes struct {
+	Dep             bazel.LabelAttribute
+	Min_sdk_version *string
+	Tags            bazel.StringListAttribute
+}
+
+func Bp2buildSyspropCc(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, minSdkVersion *string) {
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+	attrs := &bazelCcSyspropLibraryAttributes{
+		Dep:             *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
+		Min_sdk_version: minSdkVersion,
+		Tags:            apexAvailableTags,
+	}
+
+	if labels.CcSharedLibraryLabel != "" {
+		ctx.CreateBazelTargetModule(
+			bazel.BazelTargetModuleProperties{
+				Rule_class:        "cc_sysprop_library_shared",
+				Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
+			},
+			android.CommonAttributes{Name: labels.CcSharedLibraryLabel},
+			attrs)
+	}
+	if labels.CcStaticLibraryLabel != "" {
+		ctx.CreateBazelTargetModule(
+			bazel.BazelTargetModuleProperties{
+				Rule_class:        "cc_sysprop_library_static",
+				Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
+			},
+			android.CommonAttributes{Name: labels.CcStaticLibraryLabel},
+			attrs)
+	}
+}
+
+type bazelJavaLibraryAttributes struct {
+	Dep             bazel.LabelAttribute
+	Min_sdk_version *string
+	Tags            bazel.StringListAttribute
+}
+
+func Bp2buildSyspropJava(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, minSdkVersion *string) {
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "java_sysprop_library",
+			Bzl_load_location: "//build/bazel/rules/java:java_sysprop_library.bzl",
+		},
+		android.CommonAttributes{Name: labels.JavaLibraryLabel},
+		&bazelJavaLibraryAttributes{
+			Dep:             *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
+			Min_sdk_version: minSdkVersion,
+			Tags:            apexAvailableTags,
+		})
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index d16bf32..13cf68f 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -24,6 +24,8 @@
 	"sync"
 
 	"android/soong/bazel"
+	"android/soong/sysprop/bp2build"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -230,6 +232,10 @@
 	return m.BaseModuleName() + "_java_gen_public"
 }
 
+func (m *syspropLibrary) bp2buildJavaImplementationModuleName() string {
+	return m.BaseModuleName() + "_java_library"
+}
+
 func (m *syspropLibrary) BaseModuleName() string {
 	return m.ModuleBase.Name()
 }
@@ -431,6 +437,7 @@
 	Min_sdk_version   *string
 	Bazel_module      struct {
 		Bp2build_available *bool
+		Label              *string
 	}
 }
 
@@ -551,8 +558,10 @@
 		Min_sdk_version:   m.properties.Java.Min_sdk_version,
 		Bazel_module: struct {
 			Bp2build_available *bool
+			Label              *string
 		}{
-			Bp2build_available: proptools.BoolPtr(false),
+			Label: proptools.StringPtr(
+				fmt.Sprintf("//%s:%s", ctx.ModuleDir(), m.bp2buildJavaImplementationModuleName())),
 		},
 	})
 
@@ -573,6 +582,7 @@
 			Stem:        proptools.StringPtr(m.BaseModuleName()),
 			Bazel_module: struct {
 				Bp2build_available *bool
+				Label              *string
 			}{
 				Bp2build_available: proptools.BoolPtr(false),
 			},
@@ -592,13 +602,17 @@
 
 // TODO(b/240463568): Additional properties will be added for API validation
 func (m *syspropLibrary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
-	labels := cc.SyspropLibraryLabels{
-		SyspropLibraryLabel: m.BaseModuleName(),
-		SharedLibraryLabel:  m.CcImplementationModuleName(),
-		StaticLibraryLabel:  cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
+	if m.Owner() != "Platform" {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "Only sysprop libraries owned by platform are supported at this time")
+		return
 	}
-	cc.Bp2buildSysprop(ctx,
-		labels,
-		bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)),
-		m.properties.Cpp.Min_sdk_version)
+	labels := bp2build.SyspropLibraryLabels{
+		SyspropLibraryLabel:  m.BaseModuleName(),
+		CcSharedLibraryLabel: m.CcImplementationModuleName(),
+		CcStaticLibraryLabel: cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
+		JavaLibraryLabel:     m.bp2buildJavaImplementationModuleName(),
+	}
+	bp2build.Bp2buildBaseSyspropLibrary(ctx, labels.SyspropLibraryLabel, bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)))
+	bp2build.Bp2buildSyspropCc(ctx, labels, m.properties.Cpp.Min_sdk_version)
+	bp2build.Bp2buildSyspropJava(ctx, labels, m.properties.Java.Min_sdk_version)
 }
diff --git a/sysprop/sysprop_library_conversion_test.go b/sysprop/sysprop_library_conversion_test.go
index 89adf7d..dabcc92 100644
--- a/sysprop/sysprop_library_conversion_test.go
+++ b/sysprop/sysprop_library_conversion_test.go
@@ -58,13 +58,18 @@
 				bp2build.AttrNameToString{
 					"dep": `":sysprop_foo"`,
 				}),
+			bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+				"sysprop_foo_java_library",
+				bp2build.AttrNameToString{
+					"dep": `":sysprop_foo"`,
+				}),
 		},
 	})
 }
 
 func TestSyspropLibraryCppMinSdkVersion(t *testing.T) {
 	bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
-		Description:                "sysprop_library with min_sdk_version",
+		Description:                "sysprop_library with cpp min_sdk_version",
 		ModuleTypeUnderTest:        "sysprop_library",
 		ModuleTypeUnderTestFactory: syspropLibraryFactory,
 		Filesystem: map[string]string{
@@ -105,6 +110,86 @@
 					"dep":             `":sysprop_foo"`,
 					"min_sdk_version": `"5"`,
 				}),
+			bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+				"sysprop_foo_java_library",
+				bp2build.AttrNameToString{
+					"dep": `":sysprop_foo"`,
+				}),
 		},
 	})
 }
+
+func TestSyspropLibraryJavaMinSdkVersion(t *testing.T) {
+	bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
+		Description:                "sysprop_library with java min_sdk_version",
+		ModuleTypeUnderTest:        "sysprop_library",
+		ModuleTypeUnderTestFactory: syspropLibraryFactory,
+		Filesystem: map[string]string{
+			"foo.sysprop": "",
+			"bar.sysprop": "",
+		},
+		Blueprint: `
+sysprop_library {
+	name: "sysprop_foo",
+	srcs: [
+		"foo.sysprop",
+		"bar.sysprop",
+	],
+	java: {
+		min_sdk_version: "5",
+	},
+	property_owner: "Platform",
+}
+`,
+		ExpectedBazelTargets: []string{
+			bp2build.MakeBazelTargetNoRestrictions("sysprop_library",
+				"sysprop_foo",
+				bp2build.AttrNameToString{
+					"srcs": `[
+        "foo.sysprop",
+        "bar.sysprop",
+    ]`,
+				}),
+			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_shared",
+				"libsysprop_foo",
+				bp2build.AttrNameToString{
+					"dep": `":sysprop_foo"`,
+				}),
+			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_static",
+				"libsysprop_foo_bp2build_cc_library_static",
+				bp2build.AttrNameToString{
+					"dep": `":sysprop_foo"`,
+				}),
+			bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+				"sysprop_foo_java_library",
+				bp2build.AttrNameToString{
+					"dep":             `":sysprop_foo"`,
+					"min_sdk_version": `"5"`,
+				}),
+		},
+	})
+}
+
+func TestSyspropLibraryOwnerNotPlatformUnconvertible(t *testing.T) {
+	bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
+		Description:                "sysprop_library simple",
+		ModuleTypeUnderTest:        "sysprop_library",
+		ModuleTypeUnderTestFactory: syspropLibraryFactory,
+		Filesystem: map[string]string{
+			"foo.sysprop": "",
+			"bar.sysprop": "",
+		},
+		Blueprint: `
+sysprop_library {
+	name: "sysprop_foo",
+	srcs: [
+		"foo.sysprop",
+		"bar.sysprop",
+	],
+	property_owner: "Vendor",
+	device_specific: true,
+}
+`,
+		ExpectedBazelTargets: []string{},
+	})
+}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 80b86e0..e51fe39 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -42,6 +42,7 @@
 		cc_library_headers {
 			name: "libbase_headers",
 			vendor_available: true,
+			product_available: true,
 			recovery_available: true,
 		}
 
@@ -250,6 +251,16 @@
 		result.ModuleForTests("libsysprop-odm", variant)
 	}
 
+	// product variant of vendor-owned sysprop_library
+	for _, variant := range []string{
+		"android_product.29_arm_armv7-a-neon_shared",
+		"android_product.29_arm_armv7-a-neon_static",
+		"android_product.29_arm64_armv8-a_shared",
+		"android_product.29_arm64_armv8-a_static",
+	} {
+		result.ModuleForTests("libsysprop-vendor-on-product", variant)
+	}
+
 	for _, variant := range []string{
 		"android_arm_armv7-a-neon_shared",
 		"android_arm_armv7-a-neon_static",
@@ -259,9 +270,6 @@
 		library := result.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
 		expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
 		android.AssertDeepEquals(t, "apex available property on libsysprop-platform", expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
-
-		// product variant of vendor-owned sysprop_library
-		result.ModuleForTests("libsysprop-vendor-on-product", variant)
 	}
 
 	result.ModuleForTests("sysprop-platform", "android_common")
@@ -272,15 +280,15 @@
 	// Check for exported includes
 	coreVariant := "android_arm64_armv8-a_static"
 	vendorVariant := "android_vendor.29_arm64_armv8-a_static"
+	productVariant := "android_product.29_arm64_armv8-a_static"
 
 	platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/include"
-	platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/public/include"
 	platformPublicVendorPath := "libsysprop-platform/android_vendor.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
-	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
+	platformOnProductPath := "libsysprop-platform-on-product/android_product.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	vendorInternalPath := "libsysprop-vendor/android_vendor.29_arm64_armv8-a_static/gen/sysprop/include"
-	vendorPublicPath := "libsysprop-vendor-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
+	vendorOnProductPath := "libsysprop-vendor-on-product/android_product.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	platformClient := result.ModuleForTests("cc-client-platform", coreVariant)
 	platformFlags := platformClient.Rule("cc").Args["cFlags"]
@@ -294,14 +302,14 @@
 	// platform-static should use platform's internal header
 	android.AssertStringDoesContain(t, "flags for platform-static", platformStaticFlags, platformInternalPath)
 
-	productClient := result.ModuleForTests("cc-client-product", coreVariant)
+	productClient := result.ModuleForTests("cc-client-product", productVariant)
 	productFlags := productClient.Rule("cc").Args["cFlags"]
 
 	// Product should use platform's and vendor's public headers
 	if !strings.Contains(productFlags, platformOnProductPath) ||
-		!strings.Contains(productFlags, vendorPublicPath) {
+		!strings.Contains(productFlags, vendorOnProductPath) {
 		t.Errorf("flags for product must contain %#v and %#v, but was %#v.",
-			platformPublicCorePath, vendorPublicPath, productFlags)
+			platformOnProductPath, vendorOnProductPath, productFlags)
 	}
 
 	vendorClient := result.ModuleForTests("cc-client-vendor", vendorVariant)
diff --git a/tests/lib.sh b/tests/lib.sh
index 0766d85..fb3b374 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -8,6 +8,11 @@
 
 REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
 
+function make_mock_top {
+  mock=$(mktemp -t -d st.XXXXX)
+  echo "$mock"
+}
+
 if [[ -n "$HARDWIRED_MOCK_TOP" ]]; then
   MOCK_TOP="$HARDWIRED_MOCK_TOP"
 else
@@ -158,6 +163,7 @@
   symlink_directory external/bazelbuild-rules_python
   symlink_directory external/bazelbuild-rules_java
   symlink_directory external/bazelbuild-rules_rust
+  symlink_directory external/bazelbuild-rules_testing
   symlink_directory external/rust/crates/tinyjson
 
   symlink_file WORKSPACE
@@ -197,3 +203,11 @@
     info "Completed test case \e[96;1m$f\e[0m"
   done
 }
+
+function move_mock_top {
+  MOCK_TOP2=$(make_mock_top)
+  rm -rf $MOCK_TOP2
+  mv $MOCK_TOP $MOCK_TOP2
+  MOCK_TOP=$MOCK_TOP2
+  trap cleanup_mock_top EXIT
+}
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6b9ff8b..223baa4 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -23,4 +23,4 @@
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
 
 "$TOP/build/bazel/ci/b_test.sh"
-
+"$TOP/build/soong/tests/symlinks_path_test.sh"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 73fbeab..8dc1630 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -35,14 +35,15 @@
 }
 
 function run_soong {
-  target_product="$1";shift
-  out_dir="$1"; shift
-  targets="$1"; shift
+  local out_dir="$1"; shift
+  local targets="$1"; shift
   if [ "$#" -ge 1 ]; then
-    apps=$1; shift
-    TARGET_PRODUCT="${target_product}" TARGET_BUILD_VARIANT=userdebug OUT_DIR="${out_dir}" TARGET_BUILD_UNBUNDLED=true TARGET_BUILD_APPS=$apps build/soong/soong_ui.bash --make-mode ${targets}
+    local apps=$1; shift
+    TARGET_PRODUCT="${target_product}" TARGET_RELEASE="${target_release}" TARGET_BUILD_VARIANT="${target_build_variant}" OUT_DIR="${out_dir}" TARGET_BUILD_UNBUNDLED=true TARGET_BUILD_APPS=$apps \
+        build/soong/soong_ui.bash --make-mode ${targets}
   else
-    TARGET_PRODUCT="${target_product}" TARGET_BUILD_VARIANT=userdebug OUT_DIR="${out_dir}" build/soong/soong_ui.bash --make-mode ${targets}
+    TARGET_PRODUCT="${target_product}" TARGET_RELEASE="${target_release}" TARGET_BUILD_VARIANT="${target_build_variant}" OUT_DIR="${out_dir}" \
+        build/soong/soong_ui.bash --make-mode ${targets}
   fi
 }
 
@@ -67,7 +68,7 @@
 
   # Test
   # m droid, build sbom later in case additional dependencies might be built and included in partition images.
-  run_soong "aosp_cf_x86_64_phone" "${out_dir}" "droid dump.erofs lz4"
+  run_soong "${out_dir}" "droid dump.erofs lz4"
 
   product_out=$out_dir/target/product/vsoc_x86_64
   sbom_test=$product_out/sbom_test
@@ -75,7 +76,7 @@
   cp $product_out/*.img $sbom_test
 
   # m sbom
-  run_soong "aosp_cf_x86_64_phone" "${out_dir}" sbom
+  run_soong "${out_dir}" sbom
 
   # Generate installed file list from .img files in PRODUCT_OUT
   dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
@@ -217,7 +218,7 @@
   out_dir="$(setup)"
 
   # run_soong to build com.android.adbd.apex
-  run_soong "module_arm64" "${out_dir}" "sbom deapexer" "com.android.adbd"
+  run_soong "${out_dir}" "sbom deapexer" "com.android.adbd"
 
   deapexer=${out_dir}/host/linux-x86/bin/deapexer
   debugfs=${out_dir}/host/linux-x86/bin/debugfs_static
@@ -249,7 +250,7 @@
   out_dir="$(setup)"
 
   # run_soong to build Browser2.apk
-  run_soong "module_arm64" "${out_dir}" "sbom" "Browser2"
+  run_soong "${out_dir}" "sbom" "Browser2"
 
   sbom_file=${out_dir}/target/product/module_arm64/system/product/app/Browser2/Browser2.apk.spdx.json
   echo "============ Diffing files in Browser2.apk and SBOM"
@@ -271,6 +272,41 @@
   cleanup "${out_dir}"
 }
 
-test_sbom_aosp_cf_x86_64_phone
-test_sbom_unbundled_apex
-test_sbom_unbundled_apk
\ No newline at end of file
+target_product=aosp_cf_x86_64_phone
+target_release=trunk_staging
+target_build_variant=userdebug
+for i in "$@"; do
+  case $i in
+    TARGET_PRODUCT=*)
+      target_product=${i#*=}
+      shift
+      ;;
+    TARGET_RELEASE=*)
+      target_release=${i#*=}
+      shift
+      ;;
+    TARGET_BUILD_VARIANT=*)
+      target_build_variant=${i#*=}
+      shift
+      ;;
+    *)
+      echo "Unknown command line arguments: $i"
+      exit 1
+      ;;
+  esac
+done
+
+echo "target product: $target_product, target_release: $target_release, target build variant: $target_build_variant"
+case $target_product in
+  aosp_cf_x86_64_phone)
+    test_sbom_aosp_cf_x86_64_phone
+    ;;
+  module_arm64)
+    test_sbom_unbundled_apex
+    test_sbom_unbundled_apk
+    ;;
+  *)
+    echo "Unknown TARGET_PRODUCT: $target_product"
+    exit 1
+    ;;
+esac
\ No newline at end of file
diff --git a/tests/symlinks_path_test.sh b/tests/symlinks_path_test.sh
new file mode 100755
index 0000000..ed42911
--- /dev/null
+++ b/tests/symlinks_path_test.sh
@@ -0,0 +1,51 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Test that relative symlinks work by recreating the bug in b/259191764
+# In some cases, developers prefer to move their checkouts. This causes
+# issues in that symlinked files (namely, the bazel wrapper script)
+# cannot be found. As such, we implemented relative symlinks so that a
+# moved checkout doesn't need a full clean before rebuilding.
+# The bazel output base will still need to be removed, as Starlark
+# doesn't seem to support relative symlinks yet.
+
+source "$(dirname "$0")/lib.sh"
+
+function check_link_has_mock_top_prefix {
+  input_link=$1
+  link_target=`readlink $input_link`
+  if [[ $link_target != "$MOCK_TOP"* ]]; then
+    echo "Symlink for file $input_link -> $link_target doesn't start with $MOCK_TOP"
+    exit 1
+  fi
+}
+
+function test_symlinks_updated_when_top_dir_changed {
+  setup
+
+  mkdir -p a
+  touch a/g.txt
+  cat > a/Android.bp <<'EOF'
+filegroup {
+    name: "g",
+    srcs: ["g.txt"],
+    bazel_module: {bp2build_available: true},
+}
+EOF
+  # A directory under $MOCK_TOP
+  outdir=out2
+
+  # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+
+  g_txt="out2/soong/workspace/a/g.txt"
+  check_link_has_mock_top_prefix "$g_txt"
+
+  move_mock_top
+
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+  check_link_has_mock_top_prefix "$g_txt"
+}
+
+scan_and_run_tests
\ No newline at end of file
diff --git a/ui/build/build.go b/ui/build/build.go
index 14d23a7..9d5c330 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -15,11 +15,13 @@
 package build
 
 import (
+	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sync"
 	"text/template"
+	"time"
 
 	"android/soong/ui/metrics"
 )
@@ -29,6 +31,7 @@
 func SetupOutDir(ctx Context, config Config) {
 	ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
 	ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
+	ensureEmptyDirectoriesExist(ctx, config.TempDir())
 
 	// Potentially write a marker file for whether kati is enabled. This is used by soong_build to
 	// potentially run the AndroidMk singleton and postinstall commands.
@@ -56,6 +59,31 @@
 	} else {
 		ctx.Fatalln("Missing BUILD_DATETIME_FILE")
 	}
+
+	// BUILD_NUMBER should be set to the source control value that
+	// represents the current state of the source code.  E.g., a
+	// perforce changelist number or a git hash.  Can be an arbitrary string
+	// (to allow for source control that uses something other than numbers),
+	// but must be a single word and a valid file name.
+	//
+	// If no BUILD_NUMBER is set, create a useful "I am an engineering build
+	// from this date/time" value.  Make it start with a non-digit so that
+	// anyone trying to parse it as an integer will probably get "0".
+	buildNumber, ok := config.environ.Get("BUILD_NUMBER")
+	if ok {
+		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", buildNumber)
+	} else {
+		var username string
+		if username, ok = config.environ.Get("BUILD_USERNAME"); !ok {
+			ctx.Fatalln("Missing BUILD_USERNAME")
+		}
+		buildNumber = fmt.Sprintf("eng.%.6s.%s", username, time.Now().Format("20060102.150405" /* YYYYMMDD.HHMMSS */))
+		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
+	}
+	// Write the build number to a file so it can be read back in
+	// without changing the command line every time.  Avoids rebuilds
+	// when using ninja.
+	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber)
 }
 
 var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
@@ -246,8 +274,6 @@
 	// checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
 	checkCaseSensitivity(ctx, config)
 
-	ensureEmptyDirectoriesExist(ctx, config.TempDir())
-
 	SetupPath(ctx, config)
 
 	what := evaluateWhatToRun(config, ctx.Verboseln)
diff --git a/ui/build/config.go b/ui/build/config.go
index 084d28d..f80868c 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -22,6 +22,7 @@
 	"math/rand"
 	"os"
 	"os/exec"
+	"os/user"
 	"path/filepath"
 	"runtime"
 	"strconv"
@@ -455,6 +456,16 @@
 
 	ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
 
+	if _, ok := ret.environ.Get("BUILD_USERNAME"); !ok {
+		username := "unknown"
+		if u, err := user.Current(); err == nil {
+			username = u.Username
+		} else {
+			ctx.Println("Failed to get current user:", err)
+		}
+		ret.environ.Set("BUILD_USERNAME", username)
+	}
+
 	if ret.UseRBE() {
 		for k, v := range getRBEVars(ctx, Config{ret}) {
 			ret.environ.Set(k, v)
diff --git a/ui/build/kati.go b/ui/build/kati.go
index aea56d3..31e7440 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -15,6 +15,8 @@
 package build
 
 import (
+	"android/soong/ui/metrics"
+	"android/soong/ui/status"
 	"crypto/md5"
 	"fmt"
 	"io/ioutil"
@@ -22,10 +24,6 @@
 	"os/user"
 	"path/filepath"
 	"strings"
-	"time"
-
-	"android/soong/ui/metrics"
-	"android/soong/ui/status"
 )
 
 var spaceSlashReplacer = strings.NewReplacer("/", "_", " ", "_")
@@ -198,32 +196,14 @@
 		}
 	}
 	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname)
-
-	// BUILD_NUMBER should be set to the source control value that
-	// represents the current state of the source code.  E.g., a
-	// perforce changelist number or a git hash.  Can be an arbitrary string
-	// (to allow for source control that uses something other than numbers),
-	// but must be a single word and a valid file name.
-	//
-	// If no BUILD_NUMBER is set, create a useful "I am an engineering build
-	// from this date/time" value.  Make it start with a non-digit so that
-	// anyone trying to parse it as an integer will probably get "0".
-	cmd.Environment.Unset("HAS_BUILD_NUMBER")
-	buildNumber, ok := cmd.Environment.Get("BUILD_NUMBER")
+	_, ok = cmd.Environment.Get("BUILD_NUMBER")
 	// Unset BUILD_NUMBER during kati run to avoid kati rerun, kati will use BUILD_NUMBER from a file.
 	cmd.Environment.Unset("BUILD_NUMBER")
 	if ok {
 		cmd.Environment.Set("HAS_BUILD_NUMBER", "true")
-		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", buildNumber)
 	} else {
-		buildNumber = fmt.Sprintf("eng.%.6s.%s", username, time.Now().Format("20060102.150405" /* YYYYMMDD.HHMMSS */))
 		cmd.Environment.Set("HAS_BUILD_NUMBER", "false")
-		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
 	}
-	// Write the build number to a file so it can be read back in
-	// without changing the command line every time.  Avoids rebuilds
-	// when using ninja.
-	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber)
 
 	// Apply the caller's function closure to mutate the environment variables.
 	envFunc(cmd.Environment)
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 44c20a0..ac9bf3a 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -16,10 +16,13 @@
 
 import (
 	"fmt"
+	"io/fs"
 	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
+	"sync"
+	"sync/atomic"
 
 	"android/soong/bazel"
 	"android/soong/ui/metrics"
@@ -50,6 +53,13 @@
 	bootstrapEpoch = 1
 )
 
+var (
+	// Used during parallel update of symlinks in out directory to reflect new
+	// TOP dir.
+	symlinkWg            sync.WaitGroup
+	numFound, numUpdated uint32
+)
+
 func writeEnvironmentFile(_ Context, envFile string, envDeps map[string]string) error {
 	data, err := shared.EnvFileContents(envDeps)
 	if err != nil {
@@ -465,10 +475,118 @@
 	}
 }
 
+func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error {
+	defer symlinkWg.Done()
+
+	visit := func(path string, d fs.DirEntry, err error) error {
+		if d.IsDir() && path != dir {
+			symlinkWg.Add(1)
+			go updateSymlinks(ctx, path, prevCWD, cwd)
+			return filepath.SkipDir
+		}
+		f, err := d.Info()
+		if err != nil {
+			return err
+		}
+		// If the file is not a symlink, we don't have to update it.
+		if f.Mode()&os.ModeSymlink != os.ModeSymlink {
+			return nil
+		}
+
+		atomic.AddUint32(&numFound, 1)
+		target, err := os.Readlink(path)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(target, prevCWD) &&
+			(len(target) == len(prevCWD) || target[len(prevCWD)] == '/') {
+			target = filepath.Join(cwd, target[len(prevCWD):])
+			if err := os.Remove(path); err != nil {
+				return err
+			}
+			if err := os.Symlink(target, path); err != nil {
+				return err
+			}
+			atomic.AddUint32(&numUpdated, 1)
+		}
+		return nil
+	}
+
+	if err := filepath.WalkDir(dir, visit); err != nil {
+		return err
+	}
+	return nil
+}
+
+func fixOutDirSymlinks(ctx Context, config Config, outDir string) error {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return err
+	}
+
+	// Record the .top as the very last thing in the function.
+	tf := filepath.Join(outDir, ".top")
+	defer func() {
+		if err := os.WriteFile(tf, []byte(cwd), 0644); err != nil {
+			fmt.Fprintf(os.Stderr, fmt.Sprintf("Unable to log CWD: %v", err))
+		}
+	}()
+
+	// Find the previous working directory if it was recorded.
+	var prevCWD string
+	pcwd, err := os.ReadFile(tf)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No previous working directory recorded, nothing to do.
+			return nil
+		}
+		return err
+	}
+	prevCWD = strings.Trim(string(pcwd), "\n")
+
+	if prevCWD == cwd {
+		// We are in the same source dir, nothing to update.
+		return nil
+	}
+
+	symlinkWg.Add(1)
+	if err := updateSymlinks(ctx, outDir, prevCWD, cwd); err != nil {
+		return err
+	}
+	symlinkWg.Wait()
+	ctx.Println(fmt.Sprintf("Updated %d/%d symlinks in dir %v", numUpdated, numFound, outDir))
+	return nil
+}
+
+func migrateOutputSymlinks(ctx Context, config Config) error {
+	// Figure out the real out directory ("out" could be a symlink).
+	outDir := config.OutDir()
+	s, err := os.Lstat(outDir)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No out dir exists, no symlinks to migrate.
+			return nil
+		}
+		return err
+	}
+	if s.Mode()&os.ModeSymlink == os.ModeSymlink {
+		target, err := filepath.EvalSymlinks(outDir)
+		if err != nil {
+			return err
+		}
+		outDir = target
+	}
+	return fixOutDirSymlinks(ctx, config, outDir)
+}
+
 func runSoong(ctx Context, config Config) {
 	ctx.BeginTrace(metrics.RunSoong, "soong")
 	defer ctx.EndTrace()
 
+	if err := migrateOutputSymlinks(ctx, config); err != nil {
+		ctx.Fatalf("failed to migrate output directory to current TOP dir: %v", err)
+	}
+
 	// We have two environment files: .available is the one with every variable,
 	// .used with the ones that were actually used. The latter is used to
 	// determine whether Soong needs to be re-run since why re-run it if only