Merge "Revert^2 "Update clang version to clang-r487747""
diff --git a/README.md b/README.md
index 7f18463..85e24c6 100644
--- a/README.md
+++ b/README.md
@@ -184,7 +184,7 @@
 
 ```
 package {
-    default_visibility: [":__subpackages"]
+    default_visibility: [":__subpackages__"]
 }
 ```
 
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 45b8043..5203fa0 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -125,6 +125,7 @@
 		"external/eigen":                         Bp2BuildDefaultTrueRecursively,
 		"external/erofs-utils":                   Bp2BuildDefaultTrueRecursively,
 		"external/error_prone":                   Bp2BuildDefaultTrueRecursively,
+		"external/escapevelocity":                Bp2BuildDefaultTrueRecursively,
 		"external/expat":                         Bp2BuildDefaultTrueRecursively,
 		"external/f2fs-tools":                    Bp2BuildDefaultTrue,
 		"external/flac":                          Bp2BuildDefaultTrueRecursively,
@@ -216,47 +217,51 @@
 		"frameworks/native/services/batteryservice":          Bp2BuildDefaultTrue,
 		"frameworks/proto_logging/stats":                     Bp2BuildDefaultTrueRecursively,
 
-		"hardware/interfaces":                          Bp2BuildDefaultTrue,
-		"hardware/interfaces/audio/aidl":               Bp2BuildDefaultTrue,
-		"hardware/interfaces/audio/aidl/common":        Bp2BuildDefaultTrue,
-		"hardware/interfaces/common/aidl":              Bp2BuildDefaultTrue,
-		"hardware/interfaces/common/fmq/aidl":          Bp2BuildDefaultTrue,
-		"hardware/interfaces/configstore/1.0":          Bp2BuildDefaultTrue,
-		"hardware/interfaces/configstore/1.1":          Bp2BuildDefaultTrue,
-		"hardware/interfaces/configstore/utils":        Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/2.0":   Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/3.0":   Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/4.0":   Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/aidl":  Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/bufferqueue/1.0": Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/bufferqueue/2.0": Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/1.0":      Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/1.1":      Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/1.2":      Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/aidl":     Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/2.0":      Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/2.1":      Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/3.0":      Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/4.0":      Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/1.0":               Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/1.0/default":       Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/2.0":               Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/2.0/default":       Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/2.0/utils":         Bp2BuildDefaultTrueRecursively,
-		"hardware/interfaces/health/2.1":               Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/aidl":              Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/utils":             Bp2BuildDefaultTrueRecursively,
-		"hardware/interfaces/media/1.0":                Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/bufferpool/2.0":     Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/c2/1.0":             Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/c2/1.1":             Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/c2/1.2":             Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/omx/1.0":            Bp2BuildDefaultTrue,
-		"hardware/interfaces/neuralnetworks/1.0":       Bp2BuildDefaultTrue,
-		"hardware/interfaces/neuralnetworks/1.1":       Bp2BuildDefaultTrue,
-		"hardware/interfaces/neuralnetworks/1.2":       Bp2BuildDefaultTrue,
-		"hardware/interfaces/neuralnetworks/1.3":       Bp2BuildDefaultTrue,
-		"hardware/interfaces/neuralnetworks/aidl":      Bp2BuildDefaultTrue,
+		"hardware/interfaces":                                     Bp2BuildDefaultTrue,
+		"hardware/interfaces/audio/aidl":                          Bp2BuildDefaultTrue,
+		"hardware/interfaces/audio/aidl/common":                   Bp2BuildDefaultTrue,
+		"hardware/interfaces/common/aidl":                         Bp2BuildDefaultTrue,
+		"hardware/interfaces/common/fmq/aidl":                     Bp2BuildDefaultTrue,
+		"hardware/interfaces/common/support":                      Bp2BuildDefaultTrue,
+		"hardware/interfaces/configstore/1.0":                     Bp2BuildDefaultTrue,
+		"hardware/interfaces/configstore/1.1":                     Bp2BuildDefaultTrue,
+		"hardware/interfaces/configstore/utils":                   Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/2.0":              Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/3.0":              Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/4.0":              Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/aidl":             Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/bufferqueue/1.0":            Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/bufferqueue/2.0":            Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/1.0":                 Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/1.1":                 Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/1.2":                 Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/aidl":                Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/2.0":                 Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/2.1":                 Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/3.0":                 Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/4.0":                 Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/1.0":                          Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/1.0/default":                  Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/2.0":                          Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/2.0/default":                  Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/2.0/utils":                    Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/health/2.1":                          Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/aidl":                         Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/utils":                        Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/media/1.0":                           Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/bufferpool":                    Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/media/bufferpool/aidl/default/tests": Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/media/c2/1.0":                        Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/c2/1.1":                        Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/c2/1.2":                        Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/omx/1.0":                       Bp2BuildDefaultTrue,
+		"hardware/interfaces/neuralnetworks":                      Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/neuralnetworks/aidl/vts":             Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/neuralnetworks/1.0/vts":              Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/neuralnetworks/1.1/vts":              Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/neuralnetworks/1.2/vts":              Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/neuralnetworks/1.3/vts":              Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/neuralnetworks/1.4/vts":              Bp2BuildDefaultFalseRecursively,
 
 		"libnativehelper": Bp2BuildDefaultTrueRecursively,
 
@@ -398,7 +403,7 @@
 		"prebuilts/clang-tools":/* recursive = */ true,
 		"prebuilts/gcc":/* recursive = */ true,
 		"prebuilts/build-tools":/* recursive = */ true,
-		"prebuilts/jdk/jdk11":/* recursive = */ false,
+		"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,
 		"prebuilts/sdk/tools":/* recursive = */ false,
@@ -437,7 +442,6 @@
 		"gemmlowp_headers",
 		"gl_headers",
 		"ipconnectivity-proto-src",
-		"libaidlcommonsupport",
 		"libandroid_runtime_lazy",
 		"libandroid_runtime_vm_headers",
 		"libaudioclient_aidl_conversion_util",
@@ -499,13 +503,6 @@
 		"mediaswcodec.policy",
 		"mediaswcodec.xml",
 		"neuralnetworks_types",
-		"neuralnetworks_utils_hal_aidl",
-		"neuralnetworks_utils_hal_common",
-		"neuralnetworks_utils_hal_service",
-		"neuralnetworks_utils_hal_1_0",
-		"neuralnetworks_utils_hal_1_1",
-		"neuralnetworks_utils_hal_1_2",
-		"neuralnetworks_utils_hal_1_3",
 		"libneuralnetworks_common",
 		// packagemanager_aidl_interface is created implicitly in packagemanager_aidl module
 		"packagemanager_aidl_interface",
@@ -704,6 +701,14 @@
 		"kotlinx_coroutines",
 		"annotations",
 		"kotlinx-coroutines-android-annotation-stubs",
+
+		// for building com.android.neuralnetworks
+		"libimapper_stablec",
+		"libimapper_providerutils",
+
+		// min_sdk_version in android_app
+		"CtsShimUpgrade",
+		"fake-framework",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -726,15 +731,6 @@
 	// the "prebuilt_" prefix to the name, so that it's differentiable from
 	// the source versions within Soong's module graph.
 	Bp2buildModuleDoNotConvertList = []string{
-		// TODO(b/250876486): Created cc_aidl_library doesn't have static libs from parent cc module
-		"libgui_window_info_static",
-		"libgui",     // Depends on unconverted libgui_window_info_static
-		"libdisplay", // Depends on uncovnerted libgui
-		// Depends on unconverted libdisplay
-		"libdvr_static.google",
-		"libdvr.google",
-		"libvrsensor",
-		"dvr_api-test",
 		// Depends on unconverted libandroid, libgui
 		"dvr_buffer_queue-test",
 		"dvr_display-test",
@@ -863,6 +859,9 @@
 		"android.hardware.health-translate-java",
 
 		// cc_test related.
+		// b/274164834 "Could not open Configuration file test.cfg"
+		"svcenc", "svcdec",
+
 		// Failing host cc_tests
 		"memunreachable_unit_test",
 		"libprocinfo_test",
@@ -1412,25 +1411,29 @@
 		"unwind",
 		"unwind_info",
 		"unwind_symbols",
-		"libc_malloc_debug",
-		"libfdtrack",
-		"mediaswcodec",
-		"libcodec2_hidl@1.0",
 		"libEGL",
-		"libstagefright_bufferqueue_helper_novndk",
 		"libGLESv2",
+		"libc_malloc_debug",
+		"libcodec2_hidl@1.0",
 		"libcodec2_hidl@1.1",
-		"libmedia_codecserviceregistrant",
 		"libcodec2_hidl@1.2",
+		"libfdtrack",
+		"libgui",
+		"libgui_bufferqueue_static",
+		"libmedia_codecserviceregistrant",
+		"libstagefright_bufferqueue_helper_novndk",
 		"libutils_test",
 		"libutilscallstack",
+		"mediaswcodec",
 	}
 
 	// Bazel prod-mode allowlist. Modules in this list are built by Bazel
 	// in either prod mode or staging mode.
 	ProdMixedBuildsEnabledList = []string{
+		// M5: tzdata launch
 		"com.android.tzdata",
 		"test1_com.android.tzdata",
+		// M7: adbd launch
 		"com.android.adbd",
 		"test_com.android.adbd",
 		"adbd_test",
@@ -1438,6 +1441,8 @@
 		"adb_pairing_auth_test",
 		"adb_pairing_connection_test",
 		"adb_tls_connection_test",
+		// M9: mixed builds for mainline trains launch
+		"api_fingerprint",
 	}
 
 	// Staging-mode allowlist. Modules in this list are only built
@@ -1445,21 +1450,19 @@
 	// which will soon be added to the prod allowlist.
 	// It is implicit that all modules in ProdMixedBuildsEnabledList will
 	// also be built - do not add them to this list.
-	StagingMixedBuildsEnabledList = []string{
-		"api_fingerprint",
-	}
+	StagingMixedBuildsEnabledList = []string{}
 
 	// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
-	ProdDclaMixedBuildsEnabledList = []string{}
-
-	// These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
-	StagingDclaMixedBuildsEnabledList = []string{
+	ProdDclaMixedBuildsEnabledList = []string{
 		"libbase",
 		"libc++",
 		"libcrypto",
 		"libcutils",
 	}
 
+	// These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
+	StagingDclaMixedBuildsEnabledList = []string{}
+
 	// TODO(b/269342245): Enable the rest of the DCLA libs
 	// "libssl",
 	// "libstagefright_flacdec",
diff --git a/android/apex.go b/android/apex.go
index 358818f..87bff74 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -845,7 +845,7 @@
 // ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
 type ModuleWithMinSdkVersionCheck interface {
 	Module
-	MinSdkVersion(ctx EarlyModuleContext) SdkSpec
+	MinSdkVersion(ctx EarlyModuleContext) ApiLevel
 	CheckMinSdkVersion(ctx ModuleContext)
 }
 
diff --git a/android/api_levels.go b/android/api_levels.go
index 9440ee9..0c0b2b4 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -55,6 +55,9 @@
 }
 
 func (this ApiLevel) FinalInt() int {
+	if this.IsInvalid() {
+		panic(fmt.Errorf("%v is not a recognized api_level\n", this))
+	}
 	if this.IsPreview() {
 		panic("Requested a final int from a non-final ApiLevel")
 	} else {
@@ -63,6 +66,9 @@
 }
 
 func (this ApiLevel) FinalOrFutureInt() int {
+	if this.IsInvalid() {
+		panic(fmt.Errorf("%v is not a recognized api_level\n", this))
+	}
 	if this.IsPreview() {
 		return FutureApiLevelInt
 	} else {
@@ -76,6 +82,9 @@
 // - preview codenames -> preview base (9000) + index
 // - otherwise -> cast to int
 func (this ApiLevel) FinalOrPreviewInt() int {
+	if this.IsInvalid() {
+		panic(fmt.Errorf("%v is not a recognized api_level\n", this))
+	}
 	if this.IsCurrent() {
 		return this.number
 	}
@@ -97,6 +106,11 @@
 	return this.isPreview
 }
 
+// Returns true if the raw api level string is invalid
+func (this ApiLevel) IsInvalid() bool {
+	return this.EqualTo(InvalidApiLevel)
+}
+
 // Returns true if this is the unfinalized "current" API level. This means
 // different things across Java and native. Java APIs do not use explicit
 // codenames, so all non-final codenames are grouped into "current". For native
@@ -113,6 +127,72 @@
 	return this.number == -1
 }
 
+// Returns true if an app is compiling against private apis.
+// e.g. if sdk_version = "" in Android.bp, then the ApiLevel of that "sdk" is at PrivateApiLevel.
+func (this ApiLevel) IsPrivate() bool {
+	return this.number == PrivateApiLevel.number
+}
+
+// EffectiveVersion converts an ApiLevel into the concrete ApiLevel that the module should use. For
+// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns
+// FutureApiLevel(10000).
+func (l ApiLevel) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) {
+	if l.EqualTo(InvalidApiLevel) {
+		return l, fmt.Errorf("invalid version in sdk_version %q", l.value)
+	}
+	if !l.IsPreview() {
+		return l, nil
+	}
+	ret := ctx.Config().DefaultAppTargetSdk(ctx)
+	if ret.IsPreview() {
+		return FutureApiLevel, nil
+	}
+	return ret, nil
+}
+
+// EffectiveVersionString converts an SdkSpec into the concrete version string that the module
+// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
+// it returns the codename (P, Q, R, etc.)
+func (l ApiLevel) EffectiveVersionString(ctx EarlyModuleContext) (string, error) {
+	if l.EqualTo(InvalidApiLevel) {
+		return l.value, fmt.Errorf("invalid version in sdk_version %q", l.value)
+	}
+	if !l.IsPreview() {
+		return l.String(), nil
+	}
+	// Determine the default sdk
+	ret := ctx.Config().DefaultAppTargetSdk(ctx)
+	if !ret.IsPreview() {
+		// If the default sdk has been finalized, return that
+		return ret.String(), nil
+	}
+	// There can be more than one active in-development sdks
+	// If an app is targeting an active sdk, but not the default one, return the requested active sdk.
+	// e.g.
+	// SETUP
+	// In-development: UpsideDownCake, VanillaIceCream
+	// Default: VanillaIceCream
+	// Android.bp
+	// min_sdk_version: `UpsideDownCake`
+	// RETURN
+	// UpsideDownCake and not VanillaIceCream
+	for _, preview := range ctx.Config().PreviewApiLevels() {
+		if l.String() == preview.String() {
+			return preview.String(), nil
+		}
+	}
+	// Otherwise return the default one
+	return ret.String(), nil
+}
+
+// Specified returns true if the module is targeting a recognzized api_level.
+// It returns false if either
+// 1. min_sdk_version is not an int or a recognized codename
+// 2. both min_sdk_version and sdk_version are empty. In this case, MinSdkVersion() defaults to SdkSpecPrivate.ApiLevel
+func (this ApiLevel) Specified() bool {
+	return !this.IsInvalid() && !this.IsPrivate()
+}
+
 // Returns -1 if the current API level is less than the argument, 0 if they
 // are equal, and 1 if it is greater than the argument.
 func (this ApiLevel) CompareTo(other ApiLevel) int {
@@ -166,6 +246,19 @@
 	isPreview: true,
 }
 
+// Sentinel ApiLevel to validate that an apiLevel is either an int or a recognized codename.
+var InvalidApiLevel = NewInvalidApiLevel("invalid")
+
+// Returns an apiLevel object at the same level as InvalidApiLevel.
+// The object contains the raw string provied in bp file, and can be used for error handling.
+func NewInvalidApiLevel(raw string) ApiLevel {
+	return ApiLevel{
+		value:     raw,
+		number:    -2, // One less than NoneApiLevel
+		isPreview: true,
+	}
+}
+
 // The first version that introduced 64-bit ABIs.
 var FirstLp64Version = uncheckedFinalApiLevel(21)
 
@@ -204,6 +297,16 @@
 	return strconv.Itoa(num)
 }
 
+// ApiLevelFrom converts the given string `raw` to an ApiLevel.
+// If `raw` is invalid (empty string, unrecognized codename etc.) it returns an invalid ApiLevel
+func ApiLevelFrom(ctx PathContext, raw string) ApiLevel {
+	ret, err := ApiLevelFromUser(ctx, raw)
+	if err != nil {
+		return NewInvalidApiLevel(raw)
+	}
+	return ret
+}
+
 // ApiLevelFromUser converts the given string `raw` to an ApiLevel, possibly returning an error.
 //
 // `raw` must be non-empty. Passing an empty string results in a panic.
diff --git a/android/arch.go b/android/arch.go
index 6acf9cf..4b4691b 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1694,6 +1694,7 @@
 	return []archConfig{
 		{"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
 		{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
+		{"riscv64", "", "", []string{"riscv64"}},
 		{"x86_64", "", "", []string{"x86_64"}},
 		{"x86", "", "", []string{"x86"}},
 	}
diff --git a/android/arch_test.go b/android/arch_test.go
index e445ec6..5021a67 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -401,7 +401,7 @@
 		{
 			name: "same arch host and host cross",
 			preparer: FixtureModifyConfig(func(config Config) {
-				modifyTestConfigForMusl(config)
+				ModifyTestConfigForMusl(config)
 				modifyTestConfigForMuslArm64HostCross(config)
 			}),
 			fooVariants:         []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
@@ -705,7 +705,7 @@
 		{
 			name:     "linux_musl",
 			goOS:     "linux",
-			preparer: FixtureModifyConfig(modifyTestConfigForMusl),
+			preparer: FixtureModifyConfig(ModifyTestConfigForMusl),
 			results: []result{
 				{
 					module:   "foo",
diff --git a/android/bazel.go b/android/bazel.go
index 782632b..1646883 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -357,6 +357,8 @@
 	mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
 		ctx.Os() != Windows && // Windows toolchains are not currently supported.
 		ctx.Os() != LinuxBionic && // Linux Bionic toolchains are not currently supported.
+		ctx.Os() != LinuxMusl && // Linux musl toolchains are not currently supported (b/259266326).
+		ctx.Arch().ArchType != Riscv64 && // TODO(b/262192655) Riscv64 toolchains are not currently supported.
 		module.Enabled() &&
 		convertedToBazel(ctx, module) &&
 		ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index e7b84e3..44dc055 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -736,15 +736,6 @@
 		// TODO(asmundak): is it needed in every build?
 		"--profile=" + shared.BazelMetricsFilename(paths, runName),
 
-		// Set default platforms to canonicalized values for mixed builds requests.
-		// If these are set in the bazelrc, they will have values that are
-		// non-canonicalized to @sourceroot labels, and thus be invalid when
-		// referenced from the buildroot.
-		//
-		// The actual platform values here may be overridden by configuration
-		// transitions from the buildroot.
-		fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"),
-
 		// We don't need to set --host_platforms because it's set in bazelrc files
 		// that the bazel shell script wrapper passes
 
@@ -1009,31 +1000,6 @@
 	formatString := `
 # This file is generated by soong_build. Do not edit.
 
-# a drop-in replacement for json.encode(), not available in cquery environment
-# TODO(cparsons): bring json module in and remove this function
-def json_encode(input):
-  # Avoiding recursion by limiting
-  #  - a dict to contain anything except a dict
-  #  - a list to contain only primitives
-  def encode_primitive(p):
-    t = type(p)
-    if t == "string" or t == "int":
-      return repr(p)
-    fail("unsupported value '%s' of type '%s'" % (p, type(p)))
-
-  def encode_list(list):
-    return "[%s]" % ", ".join([encode_primitive(item) for item in list])
-
-  def encode_list_or_primitive(v):
-    return encode_list(v) if type(v) == "list" else encode_primitive(v)
-
-  if type(input) == "dict":
-    # TODO(juu): the result is read line by line so can't use '\n' yet
-    kv_pairs = [("%s: %s" % (encode_primitive(k), encode_list_or_primitive(v))) for (k, v) in input.items()]
-    return "{ %s }" % ", ".join(kv_pairs)
-  else:
-    return encode_list_or_primitive(input)
-
 {LABEL_REGISTRATION_MAP_SECTION}
 
 {FUNCTION_DEF_SECTION}
diff --git a/android/config.go b/android/config.go
index 8494626..e0b661b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -52,6 +52,15 @@
 // FutureApiLevelInt is a placeholder constant for unreleased API levels.
 const FutureApiLevelInt = 10000
 
+// PrivateApiLevel represents the api level of SdkSpecPrivate (sdk_version: "")
+// This api_level exists to differentiate user-provided "" from "current" sdk_version
+// The differentiation is necessary to enable different validation rules for these two possible values.
+var PrivateApiLevel = ApiLevel{
+	value:     "current",             // The value is current since aidl expects `current` as the default (TestAidlFlagsWithMinSdkVersion)
+	number:    FutureApiLevelInt + 1, // This is used to differentiate it from FutureApiLevel
+	isPreview: true,
+}
+
 // FutureApiLevel represents unreleased API levels.
 var FutureApiLevel = ApiLevel{
 	value:     "current",
@@ -83,6 +92,8 @@
 	ModuleActionsFile   string
 	DocFile             string
 
+	MultitreeBuild bool
+
 	BazelMode                bool
 	BazelModeDev             bool
 	BazelModeStaging         bool
@@ -229,6 +240,10 @@
 	Bp2buildPackageConfig          Bp2BuildConversionAllowlist
 	Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
 
+	// If MultitreeBuild is true then this is one inner tree of a multitree
+	// build directed by the multitree orchestrator.
+	MultitreeBuild bool
+
 	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
 	// in tests when a path doesn't exist.
 	TestAllowNonExistentPaths bool
@@ -449,7 +464,8 @@
 		mixedBuildEnabledModules:  make(map[string]struct{}),
 		bazelForceEnabledModules:  make(map[string]struct{}),
 
-		UseBazelProxy: cmdArgs.UseBazelProxy,
+		MultitreeBuild: cmdArgs.MultitreeBuild,
+		UseBazelProxy:  cmdArgs.UseBazelProxy,
 	}
 
 	config.deviceConfig = &deviceConfig{
diff --git a/android/fixture.go b/android/fixture.go
index c2b16f6..dbc3bc5 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"runtime"
 	"strings"
 	"testing"
 )
@@ -379,6 +380,12 @@
 	})
 }
 
+var PrepareForSkipTestOnMac = newSimpleFixturePreparer(func(fixture *fixture) {
+	if runtime.GOOS != "linux" {
+		fixture.t.Skip("Test is only supported on linux.")
+	}
+})
+
 // PrepareForDebug_DO_NOT_SUBMIT puts the fixture into debug which will cause it to output its
 // state before running the test.
 //
diff --git a/android/module.go b/android/module.go
index 773d77b..76fe8dc 100644
--- a/android/module.go
+++ b/android/module.go
@@ -37,26 +37,64 @@
 	DeviceStaticLibrary = "static_library"
 )
 
+// BuildParameters describes the set of potential parameters to build a Ninja rule.
+// In general, these correspond to a Ninja concept.
 type BuildParams struct {
-	Rule            blueprint.Rule
-	Deps            blueprint.Deps
-	Depfile         WritablePath
-	Description     string
-	Output          WritablePath
-	Outputs         WritablePaths
-	SymlinkOutput   WritablePath
-	SymlinkOutputs  WritablePaths
-	ImplicitOutput  WritablePath
+	// A Ninja Rule that will be written to the Ninja file. This allows factoring out common code
+	// among multiple modules to reduce repetition in the Ninja file of action requirements. A rule
+	// can contain variables that should be provided in Args.
+	Rule blueprint.Rule
+	// Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles
+	// are used.
+	Deps blueprint.Deps
+	// Depfile is a writeable path that allows correct incremental builds when the inputs have not
+	// been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax.
+	Depfile WritablePath
+	// A description of the build action.
+	Description string
+	// Output is an output file of the action. When using this field, references to $out in the Ninja
+	// command will refer to this file.
+	Output WritablePath
+	// Outputs is a slice of output file of the action. When using this field, references to $out in
+	// the Ninja command will refer to these files.
+	Outputs WritablePaths
+	// SymlinkOutput is an output file specifically that is a symlink.
+	SymlinkOutput WritablePath
+	// SymlinkOutputs is a slice of output files specifically that is a symlink.
+	SymlinkOutputs WritablePaths
+	// ImplicitOutput is an output file generated by the action. Note: references to `$out` in the
+	// Ninja command will NOT include references to this file.
+	ImplicitOutput WritablePath
+	// ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out`
+	// in the Ninja command will NOT include references to these files.
 	ImplicitOutputs WritablePaths
-	Input           Path
-	Inputs          Paths
-	Implicit        Path
-	Implicits       Paths
-	OrderOnly       Paths
-	Validation      Path
-	Validations     Paths
-	Default         bool
-	Args            map[string]string
+	// Input is an input file to the Ninja action. When using this field, references to $in in the
+	// Ninja command will refer to this file.
+	Input Path
+	// Inputs is a slice of input files to the Ninja action. When using this field, references to $in
+	// in the Ninja command will refer to these files.
+	Inputs Paths
+	// Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command
+	// will NOT include references to this file.
+	Implicit Path
+	// Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja
+	// command will NOT include references to these files.
+	Implicits Paths
+	// OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is
+	// not rebuilt until they are built, but changes in order-only dependencies alone do not cause the
+	// output to be rebuilt.
+	OrderOnly Paths
+	// Validation is an output path for a validation action. Validation outputs imply lower
+	// non-blocking priority to building non-validation outputs.
+	Validation Path
+	// Validations is a slice of output path for a validation action. Validation outputs imply lower
+	// non-blocking priority to building non-validation outputs.
+	Validations Paths
+	// Whether to skip outputting a default target statement which will be built by Ninja when no
+	// targets are specified on Ninja's command line.
+	Default bool
+	// Args is a key value mapping for replacements of variables within the Rule
+	Args map[string]string
 }
 
 type ModuleBuildParams BuildParams
diff --git a/android/sdk.go b/android/sdk.go
index 8b23d63..63e0bbe 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -25,7 +25,7 @@
 
 // minApiLevelForSdkSnapshot provides access to the min_sdk_version for MinApiLevelForSdkSnapshot
 type minApiLevelForSdkSnapshot interface {
-	MinSdkVersion(ctx EarlyModuleContext) SdkSpec
+	MinSdkVersion(ctx EarlyModuleContext) ApiLevel
 }
 
 // MinApiLevelForSdkSnapshot returns the ApiLevel of the min_sdk_version of the supplied module.
@@ -34,7 +34,7 @@
 func MinApiLevelForSdkSnapshot(ctx EarlyModuleContext, module Module) ApiLevel {
 	minApiLevel := NoneApiLevel
 	if m, ok := module.(minApiLevelForSdkSnapshot); ok {
-		minApiLevel = m.MinSdkVersion(ctx).ApiLevel
+		minApiLevel = m.MinSdkVersion(ctx)
 	}
 	if minApiLevel == NoneApiLevel {
 		// The default min API level is 1.
diff --git a/android/sdk_version.go b/android/sdk_version.go
index a7e03dc..7ace638 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -25,15 +25,15 @@
 	SdkVersion(ctx EarlyModuleContext) SdkSpec
 	// SystemModules returns the system_modules property of the current module, or an empty string if it is not set.
 	SystemModules() string
-	// MinSdkVersion returns SdkSpec that corresponds to the min_sdk_version property of the current module,
+	// MinSdkVersion returns ApiLevel that corresponds to the min_sdk_version property of the current module,
 	// or from sdk_version if it is not set.
-	MinSdkVersion(ctx EarlyModuleContext) SdkSpec
+	MinSdkVersion(ctx EarlyModuleContext) ApiLevel
 	// ReplaceMaxSdkVersionPlaceholder returns SdkSpec to replace the maxSdkVersion property of permission and
 	// uses-permission tags if it is set.
 	ReplaceMaxSdkVersionPlaceholder(ctx EarlyModuleContext) SdkSpec
-	// TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module,
+	// TargetSdkVersion returns the ApiLevel that corresponds to the target_sdk_version property of the current module,
 	// or from sdk_version if it is not set.
-	TargetSdkVersion(ctx EarlyModuleContext) SdkSpec
+	TargetSdkVersion(ctx EarlyModuleContext) ApiLevel
 }
 
 // SdkKind represents a particular category of an SDK spec like public, system, test, etc.
@@ -84,6 +84,40 @@
 	}
 }
 
+// JavaLibraryName returns the soong module containing the Java APIs of that API surface.
+func (k SdkKind) JavaLibraryName(c Config) string {
+	name := k.defaultJavaLibraryName()
+	return JavaLibraryNameFromText(c, name)
+}
+
+// JavaLibraryNameFromText returns the name of .txt equivalent of a java_library, but does
+// not check if either module exists.
+// TODO: Return .txt (single-tree or multi-tree equivalents) based on config
+func JavaLibraryNameFromText(c Config, name string) string {
+	// This returns the default for now.
+	// TODO: Implement this
+	return name
+}
+
+func (k SdkKind) defaultJavaLibraryName() string {
+	switch k {
+	case SdkPublic:
+		return "android_stubs_current"
+	case SdkSystem:
+		return "android_system_stubs_current"
+	case SdkTest:
+		return "android_test_stubs_current"
+	case SdkCore:
+		return "core.current.stubs"
+	case SdkModule:
+		return "android_module_lib_stubs_current"
+	case SdkSystemServer:
+		return "android_system_server_stubs_current"
+	default:
+		panic(fmt.Errorf("APIs of API surface %v cannot be provided by a single Soong module\n", k))
+	}
+}
+
 // SdkSpec represents the kind and the version of an SDK for a module to build against
 type SdkSpec struct {
 	Kind     SdkKind
@@ -187,14 +221,7 @@
 	if ctx.DeviceSpecific() || ctx.SocSpecific() {
 		s = s.ForVendorPartition(ctx)
 	}
-	if !s.ApiLevel.IsPreview() {
-		return s.ApiLevel, nil
-	}
-	ret := ctx.Config().DefaultAppTargetSdk(ctx)
-	if ret.IsPreview() {
-		return FutureApiLevel, nil
-	}
-	return ret, nil
+	return s.ApiLevel.EffectiveVersion(ctx)
 }
 
 // EffectiveVersionString converts an SdkSpec into the concrete version string that the module
@@ -208,37 +235,12 @@
 	if ctx.DeviceSpecific() || ctx.SocSpecific() {
 		s = s.ForVendorPartition(ctx)
 	}
-	if !s.ApiLevel.IsPreview() {
-		return s.ApiLevel.String(), nil
-	}
-	// Determine the default sdk
-	ret := ctx.Config().DefaultAppTargetSdk(ctx)
-	if !ret.IsPreview() {
-		// If the default sdk has been finalized, return that
-		return ret.String(), nil
-	}
-	// There can be more than one active in-development sdks
-	// If an app is targeting an active sdk, but not the default one, return the requested active sdk.
-	// e.g.
-	// SETUP
-	// In-development: UpsideDownCake, VanillaIceCream
-	// Default: VanillaIceCream
-	// Android.bp
-	// min_sdk_version: `UpsideDownCake`
-	// RETURN
-	// UpsideDownCake and not VanillaIceCream
-	for _, preview := range ctx.Config().PreviewApiLevels() {
-		if s.ApiLevel.String() == preview.String() {
-			return preview.String(), nil
-		}
-	}
-	// Otherwise return the default one
-	return ret.String(), nil
+	return s.ApiLevel.EffectiveVersionString(ctx)
 }
 
 var (
 	SdkSpecNone         = SdkSpec{SdkNone, NoneApiLevel, "(no version)"}
-	SdkSpecPrivate      = SdkSpec{SdkPrivate, FutureApiLevel, ""}
+	SdkSpecPrivate      = SdkSpec{SdkPrivate, PrivateApiLevel, ""}
 	SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, FutureApiLevel, "core_platform"}
 )
 
@@ -261,7 +263,7 @@
 
 		var kindString string
 		if sep == 0 {
-			return SdkSpec{SdkInvalid, NoneApiLevel, str}
+			return SdkSpec{SdkInvalid, NewInvalidApiLevel(str), str}
 		} else if sep == -1 {
 			kindString = ""
 		} else {
@@ -289,7 +291,7 @@
 
 		apiLevel, err := ApiLevelFromUserWithConfig(config, versionString)
 		if err != nil {
-			return SdkSpec{SdkInvalid, apiLevel, str}
+			return SdkSpec{SdkInvalid, NewInvalidApiLevel(versionString), str}
 		}
 		return SdkSpec{kind, apiLevel, str}
 	}
@@ -316,3 +318,18 @@
 	}
 	return true
 }
+
+func init() {
+	RegisterMakeVarsProvider(pctx, javaSdkMakeVars)
+}
+
+// Export the name of the soong modules representing the various Java API surfaces.
+func javaSdkMakeVars(ctx MakeVarsContext) {
+	ctx.Strict("ANDROID_PUBLIC_STUBS", SdkPublic.JavaLibraryName(ctx.Config()))
+	ctx.Strict("ANDROID_SYSTEM_STUBS", SdkSystem.JavaLibraryName(ctx.Config()))
+	ctx.Strict("ANDROID_TEST_STUBS", SdkTest.JavaLibraryName(ctx.Config()))
+	ctx.Strict("ANDROID_MODULE_LIB_STUBS", SdkModule.JavaLibraryName(ctx.Config()))
+	ctx.Strict("ANDROID_SYSTEM_SERVER_STUBS", SdkSystemServer.JavaLibraryName(ctx.Config()))
+	// TODO (jihoonkang): Create a .txt equivalent for core.current.stubs
+	ctx.Strict("ANDROID_CORE_STUBS", SdkCore.JavaLibraryName(ctx.Config()))
+}
diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go
index ec81782..ea99c4d 100644
--- a/android/sdk_version_test.go
+++ b/android/sdk_version_test.go
@@ -37,11 +37,11 @@
 		},
 		{
 			input:    "_",
-			expected: "invalid_(no version)",
+			expected: "invalid__",
 		},
 		{
 			input:    "_31",
-			expected: "invalid_(no version)",
+			expected: "invalid__31",
 		},
 		{
 			input:    "system_R",
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 064f656..4143f15 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -160,6 +160,7 @@
 // the value of the expected bool. If the expectation does not hold it reports an error prefixed with
 // the supplied message and including a reason for why it failed.
 func AssertStringListContainsEquals(t *testing.T, message string, list []string, s string, expected bool) {
+	t.Helper()
 	if expected {
 		AssertStringListContains(t, message, list, s)
 	} else {
diff --git a/android/test_config.go b/android/test_config.go
index 70c319a..07ca33d 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -109,7 +109,8 @@
 	config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
 }
 
-func modifyTestConfigForMusl(config Config) {
+// ModifyTestConfigForMusl takes a Config returned by TestConfig and changes the host targets from glibc to musl.
+func ModifyTestConfigForMusl(config Config) {
 	delete(config.Targets, config.BuildOS)
 	config.productVariables.HostMusl = boolPtr(true)
 	determineBuildOS(config.config)
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 7f03621..684833d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -63,15 +63,17 @@
 }
 
 // Return the full module name for a dependency module, which appends the apex module name unless re-using a system lib.
-func (a *apexBundle) fullModuleName(apexBundleName string, fi *apexFile) string {
-	linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
-
+func (a *apexBundle) fullModuleName(apexBundleName string, linkToSystemLib bool, fi *apexFile) string {
 	if linkToSystemLib {
 		return fi.androidMkModuleName
 	}
 	return fi.androidMkModuleName + "." + apexBundleName + a.suffix
 }
 
+// androidMkForFiles generates Make definitions for the contents of an
+// apexBundle (apexBundle#filesInfo).  The filesInfo structure can either be
+// populated by Soong for unconverted APEXes, or Bazel in mixed mode. Use
+// apexFile#isBazelPrebuilt to differentiate.
 func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir string,
 	apexAndroidMkData android.AndroidMkData) []string {
 
@@ -95,8 +97,7 @@
 
 	for _, fi := range a.filesInfo {
 		linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
-
-		moduleName := a.fullModuleName(apexBundleName, &fi)
+		moduleName := a.fullModuleName(apexBundleName, linkToSystemLib, &fi)
 
 		// This name will be added to LOCAL_REQUIRED_MODULES of the APEX. We need to be
 		// arch-specific otherwise we will end up installing both ABIs even when only
@@ -124,6 +125,7 @@
 			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
 		}
 		fmt.Fprintln(w, "LOCAL_MODULE :=", moduleName)
+
 		if fi.module != nil && fi.module.Owner() != "" {
 			fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", fi.module.Owner())
 		}
@@ -161,6 +163,7 @@
 		fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
 		fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
 		if fi.module != nil {
+			// This apexFile's module comes from Soong
 			archStr := fi.module.Target().Arch.ArchType.String()
 			host := false
 			switch fi.module.Target().Os.Class {
@@ -188,6 +191,9 @@
 				fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
 				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
 			}
+		} else if fi.isBazelPrebuilt && fi.arch != "" {
+			// This apexFile comes from Bazel
+			fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", fi.arch)
 		}
 		if fi.jacocoReportClassesFile != nil {
 			fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String())
@@ -231,17 +237,21 @@
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
 		case nativeSharedLib, nativeExecutable, nativeTest:
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.stem())
-			if ccMod, ok := fi.module.(*cc.Module); ok {
-				if ccMod.UnstrippedOutputFile() != nil {
-					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String())
-				}
-				ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
-				if ccMod.CoverageOutputFile().Valid() {
-					fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
-				}
-			} else if rustMod, ok := fi.module.(*rust.Module); ok {
-				if rustMod.UnstrippedOutputFile() != nil {
-					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", rustMod.UnstrippedOutputFile().String())
+			if fi.isBazelPrebuilt {
+				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", fi.unstrippedBuiltFile)
+			} else {
+				if ccMod, ok := fi.module.(*cc.Module); ok {
+					if ccMod.UnstrippedOutputFile() != nil {
+						fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String())
+					}
+					ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+					if ccMod.CoverageOutputFile().Valid() {
+						fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
+					}
+				} else if rustMod, ok := fi.module.(*rust.Module); ok {
+					if rustMod.UnstrippedOutputFile() != nil {
+						fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", rustMod.UnstrippedOutputFile().String())
+					}
 				}
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk")
diff --git a/apex/apex.go b/apex/apex.go
index f506876..1f700c6 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -509,6 +509,21 @@
 	shBinary
 )
 
+var (
+	classes = map[string]apexFileClass{
+		"app":              app,
+		"appSet":           appSet,
+		"etc":              etc,
+		"goBinary":         goBinary,
+		"javaSharedLib":    javaSharedLib,
+		"nativeExecutable": nativeExecutable,
+		"nativeSharedLib":  nativeSharedLib,
+		"nativeTest":       nativeTest,
+		"pyBinary":         pyBinary,
+		"shBinary":         shBinary,
+	}
+)
+
 // apexFile represents a file in an APEX bundle. This is created during the first half of
 // GenerateAndroidBuildActions by traversing the dependencies of the APEX. Then in the second half
 // of the function, this is used to create commands that copies the files into a staging directory,
@@ -543,6 +558,10 @@
 
 	multilib string
 
+	isBazelPrebuilt     bool
+	unstrippedBuiltFile android.Path
+	arch                string
+
 	// TODO(jiyong): remove this
 	module android.Module
 }
@@ -974,6 +993,9 @@
 		if !useVndk {
 			mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
 		}
+		if a.minSdkVersionValue(mctx) != "" {
+			mctx.PropertyErrorf("use_vndk_as_stable", "not supported when min_sdk_version is set")
+		}
 		mctx.VisitDirectDepsWithTag(sharedLibTag, func(dep android.Module) {
 			if c, ok := dep.(*cc.Module); ok && c.IsVndk() {
 				mctx.PropertyErrorf("use_vndk_as_stable", "Trying to include a VNDK library(%s) while use_vndk_as_stable is true.", dep.Name())
@@ -1710,6 +1732,7 @@
 	// NB: Since go binaries are static we don't need the module for anything here, which is
 	// good since the go tool is a blueprint.Module not an android.Module like we would
 	// normally use.
+	//
 	return newApexFile(ctx, fileToCopy, depName, dirInApex, goBinary, nil)
 }
 
@@ -1919,7 +1942,7 @@
 var _ android.MixedBuildBuildable = (*apexBundle)(nil)
 
 func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return ctx.ModuleType() == "apex" && a.properties.ApexType == imageApex
+	return a.properties.ApexType == imageApex
 }
 
 func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) {
@@ -2003,13 +2026,41 @@
 		panic(fmt.Errorf("internal error: unexpected apex_type for the ProcessBazelQueryResponse: %v", a.properties.ApexType))
 	}
 
-	// filesInfo is not set in mixed mode, because all information about the
-	// apex's contents should completely come from the Starlark providers.
+	// filesInfo in mixed mode must retrieve all information about the apex's
+	// contents completely from the Starlark providers. It should never rely on
+	// Android.bp information, as they might not exist for fully migrated
+	// dependencies.
 	//
 	// Prevent accidental writes to filesInfo in the earlier parts Soong by
 	// asserting it to be nil.
 	if a.filesInfo != nil {
-		panic(fmt.Errorf("internal error: filesInfo must be nil for an apex handled by Bazel."))
+		panic(
+			fmt.Errorf("internal error: filesInfo must be nil for an apex handled by Bazel. " +
+				"Did something else set filesInfo before this line of code?"))
+	}
+	for _, f := range outputs.PayloadFilesInfo {
+		fileInfo := apexFile{
+			isBazelPrebuilt: true,
+
+			builtFile:           android.PathForBazelOut(ctx, f["built_file"]),
+			unstrippedBuiltFile: android.PathForBazelOut(ctx, f["unstripped_built_file"]),
+			androidMkModuleName: f["make_module_name"],
+			installDir:          f["install_dir"],
+			class:               classes[f["class"]],
+			customStem:          f["basename"],
+			moduleDir:           f["package"],
+		}
+
+		arch := f["arch"]
+		fileInfo.arch = arch
+		if len(arch) > 0 {
+			fileInfo.multilib = "lib32"
+			if strings.HasSuffix(arch, "64") {
+				fileInfo.multilib = "lib64"
+			}
+		}
+
+		a.filesInfo = append(a.filesInfo, fileInfo)
 	}
 }
 
@@ -2898,12 +2949,8 @@
 }
 
 // Returns apex's min_sdk_version SdkSpec, honoring overrides
-func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return android.SdkSpec{
-		Kind:     android.SdkNone,
-		ApiLevel: a.minSdkVersion(ctx),
-		Raw:      a.minSdkVersionValue(ctx),
-	}
+func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return a.minSdkVersion(ctx)
 }
 
 // Returns apex's min_sdk_version ApiLevel, honoring overrides
@@ -2977,8 +3024,8 @@
 		if a.UsePlatformApis() {
 			ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs")
 		}
-		if a.SocSpecific() || a.DeviceSpecific() {
-			ctx.PropertyErrorf("updatable", "vendor APEXes are not updatable")
+		if proptools.Bool(a.properties.Use_vndk_as_stable) {
+			ctx.PropertyErrorf("use_vndk_as_stable", "updatable APEXes can't use external VNDK libs")
 		}
 		if a.FutureUpdatable() {
 			ctx.PropertyErrorf("future_updatable", "Already updatable. Remove `future_updatable: true:`")
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 1f33eca..c9665a4 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1927,13 +1927,13 @@
 	expectNoLink("libx", "shared_apex10000", "libz", "shared")
 }
 
-func TestApexMinSdkVersion_crtobjectInVendorApex(t *testing.T) {
+func TestApexMinSdkVersion_InVendorApex(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
-			updatable: false,
+			updatable: true,
 			vendor: true,
 			min_sdk_version: "29",
 		}
@@ -1946,20 +1946,34 @@
 
 		cc_library {
 			name: "mylib",
+			srcs: ["mylib.cpp"],
 			vendor_available: true,
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "myapex" ],
 			min_sdk_version: "29",
+			shared_libs: ["libbar"],
+		}
+
+		cc_library {
+			name: "libbar",
+			stubs: { versions: ["29", "30"] },
+			llndk: { symbol_file: "libbar.map.txt" },
 		}
 	`)
 
 	vendorVariant := "android_vendor.29_arm64_armv8-a"
 
-	// First check that the correct variant of crtbegin_so is used.
-	ldRule := ctx.ModuleForTests("mylib", vendorVariant+"_shared_apex29").Rule("ld")
-	crtBegin := names(ldRule.Args["crtBegin"])
-	ensureListContains(t, crtBegin, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"crtbegin_so/"+vendorVariant+"_apex29/crtbegin_so.o")
+	mylib := ctx.ModuleForTests("mylib", vendorVariant+"_shared_myapex")
+
+	// Ensure that mylib links with "current" LLNDK
+	libFlags := names(mylib.Rule("ld").Args["libFlags"])
+	ensureListContains(t, libFlags, "out/soong/.intermediates/libbar/"+vendorVariant+"_shared_current/libbar.so")
+
+	// Ensure that mylib is targeting 29
+	ccRule := ctx.ModuleForTests("mylib", vendorVariant+"_static_apex29").Output("obj/mylib.o")
+	ensureContains(t, ccRule.Args["cFlags"], "-target aarch64-linux-android29")
+
+	// Ensure that the correct variant of crtbegin_so is used.
+	crtBegin := mylib.Rule("ld").Args["crtBegin"]
+	ensureContains(t, crtBegin, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"crtbegin_so/"+vendorVariant+"_apex29/crtbegin_so.o")
 
 	// Ensure that the crtbegin_so used by the APEX is targeting 29
 	cflags := ctx.ModuleForTests("crtbegin_so", vendorVariant+"_apex29").Rule("cc").Args["cFlags"]
@@ -7860,12 +7874,13 @@
 	`)
 }
 
-func TestUpdatable_cannot_be_vendor_apex(t *testing.T) {
-	testApexError(t, `"myapex" .*: updatable: vendor APEXes are not updatable`, `
+func Test_use_vndk_as_stable_shouldnt_be_used_for_updatable_vendor_apexes(t *testing.T) {
+	testApexError(t, `"myapex" .*: use_vndk_as_stable: updatable APEXes can't use external VNDK libs`, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
 			updatable: true,
+			use_vndk_as_stable: true,
 			soc_specific: true,
 		}
 
@@ -7877,6 +7892,42 @@
 	`)
 }
 
+func Test_use_vndk_as_stable_shouldnt_be_used_with_min_sdk_version(t *testing.T) {
+	testApexError(t, `"myapex" .*: use_vndk_as_stable: not supported when min_sdk_version is set`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: false,
+			min_sdk_version: "29",
+			use_vndk_as_stable: true,
+			vendor: true,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+}
+
+func Test_use_vndk_as_stable_shouldnt_be_used_for_non_vendor_apexes(t *testing.T) {
+	testApexError(t, `"myapex" .*: use_vndk_as_stable: not supported for system/system_ext APEXes`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: false,
+			use_vndk_as_stable: true,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+}
+
 func TestUpdatable_should_not_set_generate_classpaths_proto(t *testing.T) {
 	testApexError(t, `"mysystemserverclasspathfragment" .* it must not set generate_classpaths_proto to false`, `
 		apex {
diff --git a/apex/bp2build_test.go b/apex/bp2build_test.go
index 2f2b61e..2a0f6e9 100644
--- a/apex/bp2build_test.go
+++ b/apex/bp2build_test.go
@@ -25,6 +25,7 @@
 apex_key{
 	name: "foo_key",
 }
+
 apex {
 	name: "foo",
 	key: "foo_key",
@@ -59,6 +60,16 @@
 						ProvidesLibs: []string{"a", "b"},
 
 						// ApexMkInfo Starlark provider
+						PayloadFilesInfo: []map[string]string{
+							{
+								"built_file":       "bazel-out/adbd",
+								"install_dir":      "bin",
+								"class":            "nativeExecutable",
+								"make_module_name": "adbd",
+								"basename":         "adbd",
+								"package":          "foo",
+							},
+						},
 						MakeModulesToInstall: []string{"c"}, // d deliberately omitted
 					},
 				},
@@ -68,10 +79,12 @@
 
 	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
 	ab, ok := m.(*apexBundle)
+
 	if !ok {
 		t.Fatalf("Expected module to be an apexBundle, was not")
 	}
 
+	// TODO: refactor to android.AssertStringEquals
 	if w, g := "out/bazel/execroot/__main__/public_key", ab.publicKeyFile.String(); w != g {
 		t.Errorf("Expected public key %q, got %q", w, g)
 	}
@@ -120,11 +133,136 @@
 	if len(ab.makeModulesToInstall) != 1 && ab.makeModulesToInstall[0] != "c" {
 		t.Errorf("Expected makeModulesToInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
 	}
-	if w := "LOCAL_REQUIRED_MODULES := c"; !strings.Contains(data, w) {
+	if w := "LOCAL_REQUIRED_MODULES := adbd.foo c"; !strings.Contains(data, w) {
 		t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
 	}
 }
 
+func TestApexImageCreatesFilesInfoForMake(t *testing.T) {
+	bp := `
+apex_key{
+	name: "foo_key",
+}
+
+apex {
+	name: "foo",
+	key: "foo_key",
+	updatable: true,
+	min_sdk_version: "31",
+	file_contexts: ":myapex-file_contexts",
+	bazel_module: { label: "//:foo" },
+}`
+
+	outputBaseDir := "out/bazel"
+	result := android.GroupFixturePreparers(
+		prepareForApexTest,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: outputBaseDir,
+				LabelToApexInfo: map[string]cquery.ApexInfo{
+					"//:foo": {
+						// ApexInfo Starlark provider. Necessary for the test.
+						SignedOutput:     "signed_out.apex",
+						BundleKeyInfo:    []string{"public_key", "private_key"},
+						ContainerKeyInfo: []string{"container_cert", "container_private"},
+
+						// ApexMkInfo Starlark provider
+						PayloadFilesInfo: []map[string]string{
+							{
+								"arch":                  "arm64",
+								"basename":              "libcrypto.so",
+								"built_file":            "bazel-out/64/libcrypto.so",
+								"class":                 "nativeSharedLib",
+								"install_dir":           "lib64",
+								"make_module_name":      "libcrypto",
+								"package":               "foo/bar",
+								"unstripped_built_file": "bazel-out/64/unstripped_libcrypto.so",
+							},
+							{
+								"arch":             "arm",
+								"basename":         "libcrypto.so",
+								"built_file":       "bazel-out/32/libcrypto.so",
+								"class":            "nativeSharedLib",
+								"install_dir":      "lib",
+								"make_module_name": "libcrypto",
+								"package":          "foo/bar",
+							},
+							{
+								"arch":             "arm64",
+								"basename":         "adbd",
+								"built_file":       "bazel-out/adbd",
+								"class":            "nativeExecutable",
+								"install_dir":      "bin",
+								"make_module_name": "adbd",
+								"package":          "foo",
+							},
+						},
+					},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp)
+
+	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
+	ab, ok := m.(*apexBundle)
+
+	if !ok {
+		t.Fatalf("Expected module to be an apexBundle, was not")
+	}
+
+	expectedFilesInfo := []apexFile{
+		{
+			androidMkModuleName: "libcrypto",
+			builtFile:           android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/libcrypto.so"),
+			class:               nativeSharedLib,
+			customStem:          "libcrypto.so",
+			installDir:          "lib64",
+			moduleDir:           "foo/bar",
+			arch:                "arm64",
+			unstrippedBuiltFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/unstripped_libcrypto.so"),
+		},
+		{
+			androidMkModuleName: "libcrypto",
+			builtFile:           android.PathForTesting("out/bazel/execroot/__main__/bazel-out/32/libcrypto.so"),
+			class:               nativeSharedLib,
+			customStem:          "libcrypto.so",
+			installDir:          "lib",
+			moduleDir:           "foo/bar",
+			arch:                "arm",
+		},
+		{
+			androidMkModuleName: "adbd",
+			builtFile:           android.PathForTesting("out/bazel/execroot/__main__/bazel-out/adbd"),
+			class:               nativeExecutable,
+			customStem:          "adbd",
+			installDir:          "bin",
+			moduleDir:           "foo",
+			arch:                "arm64",
+		},
+	}
+
+	if len(ab.filesInfo) != len(expectedFilesInfo) {
+		t.Errorf("Expected %d entries in ab.filesInfo, but got %d", len(ab.filesInfo), len(expectedFilesInfo))
+	}
+
+	for idx, f := range ab.filesInfo {
+		expected := expectedFilesInfo[idx]
+		android.AssertSame(t, "different class", expected.class, f.class)
+		android.AssertStringEquals(t, "different built file", expected.builtFile.String(), f.builtFile.String())
+		android.AssertStringEquals(t, "different custom stem", expected.customStem, f.customStem)
+		android.AssertStringEquals(t, "different install dir", expected.installDir, f.installDir)
+		android.AssertStringEquals(t, "different make module name", expected.androidMkModuleName, f.androidMkModuleName)
+		android.AssertStringEquals(t, "different moduleDir", expected.moduleDir, f.moduleDir)
+		android.AssertStringEquals(t, "different arch", expected.arch, f.arch)
+		if expected.unstrippedBuiltFile != nil {
+			if f.unstrippedBuiltFile == nil {
+				t.Errorf("expected an unstripped built file path.")
+			}
+			android.AssertStringEquals(t, "different unstripped built file", expected.unstrippedBuiltFile.String(), f.unstrippedBuiltFile.String())
+		}
+	}
+}
+
 func TestCompressedApexImageInMixedBuilds(t *testing.T) {
 	bp := `
 apex_key{
diff --git a/apex/builder.go b/apex/builder.go
index ee6c473..45c5267 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -1063,10 +1063,10 @@
 		} else {
 			toMinSdkVersion := "(no version)"
 			if m, ok := to.(interface {
-				MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+				MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel
 			}); ok {
-				if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() {
-					toMinSdkVersion = v.ApiLevel.String()
+				if v := m.MinSdkVersion(ctx); !v.IsNone() {
+					toMinSdkVersion = v.String()
 				}
 			} else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
 				// TODO(b/175678607) eliminate the use of MinSdkVersion returning
@@ -1087,7 +1087,7 @@
 		return !externalDep
 	})
 
-	a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).Raw, depInfos)
+	a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depInfos)
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   android.Phony,
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 0997a68..cae507e 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -35,11 +35,12 @@
 		blueprint.RuleParams{
 			Command: `rm -rf "$out" && ` +
 				`${extract_apks} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
-				`-sdk-version=${sdk-version} -abis=${abis} -screen-densities=all -extract-single ` +
+				`-sdk-version=${sdk-version} -skip-sdk-check=${skip-sdk-check} -abis=${abis} ` +
+				`-screen-densities=all -extract-single ` +
 				`${in}`,
 			CommandDeps: []string{"${extract_apks}"},
 		},
-		"abis", "allow-prereleased", "sdk-version")
+		"abis", "allow-prereleased", "sdk-version", "skip-sdk-check")
 )
 
 type prebuilt interface {
@@ -845,6 +846,7 @@
 				"abis":              strings.Join(abis, ","),
 				"allow-prereleased": strconv.FormatBool(proptools.BoolDefault(p.properties.Prerelease, defaultAllowPrerelease)),
 				"sdk-version":       ctx.Config().PlatformSdkVersion().String(),
+				"skip-sdk-check":    strconv.FormatBool(ctx.Config().IsEnvTrue("SOONG_SKIP_APPSET_SDK_CHECK")),
 			},
 		})
 }
diff --git a/apex/vndk.go b/apex/vndk.go
index c0be753..095e89d 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -72,12 +72,14 @@
 		}
 
 		targets := mctx.MultiTargets()
-		if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) {
-			// Disable VNDK apexes for VNDK versions less than the minimum supported API level for the primary
-			// architecture.
+		if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) &&
+			vndkVersion != mctx.DeviceConfig().PlatformVndkVersion() {
+			// Disable VNDK APEXes for VNDK versions less than the minimum supported API
+			// level for the primary architecture. This validation is skipped if the VNDK
+			// version matches the platform VNDK version, which can occur when the device
+			// config targets the 'current' VNDK (see `vndkVersion`).
 			ab.Disable()
 		}
-
 	}
 }
 
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 0c8247a..bf3a6b5 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -197,7 +197,7 @@
     local_whole_static_libs = androidmk_info.local_whole_static_libs
     local_shared_libs = androidmk_info.local_shared_libs
 
-return json_encode({
+return json.encode({
     "OutputFiles": outputFiles,
     "CcObjectFiles": ccObjectFiles,
     "CcSharedLibraryFiles": sharedLibraries,
@@ -266,7 +266,7 @@
 if clang_tidy_info:
     tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
 
-return json_encode({
+return json.encode({
     "signed_output": info.signed_output.path,
     "signed_compressed_output": signed_compressed_output,
     "unsigned_output": info.unsigned_output.path,
@@ -281,6 +281,7 @@
     "bundle_file": info.base_with_config_zip.path,
     "installed_files": info.installed_files.path,
     "make_modules_to_install": mk_info.make_modules_to_install,
+    "files_info": mk_info.files_info,
     "tidy_files": [t for t in tidy_files],
 })`
 }
@@ -303,7 +304,8 @@
 	TidyFiles              []string `json:"tidy_files"`
 
 	// From the ApexMkInfo provider
-	MakeModulesToInstall []string `json:"make_modules_to_install"`
+	MakeModulesToInstall []string            `json:"make_modules_to_install"`
+	PayloadFilesInfo     []map[string]string `json:"files_info"`
 }
 
 // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
@@ -333,7 +335,7 @@
 unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
 if unstripped_tag in p:
     unstripped_info = p[unstripped_tag]
-    unstripped = unstripped_info.unstripped.files.to_list()[0].path
+    unstripped = unstripped_info.unstripped[0].files.to_list()[0].path
 
 local_static_libs = []
 local_whole_static_libs = []
@@ -350,7 +352,7 @@
 if clang_tidy_info:
     tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
 
-return json_encode({
+return json.encode({
     "OutputFile":  output_path,
     "UnstrippedOutput": unstripped,
     "LocalStaticLibs": [l for l in local_static_libs],
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index 03b3d2b..ef3f124 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -344,3 +344,50 @@
 			}),
 		}})
 }
+
+func TestAndroidAppMinSdkProvided(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app with value for min_sdk_version",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+android_app {
+        name: "foo",
+        sdk_version: "current",
+				min_sdk_version: "24",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_binary", "foo", AttrNameToString{
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `[]`,
+				"manifest_values": `{
+        "minSdkVersion": "24",
+    }`,
+			}),
+		}})
+}
+
+func TestAndroidAppMinSdkDefaultToSdkVersion(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app with value for sdk_version",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+android_app {
+        name: "foo",
+        sdk_version: "30",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_binary", "foo", AttrNameToString{
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `[]`,
+				"manifest_values": `{
+        "minSdkVersion": "30",
+    }`,
+			}),
+		}})
+}
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 73c889f..03fb5d4 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -1191,9 +1191,9 @@
 				"tags":              `["apex_available=myapex"]`,
 			}),
 			MakeBazelTarget("cc_stub_suite", "foo_stub_libs", AttrNameToString{
-				"soname":         `"foo.so"`,
-				"source_library": `":foo"`,
-				"symbol_file":    `"foo.map.txt"`,
+				"soname":               `"foo.so"`,
+				"source_library_label": `"//:foo"`,
+				"symbol_file":          `"foo.map.txt"`,
 				"versions": `[
         "28",
         "29",
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index e20cffd..48e93cd 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -2780,9 +2780,9 @@
 		"stubs_symbol_file": `"a.map.txt"`,
 	})
 	expectedBazelTargets = append(expectedBazelTargets, makeCcStubSuiteTargets("a", AttrNameToString{
-		"soname":            `"a.so"`,
-		"source_library":    `":a"`,
-		"stubs_symbol_file": `"a.map.txt"`,
+		"soname":               `"a.so"`,
+		"source_library_label": `"//foo/bar:a"`,
+		"stubs_symbol_file":    `"a.map.txt"`,
 		"stubs_versions": `[
         "28",
         "29",
@@ -3035,7 +3035,7 @@
 }`,
 		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
 			"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": [":barlib_stub_libs_current"],
+        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
         "//conditions:default": [":barlib"],
     })`,
 			"local_includes": `["."]`,
@@ -3088,8 +3088,8 @@
         "//build/bazel/platforms/os:linux_musl": [":quxlib"],
         "//build/bazel/platforms/os:windows": [":quxlib"],
         "//build/bazel/rules/apex:android-in_apex": [
-            ":barlib_stub_libs_current",
-            ":quxlib_stub_libs_current",
+            "@api_surfaces//module-libapi/current:barlib",
+            "@api_surfaces//module-libapi/current:quxlib",
         ],
         "//conditions:default": [
             ":barlib",
@@ -3591,42 +3591,57 @@
 	})
 }
 
-func TestCcLibraryWithAidlAndSharedLibs(t *testing.T) {
+func TestCcLibraryWithAidlAndLibs(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_aidl_library depends on shared libs from parent cc_library_static",
+		Description:                "cc_aidl_library depends on libs from parent cc_library_static",
 		ModuleTypeUnderTest:        "cc_library",
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
 		Blueprint: `
 cc_library_static {
-    name: "foo",
-    srcs: [
-        "Foo.aidl",
-    ],
+	name: "foo",
+	srcs: [
+		"Foo.aidl",
+	],
+	static_libs: [
+		"bar-static",
+		"baz-static",
+	],
 	shared_libs: [
-		"bar",
-		"baz",
+		"bar-shared",
+		"baz-shared",
+	],
+	export_static_lib_headers: [
+		"baz-static",
 	],
 	export_shared_lib_headers: [
-		"baz",
+		"baz-shared",
 	],
 }` +
-			simpleModuleDoNotConvertBp2build("cc_library", "bar") +
-			simpleModuleDoNotConvertBp2build("cc_library", "baz"),
+			simpleModuleDoNotConvertBp2build("cc_library_static", "bar-static") +
+			simpleModuleDoNotConvertBp2build("cc_library_static", "baz-static") +
+			simpleModuleDoNotConvertBp2build("cc_library", "bar-shared") +
+			simpleModuleDoNotConvertBp2build("cc_library", "baz-shared"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
 				"srcs": `["Foo.aidl"]`,
 			}),
 			MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
 				"deps": `[":foo_aidl_library"]`,
+				"implementation_deps": `[
+        ":baz-static",
+        ":bar-static",
+    ]`,
 				"implementation_dynamic_deps": `[
-        ":baz",
-        ":bar",
+        ":baz-shared",
+        ":bar-shared",
     ]`,
 			}),
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-				"dynamic_deps":                      `[":baz"]`,
-				"implementation_dynamic_deps":       `[":bar"]`,
+				"deps":                              `[":baz-static"]`,
+				"implementation_deps":               `[":bar-static"]`,
+				"dynamic_deps":                      `[":baz-shared"]`,
+				"implementation_dynamic_deps":       `[":bar-shared"]`,
 				"local_includes":                    `["."]`,
 			}),
 		},
@@ -3640,8 +3655,17 @@
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
 		Blueprint: `
 cc_library_static {
-    name: "foo",
-    srcs: ["foo.cpp"],
+	name: "foo",
+	srcs: ["foo.cpp"],
+}
+cc_library_static {
+	name: "foo-no-tidy",
+	srcs: ["foo.cpp"],
+	tidy: false,
+}
+cc_library_static {
+	name: "foo-tidy",
+	srcs: ["foo.cpp"],
 	tidy: true,
 	tidy_checks: ["check1", "check2"],
 	tidy_checks_as_errors: ["check1error", "check2error"],
@@ -3652,7 +3676,16 @@
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"local_includes": `["."]`,
 				"srcs":           `["foo.cpp"]`,
-				"tidy":           `True`,
+			}),
+			MakeBazelTarget("cc_library_static", "foo-no-tidy", AttrNameToString{
+				"local_includes": `["."]`,
+				"srcs":           `["foo.cpp"]`,
+				"tidy":           `"never"`,
+			}),
+			MakeBazelTarget("cc_library_static", "foo-tidy", AttrNameToString{
+				"local_includes": `["."]`,
+				"srcs":           `["foo.cpp"]`,
+				"tidy":           `"local"`,
 				"tidy_checks": `[
         "check1",
         "check2",
@@ -4112,11 +4145,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": [":barlib_stub_libs_current"],
+        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
         "//conditions:default": [":barlib"],
     })`,
 				"dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": [":bazlib_stub_libs_current"],
+        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
         "//conditions:default": [":bazlib"],
     })`,
 				"local_includes": `["."]`,
@@ -4124,11 +4157,11 @@
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": [":barlib_stub_libs_current"],
+        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
         "//conditions:default": [":barlib"],
     })`,
 				"dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": [":bazlib_stub_libs_current"],
+        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
         "//conditions:default": [":bazlib"],
     })`,
 				"local_includes": `["."]`,
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 838b297..b685a2c 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -540,9 +540,9 @@
 		},
 		Blueprint: soongCcLibraryPreamble,
 		ExpectedBazelTargets: []string{makeCcStubSuiteTargets("a", AttrNameToString{
-			"soname":            `"a.so"`,
-			"source_library":    `":a"`,
-			"stubs_symbol_file": `"a.map.txt"`,
+			"soname":               `"a.so"`,
+			"source_library_label": `"//foo/bar:a"`,
+			"stubs_symbol_file":    `"a.map.txt"`,
 			"stubs_versions": `[
         "28",
         "29",
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index d16c5cc..7c18037 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1553,7 +1553,7 @@
 			}),
 			MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": [":libm_stub_libs_current"],
+        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:libm"],
         "//conditions:default": [":libm"],
     })`,
 				"system_dynamic_deps": `[]`,
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 278a9bf..1b9777c 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -56,11 +56,9 @@
     java_version: "8",
 }`,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
-				"srcs":       `["a.java"]`,
-				"main_class": `"com.android.test.MainClass"`,
-				"deps":       `["//other:jni-lib-1"]`,
-				"jvm_flags":  `["-Djava.library.path=$${RUNPATH}other"]`,
+			MakeBazelTarget("java_library", "java-binary-host-1_lib", AttrNameToString{
+				"srcs": `["a.java"]`,
+				"deps": `["//other:jni-lib-1"]`,
 				"javacopts": `[
         "-Xdoclint:all/protected",
         "-source 1.8 -target 1.8",
@@ -68,8 +66,15 @@
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
-    })`,
-			}),
+    })`}),
+			MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
+				"main_class":   `"com.android.test.MainClass"`,
+				"jvm_flags":    `["-Djava.library.path=$${RUNPATH}other"]`,
+				"runtime_deps": `[":java-binary-host-1_lib"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`}),
 		},
 	})
 }
@@ -122,15 +127,22 @@
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_binary", "java-binary-host-libs", AttrNameToString{
-				"main_class": `"com.android.test.MainClass"`,
-				"srcs":       `["a.java"]`,
-				"deps":       `[":java-lib-dep-1-neverlink"]`,
+			MakeBazelTarget("java_library", "java-binary-host-libs_lib", AttrNameToString{
+				"srcs": `["a.java"]`,
+				"deps": `[":java-lib-dep-1-neverlink"]`,
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
+			MakeBazelTarget("java_binary", "java-binary-host-libs", AttrNameToString{
+				"main_class": `"com.android.test.MainClass"`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+				"runtime_deps": `[":java-binary-host-libs_lib"]`,
+			}),
 		},
 	})
 }
@@ -146,7 +158,7 @@
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
 				"srcs": `[
         "a.java",
         "b.kt",
@@ -158,7 +170,7 @@
 			}),
 			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
 				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_kt"]`,
+				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
@@ -180,7 +192,7 @@
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
 				"srcs":        `["a.java"]`,
 				"common_srcs": `["b.kt"]`,
 				"target_compatible_with": `select({
@@ -190,7 +202,7 @@
 			}),
 			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
 				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_kt"]`,
+				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
@@ -216,7 +228,7 @@
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
 				"srcs": `[
         "a.java",
         "b.kt",
@@ -233,7 +245,7 @@
 			}),
 			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
 				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_kt"]`,
+				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
@@ -259,7 +271,7 @@
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
 				"srcs": `[
         "a.java",
         "b.kt",
@@ -275,7 +287,7 @@
 			}),
 			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
 				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_kt"]`,
+				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
@@ -297,7 +309,7 @@
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
 				"srcs": `["a.kt"]`,
 				"kotlincflags": `[
         "-flag1",
@@ -310,7 +322,7 @@
 			}),
 			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
 				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_kt"]`,
+				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
diff --git a/bp2build/testing.go b/bp2build/testing.go
index a737ea1..ee2ab08 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -623,16 +623,18 @@
 		return ""
 	}
 	STUB_SUITE_ATTRS := map[string]string{
-		"stubs_symbol_file": "symbol_file",
-		"stubs_versions":    "versions",
-		"soname":            "soname",
-		"source_library":    "source_library",
+		"stubs_symbol_file":    "symbol_file",
+		"stubs_versions":       "versions",
+		"soname":               "soname",
+		"source_library_label": "source_library_label",
 	}
 
 	stubSuiteAttrs := AttrNameToString{}
 	for key, _ := range attrs {
 		if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
 			stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
+		} else {
+			panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
 		}
 	}
 	return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
diff --git a/cc/binary.go b/cc/binary.go
index 496c610..097f822 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -512,7 +512,7 @@
 		}
 		binary.baseInstaller.subDir = "bootstrap"
 	}
-	binary.baseInstaller.install(ctx, file)
+	binary.baseInstaller.installExecutable(ctx, file)
 
 	var preferredArchSymlinkPath android.OptionalPath
 	for _, symlink := range binary.symlinks {
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 8644bf6..03d9de8 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -71,7 +71,7 @@
 }
 
 type tidyAttributes struct {
-	Tidy                  *bool
+	Tidy                  *string
 	Tidy_flags            []string
 	Tidy_checks           []string
 	Tidy_checks_as_errors []string
@@ -82,7 +82,15 @@
 func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) {
 	for _, f := range m.features {
 		if tidy, ok := f.(*tidyFeature); ok {
-			moduleAttrs.Tidy = tidy.Properties.Tidy
+			var tidyAttr *string
+			if tidy.Properties.Tidy != nil {
+				if *tidy.Properties.Tidy {
+					tidyAttr = proptools.StringPtr("local")
+				} else {
+					tidyAttr = proptools.StringPtr("never")
+				}
+			}
+			moduleAttrs.Tidy = tidyAttr
 			moduleAttrs.Tidy_flags = tidy.Properties.Tidy_flags
 			moduleAttrs.Tidy_checks = tidy.Properties.Tidy_checks
 			moduleAttrs.Tidy_checks_as_errors = tidy.Properties.Tidy_checks_as_errors
@@ -909,15 +917,12 @@
 
 		if !aidlLibs.IsEmpty() {
 			ccAidlLibrarylabel := m.Name() + "_cc_aidl_library"
-			// Since cc_aidl_library only needs the dynamic deps (aka shared libs) from the parent cc library for compiling,
-			// we err on the side of not re-exporting the headers of the dynamic deps from cc_aidl_lirary
-			// because the parent cc library already has all the dynamic deps
-			implementationDynamicDeps := bazel.MakeLabelListAttribute(
-				bazel.AppendBazelLabelLists(
-					linkerAttrs.dynamicDeps.Value,
-					linkerAttrs.implementationDynamicDeps.Value,
-				),
-			)
+			// Since parent cc_library already has these dependencies, we can add them as implementation
+			// deps so that they don't re-export
+			implementationDeps := linkerAttrs.deps.Clone()
+			implementationDeps.Append(linkerAttrs.implementationDeps)
+			implementationDynamicDeps := linkerAttrs.dynamicDeps.Clone()
+			implementationDynamicDeps.Append(linkerAttrs.implementationDynamicDeps)
 
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{
@@ -927,7 +932,8 @@
 				android.CommonAttributes{Name: ccAidlLibrarylabel},
 				&ccAidlLibraryAttributes{
 					Deps:                        aidlLibs,
-					Implementation_dynamic_deps: implementationDynamicDeps,
+					Implementation_deps:         *implementationDeps,
+					Implementation_dynamic_deps: *implementationDynamicDeps,
 				},
 			)
 			label := &bazel.LabelAttribute{
@@ -1144,6 +1150,10 @@
 	}
 }
 
+var (
+	apiSurfaceModuleLibCurrentPackage = "@api_surfaces//" + android.ModuleLibApi.String() + "/current:"
+)
+
 func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
 	config string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {
 	depsWithStubs := []bazel.Label{}
@@ -1159,8 +1169,10 @@
 
 		stubLibLabels := []bazel.Label{}
 		for _, l := range depsWithStubs {
-			l.Label = l.Label + stubsSuffix
-			stubLibLabels = append(stubLibLabels, l)
+			stubLabelInApiSurfaces := bazel.Label{
+				Label: apiSurfaceModuleLibCurrentPackage + l.OriginalModuleName,
+			}
+			stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces)
 		}
 		inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
 		nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
@@ -1276,8 +1288,10 @@
 		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, toRemove)
 		stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep))
 		for _, lib := range toRemove.Includes {
-			lib.Label += stubsSuffix
-			stubsToRemove = append(stubsToRemove, lib)
+			stubLabelInApiSurfaces := bazel.Label{
+				Label: apiSurfaceModuleLibCurrentPackage + lib.OriginalModuleName,
+			}
+			stubsToRemove = append(stubsToRemove, stubLabelInApiSurfaces)
 		}
 		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove))
 	}
diff --git a/cc/cc.go b/cc/cc.go
index 0e88c56..b029d71 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2506,20 +2506,11 @@
 	if c.isNDKStubLibrary() {
 		// NDK stubs depend on their implementation because the ABI dumps are
 		// generated from the implementation library.
-		apiImportName := c.BaseModuleName() + multitree.GetApiImportSuffix()
 
-		// If original library exists as imported API, set dependency on the imported library
-		if actx.OtherModuleExists(apiImportName) {
-			actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
-				c.ImageVariation(),
-				blueprint.Variation{Mutator: "link", Variation: "shared"},
-			), stubImplementation, apiImportName)
-		} else {
-			actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
-				c.ImageVariation(),
-				blueprint.Variation{Mutator: "link", Variation: "shared"},
-			), stubImplementation, c.BaseModuleName())
-		}
+		actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+			c.ImageVariation(),
+			blueprint.Variation{Mutator: "link", Variation: "shared"},
+		), stubImplementation, c.BaseModuleName())
 	}
 
 	for _, lib := range deps.WholeStaticLibs {
@@ -2963,7 +2954,7 @@
 		ctx.VisitDirectDeps(func(dep android.Module) {
 			depName := ctx.OtherModuleName(dep)
 			if apiLibrary, ok := targetOrigModuleList[depName]; ok {
-				if shouldUseStubForApex(ctx, dep) {
+				if ShouldUseStubForApex(ctx, dep) {
 					skipModuleList[depName] = true
 				} else {
 					skipModuleList[apiLibrary] = true
@@ -3316,7 +3307,7 @@
 	return depPaths
 }
 
-func shouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool {
+func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool {
 	depName := ctx.OtherModuleName(dep)
 	thisModule, ok := ctx.Module().(android.ApexModule)
 	if !ok {
@@ -3418,7 +3409,7 @@
 
 	if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
 		// when to use (unspecified) stubs, use the latest one.
-		if shouldUseStubForApex(ctx, dep) {
+		if ShouldUseStubForApex(ctx, dep) {
 			stubs := sharedLibraryStubsInfo.SharedStubLibraries
 			toUse := stubs[len(stubs)-1]
 			sharedLibraryInfo = toUse.SharedLibraryInfo
@@ -3475,7 +3466,6 @@
 	nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk
 
 	if ccDepModule != nil {
-		// TODO(ivanlozano) Support snapshots for Rust-produced C library variants.
 		// Use base module name for snapshots when exporting to Makefile.
 		if snapshotPrebuilt, ok := ccDepModule.linker.(SnapshotInterface); ok {
 			baseName := ccDepModule.BaseModuleName()
@@ -3880,6 +3870,7 @@
 	// When a vendor APEX needs a VNDK lib in it (use_vndk_as_stable: false), it should be a unique
 	// APEX variation. Otherwise, another vendor APEX with use_vndk_as_stable:true may use a wrong
 	// variation of the VNDK lib because APEX variations are merged/grouped.
+	// TODO(b/274401041) Find a way to merge APEX variations for vendor apexes.
 	return c.UseVndk() && c.IsVndk()
 }
 
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index b3619c8..35c57f9 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -26,12 +26,16 @@
 		// Help catch common 32/64-bit errors.
 		"-Werror=implicit-function-declaration",
 		"-fno-emulated-tls",
+		// For -fsanitize=shadow-call-stack.
+		"-ffixed-x18",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
 
 	riscv64Ldflags = []string{
 		"-Wl,--hash-style=gnu",
+		// For -fsanitize=shadow-call-stack.
+		"-ffixed-x18",
 	}
 
 	riscv64Lldflags = append(riscv64Ldflags,
diff --git a/cc/coverage.go b/cc/coverage.go
index a7356f8..c0f6973 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -219,10 +219,14 @@
 	return properties
 }
 
-// Coverage is an interface for non-CC modules to implement to be mutated for coverage
-type Coverage interface {
+type UseCoverage interface {
 	android.Module
 	IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool
+}
+
+// Coverage is an interface for non-CC modules to implement to be mutated for coverage
+type Coverage interface {
+	UseCoverage
 	SetPreventInstall()
 	HideFromMake()
 	MarkAsCoverageVariant(bool)
@@ -261,6 +265,11 @@
 
 		m[1].(Coverage).MarkAsCoverageVariant(true)
 		m[1].(Coverage).EnableCoverageIfNeeded()
+	} else if cov, ok := mctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(mctx) {
+		// Module itself doesn't have to have "cov" variant, but it should use "cov" variants of
+		// deps.
+		mctx.CreateVariations("cov")
+		mctx.AliasVariation("cov")
 	}
 }
 
diff --git a/cc/installer.go b/cc/installer.go
index e2c0e7b..716a0df 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -100,6 +100,10 @@
 	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
 }
 
+func (installer *baseInstaller) installExecutable(ctx ModuleContext, file android.Path) {
+	installer.path = ctx.InstallExecutable(installer.installDir(ctx), file.Base(), file)
+}
+
 func (installer *baseInstaller) everInstallable() bool {
 	// Most cc modules are installable.
 	return true
diff --git a/cc/library.go b/cc/library.go
index 27f0623..1b579cd 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -268,6 +268,7 @@
 
 type ccAidlLibraryAttributes struct {
 	Deps                        bazel.LabelListAttribute
+	Implementation_deps         bazel.LabelListAttribute
 	Implementation_dynamic_deps bazel.LabelListAttribute
 }
 
@@ -454,12 +455,12 @@
 		}
 		soname := m.Name() + ".so"
 		stubSuitesAttrs := &bazelCcStubSuiteAttributes{
-			Symbol_file:     compilerAttrs.stubsSymbolFile,
-			Versions:        compilerAttrs.stubsVersions,
-			Export_includes: exportedIncludes.Includes,
-			Soname:          &soname,
-			Source_library:  *bazel.MakeLabelAttribute(":" + m.Name()),
-			Deps:            baseAttributes.deps,
+			Symbol_file:          compilerAttrs.stubsSymbolFile,
+			Versions:             compilerAttrs.stubsVersions,
+			Export_includes:      exportedIncludes.Includes,
+			Soname:               &soname,
+			Source_library_label: proptools.StringPtr(m.GetBazelLabel(ctx, m)),
+			Deps:                 baseAttributes.deps,
 		}
 		ctx.CreateBazelTargetModule(stubSuitesProps,
 			android.CommonAttributes{Name: m.Name() + "_stub_libs"},
@@ -468,7 +469,7 @@
 		// Add alias for the stub shared_library in @api_surfaces repository
 		currentModuleLibApiDir := ctx.Config().ApiSurfacesDir(android.ModuleLibApi, "current")
 		actualLabelInMainWorkspace := bazel.Label{
-			Label: fmt.Sprintf("@//%s:%s_stub_libs_current", ctx.ModuleDir(), m.Name()),
+			Label: fmt.Sprintf("@//%s:%s%s", ctx.ModuleDir(), m.Name(), stubsSuffix),
 		}
 		ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, m.Name(), actualLabelInMainWorkspace)
 
@@ -3033,12 +3034,12 @@
 }
 
 type bazelCcStubSuiteAttributes struct {
-	Symbol_file     *string
-	Versions        bazel.StringListAttribute
-	Export_includes bazel.StringListAttribute
-	Source_library  bazel.LabelAttribute
-	Soname          *string
-	Deps            bazel.LabelListAttribute
+	Symbol_file          *string
+	Versions             bazel.StringListAttribute
+	Export_includes      bazel.StringListAttribute
+	Source_library_label *string
+	Soname               *string
+	Deps                 bazel.LabelListAttribute
 }
 
 type bazelCcHeaderAbiCheckerAttributes struct {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index aa61453..c899cc4 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -77,7 +77,7 @@
 		"-fno-sanitize-recover=integer,undefined"}
 	hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512",
 		"export_memory_stats=0", "max_malloc_fill_size=131072", "malloc_fill_byte=0"}
-	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
+	memtagStackCommonFlags = []string{"-march=armv8-a+memtag", "-mllvm", "-dom-tree-reachability-max-bbs-to-explore=128"}
 
 	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
 	deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all", "-ftrap-function=abort"}
@@ -254,7 +254,7 @@
 	// This should not be used in Android 11+ : https://source.android.com/devices/tech/debug/scudo
 	// deprecated
 	Scudo *bool `android:"arch_variant"`
-	// shadow-call-stack sanitizer, only available on arm64
+	// shadow-call-stack sanitizer, only available on arm64/riscv64.
 	Scs *bool `android:"arch_variant"`
 	// Memory-tagging, only available on arm64
 	// if diag.memtag unset or false, enables async memory tagging
@@ -593,8 +593,8 @@
 		s.Hwaddress = nil
 	}
 
-	// SCS is only implemented on AArch64.
-	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
+	// SCS is only implemented on AArch64/riscv64.
+	if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() {
 		s.Scs = nil
 	}
 
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index fe592dc..71c5a22 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -28,12 +28,22 @@
 var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(`
 	cc_library_shared {
 		name: "libclang_rt.asan",
+		host_supported: true,
+	}
+	cc_library_static {
+		name: "libclang_rt.asan.static",
+		host_supported: true,
+	}
+	cc_library_static {
+		name: "libclang_rt.asan_cxx.static",
+		host_supported: true,
 	}
 `))
 
 var prepareForTsanTest = android.FixtureAddFile("tsan/Android.bp", []byte(`
 	cc_library_shared {
 		name: "libclang_rt.tsan",
+		host_supported: true,
 	}
 `))
 
@@ -54,6 +64,19 @@
 	}
 }
 
+// expectNoSharedLinkDep verifies that the from module links against the to module as a
+// shared library.
+func expectNoSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
+	t.Helper()
+	fromLink := from.Description("link")
+	toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo)
+
+	if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); android.InList(w, g) {
+		t.Errorf("%s should not link against %s, expected %q, got %q",
+			from.Module(), to.Module(), w, g)
+	}
+}
+
 // expectStaticLinkDep verifies that the from module links against the to module as a
 // static library.
 func expectStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
@@ -68,6 +91,20 @@
 
 }
 
+// expectNoStaticLinkDep verifies that the from module links against the to module as a
+// static library.
+func expectNoStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
+	t.Helper()
+	fromLink := from.Description("link")
+	toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo)
+
+	if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); android.InList(w, g) {
+		t.Errorf("%s should not link against %s, expected %q, got %q",
+			from.Module(), to.Module(), w, g)
+	}
+
+}
+
 // expectInstallDep verifies that the install rule of the from module depends on the
 // install rule of the to module.
 func expectInstallDep(t *testing.T, from, to android.TestingModule) {
@@ -85,6 +122,13 @@
 	}
 }
 
+type expectedRuntimeLinkage int
+
+const (
+	RUNTIME_LINKAGE_NONE   = expectedRuntimeLinkage(0)
+	RUNTIME_LINKAGE_SHARED = iota
+)
+
 func TestAsan(t *testing.T) {
 	t.Parallel()
 	bp := `
@@ -162,12 +206,14 @@
 
 	`
 
-	result := android.GroupFixturePreparers(
+	preparer := android.GroupFixturePreparers(
 		prepareForCcTest,
 		prepareForAsanTest,
-	).RunTestWithBp(t, bp)
+	)
+	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String()
 
-	check := func(t *testing.T, result *android.TestResult, variant string) {
+	check := func(t *testing.T, variant string, runtimeLinkage expectedRuntimeLinkage, preparer android.FixturePreparer) {
+		result := preparer.RunTestWithBp(t, bp)
 		ctx := result.TestContext
 		asanVariant := variant + "_asan"
 		sharedVariant := variant + "_shared"
@@ -198,6 +244,8 @@
 		libStaticAsan := result.ModuleForTests("libstatic_asan", staticAsanVariant)
 		libStaticAsanNoAsanVariant := result.ModuleForTests("libstatic_asan", staticVariant)
 
+		libAsanSharedRuntime := result.ModuleForTests("libclang_rt.asan", sharedVariant)
+
 		expectSharedLinkDep(t, ctx, binWithAsan, libShared)
 		expectSharedLinkDep(t, ctx, binWithAsan, libAsan)
 		expectSharedLinkDep(t, ctx, libShared, libTransitive)
@@ -227,10 +275,28 @@
 		expectInstallDep(t, binNoAsan, libTransitive)
 		expectInstallDep(t, libShared, libTransitive)
 		expectInstallDep(t, libAsan, libTransitive)
+
+		if runtimeLinkage == RUNTIME_LINKAGE_SHARED {
+			expectSharedLinkDep(t, ctx, binWithAsan, libAsanSharedRuntime)
+			expectNoSharedLinkDep(t, ctx, binNoAsan, libAsanSharedRuntime)
+			expectSharedLinkDep(t, ctx, libAsan, libAsanSharedRuntime)
+			expectNoSharedLinkDep(t, ctx, libShared, libAsanSharedRuntime)
+			expectNoSharedLinkDep(t, ctx, libTransitive, libAsanSharedRuntime)
+		} else {
+			expectNoSharedLinkDep(t, ctx, binWithAsan, libAsanSharedRuntime)
+			expectNoSharedLinkDep(t, ctx, binNoAsan, libAsanSharedRuntime)
+			expectNoSharedLinkDep(t, ctx, libAsan, libAsanSharedRuntime)
+			expectNoSharedLinkDep(t, ctx, libShared, libAsanSharedRuntime)
+			expectNoSharedLinkDep(t, ctx, libTransitive, libAsanSharedRuntime)
+		}
 	}
 
-	t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
-	t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+	t.Run("host", func(t *testing.T) { check(t, buildOS, RUNTIME_LINKAGE_NONE, preparer) })
+	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", RUNTIME_LINKAGE_SHARED, preparer) })
+	t.Run("host musl", func(t *testing.T) {
+		check(t, "linux_musl_x86_64", RUNTIME_LINKAGE_SHARED,
+			android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl))
+	})
 }
 
 func TestTsan(t *testing.T) {
@@ -278,12 +344,14 @@
 	}
 `
 
-	result := android.GroupFixturePreparers(
+	preparer := android.GroupFixturePreparers(
 		prepareForCcTest,
 		prepareForTsanTest,
-	).RunTestWithBp(t, bp)
+	)
+	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String()
 
-	check := func(t *testing.T, result *android.TestResult, variant string) {
+	check := func(t *testing.T, variant string, preparer android.FixturePreparer) {
+		result := preparer.RunTestWithBp(t, bp)
 		ctx := result.TestContext
 		tsanVariant := variant + "_tsan"
 		sharedVariant := variant + "_shared"
@@ -311,8 +379,11 @@
 		expectSharedLinkDep(t, ctx, libTsan, libTransitive)
 	}
 
-	t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
-	t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) })
+	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", preparer) })
+	t.Run("host musl", func(t *testing.T) {
+		check(t, "linux_musl_x86_64", android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl))
+	})
 }
 
 func TestMiscUndefined(t *testing.T) {
@@ -369,11 +440,13 @@
 	}
 `
 
-	result := android.GroupFixturePreparers(
+	preparer := android.GroupFixturePreparers(
 		prepareForCcTest,
-	).RunTestWithBp(t, bp)
+	)
+	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String()
 
-	check := func(t *testing.T, result *android.TestResult, variant string) {
+	check := func(t *testing.T, variant string, preparer android.FixturePreparer) {
+		result := preparer.RunTestWithBp(t, bp)
 		ctx := result.TestContext
 		staticVariant := variant + "_static"
 
@@ -415,8 +488,11 @@
 		expectStaticLinkDep(t, ctx, binNoUbsan, libUbsan)
 	}
 
-	t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
-	t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) })
+	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", preparer) })
+	t.Run("host musl", func(t *testing.T) {
+		check(t, "linux_musl_x86_64", android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl))
+	})
 }
 
 func TestFuzz(t *testing.T) {
@@ -647,11 +723,13 @@
 		}
 	`
 
-	result := android.GroupFixturePreparers(
+	preparer := android.GroupFixturePreparers(
 		prepareForCcTest,
-	).RunTestWithBp(t, bp)
+	)
+	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String()
 
-	check := func(t *testing.T, result *android.TestResult, variant string) {
+	check := func(t *testing.T, variant string, preparer android.FixturePreparer) {
+		result := preparer.RunTestWithBp(t, bp)
 		staticVariant := variant + "_static"
 		sharedVariant := variant + "_shared"
 
@@ -705,8 +783,11 @@
 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
 	}
 
-	t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
-	t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) })
+	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", preparer) })
+	t.Run("host musl", func(t *testing.T) {
+		check(t, "linux_musl_x86_64", android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl))
+	})
 }
 
 type MemtagNoteType int
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 32878ca..bb6e257 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -522,6 +522,8 @@
 	return false
 }
 
+var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+
 func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool {
 	switch t {
 	case cfi:
@@ -644,8 +646,6 @@
 	return module.Init()
 }
 
-var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
-
 // Module definitions for snapshots of executable binaries.
 //
 // Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable
diff --git a/cc/testing.go b/cc/testing.go
index 992069b..d38a57c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -70,6 +70,7 @@
 	return `
 		cc_defaults {
 			name: "toolchain_libs_defaults",
+			host_supported: true,
 			vendor_available: true,
 			product_available: true,
 			recovery_available: true,
@@ -135,6 +136,12 @@
 		}
 
 		cc_prebuilt_library_static {
+			name: "libclang_rt.ubsan_standalone.static",
+			defaults: ["toolchain_libs_defaults"],
+			srcs: [""],
+		}
+
+		cc_prebuilt_library_static {
 			name: "libclang_rt.ubsan_minimal",
 			defaults: ["toolchain_libs_defaults"],
 			host_supported: true,
@@ -151,6 +158,12 @@
 				linux_glibc_x86: {
 					srcs: ["libclang_rt.ubsan_minimal.x86.a"],
 				},
+				linux_musl_x86_64: {
+					srcs: ["libclang_rt.ubsan_minimal.x86_64.a"],
+				},
+				linux_musl_x86: {
+					srcs: ["libclang_rt.ubsan_minimal.x86.a"],
+				},
 			},
 		}
 
@@ -619,6 +632,45 @@
 	}),
 )
 
+// PrepareForTestWithHostMusl sets the host configuration to musl libc instead of glibc.  It also disables the test
+// on mac, which doesn't support musl libc, and adds musl modules.
+var PrepareForTestWithHostMusl = android.GroupFixturePreparers(
+	android.FixtureModifyConfig(android.ModifyTestConfigForMusl),
+	android.PrepareForSkipTestOnMac,
+	android.FixtureAddTextFile("external/musl/Android.bp", `
+		cc_defaults {
+			name: "libc_musl_crt_defaults",
+			host_supported: true,
+			device_supported: false,
+		}
+
+		cc_object {
+			name: "libc_musl_crtbegin_so",
+			defaults: ["libc_musl_crt_defaults"],
+		}
+
+		cc_object {
+			name: "libc_musl_crtend_so",
+			defaults: ["libc_musl_crt_defaults"],
+		}
+
+		cc_object {
+			name: "libc_musl_crtbegin_dynamic",
+			defaults: ["libc_musl_crt_defaults"],
+		}
+
+		cc_object {
+			name: "libc_musl_crtbegin_static",
+			defaults: ["libc_musl_crt_defaults"],
+		}
+
+		cc_object {
+			name: "libc_musl_crtend",
+			defaults: ["libc_musl_crt_defaults"],
+		}
+	`),
+)
+
 // TestConfig is the legacy way of creating a test Config for testing cc modules.
 //
 // See testCc for an explanation as to how to stop using this deprecated method.
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 82db634..2e71fe1 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -41,6 +41,7 @@
 	abis             map[android_bundle_proto.Abi_AbiAlias]int
 	allowPrereleased bool
 	stem             string
+	skipSdkCheck     bool
 }
 
 // An APK set is a zip archive. An entry 'toc.pb' describes its contents.
@@ -322,6 +323,12 @@
 
 func (m sdkVersionTargetingMatcher) matches(config TargetConfig) bool {
 	const preReleaseVersion = 10000
+	// TODO (b274518686) This check should only be used while SHA based targeting is active
+	// Once we have switched to an SDK version, this can be changed to throw an error if
+	// it was accidentally set
+	if config.skipSdkCheck == true {
+		return true
+	}
 	if m.SdkVersionTargeting == nil {
 		return true
 	}
@@ -572,7 +579,7 @@
 func processArgs() {
 	flag.Usage = func() {
 		fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> [-zip <output-zip-file>] `+
-			`-sdk-version value -abis value `+
+			`-sdk-version value -abis value [-skip-sdk-check]`+
 			`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
 			`[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
 		flag.PrintDefaults()
@@ -585,6 +592,7 @@
 		"'all' or comma-separated list of screen density names (NODPI LDPI MDPI TVDPI HDPI XHDPI XXHDPI XXXHDPI)")
 	flag.BoolVar(&targetConfig.allowPrereleased, "allow-prereleased", false,
 		"allow prereleased")
+	flag.BoolVar(&targetConfig.skipSdkCheck, "skip-sdk-check", false, "Skip the SDK version check")
 	flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
 	flag.Parse()
 	if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 ||
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 9b51160..3a4d71a 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -78,6 +78,7 @@
 	flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
 	flag.StringVar(&cmdlineArgs.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
 	flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
+	flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
 	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
 	flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
 	flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 3d8458c..301246a 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -169,7 +169,7 @@
 
 	// Create a new Status instance, which manages action counts and event output channels.
 	stat := &status.Status{}
-	defer stat.Finish()
+
 	// Hook up the terminal output and tracer to Status.
 	stat.AddOutput(output)
 	stat.AddOutput(trace.StatusTracer())
@@ -221,13 +221,14 @@
 
 	trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
 
-	if !config.SkipMetricsUpload() {
-		defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, bazelProfileFile, bazelMetricsFile, metricsFiles...)
-	}
-	defer met.Dump(soongMetricsFile)
-	// Should run before Metric.Dump
-	defer criticalPath.WriteToMetrics(met)
-
+	defer func() {
+		stat.Finish()
+		criticalPath.WriteToMetrics(met)
+		met.Dump(soongMetricsFile)
+		if !config.SkipMetricsUpload() {
+			build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, bazelProfileFile, bazelMetricsFile, metricsFiles...)
+		}
+	}()
 	c.run(buildCtx, config, args)
 
 }
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 25b8fe8..023c69a 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -22,6 +22,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/cc"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -498,3 +499,11 @@
 	}
 	return fmt.Sprintf("%x", h.Sum(nil))
 }
+
+// Base cc.UseCoverage
+
+var _ cc.UseCoverage = (*filesystem)(nil)
+
+func (*filesystem) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+	return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
+}
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index a65d9dd..aef4756 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -20,6 +20,9 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/etc"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func TestMain(m *testing.M) {
@@ -28,6 +31,7 @@
 
 var fixture = android.GroupFixturePreparers(
 	android.PrepareForIntegrationTestWithAndroid,
+	etc.PrepareForTestWithPrebuiltEtc,
 	cc.PrepareForIntegrationTestWithCc,
 	PrepareForTestWithFilesystemBuildComponents,
 )
@@ -225,3 +229,56 @@
 		inputs.Strings(),
 		"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
 }
+
+func TestFileSystemWithCoverageVariants(t *testing.T) {
+	context := android.GroupFixturePreparers(
+		fixture,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.GcovCoverage = proptools.BoolPtr(true)
+			variables.Native_coverage = proptools.BoolPtr(true)
+		}),
+	)
+
+	result := context.RunTestWithBp(t, `
+		prebuilt_etc {
+			name: "prebuilt",
+			src: ":myfilesystem",
+		}
+
+		android_system_image {
+			name: "myfilesystem",
+			deps: [
+				"libfoo",
+			],
+			linker_config_src: "linker.config.json",
+		}
+
+		cc_library {
+			name: "libfoo",
+			shared_libs: [
+				"libbar",
+			],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libbar",
+			stl: "none",
+		}
+	`)
+
+	filesystem := result.ModuleForTests("myfilesystem", "android_common_cov")
+	inputs := filesystem.Output("deps.zip").Implicits
+	android.AssertStringListContains(t, "filesystem should have libfoo(cov)",
+		inputs.Strings(),
+		"out/soong/.intermediates/libfoo/android_arm64_armv8-a_shared_cov/libfoo.so")
+	android.AssertStringListContains(t, "filesystem should have libbar(cov)",
+		inputs.Strings(),
+		"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared_cov/libbar.so")
+
+	filesystemOutput := filesystem.Output("myfilesystem.img").Output
+	prebuiltInput := result.ModuleForTests("prebuilt", "android_arm64_armv8-a").Rule("Cp").Input
+	if filesystemOutput != prebuiltInput {
+		t.Error("prebuilt should use cov variant of filesystem")
+	}
+}
diff --git a/java/aar.go b/java/aar.go
index 7c45efe..f162a17 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -220,12 +220,12 @@
 	linkDeps = append(linkDeps, assetDeps...)
 
 	// Returns the effective version for {min|target}_sdk_version
-	effectiveVersionString := func(sdkVersion android.SdkSpec, minSdkVersion android.SdkSpec) string {
+	effectiveVersionString := func(sdkVersion android.SdkSpec, minSdkVersion android.ApiLevel) string {
 		// If {min|target}_sdk_version is current, use sdk_version to determine the effective level
 		// This is necessary for vendor modules.
 		// The effective version does not _only_ depend on {min|target}_sdk_version(level),
 		// but also on the sdk_version (kind+level)
-		if minSdkVersion.ApiLevel.IsCurrent() {
+		if minSdkVersion.IsCurrent() {
 			ret, err := sdkVersion.EffectiveVersionString(ctx)
 			if err != nil {
 				ctx.ModuleErrorf("invalid sdk_version: %s", err)
@@ -689,7 +689,7 @@
 	jniPackages android.Paths
 
 	sdkVersion    android.SdkSpec
-	minSdkVersion android.SdkSpec
+	minSdkVersion android.ApiLevel
 }
 
 var _ android.OutputFileProducer = (*AARImport)(nil)
@@ -714,19 +714,19 @@
 	return ""
 }
 
-func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 	if a.properties.Min_sdk_version != nil {
-		return android.SdkSpecFrom(ctx, *a.properties.Min_sdk_version)
+		return android.ApiLevelFrom(ctx, *a.properties.Min_sdk_version)
 	}
-	return a.SdkVersion(ctx)
+	return a.SdkVersion(ctx).ApiLevel
 }
 
 func (a *AARImport) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
 	return android.SdkSpecFrom(ctx, "")
 }
 
-func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return a.SdkVersion(ctx)
+func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return a.SdkVersion(ctx).ApiLevel
 }
 
 func (a *AARImport) javaVersion() string {
@@ -1067,10 +1067,7 @@
 
 	neverlink := true
 	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "android_library",
-			Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
-		},
+		AndroidLibraryBazelTargetModuleProperties(),
 		android.CommonAttributes{Name: name + "-neverlink"},
 		&bazelAndroidLibrary{
 			javaLibraryAttributes: &javaLibraryAttributes{
@@ -1081,6 +1078,12 @@
 	)
 
 }
+func AndroidLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
+	return bazel.BazelTargetModuleProperties{
+		Rule_class:        "android_library",
+		Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
+	}
+}
 
 func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	commonAttrs, bp2buildInfo := a.convertLibraryAttrsBp2Build(ctx)
@@ -1093,10 +1096,7 @@
 		ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
 	}
 	name := a.Name()
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "android_library",
-		Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
-	}
+	props := AndroidLibraryBazelTargetModuleProperties()
 
 	ctx.CreateBazelTargetModule(
 		props,
diff --git a/java/android_manifest.go b/java/android_manifest.go
index f6457a0..dbcf098 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -44,14 +44,14 @@
 // When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK
 // This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
 func targetSdkVersionForManifestFixer(ctx android.ModuleContext, params ManifestFixerParams) string {
-	targetSdkVersionSpec := params.SdkContext.TargetSdkVersion(ctx)
+	targetSdkVersionLevel := params.SdkContext.TargetSdkVersion(ctx)
 
 	// Check if we want to return 10000
 	// TODO(b/240294501): Determine the rules for handling test apexes
-	if shouldReturnFinalOrFutureInt(ctx, targetSdkVersionSpec, params.EnforceDefaultTargetSdkVersion) {
+	if shouldReturnFinalOrFutureInt(ctx, targetSdkVersionLevel, params.EnforceDefaultTargetSdkVersion) {
 		return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
 	}
-	targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx)
+	targetSdkVersion, err := targetSdkVersionLevel.EffectiveVersionString(ctx)
 	if err != nil {
 		ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
 	}
@@ -62,11 +62,11 @@
 // 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty)
 // 2. The module is run as part of MTS, and should be testable on stable branches
 // Do not return 10000 if we are enforcing default targetSdkVersion and sdk has been finalised
-func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionSpec android.SdkSpec, enforceDefaultTargetSdkVersion bool) bool {
+func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionLevel android.ApiLevel, enforceDefaultTargetSdkVersion bool) bool {
 	if enforceDefaultTargetSdkVersion && ctx.Config().PlatformSdkFinal() {
 		return false
 	}
-	return targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module()))
+	return targetSdkVersionLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module()))
 }
 
 // Helper function that casts android.Module to java.androidTestApp
diff --git a/java/app.go b/java/app.go
index f596673..52caf6d 100755
--- a/java/app.go
+++ b/java/app.go
@@ -752,7 +752,7 @@
 
 type appDepsInterface interface {
 	SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
-	MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+	MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel
 	RequiresStableAPIs(ctx android.BaseModuleContext) bool
 }
 
@@ -865,10 +865,10 @@
 		} else {
 			toMinSdkVersion := "(no version)"
 			if m, ok := to.(interface {
-				MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+				MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel
 			}); ok {
-				if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() {
-					toMinSdkVersion = v.ApiLevel.String()
+				if v := m.MinSdkVersion(ctx); !v.IsNone() {
+					toMinSdkVersion = v.String()
 				}
 			} else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
 				// TODO(b/175678607) eliminate the use of MinSdkVersion returning
@@ -1495,6 +1495,10 @@
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
 }
 
+type manifestValueAttribute struct {
+	MinSdkVersion *string
+}
+
 type bazelAndroidAppAttributes struct {
 	*javaCommonAttributes
 	*bazelAapt
@@ -1502,6 +1506,7 @@
 	Custom_package   *string
 	Certificate      bazel.LabelAttribute
 	Certificate_name bazel.StringAttribute
+	Manifest_values  *manifestValueAttribute
 }
 
 // ConvertWithBp2build is used to convert android_app to Bazel.
@@ -1516,11 +1521,23 @@
 
 	certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate)
 
+	manifestValues := &manifestValueAttribute{}
+	// TODO(b/274474008 ): Directly convert deviceProperties.Min_sdk_version in bp2build
+	// MinSdkVersion(ctx) calls SdkVersion(ctx) if no value for min_sdk_version is set
+	minSdkVersion := a.MinSdkVersion(ctx)
+	if !minSdkVersion.IsPreview() && !minSdkVersion.IsInvalid() {
+		minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx)
+		if err == nil {
+			manifestValues.MinSdkVersion = &minSdkStr
+		}
+	}
+
 	appAttrs := &bazelAndroidAppAttributes{
 		// TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
 		Custom_package:   a.overridableAppProperties.Package_name,
 		Certificate:      certificate,
 		Certificate_name: certificateName,
+		Manifest_values:  manifestValues,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
@@ -1535,10 +1552,7 @@
 	} else {
 		ktName := a.Name() + "_kt"
 		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "android_library",
-				Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
-			},
+			AndroidLibraryBazelTargetModuleProperties(),
 			android.CommonAttributes{Name: ktName},
 			&bazelAndroidLibrary{
 				javaLibraryAttributes: &javaLibraryAttributes{
diff --git a/java/app_import.go b/java/app_import.go
index e24e780..c1de667 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -426,8 +426,8 @@
 	return android.SdkSpecPrivate
 }
 
-func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return android.SdkSpecPrivate
+func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return android.SdkSpecPrivate.ApiLevel
 }
 
 func (a *AndroidAppImport) LintDepSets() LintDepSets {
diff --git a/java/app_set.go b/java/app_set.go
index 0f55b77..d2d3b06 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -142,6 +142,7 @@
 				"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
 				"screen-densities":  screenDensities,
 				"sdk-version":       ctx.Config().PlatformSdkVersion().String(),
+				"skip-sdk-check":    strconv.FormatBool(ctx.Config().IsEnvTrue("SOONG_SKIP_APPSET_SDK_CHECK")),
 				"stem":              as.BaseModuleName(),
 				"apkcerts":          as.apkcertsFile.String(),
 				"partition":         as.PartitionTag(ctx.DeviceConfig()),
diff --git a/java/app_set_test.go b/java/app_set_test.go
index 03eb667..10bc5de 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -89,6 +89,7 @@
 				"allow-prereleased": "false",
 				"screen-densities":  "LDPI,XXHDPI",
 				"sdk-version":       "29",
+				"skip-sdk-check":    "false",
 				"stem":              "foo",
 			},
 		},
@@ -105,6 +106,7 @@
 				"allow-prereleased": "false",
 				"screen-densities":  "all",
 				"sdk-version":       "30",
+				"skip-sdk-check":    "false",
 				"stem":              "foo",
 			},
 		},
diff --git a/java/app_test.go b/java/app_test.go
index 5b16cea..561be68 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3077,13 +3077,17 @@
 		},
 	}
 	for _, testCase := range testCases {
+		targetSdkVersionTemplate := ""
+		if testCase.targetSdkVersionInBp != "" {
+			targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, testCase.targetSdkVersionInBp)
+		}
 		bp := fmt.Sprintf(`
 			android_app {
 				name: "foo",
 				sdk_version: "current",
-				target_sdk_version: "%v",
+				%s
 			}
-			`, testCase.targetSdkVersionInBp)
+			`, targetSdkVersionTemplate)
 		fixture := android.GroupFixturePreparers(
 			prepareForJavaTest,
 			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -3161,16 +3165,20 @@
 		},
 	}
 	for _, testCase := range testCases {
+		targetSdkVersionTemplate := ""
+		if testCase.targetSdkVersionInBp != nil {
+			targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, *testCase.targetSdkVersionInBp)
+		}
 		bp := fmt.Sprintf(`
 			android_app {
 				name: "foo",
 				sdk_version: "current",
 				min_sdk_version: "29",
-				target_sdk_version: "%v",
+				%s
 				updatable: %t,
 				enforce_default_target_sdk_version: %t
 			}
-			`, proptools.String(testCase.targetSdkVersionInBp), testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable
+			`, targetSdkVersionTemplate, testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable
 
 		fixture := android.GroupFixturePreparers(
 			PrepareForTestWithJavaDefaultModules,
diff --git a/java/base.go b/java/base.go
index 85f4a5e..2d213a1 100644
--- a/java/base.go
+++ b/java/base.go
@@ -489,7 +489,7 @@
 	hideApexVariantFromMake bool
 
 	sdkVersion    android.SdkSpec
-	minSdkVersion android.SdkSpec
+	minSdkVersion android.ApiLevel
 	maxSdkVersion android.SdkSpec
 
 	sourceExtensions []string
@@ -665,11 +665,11 @@
 	return proptools.String(j.deviceProperties.System_modules)
 }
 
-func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 	if j.deviceProperties.Min_sdk_version != nil {
-		return android.SdkSpecFrom(ctx, *j.deviceProperties.Min_sdk_version)
+		return android.ApiLevelFrom(ctx, *j.deviceProperties.Min_sdk_version)
 	}
-	return j.SdkVersion(ctx)
+	return j.SdkVersion(ctx).ApiLevel
 }
 
 func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
@@ -685,14 +685,14 @@
 }
 
 func (j *Module) MinSdkVersionString() string {
-	return j.minSdkVersion.Raw
+	return j.minSdkVersion.String()
 }
 
-func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 	if j.deviceProperties.Target_sdk_version != nil {
-		return android.SdkSpecFrom(ctx, *j.deviceProperties.Target_sdk_version)
+		return android.ApiLevelFrom(ctx, *j.deviceProperties.Target_sdk_version)
 	}
-	return j.SdkVersion(ctx)
+	return j.SdkVersion(ctx).ApiLevel
 }
 
 func (j *Module) AvailableFor(what string) bool {
@@ -881,7 +881,7 @@
 		j.ignoredAidlPermissionList = android.PathsForModuleSrcExcludes(ctx, exceptions, nil)
 	}
 
-	aidlMinSdkVersion := j.MinSdkVersion(ctx).ApiLevel.String()
+	aidlMinSdkVersion := j.MinSdkVersion(ctx).String()
 	flags = append(flags, "--min_sdk_version="+aidlMinSdkVersion)
 
 	return strings.Join(flags, " "), deps
@@ -1542,9 +1542,9 @@
 	}
 
 	if ctx.Device() {
-		lintSDKVersion := func(sdkSpec android.SdkSpec) int {
-			if v := sdkSpec.ApiLevel; !v.IsPreview() {
-				return v.FinalInt()
+		lintSDKVersion := func(apiLevel android.ApiLevel) int {
+			if !apiLevel.IsPreview() {
+				return apiLevel.FinalInt()
 			} else {
 				// When running metalava, we pass --version-codename. When that value
 				// is not REL, metalava will add 1 to the --current-version argument.
@@ -1576,7 +1576,7 @@
 		j.linter.classes = j.implementationJarFile
 		j.linter.minSdkVersion = lintSDKVersion(j.MinSdkVersion(ctx))
 		j.linter.targetSdkVersion = lintSDKVersion(j.TargetSdkVersion(ctx))
-		j.linter.compileSdkVersion = lintSDKVersion(j.SdkVersion(ctx))
+		j.linter.compileSdkVersion = lintSDKVersion(j.SdkVersion(ctx).ApiLevel)
 		j.linter.compileSdkKind = j.SdkVersion(ctx).Kind
 		j.linter.javaLanguageLevel = flags.javaVersion.String()
 		j.linter.kotlinLanguageLevel = "1.3"
@@ -1846,15 +1846,14 @@
 // Implements android.ApexModule
 func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
 	sdkVersionSpec := j.SdkVersion(ctx)
-	minSdkVersionSpec := j.MinSdkVersion(ctx)
-	if !minSdkVersionSpec.Specified() {
+	minSdkVersion := j.MinSdkVersion(ctx)
+	if !minSdkVersion.Specified() {
 		return fmt.Errorf("min_sdk_version is not specified")
 	}
 	// If the module is compiling against core (via sdk_version), skip comparison check.
 	if sdkVersionSpec.Kind == android.SdkCore {
 		return nil
 	}
-	minSdkVersion := minSdkVersionSpec.ApiLevel
 	if minSdkVersion.GreaterThan(sdkVersion) {
 		return fmt.Errorf("newer SDK(%v)", minSdkVersion)
 	}
@@ -1924,15 +1923,15 @@
 		"stub-annotations", "private-stub-annotations-jar",
 		"core-lambda-stubs", "core-generated-annotation-stubs":
 		return javaCore, true
-	case "android_stubs_current":
+	case android.SdkPublic.JavaLibraryName(ctx.Config()):
 		return javaSdk, true
-	case "android_system_stubs_current":
+	case android.SdkSystem.JavaLibraryName(ctx.Config()):
 		return javaSystem, true
-	case "android_module_lib_stubs_current":
+	case android.SdkModule.JavaLibraryName(ctx.Config()):
 		return javaModule, true
-	case "android_system_server_stubs_current":
+	case android.SdkSystemServer.JavaLibraryName(ctx.Config()):
 		return javaSystemServer, true
-	case "android_test_stubs_current":
+	case android.SdkTest.JavaLibraryName(ctx.Config()):
 		return javaSystem, true
 	}
 
diff --git a/java/builder.go b/java/builder.go
index 6f8eec9..4626267 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -131,13 +131,13 @@
 		blueprint.RuleParams{
 			Command: `rm -rf "$out" && ` +
 				`${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
-				`-sdk-version=${sdk-version} -abis=${abis} ` +
+				`-sdk-version=${sdk-version} -skip-sdk-check=${skip-sdk-check} -abis=${abis} ` +
 				`--screen-densities=${screen-densities} --stem=${stem} ` +
 				`-apkcerts=${apkcerts} -partition=${partition} ` +
 				`${in}`,
 			CommandDeps: []string{"${config.ExtractApksCmd}"},
 		},
-		"abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition", "zip")
+		"abis", "allow-prereleased", "screen-densities", "sdk-version", "skip-sdk-check", "stem", "apkcerts", "partition", "zip")
 
 	turbine, turbineRE = pctx.RemoteStaticRules("turbine",
 		blueprint.RuleParams{
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index cf81ddb..45e6175 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -130,13 +130,13 @@
 				if s, ok := m.(*SdkLibrary); ok {
 					// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
 					if s.minSdkVersion.Specified() {
-						if s.minSdkVersion.ApiLevel.IsCurrent() {
+						if s.minSdkVersion.IsCurrent() {
 							jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
 						} else {
-							jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
+							jar.minSdkVersion = s.minSdkVersion.String()
 						}
 					}
-					if s.maxSdkVersion.Specified() {
+					if s.maxSdkVersion.ApiLevel.Specified() {
 						if s.maxSdkVersion.ApiLevel.IsCurrent() {
 							jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
 						} else {
diff --git a/java/config/config.go b/java/config/config.go
index 838d007..13670ee 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -94,10 +94,12 @@
 		"-JXX:+TieredCompilation",
 		"-JXX:TieredStopAtLevel=1",
 		"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
+		"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
 	}, dexerJavaVmFlagsList...))
 	exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
 		"-JXmx2048M",
 		"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
+		"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
 	}, dexerJavaVmFlagsList...))
 
 	exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
diff --git a/java/dex.go b/java/dex.go
index 7b6a99a..4d6aa34 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -343,7 +343,7 @@
 type compileDexParams struct {
 	flags         javaBuilderFlags
 	sdkVersion    android.SdkSpec
-	minSdkVersion android.SdkSpec
+	minSdkVersion android.ApiLevel
 	classesJar    android.Path
 	jarName       string
 }
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index e0a0629..0ffedf6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -293,6 +293,12 @@
 	isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
 
 	bootImage := defaultBootImageConfig(ctx)
+	// When `global.PreoptWithUpdatableBcp` is true, `bcpForDexpreopt` below includes the mainline
+	// boot jars into bootclasspath, so we should include the mainline boot image as well because it's
+	// generated from those jars.
+	if global.PreoptWithUpdatableBcp {
+		bootImage = mainlineBootImageConfig(ctx)
+	}
 	dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
 
 	targets := ctx.MultiTargets()
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 373b478..f4827ea 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -291,6 +291,9 @@
 
 	// The "--compiler-filter" argument.
 	compilerFilter string
+
+	// The "--single-image" argument.
+	singleImage bool
 }
 
 // Target-dependent description of a boot image.
@@ -398,6 +401,9 @@
 		for _, ext := range exts {
 			ret = append(ret, dir.Join(ctx, name+ext))
 		}
+		if image.singleImage {
+			break
+		}
 	}
 	return ret
 }
@@ -768,6 +774,10 @@
 		cmd.FlagWithArg("--compiler-filter=", image.compilerFilter)
 	}
 
+	if image.singleImage {
+		cmd.Flag("--single-image")
+	}
+
 	// Use the default variant/features for host builds.
 	// The map below contains only device CPU info (which might be x86 on some devices).
 	if image.target.Os == android.Android {
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 76c78cb..8c62c33 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -44,6 +44,8 @@
 	bootImageConfigRawKey  = android.NewOnceKey("bootImageConfigRaw")
 	artBootImageName       = "art"
 	frameworkBootImageName = "boot"
+	mainlineBootImageName  = "mainline"
+	bootImageStem          = "boot"
 )
 
 func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
@@ -52,37 +54,52 @@
 
 		artModules := global.ArtApexJars
 		frameworkModules := global.BootJars.RemoveList(artModules)
+		mainlineBcpModules := global.ApexBootJars
+		frameworkSubdir := "system/framework"
 
 		// ART config for the primary boot image in the ART apex.
 		// It includes the Core Libraries.
 		artCfg := bootImageConfig{
 			name:                     artBootImageName,
-			stem:                     "boot",
+			stem:                     bootImageStem,
 			installDirOnHost:         "apex/art_boot_images/javalib",
-			installDirOnDevice:       "system/framework",
+			installDirOnDevice:       frameworkSubdir,
 			profileInstallPathInApex: "etc/boot-image.prof",
 			modules:                  artModules,
 			preloadedClassesFile:     "art/build/boot/preloaded-classes",
 			compilerFilter:           "speed-profile",
+			singleImage:              false,
 		}
 
 		// Framework config for the boot image extension.
 		// It includes framework libraries and depends on the ART config.
-		frameworkSubdir := "system/framework"
 		frameworkCfg := bootImageConfig{
 			extends:              &artCfg,
 			name:                 frameworkBootImageName,
-			stem:                 "boot",
+			stem:                 bootImageStem,
 			installDirOnHost:     frameworkSubdir,
 			installDirOnDevice:   frameworkSubdir,
 			modules:              frameworkModules,
 			preloadedClassesFile: "frameworks/base/config/preloaded-classes",
 			compilerFilter:       "speed-profile",
+			singleImage:          false,
+		}
+
+		mainlineCfg := bootImageConfig{
+			extends:            &frameworkCfg,
+			name:               mainlineBootImageName,
+			stem:               bootImageStem,
+			installDirOnHost:   frameworkSubdir,
+			installDirOnDevice: frameworkSubdir,
+			modules:            mainlineBcpModules,
+			compilerFilter:     "verify",
+			singleImage:        true,
 		}
 
 		return map[string]*bootImageConfig{
 			artBootImageName:       &artCfg,
 			frameworkBootImageName: &frameworkCfg,
+			mainlineBootImageName:  &mainlineCfg,
 		}
 	}).(map[string]*bootImageConfig)
 }
@@ -174,6 +191,10 @@
 	return genBootImageConfigs(ctx)[frameworkBootImageName]
 }
 
+func mainlineBootImageConfig(ctx android.PathContext) *bootImageConfig {
+	return genBootImageConfigs(ctx)[mainlineBootImageName]
+}
+
 // Apex boot config allows to access build/install paths of apex boot jars without going
 // through the usual trouble of registering dependencies on those modules and extracting build paths
 // from those dependencies.
diff --git a/java/dexpreopt_config_test.go b/java/dexpreopt_config_test.go
index b704d09..cd7f295 100644
--- a/java/dexpreopt_config_test.go
+++ b/java/dexpreopt_config_test.go
@@ -28,8 +28,10 @@
 
 	result := android.GroupFixturePreparers(
 		PrepareForBootImageConfigTest,
+		PrepareApexBootJarConfigs,
 	).RunTest(t)
 
 	CheckArtBootImageConfig(t, result)
 	CheckFrameworkBootImageConfig(t, result)
+	CheckMainlineBootImageConfig(t, result)
 }
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index c509c1b..86dd329 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -39,6 +39,78 @@
 	FixtureConfigureBootJars("com.android.art:core1", "com.android.art:core2", "platform:framework"),
 )
 
+var PrepareApexBootJarConfigs = FixtureConfigureApexBootJars(
+	"com.android.foo:framework-foo", "com.android.bar:framework-bar")
+
+var PrepareApexBootJarConfigsAndModules = android.GroupFixturePreparers(
+	PrepareApexBootJarConfigs,
+	prepareApexBootJarModule("com.android.foo", "framework-foo"),
+	prepareApexBootJarModule("com.android.bar", "framework-bar"),
+)
+
+var ApexBootJarFragmentsForPlatformBootclasspath = fmt.Sprintf(`
+	{
+		apex: "%[1]s",
+		module: "%[1]s-bootclasspathfragment",
+	},
+	{
+		apex: "%[2]s",
+		module: "%[2]s-bootclasspathfragment",
+	},
+`, "com.android.foo", "com.android.bar")
+
+var ApexBootJarDexJarPaths = []string{
+	"out/soong/.intermediates/packages/modules/com.android.bar/framework-bar/android_common_apex10000/aligned/framework-bar.jar",
+	"out/soong/.intermediates/packages/modules/com.android.foo/framework-foo/android_common_apex10000/aligned/framework-foo.jar",
+}
+
+func prepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
+	moduleSourceDir := fmt.Sprintf("packages/modules/%s", apexName)
+	return android.GroupFixturePreparers(
+		android.FixtureAddTextFile(moduleSourceDir+"/Android.bp", fmt.Sprintf(`
+			apex {
+				name: "%[1]s",
+				key: "%[1]s.key",
+				bootclasspath_fragments: [
+					"%[1]s-bootclasspathfragment",
+				],
+				updatable: false,
+			}
+
+			apex_key {
+				name: "%[1]s.key",
+				public_key: "%[1]s.avbpubkey",
+				private_key: "%[1]s.pem",
+			}
+
+			bootclasspath_fragment {
+				name: "%[1]s-bootclasspathfragment",
+				contents: ["%[2]s"],
+				apex_available: ["%[1]s"],
+				hidden_api: {
+					split_packages: ["*"],
+				},
+			}
+
+			java_library {
+				name: "%[2]s",
+				srcs: ["%[2]s.java"],
+				system_modules: "none",
+				sdk_version: "none",
+				compile_dex: true,
+				apex_available: ["%[1]s"],
+			}
+		`, apexName, moduleName)),
+		android.FixtureMergeMockFs(android.MockFS{
+			fmt.Sprintf("%s/apex_manifest.json", moduleSourceDir):          nil,
+			fmt.Sprintf("%s/%s.avbpubkey", moduleSourceDir, apexName):      nil,
+			fmt.Sprintf("%s/%s.pem", moduleSourceDir, apexName):            nil,
+			fmt.Sprintf("system/sepolicy/apex/%s-file_contexts", apexName): nil,
+			fmt.Sprintf("%s/%s.java", moduleSourceDir, moduleName):         nil,
+		}),
+	)
+}
+
 // normalizedInstall represents a android.RuleBuilderInstall that has been normalized to remove
 // test specific parts of the From path.
 type normalizedInstall struct {
@@ -601,6 +673,290 @@
 	checkBootImageConfig(t, imageConfig, mutated, expected)
 }
 
+// getMainlineImageConfig gets the framework bootImageConfig that was created during the test.
+func getMainlineImageConfig(result *android.TestResult) *bootImageConfig {
+	pathCtx := &android.TestPathContext{TestResult: result}
+	imageConfig := mainlineBootImageConfig(pathCtx)
+	return imageConfig
+}
+
+// CheckMainlineBootImageConfig checks the status of the fields of the bootImageConfig and
+// bootImageVariant structures that are returned from mainlineBootImageConfig.
+//
+// This is before any fields are mutated.
+func CheckMainlineBootImageConfig(t *testing.T, result *android.TestResult) {
+	expectedLicenseMetadataFile := ""
+	imageConfig := getMainlineImageConfig(result)
+
+	expected := &expectedConfig{
+		name:                     "mainline",
+		stem:                     "boot",
+		dir:                      "out/soong/test_device/dex_mainlinejars",
+		symbolsDir:               "out/soong/test_device/dex_mainlinejars_unstripped",
+		installDirOnDevice:       "system/framework",
+		installDirOnHost:         "system/framework",
+		profileInstallPathInApex: "",
+		modules: android.CreateTestConfiguredJarList([]string{
+			"com.android.foo:framework-foo",
+			"com.android.bar:framework-bar",
+		}),
+		dexPaths: []string{
+			"out/soong/test_device/dex_mainlinejars_input/framework-foo.jar",
+			"out/soong/test_device/dex_mainlinejars_input/framework-bar.jar",
+		},
+		dexPathsDeps: []string{
+			"out/soong/test_device/dex_artjars_input/core1.jar",
+			"out/soong/test_device/dex_artjars_input/core2.jar",
+			"out/soong/test_device/dex_bootjars_input/framework.jar",
+			"out/soong/test_device/dex_mainlinejars_input/framework-foo.jar",
+			"out/soong/test_device/dex_mainlinejars_input/framework-bar.jar",
+		},
+		zip: "out/soong/test_device/dex_mainlinejars/mainline.zip",
+		variants: []*expectedVariant{
+			{
+				archType: android.Arm64,
+				dexLocations: []string{
+					"/apex/com.android.foo/javalib/framework-foo.jar",
+					"/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				dexLocationsDeps: []string{
+					"/apex/com.android.art/javalib/core1.jar",
+					"/apex/com.android.art/javalib/core2.jar",
+					"/system/framework/framework.jar",
+					"/apex/com.android.foo/javalib/framework-foo.jar",
+					"/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art",
+				imagePathOnDevice: "/system/framework/arm64/boot-framework-foo.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art",
+					"out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat",
+					"out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex",
+				},
+				baseImages: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+				},
+				baseImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art",
+						to:   "/system/framework/arm64/boot-framework-foo.art",
+					},
+					{
+						from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat",
+						to:   "/system/framework/arm64/boot-framework-foo.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex",
+						to:   "/system/framework/arm64/boot-framework-foo.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-foo.oat",
+						to:   "/system/framework/arm64/boot-framework-foo.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType: android.Arm,
+				dexLocations: []string{
+					"/apex/com.android.foo/javalib/framework-foo.jar",
+					"/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				dexLocationsDeps: []string{
+					"/apex/com.android.art/javalib/core1.jar",
+					"/apex/com.android.art/javalib/core2.jar",
+					"/system/framework/framework.jar",
+					"/apex/com.android.foo/javalib/framework-foo.jar",
+					"/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art",
+				imagePathOnDevice: "/system/framework/arm/boot-framework-foo.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art",
+					"out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat",
+					"out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex",
+				},
+				baseImages: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+				},
+				baseImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art",
+						to:   "/system/framework/arm/boot-framework-foo.art",
+					},
+					{
+						from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat",
+						to:   "/system/framework/arm/boot-framework-foo.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex",
+						to:   "/system/framework/arm/boot-framework-foo.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm/boot-framework-foo.oat",
+						to:   "/system/framework/arm/boot-framework-foo.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType: android.X86_64,
+				dexLocations: []string{
+					"host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+					"host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				dexLocationsDeps: []string{
+					"host/linux-x86/apex/com.android.art/javalib/core1.jar",
+					"host/linux-x86/apex/com.android.art/javalib/core2.jar",
+					"host/linux-x86/system/framework/framework.jar",
+					"host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+					"host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art",
+				imagePathOnDevice: "/system/framework/x86_64/boot-framework-foo.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art",
+					"out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
+					"out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex",
+				},
+				baseImages: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+				},
+				baseImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art",
+						to:   "/system/framework/x86_64/boot-framework-foo.art",
+					},
+					{
+						from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
+						to:   "/system/framework/x86_64/boot-framework-foo.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex",
+						to:   "/system/framework/x86_64/boot-framework-foo.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
+						to:   "/system/framework/x86_64/boot-framework-foo.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType: android.X86,
+				dexLocations: []string{
+					"host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+					"host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				dexLocationsDeps: []string{
+					"host/linux-x86/apex/com.android.art/javalib/core1.jar",
+					"host/linux-x86/apex/com.android.art/javalib/core2.jar",
+					"host/linux-x86/system/framework/framework.jar",
+					"host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+					"host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art",
+				imagePathOnDevice: "/system/framework/x86/boot-framework-foo.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art",
+					"out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat",
+					"out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex",
+				},
+				baseImages: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+				},
+				baseImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art",
+						to:   "/system/framework/x86/boot-framework-foo.art",
+					},
+					{
+						from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat",
+						to:   "/system/framework/x86/boot-framework-foo.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex",
+						to:   "/system/framework/x86/boot-framework-foo.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-foo.oat",
+						to:   "/system/framework/x86/boot-framework-foo.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+		},
+		profileInstalls:            []normalizedInstall{},
+		profileLicenseMetadataFile: expectedLicenseMetadataFile,
+	}
+
+	checkBootImageConfig(t, imageConfig, false, expected)
+}
+
 // clearMutatedFields clears fields in the expectedConfig that correspond to fields in the
 // bootImageConfig/bootImageVariant structs which are mutated outside the call to
 // genBootImageConfigs.
@@ -712,6 +1068,10 @@
 DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art:/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
 DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art:/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
 DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art:/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art:/system/framework/arm/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat:/system/framework/arm/boot-framework-foo.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art:/system/framework/arm64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art:/system/framework/x86/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art:/system/framework/x86_64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat
 DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex
 DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex
 DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex
@@ -720,6 +1080,10 @@
 DEXPREOPT_IMAGE_DEPS_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex
 DEXPREOPT_IMAGE_DEPS_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex
 DEXPREOPT_IMAGE_DEPS_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex
 DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm=%[1]s
 DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s
 DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s
@@ -728,11 +1092,17 @@
 DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
 DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
 DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
 DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/system/framework/boot.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art:/system/framework/boot-framework.art
+DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEmainline=/system/framework/boot.art:/system/framework/boot-framework.art:/system/framework/boot-framework-foo.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTart=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/test_device/dex_bootjars/android/system/framework/boot-framework.art
-DEXPREOPT_IMAGE_NAMES=art boot
+DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/test_device/dex_bootjars/android/system/framework/boot-framework.art:out/soong/test_device/dex_mainlinejars/android/system/framework/boot-framework-foo.art
+DEXPREOPT_IMAGE_NAMES=art boot mainline
 DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/test_device/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/test_device/dex_bootjars/boot.prof:/system/etc/boot-image.prof
 DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
@@ -743,6 +1113,10 @@
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_arm=out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm/boot-framework-foo.oat:/system/framework/arm/boot-framework-foo.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_arm64=out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86=out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex
@@ -751,8 +1125,13 @@
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex:/system/framework/arm64/boot-framework.vdex
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex:/system/framework/x86/boot-framework.vdex
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex:/system/framework/x86_64/boot-framework.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex:/system/framework/arm/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex:/system/framework/arm64/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex:/system/framework/x86/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex:/system/framework/x86_64/boot-framework-foo.vdex
 DEXPREOPT_IMAGE_ZIP_art=out/soong/test_device/dex_artjars/art.zip
 DEXPREOPT_IMAGE_ZIP_boot=out/soong/test_device/dex_bootjars/boot.zip
+DEXPREOPT_IMAGE_ZIP_mainline=out/soong/test_device/dex_mainlinejars/mainline.zip
 DEXPREOPT_IMAGE_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
 DEXPREOPT_IMAGE_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art
 DEXPREOPT_IMAGE_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art
@@ -761,6 +1140,10 @@
 DEXPREOPT_IMAGE_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art
 DEXPREOPT_IMAGE_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art
 DEXPREOPT_IMAGE_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art
+DEXPREOPT_IMAGE_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art
 `
 	expected := strings.TrimSpace(fmt.Sprintf(format, expectedLicenseMetadataFile))
 	actual := strings.TrimSpace(out.String())
diff --git a/java/droiddoc.go b/java/droiddoc.go
index e98b9ea..c5a957e 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -248,16 +248,16 @@
 	return proptools.String(j.properties.System_modules)
 }
 
-func (j *Javadoc) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return j.SdkVersion(ctx)
+func (j *Javadoc) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return j.SdkVersion(ctx).ApiLevel
 }
 
 func (j *Javadoc) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
 	return j.SdkVersion(ctx)
 }
 
-func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return j.SdkVersion(ctx)
+func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return j.SdkVersion(ctx).ApiLevel
 }
 
 func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
@@ -304,7 +304,7 @@
 		flags = append(flags, "-I"+src.String())
 	}
 
-	minSdkVersion := j.MinSdkVersion(ctx).ApiLevel.FinalOrFutureInt()
+	minSdkVersion := j.MinSdkVersion(ctx).FinalOrFutureInt()
 	flags = append(flags, fmt.Sprintf("--min_sdk_version=%v", minSdkVersion))
 
 	return strings.Join(flags, " "), deps
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index c4fc65f..d25096b 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -73,7 +73,7 @@
 	android.Module
 	hiddenAPIIntf
 
-	MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+	MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel
 }
 
 type hiddenAPIIntf interface {
@@ -157,7 +157,7 @@
 	// Create a copy of the dex jar which has been encoded with hiddenapi flags.
 	flagsCSV := hiddenAPISingletonPaths(ctx).flags
 	outputDir := android.PathForModuleOut(ctx, "hiddenapi").OutputPath
-	encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, android.SdkSpecNone, outputDir)
+	encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, android.NoneApiLevel, outputDir)
 
 	// Use the encoded dex jar from here onwards.
 	return encodedDex
@@ -253,7 +253,7 @@
 // The encode dex rule requires unzipping, encoding and rezipping the classes.dex files along with
 // all the resources from the input jar. It also ensures that if it was uncompressed in the input
 // it stays uncompressed in the output.
-func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, minSdkVersion android.SdkSpec, outputDir android.OutputPath) android.OutputPath {
+func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, minSdkVersion android.ApiLevel, outputDir android.OutputPath) android.OutputPath {
 
 	// The output file has the same name as the input file and is in the output directory.
 	output := outputDir.Join(ctx, dexInput.Base())
@@ -283,7 +283,7 @@
 
 	// If the library is targeted for Q and/or R then make sure that they do not
 	// have any S+ flags encoded as that will break the runtime.
-	minApiLevel := minSdkVersion.ApiLevel
+	minApiLevel := minSdkVersion
 	if !minApiLevel.IsNone() {
 		if minApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, "R")) {
 			hiddenapiFlags = hiddenapiFlags + " --max-hiddenapi-level=max-target-r"
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index be4a48e..c6176e6 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -236,9 +236,9 @@
 		testStubModules = append(testStubModules, "sdk_test_current_android")
 	} else {
 		// Use stub modules built from source
-		publicStubModules = append(publicStubModules, "android_stubs_current")
-		systemStubModules = append(systemStubModules, "android_system_stubs_current")
-		testStubModules = append(testStubModules, "android_test_stubs_current")
+		publicStubModules = append(publicStubModules, android.SdkPublic.JavaLibraryName(config))
+		systemStubModules = append(systemStubModules, android.SdkSystem.JavaLibraryName(config))
+		testStubModules = append(testStubModules, android.SdkTest.JavaLibraryName(config))
 	}
 	// We do not have prebuilts of the core platform api yet
 	corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
@@ -1278,7 +1278,7 @@
 	uncompressDex bool
 
 	// The minimum sdk version that the dex jar will be used on.
-	minSdkVersion android.SdkSpec
+	minSdkVersion android.ApiLevel
 }
 
 // bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
diff --git a/java/java.go b/java/java.go
index 15ee4a9..2a7e4e1 100644
--- a/java/java.go
+++ b/java/java.go
@@ -811,7 +811,7 @@
 	// If the min_sdk_version was set then add the canonical representation of the API level to the
 	// snapshot.
 	if j.deviceProperties.Min_sdk_version != nil {
-		canonical := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.ApiLevel.String())
+		canonical := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String())
 		p.MinSdkVersion = proptools.StringPtr(canonical)
 	}
 
@@ -1874,7 +1874,7 @@
 	hideApexVariantFromMake bool
 
 	sdkVersion    android.SdkSpec
-	minSdkVersion android.SdkSpec
+	minSdkVersion android.ApiLevel
 }
 
 var _ PermittedPackagesForUpdatableBootJars = (*Import)(nil)
@@ -1891,11 +1891,11 @@
 	return "none"
 }
 
-func (j *Import) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+func (j *Import) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 	if j.properties.Min_sdk_version != nil {
-		return android.SdkSpecFrom(ctx, *j.properties.Min_sdk_version)
+		return android.ApiLevelFrom(ctx, *j.properties.Min_sdk_version)
 	}
-	return j.SdkVersion(ctx)
+	return j.SdkVersion(ctx).ApiLevel
 }
 
 func (j *Import) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
@@ -1905,8 +1905,8 @@
 	return android.SdkSpecFrom(ctx, "")
 }
 
-func (j *Import) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return j.SdkVersion(ctx)
+func (j *Import) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return j.SdkVersion(ctx).ApiLevel
 }
 
 func (j *Import) Prebuilt() *android.Prebuilt {
@@ -2161,15 +2161,14 @@
 func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	sdkVersionSpec := j.SdkVersion(ctx)
-	minSdkVersionSpec := j.MinSdkVersion(ctx)
-	if !minSdkVersionSpec.Specified() {
+	minSdkVersion := j.MinSdkVersion(ctx)
+	if !minSdkVersion.Specified() {
 		return fmt.Errorf("min_sdk_version is not specified")
 	}
 	// If the module is compiling against core (via sdk_version), skip comparison check.
 	if sdkVersionSpec.Kind == android.SdkCore {
 		return nil
 	}
-	minSdkVersion := minSdkVersionSpec.ApiLevel
 	if minSdkVersion.GreaterThan(sdkVersion) {
 		return fmt.Errorf("newer SDK(%v)", minSdkVersion)
 	}
@@ -2815,6 +2814,20 @@
 	Kotlincflags *[]string
 }
 
+func ktJvmLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
+	return bazel.BazelTargetModuleProperties{
+		Rule_class:        "kt_jvm_library",
+		Bzl_load_location: "//build/bazel/rules/kotlin:rules.bzl",
+	}
+}
+
+func javaLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
+	return bazel.BazelTargetModuleProperties{
+		Rule_class:        "java_library",
+		Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+	}
+}
+
 func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
 	commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
 	depLabels := bp2BuildInfo.DepLabels
@@ -2844,15 +2857,9 @@
 	name := m.Name()
 
 	if !bp2BuildInfo.hasKotlin {
-		props = bazel.BazelTargetModuleProperties{
-			Rule_class:        "java_library",
-			Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
-		}
+		props = javaLibraryBazelTargetModuleProperties()
 	} else {
-		props = bazel.BazelTargetModuleProperties{
-			Rule_class:        "kt_jvm_library",
-			Bzl_load_location: "//build/bazel/rules/kotlin:rules.bzl",
-		}
+		props = ktJvmLibraryBazelTargetModuleProperties()
 	}
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
@@ -2934,33 +2941,35 @@
 		Rule_class:        "java_binary",
 		Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
 	}
-	attrs := &javaBinaryHostAttributes{
+	binAttrs := &javaBinaryHostAttributes{
 		Runtime_deps: runtimeDeps,
 		Main_class:   mainClass,
 		Jvm_flags:    jvmFlags,
 	}
 
-	if !bp2BuildInfo.hasKotlin {
-		attrs.javaCommonAttributes = commonAttrs
-		attrs.Deps = deps
-	} else {
-		ktName := m.Name() + "_kt"
-		ktProps := bazel.BazelTargetModuleProperties{
-			Rule_class:        "kt_jvm_library",
-			Bzl_load_location: "//build/bazel/rules/kotlin:rules.bzl",
-		}
-
-		ktAttrs := &javaLibraryAttributes{
-			Deps:                 deps,
-			javaCommonAttributes: commonAttrs,
-		}
-
-		ctx.CreateBazelTargetModule(ktProps, android.CommonAttributes{Name: ktName}, ktAttrs)
-		attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + ktName}})
+	if commonAttrs.Srcs.IsEmpty() {
+		binAttrs.javaCommonAttributes = commonAttrs
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
+		return
 	}
 
+	libName := m.Name() + "_lib"
+	var libProps bazel.BazelTargetModuleProperties
+	if bp2BuildInfo.hasKotlin {
+		libProps = ktJvmLibraryBazelTargetModuleProperties()
+	} else {
+		libProps = javaLibraryBazelTargetModuleProperties()
+	}
+	libAttrs := &javaLibraryAttributes{
+		Deps:                 deps,
+		javaCommonAttributes: commonAttrs,
+	}
+
+	ctx.CreateBazelTargetModule(libProps, android.CommonAttributes{Name: libName}, libAttrs)
+	binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
+
 	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
 }
 
 type bazelJavaImportAttributes struct {
@@ -2999,10 +3008,7 @@
 		Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
 	}
 	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "java_library",
-			Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
-		},
+		javaLibraryBazelTargetModuleProperties(),
 		android.CommonAttributes{Name: name + "-neverlink"},
 		neverlinkAttrs)
 
diff --git a/java/lint.go b/java/lint.go
index 58b43df..40ef484 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -496,7 +496,6 @@
 		FlagWithArg("--java-language-level ", l.javaLanguageLevel).
 		FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
 		FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
-		Flag("--exitcode").
 		Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
 		Flags(l.properties.Lint.Flags).
 		Implicit(annotationsZipPath).
@@ -505,6 +504,10 @@
 	rule.Temporary(lintPaths.projectXML)
 	rule.Temporary(lintPaths.configXML)
 
+	if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" {
+		cmd.Flag("--exitcode")
+	}
+
 	if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
 		cmd.FlagWithArg("--check ", checkOnly)
 	}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 5824f08..0ea3609 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -414,6 +414,7 @@
 	frameworkBootImageConfig := defaultBootImageConfig(ctx)
 	bootFrameworkProfileRule(ctx, frameworkBootImageConfig)
 	b.generateBootImage(ctx, frameworkBootImageName, platformModules)
+	b.generateBootImage(ctx, mainlineBootImageName, apexModules)
 	b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
 	dumpOatRules(ctx, frameworkBootImageConfig)
 }
diff --git a/java/rro.go b/java/rro.go
index 9d0667c..6a9ad9a 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -175,19 +175,19 @@
 	return ""
 }
 
-func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 	if r.properties.Min_sdk_version != nil {
-		return android.SdkSpecFrom(ctx, *r.properties.Min_sdk_version)
+		return android.ApiLevelFrom(ctx, *r.properties.Min_sdk_version)
 	}
-	return r.SdkVersion(ctx)
+	return r.SdkVersion(ctx).ApiLevel
 }
 
 func (r *RuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
 	return android.SdkSpecFrom(ctx, "")
 }
 
-func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return r.SdkVersion(ctx)
+func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return r.SdkVersion(ctx).ApiLevel
 }
 
 func (r *RuntimeResourceOverlay) Certificate() Certificate {
diff --git a/java/sdk.go b/java/sdk.go
index 1e7727b..72a5006 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -191,12 +191,8 @@
 			bootclasspath:    corePlatformBootclasspathLibraries(ctx),
 			noFrameworksLibs: true,
 		}
-	case android.SdkPublic:
-		return toModule("android_stubs_current", sdkFrameworkAidlPath(ctx))
-	case android.SdkSystem:
-		return toModule("android_system_stubs_current", sdkFrameworkAidlPath(ctx))
-	case android.SdkTest:
-		return toModule("android_test_stubs_current", sdkFrameworkAidlPath(ctx))
+	case android.SdkPublic, android.SdkSystem, android.SdkTest:
+		return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), sdkFrameworkAidlPath(ctx))
 	case android.SdkCore:
 		return sdkDep{
 			useModule:        true,
@@ -206,10 +202,10 @@
 		}
 	case android.SdkModule:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule("android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
+		return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), nonUpdatableFrameworkAidlPath(ctx))
 	case android.SdkSystemServer:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule("android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
+		return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), sdkFrameworkAidlPath(ctx))
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
 	}
@@ -272,9 +268,9 @@
 // Create framework.aidl by extracting anything that implements android.os.Parcelable from the SDK stubs modules.
 func createSdkFrameworkAidl(ctx android.SingletonContext) {
 	stubsModules := []string{
-		"android_stubs_current",
-		"android_test_stubs_current",
-		"android_system_stubs_current",
+		android.SdkPublic.JavaLibraryName(ctx.Config()),
+		android.SdkTest.JavaLibraryName(ctx.Config()),
+		android.SdkSystem.JavaLibraryName(ctx.Config()),
 	}
 
 	combinedAidl := sdkFrameworkAidlPath(ctx)
@@ -289,7 +285,7 @@
 
 // Creates a version of framework.aidl for the non-updatable part of the platform.
 func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) {
-	stubsModules := []string{"android_module_lib_stubs_current"}
+	stubsModules := []string{android.SdkModule.JavaLibraryName(ctx.Config())}
 
 	combinedAidl := nonUpdatableFrameworkAidlPath(ctx)
 	tempPath := tempPathForRestat(ctx, combinedAidl)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index d2fbfd9..5477ed6 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1231,7 +1231,7 @@
 var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil)
 
 func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) {
-	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) {
+	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.ModuleContext, do android.PayloadDepsCallback) {
 		ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 			isExternal := !module.depIsInSameApex(ctx, child)
 			if am, ok := child.(android.ApexModule); ok {
@@ -1775,7 +1775,7 @@
 
 // Creates the xml file that publicizes the runtime library
 func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
-	moduleMinApiLevel := module.Library.MinSdkVersion(mctx).ApiLevel
+	moduleMinApiLevel := module.Library.MinSdkVersion(mctx)
 	var moduleMinApiLevelStr = moduleMinApiLevel.String()
 	if moduleMinApiLevel == android.NoneApiLevel {
 		moduleMinApiLevelStr = "current"
@@ -2414,8 +2414,8 @@
 }
 
 // MinSdkVersion - Implements hiddenAPIModule
-func (module *SdkLibraryImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
-	return android.SdkSpecNone
+func (module *SdkLibraryImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return android.NoneApiLevel
 }
 
 var _ hiddenAPIModule = (*SdkLibraryImport)(nil)
diff --git a/mk2rbc/Android.bp b/mk2rbc/Android.bp
index 4fa3eb6..cd80a4d 100644
--- a/mk2rbc/Android.bp
+++ b/mk2rbc/Android.bp
@@ -19,7 +19,7 @@
 
 blueprint_go_binary {
     name: "mk2rbc",
-    srcs: ["cmd/mk2rbc.go"],
+    srcs: ["mk2rbc/mk2rbc.go"],
     deps: [
         "mk2rbc-lib",
         "androidmk-parser",
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/mk2rbc/mk2rbc.go
similarity index 100%
rename from mk2rbc/cmd/mk2rbc.go
rename to mk2rbc/mk2rbc/mk2rbc.go
diff --git a/python/scripts/stub_template_host.txt b/python/scripts/stub_template_host.txt
index 5eedc18..2d1bd4a 100644
--- a/python/scripts/stub_template_host.txt
+++ b/python/scripts/stub_template_host.txt
@@ -3,6 +3,7 @@
 import os
 import tempfile
 import shutil
+import signal
 import sys
 import subprocess
 import zipfile
@@ -43,7 +44,18 @@
     sys.stdout.flush()
     # close_fds=False so that you can run binaries with files provided on the command line:
     # my_python_app --file <(echo foo)
-    sys.exit(subprocess.call(args, close_fds=False))
+    p = subprocess.Popen(args, close_fds=False)
+
+    def handler(sig, frame):
+      p.send_signal(sig)
+
+    # Redirect SIGINT and SIGTERM to subprocess
+    signal.signal(signal.SIGINT, handler)
+    signal.signal(signal.SIGTERM, handler)
+
+    p.wait()
+
+    sys.exit(p.returncode)
   finally:
     shutil.rmtree(runfiles_path, ignore_errors=True)
 
diff --git a/python/test.go b/python/test.go
index fb8e918..31da17e 100644
--- a/python/test.go
+++ b/python/test.go
@@ -15,6 +15,8 @@
 package python
 
 import (
+	"fmt"
+
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -63,7 +65,22 @@
 	Java_data []string
 
 	// Test options.
-	Test_options android.CommonTestOptions
+	Test_options TestOptions
+}
+
+type TestOptions struct {
+	android.CommonTestOptions
+
+	// Runner for the test. Supports "tradefed" and "mobly" (for multi-device tests). Default is "tradefed".
+	Runner *string
+
+	// Metadata to describe the test configuration.
+	Metadata []Metadata
+}
+
+type Metadata struct {
+	Name  string
+	Value string
 }
 
 type PythonTestModule struct {
@@ -94,14 +111,41 @@
 	p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
 	p.buildBinary(ctx)
 
-	p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
-		TestConfigProp:         p.testProperties.Test_config,
-		TestConfigTemplateProp: p.testProperties.Test_config_template,
-		TestSuites:             p.binaryProperties.Test_suites,
-		AutoGenConfig:          p.binaryProperties.Auto_gen_config,
-		DeviceTemplate:         "${PythonBinaryHostTestConfigTemplate}",
-		HostTemplate:           "${PythonBinaryHostTestConfigTemplate}",
-	})
+	var configs []tradefed.Option
+	for _, metadata := range p.testProperties.Test_options.Metadata {
+		configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: metadata.Name, Value: metadata.Value})
+	}
+
+	runner := proptools.StringDefault(p.testProperties.Test_options.Runner, "tradefed")
+	if runner == "tradefed" {
+		p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
+			TestConfigProp:          p.testProperties.Test_config,
+			TestConfigTemplateProp:  p.testProperties.Test_config_template,
+			TestSuites:              p.binaryProperties.Test_suites,
+			OptionsForAutogenerated: configs,
+			AutoGenConfig:           p.binaryProperties.Auto_gen_config,
+			DeviceTemplate:          "${PythonBinaryHostTestConfigTemplate}",
+			HostTemplate:            "${PythonBinaryHostTestConfigTemplate}",
+		})
+	} else if runner == "mobly" {
+		if p.testProperties.Test_config != nil || p.testProperties.Test_config_template != nil || p.binaryProperties.Auto_gen_config != nil {
+			panic(fmt.Errorf("cannot set test_config, test_config_template or auto_gen_config for mobly test"))
+		}
+
+		for _, testSuite := range p.binaryProperties.Test_suites {
+			if testSuite == "cts" {
+				configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: "cts"})
+				break
+			}
+		}
+		p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
+			OptionsForAutogenerated: configs,
+			DeviceTemplate:          "${PythonBinaryHostMoblyTestConfigTemplate}",
+			HostTemplate:            "${PythonBinaryHostMoblyTestConfigTemplate}",
+		})
+	} else {
+		panic(fmt.Errorf("unknown python test runner '%s', should be 'tradefed' or 'mobly'", runner))
+	}
 
 	p.installedDest = ctx.InstallFile(installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName()), p.installSource.Base(), p.installSource)
 
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 20e9919..5e680b0 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -43,6 +43,10 @@
 	}
 }
 
+func (mod *Module) AndroidMkSuffix() string {
+	return mod.Properties.RustSubName + mod.Properties.SubName
+}
+
 func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries {
 	if mod.Properties.HideFromMake || mod.hideApexVariantFromMake {
 
@@ -79,8 +83,7 @@
 		mod.SubAndroidMk(&ret, mod.sanitize)
 	}
 
-	ret.SubName += mod.Properties.RustSubName
-	ret.SubName += mod.Properties.SubName
+	ret.SubName += mod.AndroidMkSuffix()
 
 	return []android.AndroidMkEntries{ret}
 }
@@ -152,6 +155,11 @@
 		})
 }
 
+func (library *snapshotLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
+	ctx.SubAndroidMk(ret, library.libraryDecorator)
+	ret.SubName = library.SnapshotAndroidMkSuffix()
+}
+
 func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	ctx.SubAndroidMk(ret, procMacro.baseCompiler)
 
diff --git a/rust/config/global.go b/rust/config/global.go
index 9375022..8894938 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var pctx = android.NewPackageContext("android/soong/rust/config")
 
 var (
-	RustDefaultVersion = "1.67.1"
+	RustDefaultVersion = "1.68.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/rust/rust.go b/rust/rust.go
index 8a13ba3..018cdab 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -26,6 +26,7 @@
 	"android/soong/cc"
 	cc_config "android/soong/cc/config"
 	"android/soong/fuzz"
+	"android/soong/multitree"
 	"android/soong/rust/config"
 	"android/soong/snapshot"
 )
@@ -1111,6 +1112,17 @@
 	return nil
 }
 
+func rustMakeLibName(ctx android.ModuleContext, c cc.LinkableInterface, dep cc.LinkableInterface, depName string) string {
+	if rustDep, ok := dep.(*Module); ok {
+		// Use base module name for snapshots when exporting to Makefile.
+		if snapshotPrebuilt, ok := rustDep.compiler.(cc.SnapshotInterface); ok {
+			baseName := rustDep.BaseModuleName()
+			return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix() + rustDep.AndroidMkSuffix()
+		}
+	}
+	return cc.MakeLibName(ctx, c, dep, depName)
+}
+
 func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
@@ -1136,13 +1148,59 @@
 		mod.apexSdkVersion = android.FutureApiLevel
 	}
 
+	skipModuleList := map[string]bool{}
+
+	var apiImportInfo multitree.ApiImportInfo
+	hasApiImportInfo := false
+
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		if dep.Name() == "api_imports" {
+			apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+			hasApiImportInfo = true
+		}
+	})
+
+	if hasApiImportInfo {
+		targetStubModuleList := map[string]string{}
+		targetOrigModuleList := map[string]string{}
+
+		// Search for dependency which both original module and API imported library with APEX stub exists
+		ctx.VisitDirectDeps(func(dep android.Module) {
+			depName := ctx.OtherModuleName(dep)
+			if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
+				targetStubModuleList[apiLibrary] = depName
+			}
+		})
+		ctx.VisitDirectDeps(func(dep android.Module) {
+			depName := ctx.OtherModuleName(dep)
+			if origLibrary, ok := targetStubModuleList[depName]; ok {
+				targetOrigModuleList[origLibrary] = depName
+			}
+		})
+
+		// Decide which library should be used between original and API imported library
+		ctx.VisitDirectDeps(func(dep android.Module) {
+			depName := ctx.OtherModuleName(dep)
+			if apiLibrary, ok := targetOrigModuleList[depName]; ok {
+				if cc.ShouldUseStubForApex(ctx, dep) {
+					skipModuleList[depName] = true
+				} else {
+					skipModuleList[apiLibrary] = true
+				}
+			}
+		})
+	}
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
 
+		if _, exists := skipModuleList[depName]; exists {
+			return
+		}
 		if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
 			//Handle Rust Modules
-			makeLibName := cc.MakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
+			makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
 
 			switch depTag {
 			case dylibDepTag:
@@ -1395,6 +1453,16 @@
 	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()
+}
+
+// useVendorApi returns true if the rust variant should link against LLNDK (vendorapi)
+func (r *Module) useVendorApi() bool {
+	return r.Device() && (r.InVendor() || r.InProduct())
+}
+
 func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
 	ctx := &depsContext{
 		BottomUpMutatorContext: actx,
@@ -1405,8 +1473,10 @@
 	var snapshotInfo *cc.SnapshotInfo
 
 	apiImportInfo := cc.GetApiImports(mod, actx)
-	for idx, lib := range deps.SharedLibs {
-		deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
+	if mod.usePublicApi() || mod.useVendorApi() {
+		for idx, lib := range deps.SharedLibs {
+			deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
+		}
 	}
 
 	if ctx.Os() == android.Android {
@@ -1486,7 +1556,15 @@
 		variations := []blueprint.Variation{
 			{Mutator: "link", Variation: "shared"},
 		}
-		cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
+		// For core variant, add a dep on the implementation (if it exists) and its .apiimport (if it exists)
+		// GenerateAndroidBuildActions will pick the correct impl/stub based on the api_domain boundary
+		if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
+			cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
+		}
+
+		if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
+			cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, apiLibraryName, version, false)
+		}
 	}
 
 	for _, lib := range deps.WholeStaticLibs {
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 7be0042..e1b3c86 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -424,6 +424,14 @@
 		compile_multilib: "32",
 		srcs: ["bin.rs"],
 	}
+
+	rust_library {
+		name: "librust_vendor_available",
+		crate_name: "rust_vendor",
+		vendor_available: true,
+		srcs: ["client.rs"],
+	}
+
 `
 
 	vndkBp := `
@@ -499,13 +507,6 @@
 		system_shared_libs: [],
 	}
 
-	rust_library {
-		name: "librust_vendor_available",
-		crate_name: "rust_vendor",
-		vendor_available: true,
-		srcs: ["client.rs"],
-	}
-
 	rust_ffi_shared {
 		name: "libclient",
 		crate_name: "client",
@@ -963,7 +964,7 @@
 	}
 
 	libclientAndroidMkRlibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkRlibs
-	if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
+	if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
 	}
 
@@ -978,10 +979,24 @@
 	}
 
 	libclientRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibVariant).Module().(*Module).Properties.AndroidMkRlibs
-	if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
+	if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
 	}
 
+	// rust vendor snapshot must have ".vendor" suffix in AndroidMk
+	librustVendorAvailableSnapshotModule := ctx.ModuleForTests("librust_vendor_available.vendor_rlib.30.arm64", rlibVariant).Module()
+	librustVendorSnapshotMkName := android.AndroidMkEntriesForTest(t, ctx, librustVendorAvailableSnapshotModule)[0].EntryMap["LOCAL_MODULE"][0]
+	expectedRustVendorSnapshotName := "librust_vendor_available.vendor.rlib-std"
+	if librustVendorSnapshotMkName != expectedRustVendorSnapshotName {
+		t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotMkName, expectedRustVendorSnapshotName)
+	}
+
+	rustVendorBinModule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Module()
+	rustVendorBinMkRlibName := android.AndroidMkEntriesForTest(t, ctx, rustVendorBinModule)[0].EntryMap["LOCAL_RLIB_LIBRARIES"][0]
+	if rustVendorBinMkRlibName != expectedRustVendorSnapshotName {
+		t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkRlibName, expectedRustVendorSnapshotName)
+	}
+
 	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()) {
diff --git a/scripts/Android.bp b/scripts/Android.bp
index ddbba74..26fe432 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -231,3 +231,8 @@
     srcs: ["rustfmt.toml"],
     visibility: ["//visibility:public"],
 }
+
+sh_binary_host {
+    name: "jars-to-module-info-java",
+    src: "jars-to-module-info-java.sh",
+}
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index b57963b..0d14019 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -19,7 +19,12 @@
     exit 1
 fi
 
-TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp
+# TODO: remove ALLOW_MISSING_DEPENDENCIES=true when all the riscv64
+# dependencies exist (currently blocked by http://b/273792258).
+# TODO: remove BUILD_BROKEN_DISABLE_BAZEL=1 when bazel supports riscv64 (http://b/262192655).
+ALLOW_MISSING_DEPENDENCIES=true \
+BUILD_BROKEN_DISABLE_BAZEL=1 \
+    TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp
 
 if [ -n "${DIST_DIR}" ]; then
     mkdir -p ${DIST_DIR} || true
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index d81635e..0d6496d 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -27,6 +27,11 @@
 // fixtureAddPlatformBootclasspathForBootclasspathFragment adds a platform_bootclasspath module that
 // references the bootclasspath fragment.
 func fixtureAddPlatformBootclasspathForBootclasspathFragment(apex, fragment string) android.FixturePreparer {
+	return fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(apex, fragment, "")
+}
+
+// fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra is the same as above, but also adds extra fragments.
+func fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(apex, fragment, extraFragments string) android.FixturePreparer {
 	return android.GroupFixturePreparers(
 		// Add a platform_bootclasspath module.
 		android.FixtureAddTextFile("frameworks/base/boot/Android.bp", fmt.Sprintf(`
@@ -37,9 +42,10 @@
 						apex: "%s",
 						module: "%s",
 					},
+					%s
 				],
 			}
-		`, apex, fragment)),
+		`, apex, fragment, extraFragments)),
 		android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil),
 		android.FixtureAddFile("frameworks/base/config/boot-image-profile.txt", nil),
 		android.FixtureAddFile("build/soong/scripts/check_boot_jars/package_allowed_list.txt", nil),
@@ -79,9 +85,11 @@
 		}),
 
 		// Add a platform_bootclasspath that depends on the fragment.
-		fixtureAddPlatformBootclasspathForBootclasspathFragment("com.android.art", "mybootclasspathfragment"),
+		fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(
+			"com.android.art", "mybootclasspathfragment", java.ApexBootJarFragmentsForPlatformBootclasspath),
 
 		java.PrepareForBootImageConfigTest,
+		java.PrepareApexBootJarConfigsAndModules,
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
@@ -196,9 +204,15 @@
 		snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) {
 			// Make sure that the boot jars package check rule includes the dex jars retrieved from the prebuilt apex.
 			checkBootJarsPackageCheckRule(t, result,
-				"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
-				"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
-				"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar")
+				append(
+					[]string{
+						"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
+						"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
+						"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
+					},
+					java.ApexBootJarDexJarPaths...,
+				)...,
+			)
 			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/mybootclasspathfragment/android_common_com.android.art/meta_lic")
 			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
 		}),
@@ -222,9 +236,15 @@
 
 	// Make sure that the boot jars package check rule includes the dex jars created from the source.
 	checkBootJarsPackageCheckRule(t, result,
-		"out/soong/.intermediates/core1/android_common_apex10000/aligned/core1.jar",
-		"out/soong/.intermediates/core2/android_common_apex10000/aligned/core2.jar",
-		"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar")
+		append(
+			[]string{
+				"out/soong/.intermediates/core1/android_common_apex10000/aligned/core1.jar",
+				"out/soong/.intermediates/core2/android_common_apex10000/aligned/core2.jar",
+				"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
+			},
+			java.ApexBootJarDexJarPaths...,
+		)...,
+	)
 }
 
 // checkBootJarsPackageCheckRule checks that the supplied module is an input to the boot jars
@@ -819,6 +839,7 @@
 				compile_dex: true,
 				public: {enabled: true},
 				permitted_packages: ["mysdklibrary"],
+				min_sdk_version: "current",
 			}
 
 			java_sdk_library {
diff --git a/sdk/update.go b/sdk/update.go
index 0820d62..d98ab68 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -357,6 +357,12 @@
 		// If the minApiLevel of the member is greater than the target API level then exclude it from
 		// this snapshot.
 		exclude := memberVariantDep.minApiLevel.GreaterThan(targetApiLevel)
+		// Always include host variants (e.g. host tools) in the snapshot.
+		// Host variants should not be guarded by a min_sdk_version check. In fact, host variants
+		// do not have a `min_sdk_version`.
+		if memberVariantDep.Host() {
+			exclude = false
+		}
 
 		addMember(name, export, exclude)
 
@@ -1263,6 +1269,11 @@
 	minApiLevel android.ApiLevel
 }
 
+// Host returns true if the sdk member is a host variant (e.g. host tool)
+func (s *sdkMemberVariantDep) Host() bool {
+	return s.variant.Target().Os.Class == android.Host
+}
+
 var _ android.SdkMember = (*sdkMember)(nil)
 
 // sdkMember groups all the variants of a specific member module together along with the name of the
diff --git a/soong_ui.bash b/soong_ui.bash
index 1d027c4..8e7cd19 100755
--- a/soong_ui.bash
+++ b/soong_ui.bash
@@ -33,8 +33,8 @@
 source ${TOP}/build/soong/scripts/microfactory.bash
 
 soong_build_go soong_ui android/soong/cmd/soong_ui
-soong_build_go mk2rbc android/soong/mk2rbc/cmd
-soong_build_go rbcrun rbcrun/cmd
+soong_build_go mk2rbc android/soong/mk2rbc/mk2rbc
+soong_build_go rbcrun rbcrun/rbcrun
 
 cd ${TOP}
 exec "$(getoutdir)/soong_ui" "$@"
diff --git a/tests/dcla_apex_comparison_test.sh b/tests/dcla_apex_comparison_test.sh
index 2ecb876..97ae97e 100755
--- a/tests/dcla_apex_comparison_test.sh
+++ b/tests/dcla_apex_comparison_test.sh
@@ -112,7 +112,7 @@
         sha="${sha% *}"
         if [ "${prev_sha}" == "" ]; then
           prev_sha="${sha}"
-        elif [ "${sha}" != "${prev_sha}" ]; then
+        elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [ "${module}" != "com.android.tethering" ]; }; then
           echo "Test failed, ${lib} has different hash value"
           exit 1
         fi
diff --git a/tests/lib.sh b/tests/lib.sh
index 0973beb..2bcb630 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -164,5 +164,6 @@
   fi
   for f in ${test_fns[*]}; do
     $f
+    info "Completed test case \e[96;1m$f\e[0m"
   done
 }
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index a762952..e1aa70c 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -20,3 +20,5 @@
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh"
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
+
+"$TOP/build/soong/tests/sbom_test.sh"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
new file mode 100755
index 0000000..6066d70
--- /dev/null
+++ b/tests/sbom_test.sh
@@ -0,0 +1,210 @@
+#!/bin/bash
+
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -uo pipefail
+
+# Integration test for verifying generated SBOM for cuttlefish device.
+
+if [ ! -e "build/make/core/Makefile" ]; then
+  echo "$0 must be run from the top of the Android source tree."
+  exit 1
+fi
+
+tmp_dir="$(mktemp -d tmp.XXXXXX)"
+function cleanup {
+  rm -rf "${tmp_dir}"
+}
+trap cleanup EXIT
+
+out_dir=$tmp_dir
+droid_target=droid
+
+debug=false
+if [ $debug = "true" ]; then
+  out_dir=out
+  droid_target=
+fi
+# m droid, build sbom later in case additional dependencies might be built and included in partition images.
+TARGET_PRODUCT="aosp_cf_x86_64_phone" TARGET_BUILD_VARIANT=userdebug OUT_DIR=$out_dir \
+  build/soong/soong_ui.bash --make-mode $droid_target dump.erofs
+
+product_out=$out_dir/target/product/vsoc_x86_64
+sbom_test=$product_out/sbom_test
+mkdir $sbom_test
+cp $product_out/*.img $sbom_test
+
+# m sbom
+TARGET_PRODUCT="aosp_cf_x86_64_phone" TARGET_BUILD_VARIANT=userdebug OUT_DIR=$out_dir \
+  build/soong/soong_ui.bash --make-mode sbom
+
+# Generate installed file list from .img files in PRODUCT_OUT
+dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
+
+declare -A diff_excludes
+diff_excludes[odm]="-I /odm/lib/modules"
+diff_excludes[vendor]=\
+"-I /vendor/lib64/libkeystore2_crypto.so \
+ -I /vendor/lib/modules \
+ -I /vendor/odm"
+diff_excludes[system]=\
+"-I /acct/ \
+ -I /adb_keys \
+ -I /apex/ \
+ -I /bin \
+ -I /bugreports \
+ -I /cache \
+ -I /config/ \
+ -I /d \
+ -I /data/ \
+ -I /data_mirror/ \
+ -I /debug_ramdisk/ \
+ -I /dev/ \
+ -I /etc \
+ -I /init \
+ -I /init.environ.rc \
+ -I /linkerconfig/ \
+ -I /metadata/ \
+ -I /mnt/ \
+ -I /odm/app \
+ -I /odm/bin \
+ -I /odm_dlkm/etc \
+ -I /odm/etc \
+ -I /odm/firmware \
+ -I /odm/framework \
+ -I /odm/lib \
+ -I /odm/lib64 \
+ -I /odm/overlay \
+ -I /odm/priv-app \
+ -I /odm/usr \
+ -I /oem/ \
+ -I /postinstall/ \
+ -I /proc/ \
+ -I /product/ \
+ -I /sdcard \
+ -I /second_stage_resources/ \
+ -I /storage/ \
+ -I /sys/ \
+ -I /system_dlkm/ \
+ -I /system_ext/ \
+ -I /system/lib64/android.hardware.confirmationui@1.0.so \
+ -I /system/lib64/android.hardware.confirmationui-V1-ndk.so \
+ -I /system/lib64/android.hardware.keymaster@4.1.so \
+ -I /system/lib64/android.hardware.security.rkp-V3-ndk.so \
+ -I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \
+ -I /system/lib64/android.security.compat-ndk.so \
+ -I /system/lib64/libkeymaster4_1support.so \
+ -I /system/lib64/libkeymint.so \
+ -I /system/lib64/libkeystore2_aaid.so \
+ -I /system/lib64/libkeystore2_apc_compat.so \
+ -I /system/lib64/libkeystore2_crypto.so \
+ -I /system/lib64/libkm_compat_service.so \
+ -I /system/lib64/libkm_compat.so \
+ -I /system/lib64/vndk-29 \
+ -I /system/lib64/vndk-sp-29 \
+ -I /system/lib/modules \
+ -I /system/lib/vndk-29 \
+ -I /system/lib/vndk-sp-29 \
+ -I /system/product \
+ -I /system/system_ext \
+ -I /system/usr/icu \
+ -I /system/vendor \
+ -I /vendor/ \
+ -I /vendor_dlkm/etc"
+
+# Example output of dump.erofs is as below, and the data used in the test start
+# at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name.
+# Each line is captured in variable "entry", sed is used to trim the leading
+# spaces and cut is used to get field 1 every time. Once a field is extracted,
+# "cut --complement" is used to remove the extracted field so next field can be
+# processed in the same way and to be processed field is always field 1.
+# Output of dump.erofs:
+#     File : /
+#     Size: 160  On-disk size: 160  directory
+#     NID: 39   Links: 10   Layout: 2   Compression ratio: 100.00%
+#     Inode size: 64   Extent size: 0   Xattr size: 16
+#     Uid: 0   Gid: 0  Access: 0755/rwxr-xr-x
+#     Timestamp: 2023-02-14 01:15:54.000000000
+#
+#            NID TYPE  FILENAME
+#             39    2  .
+#             39    2  ..
+#             47    2  app
+#        1286748    2  bin
+#        1286754    2  etc
+#        5304814    2  lib
+#        5309056    2  lib64
+#        5309130    2  media
+#        5388910    2  overlay
+#        5479537    2  priv-app
+EROFS_IMAGES="\
+  $sbom_test/product.img \
+  $sbom_test/system.img \
+  $sbom_test/system_ext.img \
+  $sbom_test/system_dlkm.img \
+  $sbom_test/system_other.img \
+  $sbom_test/odm.img \
+  $sbom_test/odm_dlkm.img \
+  $sbom_test/vendor.img \
+  $sbom_test/vendor_dlkm.img"
+for f in $EROFS_IMAGES; do
+  partition_name=$(basename $f | cut -d. -f1)
+  file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
+  files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+  rm "$file_list_file" > /dev/null 2>&1
+  all_dirs="/"
+  while [ ! -z "$all_dirs" ]; do
+    dir=$(echo "$all_dirs" | cut -d ' ' -f1)
+    all_dirs=$(echo "$all_dirs" | cut -d ' ' -f1 --complement -s)
+    entries=$($dump_erofs --ls --path "$dir" $f | tail -n +11)
+    while read -r entry; do
+      nid=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
+      entry=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1 --complement)
+      type=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
+      entry=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1 --complement)
+      name=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
+      case $type in
+        "2")  # directory
+          all_dirs=$(echo "$all_dirs $dir/$name" | sed 's/^\s*//')
+          ;;
+        *)
+          (
+          if [ "$partition_name" != "system" ]; then
+            # system partition is mounted to /, not to prepend partition name.
+            printf %s "/$partition_name"
+          fi
+          echo "$dir/$name" | sed 's#^//#/#'
+          ) >> "$file_list_file"
+          ;;
+      esac
+    done <<< "$entries"
+  done
+  sort -n -o "$file_list_file" "$file_list_file"
+
+  # Diff
+  echo ============ Diffing files in $f and SBOM
+  grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"
+  exclude=
+  if [ -v 'diff_excludes[$partition_name]' ]; then
+    exclude=${diff_excludes[$partition_name]}
+  fi
+  diff "$file_list_file" "$files_in_spdx_file" $exclude
+  if [ $? != "0" ]; then
+    echo Found diffs in $f and SBOM.
+    exit 1
+  else
+    echo No diffs.
+  fi
+done
\ No newline at end of file
diff --git a/tradefed/config.go b/tradefed/config.go
index 999424c..326a006 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -31,6 +31,7 @@
 	pctx.SourcePathVariable("NativeBenchmarkTestConfigTemplate", "build/make/core/native_benchmark_test_config_template.xml")
 	pctx.SourcePathVariable("NativeHostTestConfigTemplate", "build/make/core/native_host_test_config_template.xml")
 	pctx.SourcePathVariable("NativeTestConfigTemplate", "build/make/core/native_test_config_template.xml")
+	pctx.SourcePathVariable("PythonBinaryHostMoblyTestConfigTemplate", "build/make/core/python_binary_host_mobly_test_config_template.xml")
 	pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
 	pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
 	pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
diff --git a/ui/build/config.go b/ui/build/config.go
index b5ee440..20cc9fb 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -45,7 +45,8 @@
 )
 
 var (
-	rbeRandPrefix int
+	rbeRandPrefix             int
+	googleProdCredsExistCache bool
 )
 
 func init() {
@@ -77,6 +78,7 @@
 	queryview         bool
 	reportMkMetrics   bool // Collect and report mk2bp migration progress metrics.
 	soongDocs         bool
+	multitreeBuild    bool // This is a multitree build.
 	skipConfig        bool
 	skipKati          bool
 	skipKatiNinja     bool
@@ -116,8 +118,21 @@
 	bazelForceEnabledModules string
 
 	includeTags []string
+
+	// Data source to write ninja weight list
+	ninjaWeightListSource NinjaWeightListSource
 }
 
+type NinjaWeightListSource uint
+
+const (
+	// ninja doesn't use weight list.
+	NOT_USED NinjaWeightListSource = iota
+	// ninja uses weight list based on previous builds by ninja log
+	NINJA_LOG
+	// ninja thinks every task has the same weight.
+	EVENLY_DISTRIBUTED
+)
 const srcDirFileCheck = "build/soong/root.bp"
 
 var buildFiles = []string{"Android.mk", "Android.bp"}
@@ -474,6 +489,10 @@
 	ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
+	if ret.MultitreeBuild() {
+		ret.environ.Set("MULTITREE_BUILD", "true")
+	}
+
 	outDir := ret.OutDir()
 	buildDateTimeFile := filepath.Join(outDir, "build_date.txt")
 	if buildDateTime, ok := ret.environ.Get("BUILD_DATETIME"); ok && buildDateTime != "" {
@@ -522,6 +541,17 @@
 	ctx.Metrics.SystemResourceInfo(s)
 }
 
+func getNinjaWeightListSourceInMetric(s NinjaWeightListSource) *smpb.BuildConfig_NinjaWeightListSource {
+	switch s {
+	case NINJA_LOG:
+		return smpb.BuildConfig_NINJA_LOG.Enum()
+	case EVENLY_DISTRIBUTED:
+		return smpb.BuildConfig_EVENLY_DISTRIBUTED.Enum()
+	default:
+		return smpb.BuildConfig_NOT_USED.Enum()
+	}
+}
+
 func buildConfig(config Config) *smpb.BuildConfig {
 	c := &smpb.BuildConfig{
 		ForceUseGoma:                proto.Bool(config.ForceUseGoma()),
@@ -529,6 +559,7 @@
 		UseRbe:                      proto.Bool(config.UseRBE()),
 		BazelMixedBuild:             proto.Bool(config.BazelBuildEnabled()),
 		ForceDisableBazelMixedBuild: proto.Bool(config.IsBazelMixedBuildForceDisabled()),
+		NinjaWeightListSource:       getNinjaWeightListSourceInMetric(config.NinjaWeightListSource()),
 	}
 	c.Targets = append(c.Targets, config.arguments...)
 
@@ -781,6 +812,8 @@
 			c.skipMetricsUpload = true
 		} else if arg == "--mk-metrics" {
 			c.reportMkMetrics = true
+		} else if arg == "--multitree-build" {
+			c.multitreeBuild = true
 		} else if arg == "--bazel-mode" {
 			c.bazelProdMode = true
 		} else if arg == "--bazel-mode-dev" {
@@ -789,6 +822,17 @@
 			c.bazelStagingMode = true
 		} else if arg == "--search-api-dir" {
 			c.searchApiDir = true
+		} else if strings.HasPrefix(arg, "--ninja_weight_source=") {
+			source := strings.TrimPrefix(arg, "--ninja_weight_source=")
+			if source == "ninja_log" {
+				c.ninjaWeightListSource = NINJA_LOG
+			} else if source == "evenly_distributed" {
+				c.ninjaWeightListSource = EVENLY_DISTRIBUTED
+			} else if source == "not_used" {
+				c.ninjaWeightListSource = NOT_USED
+			} else {
+				ctx.Fatalf("unknown option for ninja_weight_source: %s", source)
+			}
 		} else if strings.HasPrefix(arg, "--build-command=") {
 			buildCmd := strings.TrimPrefix(arg, "--build-command=")
 			// remove quotations
@@ -1079,6 +1123,14 @@
 	return c.verbose
 }
 
+func (c *configImpl) MultitreeBuild() bool {
+	return c.multitreeBuild
+}
+
+func (c *configImpl) NinjaWeightListSource() NinjaWeightListSource {
+	return c.ninjaWeightListSource
+}
+
 func (c *configImpl) SkipKati() bool {
 	return c.skipKati
 }
@@ -1347,9 +1399,13 @@
 // GoogleProdCredsExist determine whether credentials exist on the
 // Googler machine to use remote execution.
 func (c *configImpl) GoogleProdCredsExist() bool {
+	if googleProdCredsExistCache {
+		return googleProdCredsExistCache
+	}
 	if _, err := exec.Command("/usr/bin/prodcertstatus", "--simple_output", "--nocheck_loas").Output(); err != nil {
 		return false
 	}
+	googleProdCredsExistCache = true
 	return true
 }
 
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 940d85c..a1eccf0 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -903,6 +903,15 @@
 			tidyOnly:     "",
 			expectedArgs: []string{},
 		}, {
+			description:  "multitree build action executed at root directory",
+			dirsInTrees:  []string{},
+			buildFiles:   []string{},
+			rootSymlink:  false,
+			args:         []string{"--multitree-build"},
+			curDir:       ".",
+			tidyOnly:     "",
+			expectedArgs: []string{"--multitree-build"},
+		}, {
 			description:  "build action executed at root directory in symlink",
 			dirsInTrees:  []string{},
 			buildFiles:   []string{},
@@ -1023,6 +1032,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(false),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1034,6 +1044,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(false),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1045,6 +1056,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(false),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1056,6 +1068,7 @@
 				UseRbe:                      proto.Bool(true),
 				BazelMixedBuild:             proto.Bool(false),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1067,6 +1080,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(false),
 				ForceDisableBazelMixedBuild: proto.Bool(true),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1079,6 +1093,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(false),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1091,6 +1106,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(true),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1103,6 +1119,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(true),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1115,6 +1132,7 @@
 				UseRbe:                      proto.Bool(false),
 				BazelMixedBuild:             proto.Bool(true),
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1129,6 +1147,7 @@
 				BazelMixedBuild:             proto.Bool(false),
 				Targets:                     []string{"droid", "dist"},
 				ForceDisableBazelMixedBuild: proto.Bool(false),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
@@ -1147,6 +1166,7 @@
 				UseRbe:                      proto.Bool(true),
 				BazelMixedBuild:             proto.Bool(true),
 				ForceDisableBazelMixedBuild: proto.Bool(true),
+				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 	}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 28f3c38..4734494 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -31,8 +31,51 @@
 const (
 	// File containing the environment state when ninja is executed
 	ninjaEnvFileName = "ninja.environment"
+	ninjaLogFileName = ".ninja_log"
 )
 
+func useNinjaBuildLog(ctx Context, config Config, cmd *Cmd) {
+	ninjaLogFile := filepath.Join(config.OutDir(), ninjaLogFileName)
+	data, err := os.ReadFile(ninjaLogFile)
+	var outputBuilder strings.Builder
+	if err == nil {
+		lines := strings.Split(strings.TrimSpace(string(data)), "\n")
+		// ninja log: <start>	<end>	<restat>	<name>	<cmdhash>
+		// ninja weight list: <name>,<end-start+1>
+		for _, line := range lines {
+			if strings.HasPrefix(line, "#") {
+				continue
+			}
+			fields := strings.Split(line, "\t")
+			path := fields[3]
+			start, err := strconv.Atoi(fields[0])
+			if err != nil {
+				continue
+			}
+			end, err := strconv.Atoi(fields[1])
+			if err != nil {
+				continue
+			}
+			outputBuilder.WriteString(path)
+			outputBuilder.WriteString(",")
+			outputBuilder.WriteString(strconv.Itoa(end-start+1) + "\n")
+		}
+	} else {
+		// If there is no ninja log file, just pass empty ninja weight list.
+		// Because it is still efficient with critical path calculation logic even without weight.
+		ctx.Verbosef("There is an error during reading ninja log, so ninja will use empty weight list: %s", err)
+	}
+
+	weightListFile := filepath.Join(config.OutDir(), ".ninja_weight_list")
+
+	err = os.WriteFile(weightListFile, []byte(outputBuilder.String()), 0644)
+	if err == nil {
+		cmd.Args = append(cmd.Args, "-o", "usesweightlist="+weightListFile)
+	} else {
+		ctx.Panicf("Could not write ninja weight list file %s", err)
+	}
+}
+
 // Constructs and runs the Ninja command line with a restricted set of
 // environment variables. It's important to restrict the environment Ninja runs
 // for hermeticity reasons, and to avoid spurious rebuilds.
@@ -85,6 +128,14 @@
 		cmd.Environment.AppendFromKati(config.KatiEnvFile())
 	}
 
+	switch config.NinjaWeightListSource() {
+	case NINJA_LOG:
+		useNinjaBuildLog(ctx, config, cmd)
+	case EVENLY_DISTRIBUTED:
+		// pass empty weight list means ninja considers every tasks's weight as 1(default value).
+		cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null")
+	}
+
 	// Allow both NINJA_ARGS and NINJA_EXTRA_ARGS, since both have been
 	// used in the past to specify extra ninja arguments.
 	if extra, ok := cmd.Environment.Get("NINJA_ARGS"); ok {
@@ -215,7 +266,7 @@
 	ticker := time.NewTicker(ninjaHeartbeatDuration)
 	defer ticker.Stop()
 	ninjaChecker := &ninjaStucknessChecker{
-		logPath: filepath.Join(config.OutDir(), ".ninja_log"),
+		logPath: filepath.Join(config.OutDir(), ninjaLogFileName),
 	}
 	go func() {
 		for {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a5a3263..871e637 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -168,6 +168,10 @@
 		commonArgs = append(commonArgs, "-t")
 	}
 
+	if pb.config.multitreeBuild {
+		commonArgs = append(commonArgs, "--multitree-build")
+	}
+
 	commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list"))
 	invocationEnv := make(map[string]string)
 	if pb.debugPort != "" {
@@ -275,6 +279,9 @@
 	if len(config.bazelForceEnabledModules) > 0 {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-force-enabled-modules="+config.bazelForceEnabledModules)
 	}
+	if config.MultitreeBuild() {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--multitree-build")
+	}
 
 	queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
 	// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
diff --git a/ui/metrics/BUILD.bazel b/ui/metrics/BUILD.bazel
new file mode 100644
index 0000000..15ebb88
--- /dev/null
+++ b/ui/metrics/BUILD.bazel
@@ -0,0 +1,30 @@
+# 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.
+
+load("//build/bazel/rules/python:py_proto.bzl", "py_proto_library")
+
+py_proto_library(
+    name = "metrics-py-proto",
+    visibility = ["//build/bazel/scripts/incremental_build:__pkg__"],
+    deps = [":metrics-proto"],
+)
+
+proto_library(
+    name = "metrics-proto",
+    srcs = [
+        "bp2build_metrics_proto/bp2build_metrics.proto",
+        "metrics_proto/metrics.proto",
+    ],
+    strip_import_prefix = "",
+)
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 6a664dc..4ad4a7b 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -158,6 +158,65 @@
 	return file_metrics_proto_rawDescGZIP(), []int{0, 1}
 }
 
+type BuildConfig_NinjaWeightListSource int32
+
+const (
+	BuildConfig_NOT_USED           BuildConfig_NinjaWeightListSource = 0
+	BuildConfig_NINJA_LOG          BuildConfig_NinjaWeightListSource = 1
+	BuildConfig_EVENLY_DISTRIBUTED BuildConfig_NinjaWeightListSource = 2
+)
+
+// Enum value maps for BuildConfig_NinjaWeightListSource.
+var (
+	BuildConfig_NinjaWeightListSource_name = map[int32]string{
+		0: "NOT_USED",
+		1: "NINJA_LOG",
+		2: "EVENLY_DISTRIBUTED",
+	}
+	BuildConfig_NinjaWeightListSource_value = map[string]int32{
+		"NOT_USED":           0,
+		"NINJA_LOG":          1,
+		"EVENLY_DISTRIBUTED": 2,
+	}
+)
+
+func (x BuildConfig_NinjaWeightListSource) Enum() *BuildConfig_NinjaWeightListSource {
+	p := new(BuildConfig_NinjaWeightListSource)
+	*p = x
+	return p
+}
+
+func (x BuildConfig_NinjaWeightListSource) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BuildConfig_NinjaWeightListSource) Descriptor() protoreflect.EnumDescriptor {
+	return file_metrics_proto_enumTypes[2].Descriptor()
+}
+
+func (BuildConfig_NinjaWeightListSource) Type() protoreflect.EnumType {
+	return &file_metrics_proto_enumTypes[2]
+}
+
+func (x BuildConfig_NinjaWeightListSource) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BuildConfig_NinjaWeightListSource) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BuildConfig_NinjaWeightListSource(num)
+	return nil
+}
+
+// Deprecated: Use BuildConfig_NinjaWeightListSource.Descriptor instead.
+func (BuildConfig_NinjaWeightListSource) EnumDescriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{1, 0}
+}
+
 type ModuleTypeInfo_BuildSystem int32
 
 const (
@@ -191,11 +250,11 @@
 }
 
 func (ModuleTypeInfo_BuildSystem) Descriptor() protoreflect.EnumDescriptor {
-	return file_metrics_proto_enumTypes[2].Descriptor()
+	return file_metrics_proto_enumTypes[3].Descriptor()
 }
 
 func (ModuleTypeInfo_BuildSystem) Type() protoreflect.EnumType {
-	return &file_metrics_proto_enumTypes[2]
+	return &file_metrics_proto_enumTypes[3]
 }
 
 func (x ModuleTypeInfo_BuildSystem) Number() protoreflect.EnumNumber {
@@ -253,11 +312,11 @@
 }
 
 func (ExpConfigFetcher_ConfigStatus) Descriptor() protoreflect.EnumDescriptor {
-	return file_metrics_proto_enumTypes[3].Descriptor()
+	return file_metrics_proto_enumTypes[4].Descriptor()
 }
 
 func (ExpConfigFetcher_ConfigStatus) Type() protoreflect.EnumType {
-	return &file_metrics_proto_enumTypes[3]
+	return &file_metrics_proto_enumTypes[4]
 }
 
 func (x ExpConfigFetcher_ConfigStatus) Number() protoreflect.EnumNumber {
@@ -647,8 +706,17 @@
 	Targets []string `protobuf:"bytes,6,rep,name=targets" json:"targets,omitempty"`
 	// Whether the user explicitly disabled bazel mixed builds for this build.
 	ForceDisableBazelMixedBuild *bool `protobuf:"varint,7,opt,name=force_disable_bazel_mixed_build,json=forceDisableBazelMixedBuild" json:"force_disable_bazel_mixed_build,omitempty"`
+	// NOT_USED - ninja doesn't use weight list.
+	// NINJA_LOG - ninja uses weight list based on previous builds by ninja log
+	// EVENLY_DISTRIBUTED - ninja thinks every task has the same weight.
+	NinjaWeightListSource *BuildConfig_NinjaWeightListSource `protobuf:"varint,8,opt,name=ninja_weight_list_source,json=ninjaWeightListSource,enum=soong_build_metrics.BuildConfig_NinjaWeightListSource,def=0" json:"ninja_weight_list_source,omitempty"`
 }
 
+// Default values for BuildConfig fields.
+const (
+	Default_BuildConfig_NinjaWeightListSource = BuildConfig_NOT_USED
+)
+
 func (x *BuildConfig) Reset() {
 	*x = BuildConfig{}
 	if protoimpl.UnsafeEnabled {
@@ -730,6 +798,13 @@
 	return false
 }
 
+func (x *BuildConfig) GetNinjaWeightListSource() BuildConfig_NinjaWeightListSource {
+	if x != nil && x.NinjaWeightListSource != nil {
+		return *x.NinjaWeightListSource
+	}
+	return Default_BuildConfig_NinjaWeightListSource
+}
+
 type SystemResourceInfo struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1444,10 +1519,10 @@
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	// Real time which the build system spent
-	ElapsedTime *uint64 `protobuf:"varint,1,opt,name=elapsed_time,json=elapsedTime" json:"elapsed_time,omitempty"`
-	// The sum of execution time of the longest path from leave to the root
-	CriticalPathTime *uint64 `protobuf:"varint,2,opt,name=critical_path_time,json=criticalPathTime" json:"critical_path_time,omitempty"`
+	// Real time which the build system spent in microseconds
+	ElapsedTimeMicros *uint64 `protobuf:"varint,1,opt,name=elapsed_time_micros,json=elapsedTimeMicros" json:"elapsed_time_micros,omitempty"`
+	// The sum of execution time of the longest path from leave to the root in microseconds
+	CriticalPathTimeMicros *uint64 `protobuf:"varint,2,opt,name=critical_path_time_micros,json=criticalPathTimeMicros" json:"critical_path_time_micros,omitempty"`
 	// Detailed job information in a critical path.
 	CriticalPath []*JobInfo `protobuf:"bytes,4,rep,name=critical_path,json=criticalPath" json:"critical_path,omitempty"`
 	// Detailed job information for long running jobs (>30 seconds). These may or may not also be on a critical path.
@@ -1486,16 +1561,16 @@
 	return file_metrics_proto_rawDescGZIP(), []int{11}
 }
 
-func (x *CriticalPathInfo) GetElapsedTime() uint64 {
-	if x != nil && x.ElapsedTime != nil {
-		return *x.ElapsedTime
+func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 {
+	if x != nil && x.ElapsedTimeMicros != nil {
+		return *x.ElapsedTimeMicros
 	}
 	return 0
 }
 
-func (x *CriticalPathInfo) GetCriticalPathTime() uint64 {
-	if x != nil && x.CriticalPathTime != nil {
-		return *x.CriticalPathTime
+func (x *CriticalPathInfo) GetCriticalPathTimeMicros() uint64 {
+	if x != nil && x.CriticalPathTimeMicros != nil {
+		return *x.CriticalPathTimeMicros
 	}
 	return 0
 }
@@ -1519,8 +1594,8 @@
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	// Real time which a job spent
-	ElapsedTime *uint64 `protobuf:"varint,1,opt,name=elapsed_time,json=elapsedTime" json:"elapsed_time,omitempty"`
+	// Real time which a job spent in microseconds
+	ElapsedTimeMicros *uint64 `protobuf:"varint,1,opt,name=elapsed_time_micros,json=elapsedTimeMicros" json:"elapsed_time_micros,omitempty"`
 	// Description of a job
 	JobDescription *string `protobuf:"bytes,2,opt,name=job_description,json=jobDescription" json:"job_description,omitempty"`
 }
@@ -1557,9 +1632,9 @@
 	return file_metrics_proto_rawDescGZIP(), []int{12}
 }
 
-func (x *JobInfo) GetElapsedTime() uint64 {
-	if x != nil && x.ElapsedTime != nil {
-		return *x.ElapsedTime
+func (x *JobInfo) GetElapsedTimeMicros() uint64 {
+	if x != nil && x.ElapsedTimeMicros != nil {
+		return *x.ElapsedTimeMicros
 	}
 	return 0
 }
@@ -1697,7 +1772,7 @@
 	0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10,
 	0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03,
 	0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10,
-	0x04, 0x22, 0x99, 0x02, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x04, 0x22, 0xe2, 0x03, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
 	0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20,
 	0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07,
 	0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75,
@@ -1714,153 +1789,168 @@
 	0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d,
 	0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08,
 	0x52, 0x1b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61,
-	0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x22, 0x6f, 0x0a,
-	0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
-	0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79,
-	0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61,
-	0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c,
-	0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
-	0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0xca,
-	0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64,
-	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
-	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
-	0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65,
-	0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20,
-	0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a,
-	0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65,
-	0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65,
-	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
-	0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52,
-	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f,
-	0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e,
-	0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65,
-	0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65,
-	0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65,
-	0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13,
-	0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
-	0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f,
-	0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f,
-	0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73,
-	0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12,
-	0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20,
-	0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a,
-	0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c,
-	0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50,
-	0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a,
-	0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06,
-	0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46,
-	0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75,
-	0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e,
-	0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70,
-	0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f,
-	0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e,
-	0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69,
-	0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c,
-	0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69,
-	0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e,
-	0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69,
-	0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76,
-	0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53,
-	0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75,
-	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
-	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
-	0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65,
-	0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f,
-	0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
-	0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f,
-	0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a,
-	0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f,
-	0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22,
-	0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a,
-	0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a,
-	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
-	0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
-	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a,
-	0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75,
-	0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04,
-	0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f,
+	0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x79, 0x0a,
+	0x18, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69,
+	0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x36, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x2e, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73,
+	0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45,
+	0x44, 0x52, 0x15, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69,
+	0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x4c, 0x0a, 0x15, 0x4e, 0x69, 0x6e, 0x6a,
+	0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x10, 0x00, 0x12,
+	0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x01, 0x12, 0x16,
+	0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42,
+	0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15,
+	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d,
+	0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74,
+	0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
+	0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70,
+	0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
+	0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66,
+	0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74,
+	0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09,
+	0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61,
+	0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65,
+	0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
+	0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09,
+	0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f,
+	0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
+	0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f,
 	0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75,
-	0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a,
-	0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64,
-	0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a,
-	0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75,
-	0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41,
-	0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74,
-	0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20,
-	0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53,
-	0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f,
-	0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48,
-	0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
-	0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
-	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65,
-	0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50,
-	0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69,
-	0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
+	0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e,
+	0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12,
+	0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
+	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72,
+	0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79,
+	0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69,
+	0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f,
+	0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61,
+	0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f,
+	0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c,
+	0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65,
+	0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d,
+	0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e,
+	0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20,
+	0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62,
+	0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f,
+	0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43,
+	0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40,
+	0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f,
+	0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72,
+	0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73,
+	0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49,
+	0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73,
+	0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
 	0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
-	0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52,
-	0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f,
-	0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65,
-	0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43,
-	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e,
-	0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
-	0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a,
-	0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d,
-	0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53,
-	0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46,
-	0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01,
-	0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d,
-	0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91,
-	0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e,
-	0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75,
-	0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
-	0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75,
-	0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x73, 0x22, 0xf0, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50,
-	0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x6c, 0x61, 0x70, 0x73,
-	0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65,
-	0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x72,
-	0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
-	0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74,
-	0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
-	0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
-	0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63,
-	0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c,
-	0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73,
-	0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62,
-	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e,
-	0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x55, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f,
-	0x12, 0x21, 0x0a, 0x0c, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54,
-	0x69, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42,
+	0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e,
+	0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
+	0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66,
+	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
+	0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08,
+	0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74,
+	0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f,
+	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
+	0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
+	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
+	0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53,
+	0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+	0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61,
+	0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61,
+	0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
+	0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75,
+	0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f,
+	0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f,
+	0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d,
+	0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65,
+	0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+	0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64,
+	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75,
+	0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42,
+	0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78,
+	0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a,
+	0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32,
+	0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65,
+	0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69,
+	0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69,
+	0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47,
+	0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d,
+	0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a,
+	0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52,
+	0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f,
+	0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65,
+	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d,
+	0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c,
+	0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62,
+	0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69,
+	0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
+	0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61,
+	0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10,
+	0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f,
+	0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+	0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65,
+	0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+	0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74,
+	0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74,
+	0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63,
+	0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f,
+	0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48,
+	0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a,
+	0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
+	0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
+	0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e,
+	0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49,
+	0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74,
+	0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63,
+	0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72,
 	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f,
 	0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x28, 0x5a, 0x26,
 	0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69,
@@ -1880,57 +1970,59 @@
 	return file_metrics_proto_rawDescData
 }
 
-var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
+var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
 var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
 var file_metrics_proto_goTypes = []interface{}{
-	(MetricsBase_BuildVariant)(0),       // 0: soong_build_metrics.MetricsBase.BuildVariant
-	(MetricsBase_Arch)(0),               // 1: soong_build_metrics.MetricsBase.Arch
-	(ModuleTypeInfo_BuildSystem)(0),     // 2: soong_build_metrics.ModuleTypeInfo.BuildSystem
-	(ExpConfigFetcher_ConfigStatus)(0),  // 3: soong_build_metrics.ExpConfigFetcher.ConfigStatus
-	(*MetricsBase)(nil),                 // 4: soong_build_metrics.MetricsBase
-	(*BuildConfig)(nil),                 // 5: soong_build_metrics.BuildConfig
-	(*SystemResourceInfo)(nil),          // 6: soong_build_metrics.SystemResourceInfo
-	(*PerfInfo)(nil),                    // 7: soong_build_metrics.PerfInfo
-	(*ProcessResourceInfo)(nil),         // 8: soong_build_metrics.ProcessResourceInfo
-	(*ModuleTypeInfo)(nil),              // 9: soong_build_metrics.ModuleTypeInfo
-	(*CriticalUserJourneyMetrics)(nil),  // 10: soong_build_metrics.CriticalUserJourneyMetrics
-	(*CriticalUserJourneysMetrics)(nil), // 11: soong_build_metrics.CriticalUserJourneysMetrics
-	(*SoongBuildMetrics)(nil),           // 12: soong_build_metrics.SoongBuildMetrics
-	(*ExpConfigFetcher)(nil),            // 13: soong_build_metrics.ExpConfigFetcher
-	(*MixedBuildsInfo)(nil),             // 14: soong_build_metrics.MixedBuildsInfo
-	(*CriticalPathInfo)(nil),            // 15: soong_build_metrics.CriticalPathInfo
-	(*JobInfo)(nil),                     // 16: soong_build_metrics.JobInfo
+	(MetricsBase_BuildVariant)(0),          // 0: soong_build_metrics.MetricsBase.BuildVariant
+	(MetricsBase_Arch)(0),                  // 1: soong_build_metrics.MetricsBase.Arch
+	(BuildConfig_NinjaWeightListSource)(0), // 2: soong_build_metrics.BuildConfig.NinjaWeightListSource
+	(ModuleTypeInfo_BuildSystem)(0),        // 3: soong_build_metrics.ModuleTypeInfo.BuildSystem
+	(ExpConfigFetcher_ConfigStatus)(0),     // 4: soong_build_metrics.ExpConfigFetcher.ConfigStatus
+	(*MetricsBase)(nil),                    // 5: soong_build_metrics.MetricsBase
+	(*BuildConfig)(nil),                    // 6: soong_build_metrics.BuildConfig
+	(*SystemResourceInfo)(nil),             // 7: soong_build_metrics.SystemResourceInfo
+	(*PerfInfo)(nil),                       // 8: soong_build_metrics.PerfInfo
+	(*ProcessResourceInfo)(nil),            // 9: soong_build_metrics.ProcessResourceInfo
+	(*ModuleTypeInfo)(nil),                 // 10: soong_build_metrics.ModuleTypeInfo
+	(*CriticalUserJourneyMetrics)(nil),     // 11: soong_build_metrics.CriticalUserJourneyMetrics
+	(*CriticalUserJourneysMetrics)(nil),    // 12: soong_build_metrics.CriticalUserJourneysMetrics
+	(*SoongBuildMetrics)(nil),              // 13: soong_build_metrics.SoongBuildMetrics
+	(*ExpConfigFetcher)(nil),               // 14: soong_build_metrics.ExpConfigFetcher
+	(*MixedBuildsInfo)(nil),                // 15: soong_build_metrics.MixedBuildsInfo
+	(*CriticalPathInfo)(nil),               // 16: soong_build_metrics.CriticalPathInfo
+	(*JobInfo)(nil),                        // 17: soong_build_metrics.JobInfo
 }
 var file_metrics_proto_depIdxs = []int32{
 	0,  // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant
 	1,  // 1: soong_build_metrics.MetricsBase.target_arch:type_name -> soong_build_metrics.MetricsBase.Arch
 	1,  // 2: soong_build_metrics.MetricsBase.host_arch:type_name -> soong_build_metrics.MetricsBase.Arch
 	1,  // 3: soong_build_metrics.MetricsBase.host_2nd_arch:type_name -> soong_build_metrics.MetricsBase.Arch
-	7,  // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo
-	7,  // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo
-	7,  // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
-	7,  // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
-	7,  // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
-	12, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
-	5,  // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
-	6,  // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
-	7,  // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
-	13, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
-	15, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
-	8,  // 15: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
-	2,  // 16: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
-	4,  // 17: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
-	10, // 18: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
-	7,  // 19: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
-	14, // 20: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
-	3,  // 21: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
-	16, // 22: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
-	16, // 23: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
-	24, // [24:24] is the sub-list for method output_type
-	24, // [24:24] is the sub-list for method input_type
-	24, // [24:24] is the sub-list for extension type_name
-	24, // [24:24] is the sub-list for extension extendee
-	0,  // [0:24] is the sub-list for field type_name
+	8,  // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo
+	8,  // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo
+	8,  // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
+	8,  // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
+	8,  // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
+	13, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
+	6,  // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
+	7,  // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
+	8,  // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
+	14, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
+	16, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
+	2,  // 15: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource
+	9,  // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
+	3,  // 17: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
+	5,  // 18: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
+	11, // 19: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
+	8,  // 20: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
+	15, // 21: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
+	4,  // 22: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
+	17, // 23: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
+	17, // 24: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
+	25, // [25:25] is the sub-list for method output_type
+	25, // [25:25] is the sub-list for method input_type
+	25, // [25:25] is the sub-list for extension type_name
+	25, // [25:25] is the sub-list for extension extendee
+	0,  // [0:25] is the sub-list for field type_name
 }
 
 func init() { file_metrics_proto_init() }
@@ -2101,7 +2193,7 @@
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_metrics_proto_rawDesc,
-			NumEnums:      4,
+			NumEnums:      5,
 			NumMessages:   13,
 			NumExtensions: 0,
 			NumServices:   0,
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index d95efa6..5e9a055 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -134,6 +134,12 @@
 }
 
 message BuildConfig {
+  enum NinjaWeightListSource {
+    NOT_USED = 0;
+    NINJA_LOG = 1;
+    EVENLY_DISTRIBUTED = 2;
+  }
+
   optional bool use_goma = 1;
 
   optional bool use_rbe = 2;
@@ -153,6 +159,11 @@
 
   // Whether the user explicitly disabled bazel mixed builds for this build.
   optional bool force_disable_bazel_mixed_build = 7;
+
+  // NOT_USED - ninja doesn't use weight list.
+  // NINJA_LOG - ninja uses weight list based on previous builds by ninja log
+  // EVENLY_DISTRIBUTED - ninja thinks every task has the same weight.
+  optional NinjaWeightListSource ninja_weight_list_source = 8 [default = NOT_USED];
 }
 
 message SystemResourceInfo {
@@ -321,10 +332,10 @@
 // CriticalPathInfo contains critical path nodes's information.
 // A critical path is a path determining the minimum time needed for the whole build given perfect parallelism.
 message CriticalPathInfo {
-  // Real time which the build system spent
-  optional uint64 elapsed_time = 1;
-  // The sum of execution time of the longest path from leave to the root
-  optional uint64 critical_path_time = 2;
+  // Real time which the build system spent in microseconds
+  optional uint64 elapsed_time_micros = 1;
+  // The sum of execution time of the longest path from leave to the root in microseconds
+  optional uint64 critical_path_time_micros = 2;
   // Detailed job information in a critical path.
   repeated JobInfo critical_path = 4;
   // Detailed job information for long running jobs (>30 seconds). These may or may not also be on a critical path.
@@ -332,8 +343,8 @@
 }
 
 message JobInfo {
-  // Real time which a job spent
-  optional uint64 elapsed_time = 1;
+  // Real time which a job spent in microseconds
+  optional uint64 elapsed_time_micros = 1;
   // Description of a job
   optional string job_description = 2;
 }
diff --git a/ui/status/critical_path.go b/ui/status/critical_path.go
index 3c0c4c0..bf32c58 100644
--- a/ui/status/critical_path.go
+++ b/ui/status/critical_path.go
@@ -140,7 +140,7 @@
 func addJobInfos(jobInfos *[]*soong_metrics_proto.JobInfo, sources []*node) {
 	for _, job := range sources {
 		jobInfo := soong_metrics_proto.JobInfo{}
-		jobInfo.ElapsedTime = proto.Uint64(uint64(job.duration.Microseconds()))
+		jobInfo.ElapsedTimeMicros = proto.Uint64(uint64(job.duration.Microseconds()))
 		jobInfo.JobDescription = &job.action.Description
 		*jobInfos = append(*jobInfos, &jobInfo)
 	}
@@ -149,8 +149,8 @@
 func (cp *CriticalPath) WriteToMetrics(met *metrics.Metrics) {
 	criticalPathInfo := soong_metrics_proto.CriticalPathInfo{}
 	path, elapsedTime, criticalTime := cp.criticalPath()
-	criticalPathInfo.ElapsedTime = proto.Uint64(uint64(elapsedTime.Microseconds()))
-	criticalPathInfo.CriticalPathTime = proto.Uint64(uint64(criticalTime.Microseconds()))
+	criticalPathInfo.ElapsedTimeMicros = proto.Uint64(uint64(elapsedTime.Microseconds()))
+	criticalPathInfo.CriticalPathTimeMicros = proto.Uint64(uint64(criticalTime.Microseconds()))
 	addJobInfos(&criticalPathInfo.LongRunningJobs, cp.longRunningJobs())
 	addJobInfos(&criticalPathInfo.CriticalPath, path)
 	met.SetCriticalPathInfo(criticalPathInfo)