Merge "libbuildversion should be linked as a whole archive dep as soong does."
diff --git a/OWNERS b/OWNERS
index 964e27a..0234f27 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,7 +3,6 @@
 
 # AMER
 agespino@google.com
-alexmarquez@google.com
 ccross@android.com
 colefaust@google.com
 cparsons@google.com
diff --git a/android/Android.bp b/android/Android.bp
index 641c438..118087d 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -17,6 +17,7 @@
         "soong-remoteexec",
         "soong-response",
         "soong-shared",
+        "soong-starlark",
         "soong-starlark-format",
         "soong-ui-metrics_proto",
         "soong-android-allowlists",
@@ -60,7 +61,6 @@
         "license_metadata.go",
         "license_sdk_member.go",
         "licenses.go",
-        "makefile_goal.go",
         "makevars.go",
         "metrics.go",
         "module.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 9c1824e..6bd4e26 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -183,6 +183,7 @@
 		"external/selinux/libselinux":            Bp2BuildDefaultTrueRecursively,
 		"external/selinux/libsepol":              Bp2BuildDefaultTrueRecursively,
 		"external/speex":                         Bp2BuildDefaultTrueRecursively,
+		"external/sqlite":                        Bp2BuildDefaultTrueRecursively,
 		"external/tinyalsa":                      Bp2BuildDefaultTrueRecursively,
 		"external/tinyalsa_new":                  Bp2BuildDefaultTrueRecursively,
 		"external/toybox":                        Bp2BuildDefaultTrueRecursively,
@@ -191,11 +192,12 @@
 		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
 
 		"frameworks/av": Bp2BuildDefaultTrue,
+		"frameworks/av/media/audioaidlconversion":            Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/codec2/components/aom":          Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/libmediahelper":                 Bp2BuildDefaultTrue,
 		"frameworks/av/media/libshmem":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/audioaidlconversion":            Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/module/minijail":                Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
@@ -213,13 +215,13 @@
 		"frameworks/native/libs/gui":                         Bp2BuildDefaultTrue,
 		"frameworks/native/libs/math":                        Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/nativebase":                  Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/permission":                  Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/vr":                          Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/opengl/tests/gl2_cameraeye":       Bp2BuildDefaultTrue,
 		"frameworks/native/opengl/tests/gl2_java":            Bp2BuildDefaultTrue,
 		"frameworks/native/opengl/tests/testLatency":         Bp2BuildDefaultTrue,
 		"frameworks/native/opengl/tests/testPauseResume":     Bp2BuildDefaultTrue,
 		"frameworks/native/opengl/tests/testViewport":        Bp2BuildDefaultTrue,
-		"frameworks/native/libs/permission":                  Bp2BuildDefaultTrue,
 		"frameworks/native/services/batteryservice":          Bp2BuildDefaultTrue,
 		"frameworks/proto_logging/stats":                     Bp2BuildDefaultTrueRecursively,
 
@@ -291,6 +293,7 @@
 		"packages/modules/Gki/libkver":                       Bp2BuildDefaultTrue,
 		"packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
 		"packages/modules/NeuralNetworks/apex":               Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/apex/testing":       Bp2BuildDefaultTrue,
 		"packages/providers/MediaProvider/tools/dialogs":     Bp2BuildDefaultFalse, // TODO(b/242834374)
 		"packages/screensavers/Basic":                        Bp2BuildDefaultTrue,
 		"packages/services/Car/tests/SampleRearViewCamera":   Bp2BuildDefaultFalse, // TODO(b/242834321)
@@ -545,6 +548,14 @@
 		"liblp",
 		"libstorage_literals_headers",
 
+		"PluginCoreLib",
+		"dagger2",
+		"dagger2-android-annotation-stubs",
+		"dagger2-bootstrap-compiler",
+		"dagger2-producers",
+		"okio-lib",
+		"setupdesign-strings",
+
 		//external/avb
 		"avbtool",
 		"libavb",
@@ -718,11 +729,12 @@
 		"api_fingerprint",
 
 		// allowlisting for kotlinx_coroutines
+		"annotations",
+		"kotlinx-coroutines-android-annotation-stubs",
+		"kotlinx-coroutines-core",
 		"kotlinx_coroutines",
 		"kotlinx_coroutines-device",
 		"kotlinx_coroutines-host",
-		"annotations",
-		"kotlinx-coroutines-android-annotation-stubs",
 
 		// for building com.android.neuralnetworks
 		"libimapper_stablec",
@@ -731,6 +743,8 @@
 		// min_sdk_version in android_app
 		"CtsShimUpgrade",
 
+		"art_cmdlineparser_headers",
+
 		// Mainline Module Apps
 		"CaptivePortalLogin",
 	}
@@ -764,7 +778,6 @@
 		"buffer_hub_queue_producer-test",
 
 		// cc bugs
-		"libactivitymanager_aidl", // TODO(b/207426160): Unsupported use of aidl sources (via Dactivity_manager_procstate_aidl) in a cc_library
 
 		// TODO(b/198619163) module has same name as source
 		"logtagd.rc",
@@ -777,13 +790,12 @@
 		"libcutils_test_static",
 		"KernelLibcutilsTest",
 
-		"linker",                 // TODO(b/228316882): cc_binary uses link_crt
-		"versioner",              // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
-		"art_libartbase_headers", // TODO(b/236268577): Header libraries do not support export_shared_libs_headers
-		"apexer_test",            // Requires aapt2
-		"apexer_test_host_tools",
-		"host_apex_verifier",
-		"tjbench", // TODO(b/240563612): Stem property
+		"linker",    // TODO(b/228316882): cc_binary uses link_crt
+		"versioner", // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
+		"tjbench",   // TODO(b/240563612): Stem property
+
+		// requires host tools for apexer
+		"apexer_test", "apexer_test_host_tools", "host_apex_verifier",
 
 		// java bugs
 		"libbase_ndk",  // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
@@ -1070,7 +1082,7 @@
 		"libcfi-test",
 		"libcfi-test-bad",
 		"libcrash_test",
-		// "libcrypto_fuzz_unsafe",
+		"libcrypto_fuzz_unsafe",
 		"libdl_preempt_test_1",
 		"libdl_preempt_test_2",
 		"libdl_test_df_1_global",
@@ -1281,7 +1293,7 @@
 		"librelocations-fat",
 		"libsegment_gap_inner",
 		"libsegment_gap_outer",
-		// "libssl_fuzz_unsafe",
+		"libssl_fuzz_unsafe",
 		"libstatssocket_private",
 		"libsysv-hash-table-library",
 		"libtest_atexit",
@@ -1521,6 +1533,11 @@
 		"adb_tls_connection_test",
 		// M9: mixed builds for mainline trains launch
 		"api_fingerprint",
+		// M11: neuralnetworks launch
+		"com.android.neuralnetworks",
+		"test_com.android.neuralnetworks",
+		"libneuralnetworks",
+		"libneuralnetworks_static",
 	}
 
 	// Staging-mode allowlist. Modules in this list are only built
@@ -1528,11 +1545,7 @@
 	// 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{
-		"com.android.neuralnetworks",
-		"libneuralnetworks",
-		"libneuralnetworks_static",
-	}
+	StagingMixedBuildsEnabledList = []string{}
 
 	// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
 	ProdDclaMixedBuildsEnabledList = []string{
diff --git a/android/apex.go b/android/apex.go
index 5bbc02e..6119b08 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -84,6 +84,9 @@
 	//
 	// See Prebuilt.ApexInfoMutator for more information.
 	ForPrebuiltApex bool
+
+	// Returns the name of the test apexes that this module is included in.
+	TestApexes []string
 }
 
 var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
@@ -287,6 +290,9 @@
 
 	// See ApexModule.UniqueApexVariants()
 	UniqueApexVariationsForDeps bool `blueprint:"mutated"`
+
+	// The test apexes that includes this apex variant
+	TestApexes []string `blueprint:"mutated"`
 }
 
 // Marker interface that identifies dependencies that are excluded from APEX contents.
@@ -429,6 +435,11 @@
 	return nil
 }
 
+// Returns the test apexes that this module is included in.
+func (m *ApexModuleBase) TestApexes() []string {
+	return m.ApexProperties.TestApexes
+}
+
 // Implements ApexModule
 func (m *ApexModuleBase) UniqueApexVariations() bool {
 	// If needed, this will bel overridden by concrete types inheriting
@@ -451,6 +462,14 @@
 	AvailableToGkiApex  = "com.android.gki.*"
 )
 
+var (
+	AvailableToRecognziedWildcards = []string{
+		AvailableToPlatform,
+		AvailableToAnyApex,
+		AvailableToGkiApex,
+	}
+)
+
 // CheckAvailableForApex provides the default algorithm for checking the apex availability. When the
 // availability is empty, it defaults to ["//apex_available:platform"] which means "available to the
 // platform but not available to any APEX". When the list is not empty, `what` is matched against
@@ -549,12 +568,14 @@
 			// Platform APIs is allowed for this module only when all APEXes containing
 			// the module are with `use_platform_apis: true`.
 			merged[index].UsePlatformApis = merged[index].UsePlatformApis && apexInfo.UsePlatformApis
+			merged[index].TestApexes = append(merged[index].TestApexes, apexInfo.TestApexes...)
 		} else {
 			seen[mergedName] = len(merged)
 			apexInfo.ApexVariationName = mergedName
 			apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
 			apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
 			apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
+			apexInfo.TestApexes = CopyOf(apexInfo.TestApexes)
 			merged = append(merged, apexInfo)
 		}
 		aliases = append(aliases, [2]string{variantName, mergedName})
@@ -602,8 +623,10 @@
 	mctx.SetDefaultDependencyVariation(&defaultVariation)
 
 	variations := []string{defaultVariation}
+	testApexes := []string{}
 	for _, a := range apexInfos {
 		variations = append(variations, a.ApexVariationName)
+		testApexes = append(testApexes, a.TestApexes...)
 	}
 	modules := mctx.CreateVariations(variations...)
 	for i, mod := range modules {
@@ -617,6 +640,9 @@
 		if !platformVariation {
 			mctx.SetVariationProvider(mod, ApexInfoProvider, apexInfos[i-1])
 		}
+		// Set the value of TestApexes in every single apex variant.
+		// This allows each apex variant to be aware of the test apexes in the user provided apex_available.
+		mod.(ApexModule).apexModuleBase().ApexProperties.TestApexes = testApexes
 	}
 
 	for _, alias := range aliases {
@@ -907,3 +933,9 @@
 		return true
 	})
 }
+
+// Implemented by apexBundle.
+type ApexTestInterface interface {
+	// Return true if the apex bundle is an apex_test
+	IsTestApex() bool
+}
diff --git a/android/apex_test.go b/android/apex_test.go
index 0bf4c9c..ddc730d 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
 		{
 			name: "single",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"foo", "apex10000"},
@@ -45,11 +45,11 @@
 		{
 			name: "merge",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
+				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false, nil}},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
 				{"foo", "apex10000"},
@@ -58,12 +58,12 @@
 		{
 			name: "don't merge version",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
-				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex30"},
@@ -73,11 +73,11 @@
 		{
 			name: "merge updatable",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -87,15 +87,15 @@
 		{
 			name: "don't merge when for prebuilt_apex",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 				// This one should not be merged in with the others because it is for
 				// a prebuilt_apex.
-				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
-				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
+				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -105,11 +105,11 @@
 		{
 			name: "merge different UsePlatformApis but don't allow using platform api",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -119,11 +119,11 @@
 		{
 			name: "merge same UsePlatformApis and allow using platform api",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
diff --git a/android/bazel.go b/android/bazel.go
index 1646883..58d9d87 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -32,6 +32,22 @@
 	Bp2BuildTopLevel = "."
 )
 
+type MixedBuildEnabledStatus int
+
+const (
+	// This module can be mixed_built.
+	MixedBuildEnabled = iota
+
+	// There is a technical incompatibility preventing this module from being
+	// bazel-analyzed. Note: the module might also be incompatible.
+	TechnicalIncompatibility
+
+	// This module cannot be mixed_built due to some incompatibility with it
+	// that is not a platform incompatibility. Example: the module-type is not
+	// enabled, or is not bp2build-converted.
+	ModuleIncompatibility
+)
+
 // FileGroupAsLibrary describes a filegroup module that is converted to some library
 // such as aidl_library or proto_library.
 type FileGroupAsLibrary interface {
@@ -346,24 +362,31 @@
 	}).(Bp2BuildConversionAllowlist)
 }
 
-// MixedBuildsEnabled returns true if a module is ready to be replaced by a
-// converted or handcrafted Bazel target. As a side effect, calling this
-// method will also log whether this module is mixed build enabled for
-// metrics reporting.
-func MixedBuildsEnabled(ctx BaseModuleContext) bool {
+// MixedBuildsEnabled returns a MixedBuildEnabledStatus regarding whether
+// a module is ready to be replaced by a converted or handcrafted Bazel target.
+// As a side effect, calling this method will also log whether this module is
+// mixed build enabled for metrics reporting.
+func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus {
 	module := ctx.Module()
 	apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
 	withinApex := !apexInfo.IsForPlatform()
+
+	platformIncompatible := isPlatformIncompatible(ctx.Os(), ctx.Arch().ArchType)
+	if platformIncompatible {
+		ctx.Config().LogMixedBuild(ctx, false)
+		return TechnicalIncompatibility
+	}
+
 	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)
 	ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
-	return mixedBuildEnabled
+
+	if mixedBuildEnabled {
+		return MixedBuildEnabled
+	}
+	return ModuleIncompatibility
 }
 
 // ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
@@ -388,6 +411,13 @@
 	OtherModuleDir(m blueprint.Module) string
 }
 
+func isPlatformIncompatible(osType OsType, arch ArchType) bool {
+	return osType == Windows || // Windows toolchains are not currently supported.
+		osType == LinuxBionic || // Linux Bionic toolchains are not currently supported.
+		osType == LinuxMusl || // Linux musl toolchains are not currently supported (b/259266326).
+		arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported.
+}
+
 func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool {
 	if !b.bazelProps().Bazel_module.CanConvertToBazel {
 		return false
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 9c273d9..5291eca 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -18,7 +18,6 @@
 	"bytes"
 	"fmt"
 	"os"
-	"os/exec"
 	"path"
 	"path/filepath"
 	"runtime"
@@ -30,7 +29,6 @@
 	"android/soong/bazel/cquery"
 	"android/soong/shared"
 	"android/soong/starlark_fmt"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/metrics"
 
@@ -61,6 +59,8 @@
 		"AUTO_UNINITIALIZE",
 		"USE_CCACHE",
 		"LLVM_NEXT",
+		"LLVM_PREBUILTS_VERSION",
+		"LLVM_RELEASE_VERSION",
 		"ALLOW_UNKNOWN_WARNING_OPTION",
 
 		"UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT",
@@ -86,12 +86,10 @@
 func mixedBuildsPrepareMutator(ctx BottomUpMutatorContext) {
 	if m := ctx.Module(); m.Enabled() {
 		if mixedBuildMod, ok := m.(MixedBuildBuildable); ok {
-			queueMixedBuild := mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx)
+			mixedBuildEnabled := MixedBuildsEnabled(ctx)
+			queueMixedBuild := mixedBuildMod.IsMixedBuildSupported(ctx) && mixedBuildEnabled == MixedBuildEnabled
 			if queueMixedBuild {
 				mixedBuildMod.QueueBazelCall(ctx)
-			} else if _, ok := ctx.Config().bazelForceEnabledModules[m.Name()]; ok {
-				// TODO(b/273910287) - remove this once --ensure_allowlist_integrity is added
-				ctx.ModuleErrorf("Attempted to force enable an unready module: %s. Did you forget to Bp2BuildDefaultTrue its directory?\n", m.Name())
 			}
 		}
 	}
@@ -220,8 +218,7 @@
 }
 
 type bazelRunner interface {
-	createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
-	issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
+	issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
 }
 
 type bazelPaths struct {
@@ -660,36 +657,6 @@
 	expression string
 }
 
-type mockBazelRunner struct {
-	bazelCommandResults map[bazelCommand]string
-	// use *exec.Cmd as a key to get the bazelCommand, the map will be used in issueBazelCommand()
-	// Register createBazelCommand() invocations. Later, an
-	// issueBazelCommand() invocation can be mapped to the *exec.Cmd instance
-	// and then to the expected result via bazelCommandResults
-	tokens     map[*exec.Cmd]bazelCommand
-	commands   []bazelCommand
-	extraFlags []string
-}
-
-func (r *mockBazelRunner) createBazelCommand(_ Config, _ *bazelPaths, _ bazel.RunName,
-	command bazelCommand, extraFlags ...string) *exec.Cmd {
-	r.commands = append(r.commands, command)
-	r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
-	cmd := &exec.Cmd{}
-	if r.tokens == nil {
-		r.tokens = make(map[*exec.Cmd]bazelCommand)
-	}
-	r.tokens[cmd] = command
-	return cmd
-}
-
-func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, _ *metrics.EventHandler) (string, string, error) {
-	if command, ok := r.tokens[bazelCmd]; ok {
-		return r.bazelCommandResults[command], "", nil
-	}
-	return "", "", nil
-}
-
 type builtinBazelRunner struct {
 	useBazelProxy bool
 	outDir        string
@@ -699,17 +666,12 @@
 // Returns (stdout, stderr, error). The first and second return values are strings
 // containing the stdout and stderr of the run command, and an error is returned if
 // the invocation returned an error code.
-func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (string, string, error) {
+func (r *builtinBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
 	if r.useBazelProxy {
 		eventHandler.Begin("client_proxy")
 		defer eventHandler.End("client_proxy")
 		proxyClient := bazel.NewProxyClient(r.outDir)
-		// Omit the arg containing the Bazel binary, as that is handled by the proxy
-		// server.
-		bazelFlags := bazelCmd.Args[1:]
-		// TODO(b/270989498): Refactor these functions to not take exec.Cmd, as its
-		// not actually executed for client proxying.
-		resp, err := proxyClient.IssueCommand(bazel.CmdRequest{bazelFlags, bazelCmd.Env})
+		resp, err := proxyClient.IssueCommand(cmdRequest)
 
 		if err != nil {
 			return "", "", err
@@ -721,26 +683,19 @@
 	} else {
 		eventHandler.Begin("bazel command")
 		defer eventHandler.End("bazel command")
-		stderr := &bytes.Buffer{}
-		bazelCmd.Stderr = stderr
-		if output, err := bazelCmd.Output(); err != nil {
-			return "", string(stderr.Bytes()),
-				fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
-					err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
-		} else {
-			return string(output), string(stderr.Bytes()), nil
-		}
+
+		stdout, stderr, err := bazel.ExecBazel(paths.bazelPath, absolutePath(paths.syntheticWorkspaceDir()), cmdRequest)
+		return string(stdout), string(stderr), err
 	}
 }
 
-func (r *builtinBazelRunner) createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand,
-	extraFlags ...string) *exec.Cmd {
+func (context *mixedBuildBazelContext) createBazelCommand(config Config, runName bazel.RunName, command bazelCommand,
+	extraFlags ...string) bazel.CmdRequest {
 	cmdFlags := []string{
-		"--output_base=" + absolutePath(paths.outputBase),
+		"--output_base=" + absolutePath(context.paths.outputBase),
 		command.command,
 		command.expression,
-		// TODO(asmundak): is it needed in every build?
-		"--profile=" + shared.BazelMetricsFilename(paths, runName),
+		"--profile=" + shared.BazelMetricsFilename(context.paths, runName),
 
 		// We don't need to set --host_platforms because it's set in bazelrc files
 		// that the bazel shell script wrapper passes
@@ -755,15 +710,13 @@
 	}
 	cmdFlags = append(cmdFlags, extraFlags...)
 
-	bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
-	bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
 	extraEnv := []string{
-		"HOME=" + paths.homeDir,
+		"HOME=" + context.paths.homeDir,
 		pwdPrefix(),
-		"BUILD_DIR=" + absolutePath(paths.soongOutDir),
+		"BUILD_DIR=" + absolutePath(context.paths.soongOutDir),
 		// Make OUT_DIR absolute here so build/bazel/bin/bazel uses the correct
 		// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
-		"OUT_DIR=" + absolutePath(paths.outDir()),
+		"OUT_DIR=" + absolutePath(context.paths.outDir()),
 		// Disables local host detection of gcc; toolchain information is defined
 		// explicitly in BUILD files.
 		"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
@@ -775,15 +728,15 @@
 		}
 		extraEnv = append(extraEnv, fmt.Sprintf("%s=%s", envvar, val))
 	}
-	bazelCmd.Env = append(os.Environ(), extraEnv...)
+	envVars := append(os.Environ(), extraEnv...)
 
-	return bazelCmd
+	return bazel.CmdRequest{cmdFlags, envVars}
 }
 
-func printableCqueryCommand(bazelCmd *exec.Cmd) string {
-	outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(bazelCmd.Args, "\" \"") + "\""
+func (context *mixedBuildBazelContext) printableCqueryCommand(bazelCmd bazel.CmdRequest) string {
+	args := append([]string{context.paths.bazelPath}, bazelCmd.Argv...)
+	outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(args, "\" \"") + "\""
 	return outputString
-
 }
 
 func (context *mixedBuildBazelContext) mainBzlFileContents() []byte {
@@ -1106,9 +1059,10 @@
 const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
 
 var (
-	cqueryCmd = bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
-	aqueryCmd = bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
-	buildCmd  = bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+	cqueryCmd        = bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
+	aqueryCmd        = bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
+	buildCmd         = bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+	allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
 )
 
 // Issues commands to Bazel to receive results for all cquery requests
@@ -1170,12 +1124,12 @@
 		extraFlags = append(extraFlags, "--collect_code_coverage")
 	}
 
-	cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
-	cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag, eventHandler)
+	cqueryCmdRequest := context.createBazelCommand(config, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
+	cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCmdRequest, context.paths, eventHandler)
 	if cqueryErr != nil {
 		return cqueryErr
 	}
-	cqueryCommandPrint := fmt.Sprintf("cquery command line:\n  %s \n\n\n", printableCqueryCommand(cqueryCommandWithFlag))
+	cqueryCommandPrint := fmt.Sprintf("cquery command line:\n  %s \n\n\n", context.printableCqueryCommand(cqueryCmdRequest))
 	if err := os.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryCommandPrint+cqueryOutput), 0666); err != nil {
 		return err
 	}
@@ -1233,8 +1187,8 @@
 			extraFlags = append(extraFlags, "--instrumentation_filter="+strings.Join(paths, ","))
 		}
 	}
-	aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
-		extraFlags...), eventHandler)
+	aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.AqueryBuildRootRunName, aqueryCmd,
+		extraFlags...), context.paths, eventHandler)
 	if err != nil {
 		return err
 	}
@@ -1249,7 +1203,7 @@
 	// Issue a build command of the phony root to generate symlink forests for dependencies of the
 	// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
 	// but some of symlinks may be required to resolve source dependencies of the build.
-	_, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd), eventHandler)
+	_, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.BazelBuildPhonyRootRunName, buildCmd), context.paths, eventHandler)
 	return err
 }
 
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index c67d7fb..b17b765 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -8,6 +8,7 @@
 	"strings"
 	"testing"
 
+	"android/soong/bazel"
 	"android/soong/bazel/cquery"
 	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 
@@ -19,6 +20,34 @@
 
 type testInvokeBazelContext struct{}
 
+type mockBazelRunner struct {
+	testHelper *testing.T
+	// Stores mock behavior. If an issueBazelCommand request is made for command
+	// k, and {k:v} is present in this map, then the mock will return v.
+	bazelCommandResults map[bazelCommand]string
+	// Requests actually made of the mockBazelRunner with issueBazelCommand,
+	// keyed by the command they represent.
+	bazelCommandRequests map[bazelCommand]bazel.CmdRequest
+}
+
+func (r *mockBazelRunner) bazelCommandForRequest(cmdRequest bazel.CmdRequest) bazelCommand {
+	for _, arg := range cmdRequest.Argv {
+		for _, cmdType := range allBazelCommands {
+			if arg == cmdType.command {
+				return cmdType
+			}
+		}
+	}
+	r.testHelper.Fatalf("Unrecognized bazel request: %s", cmdRequest)
+	return cqueryCmd
+}
+
+func (r *mockBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
+	command := r.bazelCommandForRequest(cmdRequest)
+	r.bazelCommandRequests[command] = cmdRequest
+	return r.bazelCommandResults[command], "", nil
+}
+
 func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler {
 	return &metrics.EventHandler{}
 }
@@ -36,9 +65,7 @@
 		`@//foo:foo|arm64_armv8-a|android|within_apex|29>>out/foo/foo.txt`,
 		`@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
 	}
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
-		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: strings.Join(cmd_results, "\n"),
-	})
+	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{cqueryCmd: strings.Join(cmd_results, "\n")})
 
 	bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
 	bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
@@ -139,8 +166,7 @@
 		if err != nil {
 			t.Error(err)
 		}
-		bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
-			bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: string(data)})
+		bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
 
 		err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
 		if err != nil {
@@ -166,30 +192,26 @@
 
 	testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
 	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,+foo2,-bar1,-bar2`)
+	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,+foo2,-bar1,-bar2")
 
 	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
 	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,-bar1`)
+	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,-bar1")
 
 	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
 	testConfig.productVariables.NativeCoverageExcludePaths = nil
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1`)
+	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1")
 
 	testConfig.productVariables.NativeCoveragePaths = nil
 	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=-bar1`)
+	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=-bar1")
 
 	testConfig.productVariables.NativeCoveragePaths = []string{"*"}
 	testConfig.productVariables.NativeCoverageExcludePaths = nil
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+.*`)
+	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+.*")
 
 	testConfig.productVariables.ClangCoverage = boolPtr(false)
-	actual := verifyExtraFlags(t, testConfig, ``)
-	if strings.Contains(actual, "--collect_code_coverage") ||
-		strings.Contains(actual, "--instrumentation_filter=") {
-		t.Errorf("Expected code coverage disabled, but got %#v", actual)
-	}
+	verifyAqueryDoesNotContainSubstrings(t, testConfig, "collect_code_coverage", "instrumentation_filter")
 }
 
 func TestBazelRequestsSorted(t *testing.T) {
@@ -268,7 +290,8 @@
 	}
 }
 
-func verifyExtraFlags(t *testing.T, config Config, expected string) string {
+func verifyAqueryContainsFlags(t *testing.T, config Config, expected ...string) {
+	t.Helper()
 	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
 
 	err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
@@ -276,17 +299,49 @@
 		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
 	}
 
-	flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
-	if expected := 3; len(flags) != expected {
-		t.Errorf("Expected %d extra flags got %#v", expected, flags)
+	sliceContains := func(slice []string, x string) bool {
+		for _, s := range slice {
+			if s == x {
+				return true
+			}
+		}
+		return false
 	}
 
-	actual := flags[1]
-	if !strings.Contains(actual, expected) {
-		t.Errorf("Expected %#v got %#v", expected, actual)
+	aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
+
+	for _, expectedFlag := range expected {
+		if !sliceContains(aqueryArgv, expectedFlag) {
+			t.Errorf("aquery does not contain expected flag %#v. Argv was: %#v", expectedFlag, aqueryArgv)
+		}
+	}
+}
+
+func verifyAqueryDoesNotContainSubstrings(t *testing.T, config Config, substrings ...string) {
+	t.Helper()
+	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
+
+	err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
+	if err != nil {
+		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
 	}
 
-	return actual
+	sliceContainsSubstring := func(slice []string, substring string) bool {
+		for _, s := range slice {
+			if strings.Contains(s, substring) {
+				return true
+			}
+		}
+		return false
+	}
+
+	aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
+
+	for _, substring := range substrings {
+		if sliceContainsSubstring(aqueryArgv, substring) {
+			t.Errorf("aquery contains unexpected substring %#v. Argv was: %#v", substring, aqueryArgv)
+		}
+	}
 }
 
 func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
@@ -296,11 +351,14 @@
 		outputBase:   "outputbase",
 		workspaceDir: "workspace_dir",
 	}
-	aqueryCommand := bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}
-	if _, exists := bazelCommandResults[aqueryCommand]; !exists {
-		bazelCommandResults[aqueryCommand] = ""
+	if _, exists := bazelCommandResults[aqueryCmd]; !exists {
+		bazelCommandResults[aqueryCmd] = ""
 	}
-	runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
+	runner := &mockBazelRunner{
+		testHelper:           t,
+		bazelCommandResults:  bazelCommandResults,
+		bazelCommandRequests: map[bazelCommand]bazel.CmdRequest{},
+	}
 	return &mixedBuildBazelContext{
 		bazelRunner: runner,
 		paths:       &p,
diff --git a/android/config.go b/android/config.go
index 032172d..0b54ed9 100644
--- a/android/config.go
+++ b/android/config.go
@@ -102,6 +102,8 @@
 	UseBazelProxy bool
 
 	BuildFromTextStub bool
+
+	EnsureAllowlistIntegrity bool
 }
 
 // Build modes that soong_build can run as.
@@ -174,6 +176,13 @@
 	return c.config.TestProductVariables != nil
 }
 
+// MaxPageSizeSupported returns the max page size supported by the device. This
+// value will define the ELF segment alignment for binaries (executables and
+// shared libraries).
+func (c Config) MaxPageSizeSupported() string {
+	return String(c.config.productVariables.DeviceMaxPageSizeSupported)
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
@@ -278,6 +287,11 @@
 	// If buildFromTextStub is true then the Java API stubs are
 	// built from the signature text files, not the source Java files.
 	buildFromTextStub bool
+
+	// If ensureAllowlistIntegrity is true, then the presence of any allowlisted
+	// modules that aren't mixed-built for at least one variant will cause a build
+	// failure
+	ensureAllowlistIntegrity bool
 }
 
 type deviceConfig struct {
@@ -1557,6 +1571,13 @@
 	return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
 }
 
+func (c *config) HWASanEnabledForPath(path string) bool {
+	if len(c.productVariables.HWASanIncludePaths) == 0 {
+		return false
+	}
+	return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths)
+}
+
 func (c *config) VendorConfig(name string) VendorConfig {
 	return soongconfig.Config(c.productVariables.VendorVars[name])
 }
@@ -1904,6 +1925,10 @@
 	return Bool(c.productVariables.HostMusl)
 }
 
+func (c *config) GetMixedBuildsEnabledModules() map[string]struct{} {
+	return c.mixedBuildEnabledModules
+}
+
 func (c *config) LogMixedBuild(ctx BaseModuleContext, useBazel bool) {
 	moduleName := ctx.Module().Name()
 	c.mixedBuildsLock.Lock()
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index 830890d..2beeb51 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -95,15 +95,6 @@
 	return ev.pctx.VariableConfigMethod(name, method)
 }
 
-func (ev ExportedVariables) ExportStringStaticVariableWithEnvOverride(name, envVar, defaultVal string) {
-	ev.ExportVariableConfigMethod(name, func(config Config) string {
-		if override := config.Getenv(envVar); override != "" {
-			return override
-		}
-		return defaultVal
-	})
-}
-
 // ExportSourcePathVariable declares a static "source path" variable and exports
 // it to Bazel's toolchain.
 func (ev ExportedVariables) ExportSourcePathVariable(name string, value string) {
diff --git a/android/makefile_goal.go b/android/makefile_goal.go
deleted file mode 100644
index 07354a6..0000000
--- a/android/makefile_goal.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"fmt"
-	"io"
-	"path/filepath"
-
-	"github.com/google/blueprint/proptools"
-)
-
-func init() {
-	RegisterModuleType("makefile_goal", MakefileGoalFactory)
-}
-
-type makefileGoalProperties struct {
-	// Sources.
-
-	// Makefile goal output file path, relative to PRODUCT_OUT.
-	Product_out_path *string
-}
-
-type makefileGoal struct {
-	ModuleBase
-
-	properties makefileGoalProperties
-
-	// Destination. Output file path of this module.
-	outputFilePath OutputPath
-}
-
-var _ AndroidMkEntriesProvider = (*makefileGoal)(nil)
-var _ OutputFileProducer = (*makefileGoal)(nil)
-
-// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles.
-func (p *makefileGoal) inputPath() *string {
-	if p.properties.Product_out_path != nil {
-		return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path)))
-	}
-	return nil
-}
-
-// OutputFileProducer
-func (p *makefileGoal) OutputFiles(tag string) (Paths, error) {
-	if tag != "" {
-		return nil, fmt.Errorf("unsupported tag %q", tag)
-	}
-	return Paths{p.outputFilePath}, nil
-}
-
-// AndroidMkEntriesProvider
-func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) {
-	if p.inputPath() == nil {
-		ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required")
-	}
-}
-
-func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) {
-	filename := filepath.Base(proptools.String(p.inputPath()))
-	p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
-
-	ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath)
-}
-
-func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries {
-	return []AndroidMkEntries{AndroidMkEntries{
-		Class:      "ETC",
-		OutputFile: OptionalPathForPath(p.outputFilePath),
-		ExtraFooters: []AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string) {
-				// Can't use Cp because inputPath() is not a valid Path.
-				fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
-			},
-		},
-	}}
-}
-
-// Import a Makefile goal to Soong by copying the file built by
-// the goal to a path visible to Soong. This rule only works on boot images.
-func MakefileGoalFactory() Module {
-	module := &makefileGoal{}
-	module.AddProperties(&module.properties)
-	InitAndroidModule(module)
-	return module
-}
diff --git a/android/module.go b/android/module.go
index ba47453..c8670c3 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2438,7 +2438,7 @@
 
 func (m *ModuleBase) isHandledByBazel(ctx ModuleContext) (MixedBuildBuildable, bool) {
 	if mixedBuildMod, ok := m.module.(MixedBuildBuildable); ok {
-		if mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx) {
+		if mixedBuildMod.IsMixedBuildSupported(ctx) && (MixedBuildsEnabled(ctx) == MixedBuildEnabled) {
 			return mixedBuildMod, true
 		}
 	}
diff --git a/android/mutator.go b/android/mutator.go
index 4ec9604..0a091eb 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -273,6 +273,12 @@
 	// This function can be used to create alias definitions in a directory that is different
 	// from the directory of the visited Soong module.
 	CreateBazelTargetAliasInDir(dir string, name string, actual bazel.Label)
+
+	// CreateBazelConfigSetting creates a config_setting in <dir>/BUILD.bazel
+	// build/bazel has several static config_setting(s) that are used in Bazel builds.
+	// This function can be used to createa additional config_setting(s) based on the build graph
+	// (e.g. a config_setting specific to an apex variant)
+	CreateBazelConfigSetting(csa bazel.ConfigSettingAttributes, ca CommonAttributes, dir string)
 }
 
 type topDownMutatorContext struct {
@@ -738,6 +744,23 @@
 	mod.base().addBp2buildInfo(info)
 }
 
+func (t *topDownMutatorContext) CreateBazelConfigSetting(
+	csa bazel.ConfigSettingAttributes,
+	ca CommonAttributes,
+	dir string) {
+	mod := t.Module()
+	info := bp2buildInfo{
+		Dir: dir,
+		BazelProps: bazel.BazelTargetModuleProperties{
+			Rule_class: "config_setting",
+		},
+		CommonAttrs:     ca,
+		ConstraintAttrs: constraintAttributes{},
+		Attrs:           &csa,
+	}
+	mod.base().addBp2buildInfo(info)
+}
+
 // ApexAvailableTags converts the apex_available property value of an ApexModule
 // module and returns it as a list of keyed tags.
 func ApexAvailableTags(mod Module) bazel.StringListAttribute {
@@ -758,6 +781,35 @@
 	return attr
 }
 
+func ApexAvailableTagsWithoutTestApexes(ctx BaseModuleContext, mod Module) bazel.StringListAttribute {
+	attr := bazel.StringListAttribute{}
+	if am, ok := mod.(ApexModule); ok {
+		apexAvailableWithoutTestApexes := removeTestApexes(ctx, am.apexModuleBase().ApexAvailable())
+		// If a user does not specify apex_available in Android.bp, then soong provides a default.
+		// To avoid verbosity of BUILD files, remove this default from user-facing BUILD files.
+		if len(am.apexModuleBase().ApexProperties.Apex_available) == 0 {
+			apexAvailableWithoutTestApexes = []string{}
+		}
+		attr.Value = ConvertApexAvailableToTags(apexAvailableWithoutTestApexes)
+	}
+	return attr
+}
+
+func removeTestApexes(ctx BaseModuleContext, apex_available []string) []string {
+	testApexes := []string{}
+	for _, aa := range apex_available {
+		// ignore the wildcards
+		if InList(aa, AvailableToRecognziedWildcards) {
+			continue
+		}
+		mod, _ := ctx.ModuleFromName(aa)
+		if apex, ok := mod.(ApexTestInterface); ok && apex.IsTestApex() {
+			testApexes = append(testApexes, aa)
+		}
+	}
+	return RemoveListFromList(CopyOf(apex_available), testApexes)
+}
+
 func ConvertApexAvailableToTags(apexAvailable []string) []string {
 	if len(apexAvailable) == 0 {
 		// We need nil specifically to make bp2build not add the tags property at all,
@@ -771,6 +823,13 @@
 	return result
 }
 
+// ConvertApexAvailableToTagsWithoutTestApexes converts a list of apex names to a list of bazel tags
+// This function drops any test apexes from the input.
+func ConvertApexAvailableToTagsWithoutTestApexes(ctx BaseModuleContext, apexAvailable []string) []string {
+	noTestApexes := removeTestApexes(ctx, apexAvailable)
+	return ConvertApexAvailableToTags(noTestApexes)
+}
+
 func (t *topDownMutatorContext) createBazelTargetModule(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
diff --git a/android/neverallow.go b/android/neverallow.go
index 2139c3c..5b5e613 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -55,7 +55,6 @@
 	AddNeverAllowRules(createJavaDeviceForHostRules()...)
 	AddNeverAllowRules(createCcSdkVariantRules()...)
 	AddNeverAllowRules(createUncompressDexRules()...)
-	AddNeverAllowRules(createMakefileGoalRules()...)
 	AddNeverAllowRules(createInitFirstStageRules()...)
 	AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
 	AddNeverAllowRules(createBp2BuildRule())
@@ -236,20 +235,6 @@
 	}
 }
 
-func createMakefileGoalRules() []Rule {
-	allowlist := []string{
-		// libwifi_hal uses makefile_goal for its dependencies
-		"frameworks/opt/net/wifi/libwifi_hal",
-	}
-	return []Rule{
-		NeverAllow().
-			ModuleType("makefile_goal").
-			WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
-			NotIn(allowlist...).
-			Because("Only boot images may be imported as a makefile goal if not in allowed projects"),
-	}
-}
-
 func createInitFirstStageRules() []Rule {
 	return []Rule{
 		NeverAllow().
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 5f5f9a1..ddd982d 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -313,45 +313,6 @@
 			"module \"outside_art_libraries\": violates neverallow",
 		},
 	},
-	{
-		name: "disallowed makefile_goal",
-		fs: map[string][]byte{
-			"Android.bp": []byte(`
-				makefile_goal {
-					name: "foo",
-					product_out_path: "boot/trap.img"
-				}
-			`),
-		},
-		expectedErrors: []string{
-			"Only boot images.* may be imported as a makefile goal",
-		},
-	},
-	{
-		name: "disallowed makefile_goal outside external",
-		fs: map[string][]byte{
-			"project/Android.bp": []byte(`
-				makefile_goal {
-					name: "foo",
-					product_out_path: "obj/EXE/foo",
-				}
-			`),
-		},
-		expectedErrors: []string{
-			"not in allowed projects",
-		},
-	},
-	{
-		name: "allow makefile_goal within external",
-		fs: map[string][]byte{
-			"frameworks/opt/net/wifi/libwifi_hal/Android.bp": []byte(`
-				makefile_goal {
-					name: "foo",
-					product_out_path: "obj/EXE/foo",
-				}
-			`),
-		},
-	},
 	// Tests for the rule prohibiting the use of framework
 	{
 		name: "prohibit framework",
@@ -391,7 +352,6 @@
 		ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
 		ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
 		ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
-		ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
 	}),
 )
 
@@ -489,22 +449,3 @@
 
 func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
 }
-
-type mockMakefileGoalProperties struct {
-	Product_out_path *string
-}
-
-type mockMakefileGoalModule struct {
-	ModuleBase
-	properties mockMakefileGoalProperties
-}
-
-func newMockMakefileGoalModule() Module {
-	m := &mockMakefileGoalModule{}
-	m.AddProperties(&m.properties)
-	InitAndroidModule(m)
-	return m
-}
-
-func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
-}
diff --git a/android/ninja_deps.go b/android/ninja_deps.go
index 2f442d5..1d50a47 100644
--- a/android/ninja_deps.go
+++ b/android/ninja_deps.go
@@ -14,7 +14,10 @@
 
 package android
 
-import "sort"
+import (
+	"android/soong/starlark_import"
+	"sort"
+)
 
 func (c *config) addNinjaFileDeps(deps ...string) {
 	for _, dep := range deps {
@@ -40,4 +43,11 @@
 
 func (ninjaDepsSingleton) GenerateBuildActions(ctx SingletonContext) {
 	ctx.AddNinjaFileDeps(ctx.Config().ninjaFileDeps()...)
+
+	deps, err := starlark_import.GetNinjaDeps()
+	if err != nil {
+		ctx.Errorf("Error running starlark code: %s", err)
+	} else {
+		ctx.AddNinjaFileDeps(deps...)
+	}
 }
diff --git a/android/override_module.go b/android/override_module.go
index 2d30a85..86f582b 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -304,8 +304,9 @@
 		for i, o := range overrides {
 			mods[i+1].(OverridableModule).override(ctx, o)
 			if o.getOverriddenByPrebuilt() {
-				// The overriding module itself, too, is overridden by a prebuilt. Skip its installation.
-				mods[i+1].HideFromMake()
+				// The overriding module itself, too, is overridden by a prebuilt.
+				// Copy the flag and hide it in make
+				mods[i+1].ReplacedByPrebuilt()
 			}
 		}
 	} else if o, ok := ctx.Module().(OverrideModule); ok {
diff --git a/android/proto.go b/android/proto.go
index 09e50c8..cebbd59 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -234,7 +234,7 @@
 			}
 		}
 
-		tags := ApexAvailableTags(ctx.Module())
+		tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
 
 		ctx.CreateBazelTargetModule(
 			bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 0ae8073..08762ef 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -100,6 +100,15 @@
 	return name
 }
 
+// JavaApiLibraryNames applies JavaApiLibraryName to the list of java_library names.
+func JavaApiLibraryNames(c Config, names []string) []string {
+	apiLibs := make([]string, len(names))
+	for i, name := range names {
+		apiLibs[i] = JavaApiLibraryName(c, name)
+	}
+	return apiLibs
+}
+
 func (k SdkKind) DefaultJavaLibraryName() string {
 	switch k {
 	case SdkPublic:
diff --git a/android/util.go b/android/util.go
index 38e0a4d..08a3521 100644
--- a/android/util.go
+++ b/android/util.go
@@ -26,7 +26,11 @@
 
 // CopyOf returns a new slice that has the same contents as s.
 func CopyOf(s []string) []string {
-	return append([]string(nil), s...)
+	// If the input is nil, return nil and not an empty list
+	if s == nil {
+		return s
+	}
+	return append([]string{}, s...)
 }
 
 // Concat returns a new slice concatenated from the two input slices. It does not change the input
@@ -276,6 +280,8 @@
 // FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
 // each.  It modifies the slice contents in place, and returns a subslice of the original slice.
 func FirstUniqueStrings(list []string) []string {
+	// Do not moodify the input in-place, operate on a copy instead.
+	list = CopyOf(list)
 	// 128 was chosen based on BenchmarkFirstUniqueStrings results.
 	if len(list) > 128 {
 		return firstUniqueStringsMap(list)
@@ -332,6 +338,7 @@
 
 // SortedUniqueStrings returns what the name says
 func SortedUniqueStrings(list []string) []string {
+	// FirstUniqueStrings creates a copy of `list`, so the input remains untouched.
 	unique := FirstUniqueStrings(list)
 	sort.Strings(unique)
 	return unique
diff --git a/android/util_test.go b/android/util_test.go
index 5584b38..a2ef589 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -381,6 +381,14 @@
 	}
 }
 
+func TestCopyOfEmptyAndNil(t *testing.T) {
+	emptyList := []string{}
+	copyOfEmptyList := CopyOf(emptyList)
+	AssertBoolEquals(t, "Copy of an empty list should be an empty list and not nil", true, copyOfEmptyList != nil)
+	copyOfNilList := CopyOf(nil)
+	AssertBoolEquals(t, "Copy of a nil list should be a nil list and not an empty list", true, copyOfNilList == nil)
+}
+
 func ExampleCopyOf() {
 	a := []string{"1", "2", "3"}
 	b := CopyOf(a)
diff --git a/android/variable.go b/android/variable.go
index 249d53b..496f523 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -218,6 +218,7 @@
 	DeviceVndkVersion                     *string  `json:",omitempty"`
 	DeviceCurrentApiLevelForVendorModules *string  `json:",omitempty"`
 	DeviceSystemSdkVersions               []string `json:",omitempty"`
+	DeviceMaxPageSizeSupported            *string  `json:",omitempty"`
 
 	RecoverySnapshotVersion *string `json:",omitempty"`
 
@@ -306,6 +307,8 @@
 	MemtagHeapAsyncIncludePaths []string `json:",omitempty"`
 	MemtagHeapSyncIncludePaths  []string `json:",omitempty"`
 
+	HWASanIncludePaths []string `json:",omitempty"`
+
 	VendorPath    *string `json:",omitempty"`
 	OdmPath       *string `json:",omitempty"`
 	ProductPath   *string `json:",omitempty"`
@@ -505,6 +508,7 @@
 		DeviceSecondaryArchVariant: stringPtr("armv8-a"),
 		DeviceSecondaryCpuVariant:  stringPtr("generic"),
 		DeviceSecondaryAbi:         []string{"armeabi-v7a", "armeabi"},
+		DeviceMaxPageSizeSupported: stringPtr("4096"),
 
 		AAPTConfig:          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 		AAPTPreferredConfig: stringPtr("xhdpi"),
diff --git a/apex/apex.go b/apex/apex.go
index 4fda505..69547c3 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1064,6 +1064,10 @@
 
 	apexVariationName := mctx.ModuleName() // could be com.android.foo
 	a.properties.ApexVariationName = apexVariationName
+	testApexes := []string{}
+	if a.testApex {
+		testApexes = []string{apexVariationName}
+	}
 	apexInfo := android.ApexInfo{
 		ApexVariationName: apexVariationName,
 		MinSdkVersion:     minSdkVersion,
@@ -1072,6 +1076,7 @@
 		InApexVariants:    []string{apexVariationName},
 		InApexModules:     []string{a.Name()}, // could be com.mycompany.android.foo
 		ApexContents:      []*android.ApexContents{apexContents},
+		TestApexes:        testApexes,
 	}
 	mctx.WalkDeps(func(child, parent android.Module) bool {
 		if !continueApexDepsWalk(child, parent) {
@@ -3806,3 +3811,7 @@
 func invalidCompileMultilib(ctx android.TopDownMutatorContext, value string) {
 	ctx.PropertyErrorf("compile_multilib", "Invalid value: %s", value)
 }
+
+func (a *apexBundle) IsTestApex() bool {
+	return a.testApex
+}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 1581949..ebc35cf 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -23,7 +23,11 @@
 )
 
 func init() {
-	android.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
+	registerApexDepsInfoComponents(android.InitRegistrationContext)
+}
+
+func registerApexDepsInfoComponents(ctx android.RegistrationContext) {
+	ctx.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
 }
 
 type apexDepsInfoSingleton struct {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 4e063cb..3ba4d8d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1980,6 +1980,93 @@
 	android.AssertStringDoesContain(t, "cflags", cflags, "-target aarch64-linux-android29")
 }
 
+func TestTrackAllowedDeps(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: true,
+			native_shared_libs: [
+				"mylib",
+				"yourlib",
+			],
+			min_sdk_version: "29",
+		}
+
+		apex {
+			name: "myapex2",
+			key: "myapex.key",
+			updatable: false,
+			native_shared_libs: ["yourlib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libbar"],
+			min_sdk_version: "29",
+			apex_available: ["myapex"],
+		}
+
+		cc_library {
+			name: "libbar",
+			stubs: { versions: ["29", "30"] },
+		}
+
+		cc_library {
+			name: "yourlib",
+			srcs: ["mylib.cpp"],
+			min_sdk_version: "29",
+			apex_available: ["myapex", "myapex2", "//apex_available:platform"],
+		}
+	`, withFiles(android.MockFS{
+		"packages/modules/common/build/allowed_deps.txt": nil,
+	}))
+
+	depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+	inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
+	android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
+		"out/soong/.intermediates/myapex/android_common_myapex_image/depsinfo/flatlist.txt")
+	android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
+		"out/soong/.intermediates/myapex2/android_common_myapex2_image/depsinfo/flatlist.txt")
+
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	flatlist := strings.Split(myapex.Output("depsinfo/flatlist.txt").BuildParams.Args["content"], "\\n")
+	android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+		flatlist, "libbar(minSdkVersion:(no version)) (external)")
+	android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
+		flatlist, "mylib:(minSdkVersion:29)")
+	android.AssertStringListContains(t, "track platform-available lib",
+		flatlist, "yourlib(minSdkVersion:29)")
+}
+
+func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: true,
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+	depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+	if nil != depsinfo.MaybeRule("generateApexDepsInfoFilesRule").Output {
+		t.Error("apex_depsinfo_singleton shouldn't run when allowed_deps.txt doesn't exist")
+	}
+}
+
 func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -3131,10 +3218,7 @@
 			stubs: {
 				versions: ["1", "2", "3"],
 			},
-			apex_available: [
-				"//apex_available:platform",
-				"myapex",
-			],
+			apex_available: ["myapex"],
 		}
 
 		cc_binary {
@@ -4134,7 +4218,7 @@
 		apex {
 			name: "myapex_selfcontained",
 			key: "myapex.key",
-			native_shared_libs: ["lib_dep", "libfoo"],
+			native_shared_libs: ["lib_dep_on_bar", "libbar"],
 			compile_multilib: "both",
 			file_contexts: ":myapex-file_contexts",
 			updatable: false,
@@ -4168,6 +4252,18 @@
 		}
 
 		cc_library {
+			name: "lib_dep_on_bar",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libbar"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [
+				"myapex_selfcontained",
+			],
+		}
+
+
+		cc_library {
 			name: "libfoo",
 			srcs: ["mytest.cpp"],
 			stubs: {
@@ -4177,9 +4273,22 @@
 			stl: "none",
 			apex_available: [
 				"myapex_provider",
+			],
+		}
+
+		cc_library {
+			name: "libbar",
+			srcs: ["mytest.cpp"],
+			stubs: {
+				versions: ["1"],
+			},
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [
 				"myapex_selfcontained",
 			],
 		}
+
 	`)
 
 	var apexManifestRule android.TestingBuildParams
@@ -4206,7 +4315,7 @@
 	apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
-	ensureListContains(t, provideNativeLibs, "libfoo.so")
+	ensureListContains(t, provideNativeLibs, "libbar.so")
 	ensureListEmpty(t, requireNativeLibs)
 }
 
@@ -5689,58 +5798,6 @@
 	})
 }
 
-func TestPrebuiltSkipsSymbols(t *testing.T) {
-	testCases := []struct {
-		name               string
-		usePrebuilt        bool
-		installSymbolFiles bool
-	}{
-		{
-			name:               "Source module build rule doesn't install symbol files",
-			usePrebuilt:        true,
-			installSymbolFiles: false,
-		},
-		{
-			name:               "Source module is installed with symbols",
-			usePrebuilt:        false,
-			installSymbolFiles: true,
-		},
-	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			preferProperty := "prefer: false"
-			if tc.usePrebuilt {
-				preferProperty = "prefer: true"
-			}
-			ctx := testApex(t, `
-				// Source module
-				apex {
-					name: "myapex",
-					key: "myapex.key",
-					updatable: false,
-				}
-
-				apex_key {
-					name: "myapex.key",
-					public_key: "testkey.avbpubkey",
-					private_key: "testkey.pem",
-				}
-
-				apex_set {
-					name: "myapex",
-					set: "myapex.apks",
-					`+preferProperty+`
-				}
-			`)
-			// Symbol files are installed by installing entries under ${OUT}/apex/{apex name}
-			android.AssertStringListContainsEquals(t, "Implicits",
-				ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule").Implicits.Strings(),
-				"out/soong/target/product/test_device/apex/myapex/apex_manifest.pb",
-				tc.installSymbolFiles)
-		})
-	}
-}
-
 func TestApexWithTests(t *testing.T) {
 	ctx := testApex(t, `
 		apex_test {
@@ -8540,14 +8597,14 @@
 		apex {
 			name: "com.android.art",
 			key: "myapex.key",
-			native_shared_libs: ["mylib"],
+			native_shared_libs: ["libnativebridge"],
 			updatable: false,
 		}
 
 		apex {
 			name: "com.android.art.debug",
 			key: "myapex.key",
-			native_shared_libs: ["mylib", "mytestlib"],
+			native_shared_libs: ["libnativebridge", "libnativebrdige_test"],
 			updatable: false,
 		}
 
@@ -8558,8 +8615,8 @@
 		}
 
 		cc_library {
-			name: "mylib",
-			srcs: ["mylib.cpp"],
+			name: "libnativebridge",
+			srcs: ["libnativebridge.cpp"],
 			system_shared_libs: [],
 			stl: "none",
 			stubs: {
@@ -8569,10 +8626,10 @@
 		}
 
 		cc_library {
-			name: "mytestlib",
+			name: "libnativebrdige_test",
 			srcs: ["mylib.cpp"],
 			system_shared_libs: [],
-			shared_libs: ["mylib"],
+			shared_libs: ["libnativebridge"],
 			stl: "none",
 			apex_available: ["com.android.art.debug"],
 			test_for: ["com.android.art"],
@@ -10244,3 +10301,77 @@
 	// Ensure that canned_fs_config has "cat my_config" at the end
 	ensureContains(t, cmd, `( echo '/ 1000 1000 0755'; echo '/apex_manifest.json 1000 1000 0644'; echo '/apex_manifest.pb 1000 1000 0644'; cat my_config ) >`)
 }
+
+func TestStubLibrariesMultipleApexViolation(t *testing.T) {
+	testCases := []struct {
+		desc          string
+		hasStubs      bool
+		apexAvailable string
+		expectedError string
+	}{
+		{
+			desc:          "non-stub library can have multiple apex_available",
+			hasStubs:      false,
+			apexAvailable: `["myapex", "otherapex"]`,
+		},
+		{
+			desc:          "stub library should not be available to anyapex",
+			hasStubs:      true,
+			apexAvailable: `["//apex_available:anyapex"]`,
+			expectedError: "Stub libraries should have a single apex_available.*anyapex",
+		},
+		{
+			desc:          "stub library should not be available to multiple apexes",
+			hasStubs:      true,
+			apexAvailable: `["myapex", "otherapex"]`,
+			expectedError: "Stub libraries should have a single apex_available.*myapex.*otherapex",
+		},
+		{
+			desc:          "stub library can be available to a core apex and a test apex",
+			hasStubs:      true,
+			apexAvailable: `["myapex", "test_myapex"]`,
+		},
+	}
+	bpTemplate := `
+		cc_library {
+			name: "libfoo",
+			%v
+			apex_available: %v,
+		}
+		apex {
+			name: "myapex",
+			key: "apex.key",
+			updatable: false,
+			native_shared_libs: ["libfoo"],
+		}
+		apex {
+			name: "otherapex",
+			key: "apex.key",
+			updatable: false,
+		}
+		apex_test {
+			name: "test_myapex",
+			key: "apex.key",
+			updatable: false,
+			native_shared_libs: ["libfoo"],
+		}
+		apex_key {
+			name: "apex.key",
+		}
+	`
+	for _, tc := range testCases {
+		stubs := ""
+		if tc.hasStubs {
+			stubs = `stubs: {symbol_file: "libfoo.map.txt"},`
+		}
+		bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable)
+		mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) {
+			fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil
+		})
+		if tc.expectedError == "" {
+			testApex(t, bp, mockFsFixturePreparer)
+		} else {
+			testApexError(t, tc.expectedError, bp, mockFsFixturePreparer)
+		}
+	}
+}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 2ddfd03..d784818 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -116,18 +116,18 @@
 	// Make sure that the art-bootclasspath-fragment is using the correct configuration.
 	checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000",
 		"com.android.art:baz,com.android.art:quuz", `
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.art
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.oat
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.vdex
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.art
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.oat
-test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.vdex
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.art
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.oat
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.vdex
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.art
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.oat
+dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.vdex
 `)
 }
 
@@ -764,7 +764,7 @@
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 
 		// Check that the right deapexer module was chosen for a boot image.
-		param := module.Output("out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art")
+		param := module.Output("out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art")
 		android.AssertStringDoesContain(t, "didn't find the expected deapexer in the input path", param.Input.String(), "/com.android.art.deapexer")
 	})
 
@@ -782,7 +782,7 @@
 	bootJarLocations := []string{}
 	for _, output := range module.AllOutputs() {
 		output = android.StringRelativeToTop(config, output)
-		if strings.HasPrefix(output, "out/soong/test_device/dex_artjars_input/") {
+		if strings.HasPrefix(output, "out/soong/dexpreopt_arm64/dex_artjars_input/") {
 			bootJarLocations = append(bootJarLocations, output)
 		}
 	}
@@ -790,7 +790,7 @@
 	sort.Strings(bootJarLocations)
 	expected := []string{}
 	for _, m := range modules {
-		expected = append(expected, fmt.Sprintf("out/soong/test_device/dex_artjars_input/%s.jar", m))
+		expected = append(expected, fmt.Sprintf("out/soong/dexpreopt_arm64/dex_artjars_input/%s.jar", m))
 	}
 	sort.Strings(expected)
 
diff --git a/apex/builder.go b/apex/builder.go
index 2f8a4ec..7c6522d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -231,7 +231,7 @@
 
 	apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
 		Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
-			`&& ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
+			` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
 		CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
 		Description: "run apex_sepolicy_tests",
 	})
@@ -468,10 +468,6 @@
 	imageDir := android.PathForModuleOut(ctx, "image"+suffix)
 
 	installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
-	// We can't install symbol files when prebuilt is used.
-	if a.IsReplacedByPrebuilt() {
-		installSymbolFiles = false
-	}
 
 	// set of dependency module:location mappings
 	installMapSet := make(map[string]bool)
@@ -517,9 +513,6 @@
 				}
 			}
 			implicitInputs = append(implicitInputs, fi.builtFile)
-			if installSymbolFiles {
-				implicitInputs = append(implicitInputs, installedPath)
-			}
 
 			// Create additional symlinks pointing the file inside the APEX (if any). Note that
 			// this is independent from the symlink optimization.
@@ -527,8 +520,7 @@
 				symlinkDest := imageDir.Join(ctx, symlinkPath).String()
 				copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
 				if installSymbolFiles {
-					installedSymlink := ctx.InstallSymlink(apexDir.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
-					implicitInputs = append(implicitInputs, installedSymlink)
+					ctx.InstallSymlink(apexDir.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
 				}
 			}
 
@@ -553,11 +545,6 @@
 		installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
 	}
 	implicitInputs = append(implicitInputs, a.manifestPbOut)
-	if installSymbolFiles {
-		installedManifest := ctx.InstallFile(apexDir, "apex_manifest.pb", a.manifestPbOut)
-		installedKey := ctx.InstallFile(apexDir, "apex_pubkey", a.publicKeyFile)
-		implicitInputs = append(implicitInputs, installedManifest, installedKey)
-	}
 
 	if len(installMapSet) > 0 {
 		var installs []string
@@ -885,7 +872,8 @@
 		args["outCommaList"] = signedOutputFile.String()
 	}
 	var validations android.Paths
-	if suffix == imageApexSuffix {
+	// TODO(b/279688635) deapexer supports [ext4]
+	if suffix == imageApexSuffix && ext4 == a.payloadFsType {
 		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
 	}
 	ctx.Build(pctx, android.BuildParams{
diff --git a/apex/testing.go b/apex/testing.go
index 69bd73e..3b200f0 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -19,6 +19,7 @@
 var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers(
 	android.FixtureRegisterWithContext(registerApexBuildComponents),
 	android.FixtureRegisterWithContext(registerApexKeyBuildComponents),
+	android.FixtureRegisterWithContext(registerApexDepsInfoComponents),
 	// Additional files needed in tests that disallow non-existent source files.
 	// This includes files that are needed by all, or at least most, instances of an apex module type.
 	android.MockFS{
diff --git a/bazel/bazel_proxy.go b/bazel/bazel_proxy.go
index d7f5e64..2940b99 100644
--- a/bazel/bazel_proxy.go
+++ b/bazel/bazel_proxy.go
@@ -128,6 +128,24 @@
 	}
 }
 
+func ExecBazel(bazelPath string, workspaceDir string, request CmdRequest) (stdout []byte, stderr []byte, cmdErr error) {
+	bazelCmd := exec.Command(bazelPath, request.Argv...)
+	bazelCmd.Dir = workspaceDir
+	bazelCmd.Env = request.Env
+
+	stderrBuffer := &bytes.Buffer{}
+	bazelCmd.Stderr = stderrBuffer
+
+	if output, err := bazelCmd.Output(); err != nil {
+		cmdErr = fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
+			err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderrBuffer)
+	} else {
+		stdout = output
+	}
+	stderr = stderrBuffer.Bytes()
+	return
+}
+
 func (b *ProxyServer) handleRequest(conn net.Conn) error {
 	defer conn.Close()
 
@@ -137,23 +155,13 @@
 		return fmt.Errorf("Error decoding request: %s", err)
 	}
 
-	bazelCmd := exec.Command("./build/bazel/bin/bazel", req.Argv...)
-	bazelCmd.Dir = b.workspaceDir
-	bazelCmd.Env = req.Env
-
-	stderr := &bytes.Buffer{}
-	bazelCmd.Stderr = stderr
-	var stdout string
-	var bazelErrString string
-
-	if output, err := bazelCmd.Output(); err != nil {
-		bazelErrString = fmt.Sprintf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
-			err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
-	} else {
-		stdout = string(output)
+	stdout, stderr, cmdErr := ExecBazel("./build/bazel/bin/bazel", b.workspaceDir, req)
+	errorString := ""
+	if cmdErr != nil {
+		errorString = cmdErr.Error()
 	}
 
-	resp := CmdResponse{stdout, string(stderr.Bytes()), bazelErrString}
+	resp := CmdResponse{string(stdout), string(stderr), errorString}
 	enc := gob.NewEncoder(conn)
 	if err := enc.Encode(&resp); err != nil {
 		return fmt.Errorf("Error encoding response: %s", err)
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 4680256..d01877d 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -268,9 +268,8 @@
 	case productVariables:
 		// do nothing
 	case osAndInApex:
-		if _, ok := osAndInApexMap[config]; !ok {
-			panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
-		}
+		// do nothing
+		// this axis can contain additional per-apex keys
 	case inApex:
 		if _, ok := inApexMap[config]; !ok {
 			panic(fmt.Errorf("Unknown in_apex config: %s", config))
@@ -299,7 +298,10 @@
 		}
 		return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
 	case osAndInApex:
-		return osAndInApexMap[config]
+		if ret, exists := osAndInApexMap[config]; exists {
+			return ret
+		}
+		return config
 	case inApex:
 		return inApexMap[config]
 	default:
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index bf3a6b5..6a3b3c8 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -149,6 +149,7 @@
 rootSharedLibraries = []
 
 shared_info_tag = "//build/bazel/rules/cc:cc_library_shared.bzl%CcSharedLibraryOutputInfo"
+stubs_tag = "//build/bazel/rules/cc:cc_stub_library.bzl%CcStubInfo"
 unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
 unstripped = ""
 
@@ -160,6 +161,8 @@
   unstripped = path
   if unstripped_tag in p:
     unstripped = p[unstripped_tag].unstripped.path
+elif stubs_tag in p:
+  rootSharedLibraries.extend([f.path for f in target.files.to_list()])
 else:
   for linker_input in linker_inputs:
     for library in linker_input.libraries:
diff --git a/bazel/properties.go b/bazel/properties.go
index 40d0ba3..1757bad 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -1424,3 +1424,14 @@
 	sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
 	return sub, s != sub
 }
+
+// StringMapAttribute is a map of strings.
+// The use case for this is storing the flag_values in a config_setting object.
+// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules.
+type StringMapAttribute map[string]string
+
+// ConfigSettingAttributes stores the keys of a config_setting object.
+type ConfigSettingAttributes struct {
+	// Each key in Flag_values is a label to a custom string_setting
+	Flag_values StringMapAttribute
+}
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index d1dfb9d..b22cb28 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -15,6 +15,7 @@
 package bp2build
 
 import (
+	"android/soong/starlark_import"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -93,6 +94,12 @@
 		os.Exit(1)
 	}
 	writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
+	starlarkDeps, err := starlark_import.GetNinjaDeps()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "%s\n", err)
+		os.Exit(1)
+	}
+	ctx.AddNinjaFileDeps(starlarkDeps...)
 	return &res.metrics
 }
 
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index b7678a4..a860484 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -600,6 +600,11 @@
 		// TODO(b/164227191): implement pretty print for interfaces.
 		// Interfaces are used for for arch, multilib and target properties.
 		return "", nil
+	case reflect.Map:
+		if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok {
+			return starlark_fmt.PrintStringStringDict(v, indent), nil
+		}
+		return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue)
 	default:
 		return "", fmt.Errorf(
 			"unexpected kind for property struct field: %s", propertyValue.Kind())
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 73ee26b..1b64055 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1898,3 +1898,36 @@
 		Description:          "Generating API contribution Bazel targets for custom module",
 	})
 }
+
+func TestGenerateConfigSetting(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+		test_config_setting: true,
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTargetNoRestrictions(
+			"config_setting",
+			"foo_config_setting",
+			AttrNameToString{
+				"flag_values": `{
+        "//build/bazel/rules/my_string_setting": "foo",
+    }`,
+			},
+		),
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Generating API contribution Bazel targets for custom module",
+	})
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index a8e557d..fa1bf8a 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -108,6 +108,7 @@
         "string_literal_prop": attr.string(),
         "string_prop": attr.string(),
         "string_ptr_prop": attr.string(),
+        "test_config_setting": attr.bool(),
     },
 )
 
@@ -139,6 +140,7 @@
         "string_literal_prop": attr.string(),
         "string_prop": attr.string(),
         "string_ptr_prop": attr.string(),
+        "test_config_setting": attr.bool(),
     },
 )
 
@@ -170,6 +172,7 @@
         "string_literal_prop": attr.string(),
         "string_prop": attr.string(),
         "string_ptr_prop": attr.string(),
+        "test_config_setting": attr.bool(),
         # test_prop start
 #         "test_string_prop": attr.string(),
         # test_prop end
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 0315732..89eac8a 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -996,3 +996,44 @@
 		},
 	})
 }
+
+func TestCcBinaryHiddenVisibilityConvertedToFeature(t *testing.T) {
+	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary changes hidden visibility to feature",
+		blueprint: `
+{rule_name} {
+	name: "foo",
+	cflags: ["-fvisibility=hidden"],
+}`,
+		targets: []testBazelTarget{
+			{"cc_binary", "foo", AttrNameToString{
+				"local_includes": `["."]`,
+				"features":       `["visibility_hidden"]`,
+			}},
+		},
+	})
+}
+
+func TestCcBinaryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary changes hidden visibility to feature for specific os",
+		blueprint: `
+{rule_name} {
+	name: "foo",
+	target: {
+		android: {
+			cflags: ["-fvisibility=hidden"],
+		},
+	},
+}`,
+		targets: []testBazelTarget{
+			{"cc_binary", "foo", AttrNameToString{
+				"local_includes": `["."]`,
+				"features": `select({
+        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//conditions:default": [],
+    })`,
+			}},
+		},
+	})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 27a4c22..776129f 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -4350,3 +4350,176 @@
 		},
 	})
 }
+
+func TestCcLibraryHiddenVisibilityConvertedToFeature(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library changes hidden visibility flag to feature",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "foo",
+	cflags: ["-fvisibility=hidden"],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"features":       `["visibility_hidden"]`,
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features":       `["visibility_hidden"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureSharedSpecific(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library changes hidden visibility flag to feature when specific to shared variant",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "foo",
+	shared: {
+		cflags: ["-fvisibility=hidden"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features":       `["visibility_hidden"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureStaticSpecific(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library changes hidden visibility flag to feature when specific to static variant",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "foo",
+	static: {
+		cflags: ["-fvisibility=hidden"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"features":       `["visibility_hidden"]`,
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library changes hidden visibility flag to feature when specific to an os",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "foo",
+	target: {
+		android: {
+			cflags: ["-fvisibility=hidden"],
+		},
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"features": `select({
+        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features": `select({
+        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+// Test that a config_setting specific to an apex is created by cc_library.
+func TestCcLibraryCreatesInApexConfigSetting(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library creates a config_setting for each apex in apex_available",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "build/bazel/rules/apex",
+		Blueprint: `
+cc_library {
+	name: "foo",
+	apex_available: [
+	"//apex_available:platform", // This will be skipped, since it is equivalent to //build/bazel/rules/apex:android-non_apex
+	"myapex"
+	],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions(
+				"config_setting",
+				"android-in_myapex",
+				AttrNameToString{
+					"flag_values": `{
+        "//build/bazel/rules/apex:apex_name": "myapex",
+    }`,
+				},
+			),
+		},
+	})
+}
+
+func TestCcLibraryCppFlagsInProductVariables(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library cppflags in product variables",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `cc_library {
+    name: "a",
+    srcs: ["a.cpp"],
+    cppflags: [
+        "-Wextra",
+        "-DDEBUG_ONLY_CODE=0",
+    ],
+    product_variables: {
+        eng: {
+            cppflags: [
+                "-UDEBUG_ONLY_CODE",
+                "-DDEBUG_ONLY_CODE=1",
+            ],
+        },
+    },
+    include_build_directory: false,
+}
+`,
+		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
+			"cppflags": `[
+        "-Wextra",
+        "-DDEBUG_ONLY_CODE=0",
+    ] + select({
+        "//build/bazel/product_variables:eng": [
+            "-UDEBUG_ONLY_CODE",
+            "-DDEBUG_ONLY_CODE=1",
+        ],
+        "//conditions:default": [],
+    })`,
+			"srcs": `["a.cpp"]`,
+		}),
+	},
+	)
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 59fbd43..47dff8a 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -1250,3 +1250,107 @@
 		},
 	})
 }
+
+func TestCcLibrarySharedHiddenVisibilityConvertedToFeature(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared changes hidden visibility flag to feature",
+		Blueprint: `
+cc_library_shared{
+	name: "foo",
+	cflags: ["-fvisibility=hidden"],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features":       `["visibility_hidden"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibrarySharedHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared changes hidden visibility flag to feature for specific os",
+		Blueprint: `
+cc_library_shared{
+	name: "foo",
+	target: {
+		android: {
+			cflags: ["-fvisibility=hidden"],
+		},
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"features": `select({
+        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibrarySharedStubsDessertVersionConversion(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared converts dessert codename versions to numerical versions",
+		Blueprint: `
+cc_library_shared {
+	name: "a",
+	include_build_directory: false,
+	stubs: {
+		symbol_file: "a.map.txt",
+		versions: [
+			"Q",
+			"R",
+			"31",
+		],
+	},
+}
+cc_library_shared {
+	name: "b",
+	include_build_directory: false,
+	stubs: {
+		symbol_file: "b.map.txt",
+		versions: [
+			"Q",
+			"R",
+			"31",
+			"current",
+		],
+	},
+}
+`,
+		ExpectedBazelTargets: []string{
+			makeCcStubSuiteTargets("a", AttrNameToString{
+				"soname":               `"a.so"`,
+				"source_library_label": `"//:a"`,
+				"stubs_symbol_file":    `"a.map.txt"`,
+				"stubs_versions": `[
+        "29",
+        "30",
+        "31",
+        "current",
+    ]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+				"stubs_symbol_file": `"a.map.txt"`,
+			}),
+			makeCcStubSuiteTargets("b", AttrNameToString{
+				"soname":               `"b.so"`,
+				"source_library_label": `"//:b"`,
+				"stubs_symbol_file":    `"b.map.txt"`,
+				"stubs_versions": `[
+        "29",
+        "30",
+        "31",
+        "current",
+    ]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
+				"stubs_symbol_file": `"b.map.txt"`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 0583ada..9488014 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -2032,3 +2032,44 @@
 		},
 	})
 }
+
+func TestCcLibraryStaticHiddenVisibilityConvertedToFeature(t *testing.T) {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static changes hidden visibility flag to feature",
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	cflags: ["-fvisibility=hidden"],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"features":       `["visibility_hidden"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryStaticHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static changes hidden visibility flag to feature for specific os",
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	target: {
+		android: {
+			cflags: ["-fvisibility=hidden"],
+		},
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"features": `select({
+        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 20adddb..4df4d4d 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -76,17 +76,28 @@
             static_libs: ["hostlib"],
         },
     },
+    static_libs: ["cc_test_lib1"],
+    shared_libs: ["cc_test_lib2"],
     data: [":data_mod", "file.txt"],
     data_bins: [":cc_bin"],
     data_libs: [":cc_lib"],
     cflags: ["-Wall"],
 }
+
+cc_test_library {
+    name: "cc_test_lib1",
+    host_supported: true,
+    include_build_directory: false,
+}
 ` + simpleModuleDoNotConvertBp2build("cc_library", "foolib") +
 			simpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") +
 			simpleModuleDoNotConvertBp2build("genrule", "data_mod") +
 			simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
-			simpleModuleDoNotConvertBp2build("cc_test_library", "cc_lib"),
+			simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") +
+			simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2"),
 		targets: []testBazelTarget{
+			{"cc_library_shared", "cc_test_lib1", AttrNameToString{}},
+			{"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}},
 			{"cc_test", "mytest", AttrNameToString{
 				"copts": `["-Wall"]`,
 				"data": `[
@@ -95,7 +106,7 @@
         ":cc_bin",
         ":cc_lib",
     ]`,
-				"deps": `select({
+				"deps": `[":cc_test_lib1_bp2build_cc_library_static"] + select({
         "//build/bazel/platforms/os:darwin": [":hostlib"],
         "//build/bazel/platforms/os:linux_bionic": [":hostlib"],
         "//build/bazel/platforms/os:linux_glibc": [":hostlib"],
@@ -106,7 +117,7 @@
 				"gtest":          "True",
 				"isolated":       "True",
 				"local_includes": `["."]`,
-				"dynamic_deps": `select({
+				"dynamic_deps": `[":cc_test_lib2"] + select({
         "//build/bazel/platforms/os:android": [":foolib"],
         "//conditions:default": [],
     })`,
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 6e919db..fd99ff0 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -317,6 +317,8 @@
 	One_to_many_prop *bool
 
 	Api *string // File describing the APIs of this module
+
+	Test_config_setting *bool // Used to test generation of config_setting targets
 }
 
 type customModule struct {
@@ -490,6 +492,27 @@
 	}
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+
+	if proptools.Bool(m.props.Test_config_setting) {
+		m.createConfigSetting(ctx)
+	}
+
+}
+
+func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
+	csa := bazel.ConfigSettingAttributes{
+		Flag_values: bazel.StringMapAttribute{
+			"//build/bazel/rules/my_string_setting": m.Name(),
+		},
+	}
+	ca := android.CommonAttributes{
+		Name: m.Name() + "_config_setting",
+	}
+	ctx.CreateBazelConfigSetting(
+		csa,
+		ca,
+		ctx.ModuleDir(),
+	)
 }
 
 var _ android.ApiProvider = (*customModule)(nil)
diff --git a/cc/afdo.go b/cc/afdo.go
index be4f50a..49f6987 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -34,7 +34,7 @@
 
 var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
 
-const afdoCFlagsFormat = "-funique-internal-linkage-names -fprofile-sample-accurate -fprofile-sample-use=%s"
+const afdoCFlagsFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
 
 func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
 	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
@@ -66,10 +66,24 @@
 // afdoEnabled returns true for binaries and shared libraries
 // that set afdo prop to True and there is a profile available
 func (afdo *afdo) afdoEnabled() bool {
-	return afdo != nil && afdo.Properties.Afdo && afdo.Properties.FdoProfilePath != nil
+	return afdo != nil && afdo.Properties.Afdo
 }
 
 func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
+	if afdo.Properties.Afdo {
+		// We use `-funique-internal-linkage-names` to associate profiles to the right internal
+		// functions. This option should be used before generating a profile. Because a profile
+		// generated for a binary without unique names doesn't work well building a binary with
+		// unique names (they have different internal function names).
+		// To avoid a chicken-and-egg problem, we enable `-funique-internal-linkage-names` when
+		// `afdo=true`, whether a profile exists or not.
+		// The profile can take effect in three steps:
+		// 1. Add `afdo: true` in Android.bp, and build the binary.
+		// 2. Collect an AutoFDO profile for the binary.
+		// 3. Make the profile searchable by the build system. So it's used the next time the binary
+		//	  is built.
+		flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...)
+	}
 	if path := afdo.Properties.FdoProfilePath; path != nil {
 		// The flags are prepended to allow overriding.
 		profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
@@ -129,42 +143,41 @@
 // Propagate afdo requirements down from binaries and shared libraries
 func afdoDepsMutator(mctx android.TopDownMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
-		if path := m.afdo.Properties.FdoProfilePath; path != nil {
-			mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
-				tag := mctx.OtherModuleDependencyTag(dep)
-				libTag, isLibTag := tag.(libraryDependencyTag)
+		path := m.afdo.Properties.FdoProfilePath
+		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+			tag := mctx.OtherModuleDependencyTag(dep)
+			libTag, isLibTag := tag.(libraryDependencyTag)
 
-				// Do not recurse down non-static dependencies
-				if isLibTag {
-					if !libTag.static() {
-						return false
-					}
-				} else {
-					if tag != objDepTag && tag != reuseObjTag {
-						return false
-					}
+			// Do not recurse down non-static dependencies
+			if isLibTag {
+				if !libTag.static() {
+					return false
 				}
-
-				if dep, ok := dep.(*Module); ok {
-					dep.afdo.Properties.AfdoRDeps = append(
-						dep.afdo.Properties.AfdoRDeps,
-						afdoRdep{
-							VariationName: proptools.StringPtr(encodeTarget(m.Name())),
-							ProfilePath:   path,
-						},
-					)
+			} else {
+				if tag != objDepTag && tag != reuseObjTag {
+					return false
 				}
+			}
 
-				return true
-			})
-		}
+			if dep, ok := dep.(*Module); ok {
+				dep.afdo.Properties.AfdoRDeps = append(
+					dep.afdo.Properties.AfdoRDeps,
+					afdoRdep{
+						VariationName: proptools.StringPtr(encodeTarget(m.Name())),
+						ProfilePath:   path,
+					},
+				)
+			}
+
+			return true
+		})
 	}
 }
 
 // Create afdo variants for modules that need them
 func afdoMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
-		if !m.static() && m.afdo.Properties.Afdo && m.afdo.Properties.FdoProfilePath != nil {
+		if !m.static() && m.afdo.Properties.Afdo {
 			mctx.SetDependencyVariation(encodeTarget(m.Name()))
 			return
 		}
@@ -182,7 +195,7 @@
 			//                   \                      ^
 			//                    ----------------------|
 			// We only need to create one variant per unique rdep
-			if variantNameToProfilePath[variantName] == nil {
+			if _, exists := variantNameToProfilePath[variantName]; !exists {
 				variationNames = append(variationNames, variantName)
 				variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
 			}
@@ -197,6 +210,7 @@
 				variation := modules[i].(*Module)
 				variation.Properties.PreventInstall = true
 				variation.Properties.HideFromMake = true
+				variation.afdo.Properties.Afdo = true
 				variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
 			}
 		}
diff --git a/cc/afdo_test.go b/cc/afdo_test.go
index 1c20bfc..b250ad1 100644
--- a/cc/afdo_test.go
+++ b/cc/afdo_test.go
@@ -379,3 +379,85 @@
 		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
 	}
 }
+
+func TestAfdoDepsWithoutProfile(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		static_libs: ["libFoo"],
+		afdo: true,
+	}
+
+	cc_library_static {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithFdoProfile,
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	// Even without a profile path, the afdo enabled libraries should be built with
+	// -funique-internal-linkage-names.
+	expectedCFlag := "-funique-internal-linkage-names"
+
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+	libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
+	libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
+
+	// Check cFlags of afdo-enabled module and the afdo-variant of its static deps
+	cFlags := libTest.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+	// Check dependency edge from afdo-enabled module to static deps
+	if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) {
+		t.Errorf("libTest missing dependency on afdo variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) {
+		t.Errorf("libTest missing dependency on afdo variant of libBar")
+	}
+
+	// Verify non-afdo variant exists and doesn't contain afdo
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+	cFlags = libFoo.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+	}
+	cFlags = libBar.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edges of static deps
+	if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest should not depend on non-afdo variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
+	}
+}
diff --git a/cc/binary.go b/cc/binary.go
index 097f822..98b9923 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -661,7 +661,7 @@
 	// shared with cc_test
 	binaryAttrs := binaryBp2buildAttrs(ctx, m)
 
-	tags := android.ApexAvailableTags(m)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 	ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
 		Rule_class:        "cc_binary",
 		Bzl_load_location: "//build/bazel/rules/cc:cc_binary.bzl",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 9f5da6b..749fce5 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -17,6 +17,7 @@
 	"fmt"
 	"path/filepath"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -67,6 +68,8 @@
 
 	Apex_available []string
 
+	Features bazel.StringListAttribute
+
 	sdkAttributes
 
 	tidyAttributes
@@ -226,7 +229,7 @@
 	attrs := staticOrSharedAttributes{}
 
 	setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
-		attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
+		attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutHiddenVisibility))
 		attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
 		attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
 
@@ -268,7 +271,9 @@
 	attrs.Srcs_c = partitionedSrcs[cSrcPartition]
 	attrs.Srcs_as = partitionedSrcs[asSrcPartition]
 
-	attrs.Apex_available = android.ConvertApexAvailableToTags(apexAvailable)
+	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), apexAvailable)
+
+	attrs.Features.Append(convertHiddenVisibilityToFeatureStaticOrShared(ctx, module, isStatic))
 
 	if !partitionedSrcs[protoSrcPartition].IsEmpty() {
 		// TODO(b/208815215): determine whether this is used and add support if necessary
@@ -428,6 +433,12 @@
 
 type filterOutFn func(string) bool
 
+// filterOutHiddenVisibility removes the flag specifying hidden visibility as
+// this flag is converted to a toolchain feature
+func filterOutHiddenVisibility(flag string) bool {
+	return flag == config.VisibilityHiddenFlag
+}
+
 func filterOutStdFlag(flag string) bool {
 	return strings.HasPrefix(flag, "-std=")
 }
@@ -490,7 +501,7 @@
 	// overridden. In Bazel we always allow overriding, via flags; however, this can cause
 	// incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
 	// cases.
-	ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags))
+	ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags, filterOutHiddenVisibility))
 	ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil))
 	ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, filterOutClangUnknownCflags))
 	ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, filterOutClangUnknownCflags))
@@ -517,7 +528,7 @@
 	productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{
 		"Cflags":   &ca.copts,
 		"Asflags":  &ca.asFlags,
-		"CppFlags": &ca.cppFlags,
+		"Cppflags": &ca.cppFlags,
 	}
 	for propName, attr := range productVarPropNameToAttribute {
 		if productConfigProps, exists := productVariableProps[propName]; exists {
@@ -762,8 +773,13 @@
 
 			if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok {
 				if axis == bazel.NoConfigAxis {
-					compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
-					compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, libraryProps.Stubs.Versions)
+					if libraryProps.Stubs.Symbol_file != nil {
+						compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
+						versions := android.CopyOf(libraryProps.Stubs.Versions)
+						normalizeVersions(ctx, versions)
+						versions = addCurrentVersionIfNotPresent(versions)
+						compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, versions)
+					}
 				}
 				if suffix := libraryProps.Suffix; suffix != nil {
 					compilerAttrs.suffix.SetSelectValue(axis, cfg, suffix)
@@ -833,6 +849,7 @@
 
 	features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
 	features = features.Append(bp2buildLtoFeatures(ctx, module))
+	features = features.Append(convertHiddenVisibilityToFeatureBase(ctx, module))
 	features.DeduplicateAxesFromBase()
 
 	addMuslSystemDynamicDeps(ctx, linkerAttrs)
@@ -907,7 +924,7 @@
 			return false
 		})
 
-		apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+		apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
 		sdkAttrs := bp2BuildParseSdkAttributes(m)
 
 		if !aidlSrcs.IsEmpty() {
@@ -1103,8 +1120,11 @@
 		// having stubs or not, so Bazel select() statement can be used to choose
 		// source/stub variants of them.
 		apexAvailable := module.ApexAvailable()
-		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0)
-		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1)
+		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false)
+		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false)
+		if len(systemSharedLibs) > 0 {
+			setStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
+		}
 	}
 
 	if !BoolDefault(props.Pack_relocations, packRelocationsDefault) {
@@ -1173,8 +1193,65 @@
 	return !differ
 }
 
+var (
+	apexConfigSettingKey  = android.NewOnceKey("apexConfigSetting")
+	apexConfigSettingLock sync.Mutex
+)
+
+func getApexConfigSettingMap(config android.Config) *map[string]bool {
+	return config.Once(apexConfigSettingKey, func() interface{} {
+		return &map[string]bool{}
+	}).(*map[string]bool)
+}
+
+// Create a config setting for this apex in build/bazel/rules/apex
+// The use case for this is stub/impl selection in cc libraries
+// Long term, these config_setting(s) should be colocated with the respective apex definitions.
+// Note that this is an anti-pattern: The config_setting should be created from the apex definition
+// and not from a cc_library.
+// This anti-pattern is needed today since not all apexes have been allowlisted.
+func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
+	if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
+		// These correspond to android-non_apex and android-in_apex
+		return
+	}
+	apexConfigSettingLock.Lock()
+	defer apexConfigSettingLock.Unlock()
+
+	// Return if a config_setting has already been created
+	acsm := getApexConfigSettingMap(ctx.Config())
+	if _, exists := (*acsm)[apexName]; exists {
+		return
+	}
+	(*acsm)[apexName] = true
+
+	csa := bazel.ConfigSettingAttributes{
+		Flag_values: bazel.StringMapAttribute{
+			"//build/bazel/rules/apex:apex_name": apexName,
+		},
+	}
+	ca := android.CommonAttributes{
+		Name: "android-in_" + apexName,
+	}
+	ctx.CreateBazelConfigSetting(
+		csa,
+		ca,
+		"build/bazel/rules/apex",
+	)
+}
+
+func inApexConfigSetting(apexAvailable string) string {
+	if apexAvailable == android.AvailableToPlatform {
+		return bazel.AndroidAndNonApex
+	}
+	if apexAvailable == android.AvailableToAnyApex {
+		return bazel.AndroidAndInApex
+	}
+	return "//build/bazel/rules/apex:android-in_" + apexAvailable
+}
+
 func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
-	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {
+	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
 
 	depsWithStubs := []bazel.Label{}
 	for _, l := range dynamicLibs.Includes {
@@ -1200,20 +1277,31 @@
 		inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
 		nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
 		defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
+		nonApexDeps := depsWithStubs
+		if buildNonApexWithStubs {
+			nonApexDeps = stubLibLabels
+		}
 		if axis == bazel.NoConfigAxis {
 			(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
-			(&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
+			(&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps))
 			(&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
 			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
 			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
 			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
 		} else if config == bazel.OsAndroid {
 			(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
-			(&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
+			(&nonApexSelectValue).Append(bazel.MakeLabelList(nonApexDeps))
 			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
 			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
 		}
 	}
+
+	// Create a config_setting for each apex_available.
+	// This will be used to select impl of a dep if dep is available to the same apex.
+	for _, aa := range apexAvailable {
+		createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
+	}
+
 }
 
 func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
@@ -1543,3 +1631,38 @@
 	}
 	return ltoStringFeatures
 }
+
+func convertHiddenVisibilityToFeatureBase(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
+	visibilityHiddenFeature := bazel.StringListAttribute{}
+	bp2BuildPropParseHelper(ctx, m, &BaseCompilerProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+			convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, baseCompilerProps.Cflags)
+		}
+	})
+	return visibilityHiddenFeature
+}
+
+func convertHiddenVisibilityToFeatureStaticOrShared(ctx android.BazelConversionPathContext, m *Module, isStatic bool) bazel.StringListAttribute {
+	visibilityHiddenFeature := bazel.StringListAttribute{}
+	if isStatic {
+		bp2BuildPropParseHelper(ctx, m, &StaticProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+			if staticProps, ok := props.(*StaticProperties); ok {
+				convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, staticProps.Static.Cflags)
+			}
+		})
+	} else {
+		bp2BuildPropParseHelper(ctx, m, &SharedProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+			if sharedProps, ok := props.(*SharedProperties); ok {
+				convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, sharedProps.Shared.Cflags)
+			}
+		})
+	}
+
+	return visibilityHiddenFeature
+}
+
+func convertHiddenVisibilityToFeatureHelper(feature *bazel.StringListAttribute, axis bazel.ConfigurationAxis, configString string, cflags []string) {
+	if inList(config.VisibilityHiddenFlag, cflags) {
+		feature.SetSelectValue(axis, configString, []string{"visibility_hidden"})
+	}
+}
diff --git a/cc/cc.go b/cc/cc.go
index 6054222..3fbefcd 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1893,17 +1893,46 @@
 // IsMixedBuildSupported returns true if the module should be analyzed by Bazel
 // in any of the --bazel-mode(s).
 func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	// TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan)
-	// Currently we can only support ubsan when minimum runtime is used.
-	return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded())
-}
-
-func isUbsanEnabled(c *Module) bool {
-	if c.sanitize == nil {
+	if !allEnabledSanitizersSupportedByBazel(c) {
+		//TODO(b/278772861) support sanitizers in Bazel rules
 		return false
 	}
+	return c.bazelHandler != nil
+}
+
+func allEnabledSanitizersSupportedByBazel(c *Module) bool {
+	if c.sanitize == nil {
+		return true
+	}
 	sanitizeProps := &c.sanitize.Properties.SanitizeMutated
-	return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+
+	unsupportedSanitizers := []*bool{
+		sanitizeProps.Safestack,
+		sanitizeProps.Cfi,
+		sanitizeProps.Scudo,
+		BoolPtr(len(c.sanitize.Properties.Sanitize.Recover) > 0),
+		BoolPtr(c.sanitize.Properties.Sanitize.Blocklist != nil),
+	}
+	for _, san := range unsupportedSanitizers {
+		if Bool(san) {
+			return false
+		}
+	}
+
+	for _, san := range Sanitizers {
+		if san == intOverflow {
+			// TODO(b/261058727): enable mixed builds for all modules with UBSan
+			// Currently we can only support ubsan when minimum runtime is used.
+			ubsanEnabled := Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+			if ubsanEnabled && !c.MinimalRuntimeNeeded() {
+				return false
+			}
+		} else if c.sanitize.isSanitizerEnabled(san) {
+			return false
+		}
+	}
+
+	return true
 }
 
 func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
@@ -1947,6 +1976,67 @@
 	c.maybeInstall(mctx, apexInfo)
 }
 
+func moduleContextFromAndroidModuleContext(actx android.ModuleContext, c *Module) ModuleContext {
+	ctx := &moduleContext{
+		ModuleContext: actx,
+		moduleContextImpl: moduleContextImpl{
+			mod: c,
+		},
+	}
+	ctx.ctx = ctx
+	return ctx
+}
+
+// TODO (b/277651159): Remove this allowlist
+var (
+	skipStubLibraryMultipleApexViolation = map[string]bool{
+		"libclang_rt.asan":   true,
+		"libclang_rt.hwasan": true,
+		// runtime apex
+		"libc":          true,
+		"libc_hwasan":   true,
+		"libdl_android": true,
+		"libm":          true,
+		"libdl":         true,
+		// art apex
+		"libandroidio":    true,
+		"libdexfile":      true,
+		"libnativebridge": true,
+		"libnativehelper": true,
+		"libnativeloader": true,
+		"libsigchain":     true,
+	}
+)
+
+// Returns true if a stub library could be installed in multiple apexes
+func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool {
+	// If this is not an apex variant, no check necessary
+	if !c.InAnyApex() {
+		return false
+	}
+	// If this is not a stub library, no check necessary
+	if !c.HasStubsVariants() {
+		return false
+	}
+	// Skip the allowlist
+	// Use BaseModuleName so that this matches prebuilts.
+	if _, exists := skipStubLibraryMultipleApexViolation[c.BaseModuleName()]; exists {
+		return false
+	}
+
+	_, aaWithoutTestApexes, _ := android.ListSetDifference(c.ApexAvailable(), c.TestApexes())
+	// Stub libraries should not have more than one apex_available
+	if len(aaWithoutTestApexes) > 1 {
+		return true
+	}
+	// Stub libraries should not use the wildcard
+	if aaWithoutTestApexes[0] == android.AvailableToAnyApex {
+		return true
+	}
+	// Default: no violation
+	return false
+}
+
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
 	// Handle the case of a test module split by `test_per_src` mutator.
 	//
@@ -1966,19 +2056,17 @@
 
 	c.makeLinkType = GetMakeLinkType(actx, c)
 
-	ctx := &moduleContext{
-		ModuleContext: actx,
-		moduleContextImpl: moduleContextImpl{
-			mod: c,
-		},
-	}
-	ctx.ctx = ctx
+	ctx := moduleContextFromAndroidModuleContext(actx, c)
 
 	deps := c.depsToPaths(ctx)
 	if ctx.Failed() {
 		return
 	}
 
+	if c.stubLibraryMultipleApexViolation(actx) {
+		actx.PropertyErrorf("apex_available",
+			"Stub libraries should have a single apex_available (test apexes excluded). Got %v", c.ApexAvailable())
+	}
 	if c.Properties.Clang != nil && *c.Properties.Clang == false {
 		ctx.PropertyErrorf("clang", "false (GCC) is no longer supported")
 	} else if c.Properties.Clang != nil && !ctx.DeviceConfig().BuildBrokenClangProperty() {
@@ -3901,8 +3989,8 @@
 		// TODO(b/244431896) properly convert cc_test_library to its own macro. This
 		// will let them add implicit compile deps on gtest, for example.
 		//
-		// For now, treat them as regular shared libraries.
-		return sharedLibrary
+		// For now, treat them as regular libraries.
+		return fullLibrary
 	} else if c.CcLibrary() {
 		static := false
 		shared := false
diff --git a/cc/cc_test.go b/cc/cc_test.go
index b986511..f9e661f 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -59,7 +59,7 @@
 func mixedBuildsPrepareMutator(ctx android.BottomUpMutatorContext) {
 	if m := ctx.Module(); m.Enabled() {
 		if mixedBuildMod, ok := m.(android.MixedBuildBuildable); ok {
-			if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) {
+			if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) == android.MixedBuildEnabled {
 				mixedBuildMod.QueueBazelCall(ctx)
 			}
 		}
@@ -3114,6 +3114,11 @@
 			whole_static_libs: ["whole_static_dep"],
 			shared_libs: ["shared_dep"],
 			gtest: false,
+			sanitize: {
+				// cc_test modules default to memtag_heap: true,
+				// but this adds extra dependencies that we don't care about
+				never: true,
+			}
 		}
 		cc_binary {
 			name: "binary",
@@ -3573,9 +3578,6 @@
 }
 
 func TestStubsForLibraryInMultipleApexes(t *testing.T) {
-	// TODO(b/275313114): Test exposes non-determinism which should be corrected and the test
-	// reenabled.
-	t.Skip()
 	t.Parallel()
 	ctx := testCc(t, `
 		cc_library_shared {
@@ -3680,6 +3682,130 @@
 	}
 }
 
+func TestMixedBuildUsesStubs(t *testing.T) {
+	t.Parallel()
+	bp := `
+		cc_library_shared {
+			name: "libFoo",
+			bazel_module: { label: "//:libFoo" },
+			srcs: ["foo.c"],
+			stubs: {
+				symbol_file: "foo.map.txt",
+				versions: ["current"],
+			},
+			apex_available: ["bar", "a1"],
+		}
+
+		cc_library_shared {
+			name: "libBar",
+			srcs: ["bar.c"],
+			shared_libs: ["libFoo"],
+			apex_available: ["a1"],
+		}
+
+		cc_library_shared {
+			name: "libA1",
+			srcs: ["a1.c"],
+			shared_libs: ["libFoo"],
+			apex_available: ["a1"],
+		}
+
+		cc_library_shared {
+			name: "libBarA1",
+			srcs: ["bara1.c"],
+			shared_libs: ["libFoo"],
+			apex_available: ["bar", "a1"],
+		}
+
+		cc_library_shared {
+			name: "libAnyApex",
+			srcs: ["anyApex.c"],
+			shared_libs: ["libFoo"],
+			apex_available: ["//apex_available:anyapex"],
+		}
+
+		cc_library_shared {
+			name: "libBaz",
+			srcs: ["baz.c"],
+			shared_libs: ["libFoo"],
+			apex_available: ["baz"],
+		}
+
+		cc_library_shared {
+			name: "libQux",
+			srcs: ["qux.c"],
+			shared_libs: ["libFoo"],
+			apex_available: ["qux", "bar"],
+		}`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: "out/bazel",
+				LabelToCcInfo: map[string]cquery.CcInfo{
+					"//:libFoo": {
+						RootDynamicLibraries: []string{"libFoo.so"},
+					},
+					"//:libFoo_stub_libs-current": {
+						RootDynamicLibraries: []string{"libFoo_stub_libs-current.so"},
+					},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp)
+	ctx := result.TestContext
+
+	variants := ctx.ModuleVariantsForTests("libFoo")
+	expectedVariants := []string{
+		"android_arm64_armv8-a_shared",
+		"android_arm64_armv8-a_shared_current",
+		"android_arm_armv7-a-neon_shared",
+		"android_arm_armv7-a-neon_shared_current",
+	}
+	variantsMismatch := false
+	if len(variants) != len(expectedVariants) {
+		variantsMismatch = true
+	} else {
+		for _, v := range expectedVariants {
+			if !inList(v, variants) {
+				variantsMismatch = false
+			}
+		}
+	}
+	if variantsMismatch {
+		t.Errorf("variants of libFoo expected:\n")
+		for _, v := range expectedVariants {
+			t.Errorf("%q\n", v)
+		}
+		t.Errorf(", but got:\n")
+		for _, v := range variants {
+			t.Errorf("%q\n", v)
+		}
+	}
+
+	linkAgainstFoo := []string{"libBarA1"}
+	linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"}
+
+	libFooPath := "out/bazel/execroot/__main__/libFoo.so"
+	for _, lib := range linkAgainstFoo {
+		libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
+		libFlags := libLinkRule.Args["libFlags"]
+		if !strings.Contains(libFlags, libFooPath) {
+			t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags)
+		}
+	}
+
+	libFooStubPath := "out/bazel/execroot/__main__/libFoo_stub_libs-current.so"
+	for _, lib := range linkAgainstFooStubs {
+		libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
+		libFlags := libLinkRule.Args["libFlags"]
+		if !strings.Contains(libFlags, libFooStubPath) {
+			t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags)
+		}
+	}
+}
+
 func TestVersioningMacro(t *testing.T) {
 	t.Parallel()
 	for _, tc := range []struct{ moduleName, expected string }{
@@ -5101,3 +5227,256 @@
 	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
 	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
 }
+
+func TestDisableSanitizerVariantsInMixedBuilds(t *testing.T) {
+	t.Parallel()
+	bp := `
+		cc_library_static {
+			name: "foo_ubsan_minimal",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo_ubsan_minimal" },
+			sanitize: {
+				all_undefined: true,
+				integer_overflow: true,
+			},
+		}
+		cc_library_static {
+			name: "foo",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo" },
+			sanitize: {
+				address: true,
+				hwaddress: true,
+				fuzzer: true,
+				integer_overflow: true,
+				scs: true,
+			},
+		}
+		cc_library_static {
+			name: "foo_tsan",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo_tsan" },
+			sanitize: {
+				thread: true,
+			},
+		}
+		cc_library_static {
+			name: "foo_cfi",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo_cfi" },
+			sanitize: {
+				cfi: true,
+			},
+		}
+		cc_library_static {
+			name: "foo_memtag_stack",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo_memtag_stack" },
+			sanitize: {
+				memtag_stack: true,
+			},
+		}
+		cc_library_static {
+			name: "foo_memtag_heap",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo_memtag_heap" },
+			sanitize: {
+				memtag_heap: true,
+			},
+		}
+		cc_library_static {
+			name: "foo_safestack",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo_safestack" },
+			sanitize: {
+				safestack: true,
+			},
+		}
+		cc_library_static {
+			name: "foo_scudo",
+			srcs: ["foo.cc"],
+			bazel_module: { label: "//foo_scudo" },
+			sanitize: {
+				scudo: true,
+			},
+		}
+	`
+	testcases := []struct {
+		name                string
+		variant             string
+		expectedOutputPaths []string
+	}{
+		{
+			name:    "foo_ubsan_minimal",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"outputbase/execroot/__main__/foo_ubsan_minimal.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"outputbase/execroot/__main__/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm_armv7-a-neon_static_asan_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm64_armv8-a_static_hwasan_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm64_armv8-a_static_fuzzer_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_fuzzer_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm_armv7-a-neon_static_asan_fuzzer_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_fuzzer_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm64_armv8-a_static_hwasan_fuzzer_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_fuzzer_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm64_armv8-a_static_scs_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_scs_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm64_armv8-a_static_hwasan_scs_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo",
+			variant: "android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28/foo.a",
+			},
+		},
+		{
+			name:    "foo_tsan",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"outputbase/execroot/__main__/foo_tsan.a",
+			},
+		},
+		{
+			name:    "foo_tsan",
+			variant: "android_arm64_armv8-a_static_tsan_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo_tsan/android_arm64_armv8-a_static_tsan_apex28/foo_tsan.a",
+			},
+		},
+		{
+			name:    "foo_cfi",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"outputbase/execroot/__main__/foo_cfi.a",
+			},
+		},
+		{
+			name:    "foo_cfi",
+			variant: "android_arm64_armv8-a_static_cfi_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo_cfi/android_arm64_armv8-a_static_cfi_apex28/foo_cfi.a",
+			},
+		},
+		{
+			name:    "foo_memtag_stack",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo_memtag_stack/android_arm64_armv8-a_static_apex28/foo_memtag_stack.a",
+			},
+		},
+		{
+			name:    "foo_memtag_heap",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo_memtag_heap/android_arm64_armv8-a_static_apex28/foo_memtag_heap.a",
+			},
+		},
+		{
+			name:    "foo_safestack",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo_safestack/android_arm64_armv8-a_static_apex28/foo_safestack.a",
+			},
+		},
+		{
+			name:    "foo_scudo",
+			variant: "android_arm64_armv8-a_static_apex28",
+			expectedOutputPaths: []string{
+				"out/soong/.intermediates/foo_scudo/android_arm64_armv8-a_static_apex28/foo_scudo.a",
+			},
+		},
+	}
+
+	ctx := android.GroupFixturePreparers(
+		prepareForCcTest,
+		prepareForAsanTest,
+		android.FixtureRegisterWithContext(registerTestMutators),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: "outputbase",
+				LabelToCcInfo: map[string]cquery.CcInfo{
+					"//foo_ubsan_minimal": {
+						RootStaticArchives: []string{"foo_ubsan_minimal.a"},
+					},
+					"//foo": {
+						RootStaticArchives: []string{"foo.a"},
+					},
+					"//foo_tsan": {
+						RootStaticArchives: []string{"foo_tsan.a"},
+					},
+					"//foo_cfi": {
+						RootStaticArchives: []string{"foo_cfi.a"},
+					},
+					"//foo_memtag_stack": {
+						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+					},
+					"//foo_memtag_heap": {
+						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+					},
+					"//foo_safestack": {
+						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+					},
+					"//foo_scudo": {
+						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+					},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp).TestContext
+
+	for _, tc := range testcases {
+		fooMod := ctx.ModuleForTests(tc.name, tc.variant).Module()
+		outputFiles, err := fooMod.(android.OutputFileProducer).OutputFiles("")
+		if err != nil {
+			t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+		}
+		android.AssertPathsRelativeToTopEquals(t, "output files", tc.expectedOutputPaths, outputFiles)
+	}
+}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 28f3682..ca2e05f 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -53,8 +53,7 @@
 		"-Wl,-z,separate-code",
 	}
 
-	arm64Lldflags = append(arm64Ldflags,
-		"-Wl,-z,max-page-size=4096")
+	arm64Lldflags = arm64Ldflags
 
 	arm64Cppflags = []string{}
 
@@ -93,7 +92,13 @@
 
 func init() {
 	exportedVars.ExportStringListStaticVariable("Arm64Ldflags", arm64Ldflags)
-	exportedVars.ExportStringListStaticVariable("Arm64Lldflags", arm64Lldflags)
+
+	exportedVars.ExportStringList("Arm64Lldflags", arm64Lldflags)
+	pctx.VariableFunc("Arm64Lldflags", func(ctx android.PackageVarContext) string {
+		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
+		flags := append(arm64Lldflags, maxPageSizeFlag)
+		return strings.Join(flags, " ")
+	})
 
 	exportedVars.ExportStringListStaticVariable("Arm64Cflags", arm64Cflags)
 	exportedVars.ExportStringListStaticVariable("Arm64Cppflags", arm64Cppflags)
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 0704550..dec2b45 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -185,7 +185,12 @@
 	exportedVars.ExportString("ArmClangTriple", clangTriple)
 
 	exportedVars.ExportStringListStaticVariable("ArmLdflags", armLdflags)
-	exportedVars.ExportStringListStaticVariable("ArmLldflags", armLldflags)
+	exportedVars.ExportStringList("ArmLldflags", armLldflags)
+	pctx.VariableFunc("ArmLldflags", func(ctx android.PackageVarContext) string {
+		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
+		flags := append(armLldflags, maxPageSizeFlag)
+		return strings.Join(flags, " ")
+	})
 
 	exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags)
 	exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags)
diff --git a/cc/config/global.go b/cc/config/global.go
index a2d5cf4..20298dd 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -311,7 +311,7 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r487747"
+	ClangDefaultVersion      = "clang-r487747b"
 	ClangDefaultShortVersion = "17"
 
 	// Directories with warnings from Android.bp files.
@@ -433,12 +433,15 @@
 	exportedVars.ExportStringList("CommonGlobalIncludes", commonGlobalIncludes)
 	pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
 
+	exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
+	exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
+
 	pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase)
-	exportedVars.ExportStringStaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
+	pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
 	pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
 	pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
 
-	exportedVars.ExportStringStaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
+	pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
 	pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux")
 
 	// These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts
diff --git a/cc/library.go b/cc/library.go
index 172ca64..13b333a 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -311,6 +311,11 @@
 		asFlags = bazel.MakeStringListAttribute(nil)
 	}
 
+	sharedFeatures := baseAttributes.features.Clone().Append(sharedAttrs.Features)
+	sharedFeatures.DeduplicateAxesFromBase()
+	staticFeatures := baseAttributes.features.Clone().Append(staticAttrs.Features)
+	staticFeatures.DeduplicateAxesFromBase()
+
 	staticCommonAttrs := staticOrSharedAttributes{
 		Srcs:    *srcs.Clone().Append(staticAttrs.Srcs),
 		Srcs_c:  *compilerAttrs.cSrcs.Clone().Append(staticAttrs.Srcs_c),
@@ -366,7 +371,7 @@
 		Cpp_std:                  compilerAttrs.cppStd,
 		C_std:                    compilerAttrs.cStd,
 
-		Features: baseAttributes.features,
+		Features: *staticFeatures,
 	}
 
 	sharedTargetAttrs := &bazelCcLibrarySharedAttributes{
@@ -390,7 +395,7 @@
 		Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
 
 		Strip:                             stripAttrsFromLinkerAttrs(&linkerAttrs),
-		Features:                          baseAttributes.features,
+		Features:                          *sharedFeatures,
 		bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, m),
 
 		Fdo_profile: compilerAttrs.fdoProfile,
@@ -428,11 +433,11 @@
 
 	var tagsForStaticVariant bazel.StringListAttribute
 	if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 {
-		tagsForStaticVariant = android.ApexAvailableTags(m)
+		tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 	}
 	tagsForStaticVariant.Append(bazel.StringListAttribute{Value: staticAttrs.Apex_available})
 
-	tagsForSharedVariant := android.ApexAvailableTags(m)
+	tagsForSharedVariant := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 	tagsForSharedVariant.Append(bazel.StringListAttribute{Value: sharedAttrs.Apex_available})
 
 	ctx.CreateBazelTargetModuleWithRestrictions(staticProps,
@@ -931,9 +936,17 @@
 func (handler *ccLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
 	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
+	if v := handler.module.library.stubsVersion(); v != "" {
+		stubsLabel := label + "_stub_libs-" + v
+		bazelCtx.QueueBazelRequest(stubsLabel, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
+	}
 }
 
 func (handler *ccLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
+	if v := handler.module.library.stubsVersion(); v != "" {
+		// if we are a stubs variant, just use the Bazel stubs target
+		label = label + "_stub_libs-" + v
+	}
 	bazelCtx := ctx.Config().BazelContext
 	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
 	if err != nil {
@@ -962,6 +975,9 @@
 	}
 
 	handler.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo)
+
+	cctx := moduleContextFromAndroidModuleContext(ctx, handler.module)
+	addStubDependencyProviders(cctx)
 }
 
 func (library *libraryDecorator) setFlagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) {
@@ -1787,6 +1803,12 @@
 		Target:                               ctx.Target(),
 	})
 
+	addStubDependencyProviders(ctx)
+
+	return unstrippedOutputFile
+}
+
+func addStubDependencyProviders(ctx ModuleContext) {
 	stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
 	if len(stubs) > 0 {
 		var stubsInfo []SharedStubLibrary
@@ -1801,12 +1823,9 @@
 		}
 		ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
 			SharedStubLibraries: stubsInfo,
-
-			IsLLNDK: ctx.IsLlndk(),
+			IsLLNDK:             ctx.IsLlndk(),
 		})
 	}
-
-	return unstrippedOutputFile
 }
 
 func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
@@ -2392,7 +2411,10 @@
 	}
 
 	// Future API level is implicitly added if there isn't
-	vers := library.Properties.Stubs.Versions
+	return addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+}
+
+func addCurrentVersionIfNotPresent(vers []string) []string {
 	if inList(android.FutureApiLevel.String(), vers) {
 		return vers
 	}
@@ -2657,7 +2679,7 @@
 // normalizeVersions modifies `versions` in place, so that each raw version
 // string becomes its normalized canonical form.
 // Validates that the versions in `versions` are specified in least to greatest order.
-func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
+func normalizeVersions(ctx android.BazelConversionPathContext, versions []string) {
 	var previous android.ApiLevel
 	for i, v := range versions {
 		ver, err := android.ApiLevelFromUser(ctx, v)
@@ -2881,6 +2903,9 @@
 		asFlags = bazel.MakeStringListAttribute(nil)
 	}
 
+	features := baseAttributes.features.Clone().Append(libSharedOrStaticAttrs.Features)
+	features.DeduplicateAxesFromBase()
+
 	commonAttrs := staticOrSharedAttributes{
 		Srcs:    compilerAttrs.srcs,
 		Srcs_c:  compilerAttrs.cSrcs,
@@ -2922,7 +2947,7 @@
 			Conlyflags: compilerAttrs.conlyFlags,
 			Asflags:    asFlags,
 
-			Features: baseAttributes.features,
+			Features: *features,
 		}
 	} else {
 		commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
@@ -2951,7 +2976,7 @@
 
 			Strip: stripAttrsFromLinkerAttrs(&linkerAttrs),
 
-			Features: baseAttributes.features,
+			Features: *features,
 
 			Suffix: compilerAttrs.suffix,
 
@@ -2977,7 +3002,7 @@
 		Bzl_load_location: fmt.Sprintf("//build/bazel/rules/cc:%s.bzl", modType),
 	}
 
-	tags := android.ApexAvailableTags(module)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name(), Tags: tags}, attrs)
 }
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 1dee726..ce9c4aa 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -151,7 +151,7 @@
 		Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
 	}
 
-	tags := android.ApexAvailableTags(module)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
 		Name: module.Name(),
diff --git a/cc/object.go b/cc/object.go
index d65cdea..5d61872 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -226,7 +226,7 @@
 		Bzl_load_location: "//build/bazel/rules/cc:cc_object.bzl",
 	}
 
-	tags := android.ApexAvailableTags(m)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
 		Name: m.Name(),
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 0b5841e..44cd0d7 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -389,7 +389,7 @@
 		name += "_bp2build_cc_library_static"
 	}
 
-	tags := android.ApexAvailableTags(module)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
 	ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
 
 	_true := true
@@ -420,7 +420,7 @@
 	}
 
 	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-	tags := android.ApexAvailableTags(module)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
 	ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
 }
 
@@ -650,7 +650,7 @@
 	}
 
 	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-	tags := android.ApexAvailableTags(module)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
 }
 
@@ -813,7 +813,7 @@
 	}
 
 	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-	tags := android.ApexAvailableTags(module)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
 }
 
diff --git a/cc/proto.go b/cc/proto.go
index 97470e5..5d9aef6 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -207,7 +207,7 @@
 	protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
 
 	name := m.Name() + suffix
-	tags := android.ApexAvailableTags(m)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), m)
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        rule_class,
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 45d7fab..7fddc1b 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -593,6 +593,12 @@
 		}
 	}
 
+	// Enable HWASan for all components in the include paths (for Aarch64 only)
+	if s.Hwaddress == nil && ctx.Config().HWASanEnabledForPath(ctx.ModuleDir()) &&
+		ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
+		s.Hwaddress = proptools.BoolPtr(true)
+	}
+
 	// Enable CFI for non-host components in the include paths
 	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && !ctx.Host() {
 		s.Cfi = proptools.BoolPtr(true)
diff --git a/cc/sysprop.go b/cc/sysprop.go
index 0df290a..7ddd476 100644
--- a/cc/sysprop.go
+++ b/cc/sysprop.go
@@ -38,7 +38,7 @@
 }
 
 func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
-	apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        "sysprop_library",
diff --git a/cc/util.go b/cc/util.go
index aa0f6b5..6d8ac43 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -100,17 +100,6 @@
 		"ln -sf " + target + " " + filepath.Join(dir, linkName)
 }
 
-func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
-	outPath := android.PathForOutput(ctx, out)
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cat,
-		Inputs:      paths,
-		Output:      outPath,
-		Description: "combine notices for " + out,
-	})
-	return outPath
-}
-
 // Dump a map to a list file as:
 //
 // {key1} {value1}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index aed3775..e6e5660 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -160,7 +160,7 @@
 	MinSdkVersion  string   `json:",omitempty"`
 }
 
-var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths {
+var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths {
 	/*
 		Vendor snapshot zipped artifacts directory structure for cc modules:
 		{SNAPSHOT_ARCH}/
@@ -195,10 +195,10 @@
 	*/
 
 	var snapshotOutputs android.Paths
+	var snapshotNotices android.Paths
 
 	includeDir := filepath.Join(snapshotArchDir, "include")
 	configsDir := filepath.Join(snapshotArchDir, "configs")
-	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
 
 	installedNotices := make(map[string]bool)
 	installedConfigs := make(map[string]bool)
@@ -228,7 +228,7 @@
 		prop := snapshotJsonFlags{}
 
 		// Common properties among snapshots.
-		prop.ModuleName = ctx.ModuleName(m)
+		prop.InitBaseSnapshotPropsWithName(m, ctx.ModuleName(m))
 		if supportsVndkExt(s.Image) && m.IsVndkExt() {
 			// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
 			if m.IsVndkSp() {
@@ -406,13 +406,10 @@
 			headers = append(headers, m.SnapshotHeaders()...)
 		}
 
-		if len(m.EffectiveLicenseFiles()) > 0 {
-			noticeName := ctx.ModuleName(m) + ".txt"
-			noticeOut := filepath.Join(noticeDir, noticeName)
-			// skip already copied notice file
-			if !installedNotices[noticeOut] {
-				installedNotices[noticeOut] = true
-				snapshotOutputs = append(snapshotOutputs, combineNoticesRule(ctx, m.EffectiveLicenseFiles(), noticeOut))
+		for _, notice := range m.EffectiveLicenseFiles() {
+			if _, ok := installedNotices[notice.String()]; !ok {
+				installedNotices[notice.String()] = true
+				snapshotNotices = append(snapshotNotices, notice)
 			}
 		}
 	})
@@ -422,7 +419,7 @@
 		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), s.Fake))
 	}
 
-	return snapshotOutputs
+	return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices}
 }
 
 func init() {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 79a5ce4..53e0e55 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -85,7 +85,7 @@
 	flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
 	flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
 	flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files")
-
+	flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
 	// Flags that probably shouldn't be flags of soong_build, but we haven't found
 	// the time to remove them yet
 	flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
@@ -288,6 +288,46 @@
 	maybeQuit(err, "error writing soong_build metrics %s", metricsFile)
 }
 
+// Errors out if any modules expected to be mixed_built were not, unless
+// there is a platform incompatibility.
+func checkForAllowlistIntegrityError(configuration android.Config, isStagingMode bool) error {
+	modules := findModulesNotMixedBuiltForAnyVariant(configuration, isStagingMode)
+	if len(modules) == 0 {
+		return nil
+	}
+
+	return fmt.Errorf("Error: expected the following modules to be mixed_built: %s", modules)
+}
+
+// Returns the list of modules that should have been mixed_built (per the
+// allowlists and cmdline flags) but were not.
+func findModulesNotMixedBuiltForAnyVariant(configuration android.Config, isStagingMode bool) []string {
+	retval := []string{}
+	forceEnabledModules := configuration.BazelModulesForceEnabledByFlag()
+
+	mixedBuildsEnabled := configuration.GetMixedBuildsEnabledModules()
+	for _, module := range allowlists.ProdMixedBuildsEnabledList {
+		if _, ok := mixedBuildsEnabled[module]; !ok && module != "" {
+			retval = append(retval, module)
+		}
+	}
+
+	if isStagingMode {
+		for _, module := range allowlists.StagingMixedBuildsEnabledList {
+			if _, ok := mixedBuildsEnabled[module]; !ok && module != "" {
+				retval = append(retval, module)
+			}
+		}
+	}
+
+	for module, _ := range forceEnabledModules {
+		if _, ok := mixedBuildsEnabled[module]; !ok && module != "" {
+			retval = append(retval, module)
+		}
+	}
+	return retval
+}
+
 func writeJsonModuleGraphAndActions(ctx *android.Context, cmdArgs android.CmdArgs) {
 	graphFile, graphErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleGraphFile))
 	maybeQuit(graphErr, "graph err")
@@ -433,8 +473,14 @@
 		writeMetrics(configuration, ctx.EventHandler, metricsDir)
 	default:
 		ctx.Register()
-		if configuration.IsMixedBuildsEnabled() {
+		isMixedBuildsEnabled := configuration.IsMixedBuildsEnabled()
+		if isMixedBuildsEnabled {
 			finalOutputFile = runMixedModeBuild(ctx, extraNinjaDeps)
+			if cmdlineArgs.EnsureAllowlistIntegrity {
+				if err := checkForAllowlistIntegrityError(configuration, cmdlineArgs.BazelModeStaging); err != nil {
+					maybeQuit(err, "")
+				}
+			}
 		} else {
 			finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
 		}
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index ce32184..67cb6cf 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -15,6 +15,7 @@
 package main
 
 import (
+	"android/soong/starlark_import"
 	"io/fs"
 	"io/ioutil"
 	"os"
@@ -47,6 +48,14 @@
 		}
 	}
 
+	// Add starlark deps here, so that they apply to both queryview and apibp2build which
+	// both run this function.
+	starlarkDeps, err2 := starlark_import.GetNinjaDeps()
+	if err2 != nil {
+		return err2
+	}
+	ctx.AddNinjaFileDeps(starlarkDeps...)
+
 	return nil
 }
 
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index 491267b..5ab9656 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -128,12 +128,6 @@
 	}
 
 	for _, arg := range args {
-		// Reserve escaping for future implementation, so make sure no
-		// one is using \ and expecting a certain behavior.
-		if strings.Contains(arg, "\\") {
-			return fmt.Errorf("\\ characters are not currently supported")
-		}
-
 		input, output := includeSplit(arg)
 
 		var includeMatches []pair
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 2c4e005..c238098 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -38,13 +38,6 @@
 	storedFiles []string
 	err         error
 }{
-	{
-		name: "unsupported \\",
-
-		args: []string{"a\\b:b"},
-
-		err: fmt.Errorf("\\ characters are not currently supported"),
-	},
 	{ // This is modelled after the update package build rules in build/make/core/Makefile
 		name: "filter globs",
 
@@ -406,6 +399,13 @@
 			"b/a/b",
 		},
 	},
+	{
+		name: "escaping",
+
+		inputFiles:  []string{"a"},
+		args:        []string{"\\a"},
+		outputFiles: []string{"a"},
+	},
 }
 
 func errorString(e error) string {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index dcd7fdc..6817dce 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -617,7 +617,7 @@
 	return true
 }
 
-func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths {
+func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths {
 	/*
 		Snapshot zipped artifacts directory structure for etc modules:
 		{SNAPSHOT_ARCH}/
@@ -631,7 +631,7 @@
 				(notice files)
 	*/
 	var snapshotOutputs android.Paths
-	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+	var snapshotNotices android.Paths
 	installedNotices := make(map[string]bool)
 
 	ctx.VisitAllModules(func(module android.Module) {
@@ -651,7 +651,7 @@
 
 		prop := snapshot.SnapshotJsonFlags{}
 		propOut := snapshotLibOut + ".json"
-		prop.ModuleName = m.BaseModuleName()
+		prop.InitBaseSnapshotProps(m)
 		if m.subdirProperties.Relative_install_path != nil {
 			prop.RelativeInstallPath = *m.subdirProperties.Relative_install_path
 		}
@@ -667,27 +667,16 @@
 		}
 		snapshotOutputs = append(snapshotOutputs, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
 
-		if len(m.EffectiveLicenseFiles()) > 0 {
-			noticeName := ctx.ModuleName(m) + ".txt"
-			noticeOut := filepath.Join(noticeDir, noticeName)
-			// skip already copied notice file
-			if !installedNotices[noticeOut] {
-				installedNotices[noticeOut] = true
-
-				noticeOutPath := android.PathForOutput(ctx, noticeOut)
-				ctx.Build(pctx, android.BuildParams{
-					Rule:        android.Cat,
-					Inputs:      m.EffectiveLicenseFiles(),
-					Output:      noticeOutPath,
-					Description: "combine notices for " + noticeOut,
-				})
-				snapshotOutputs = append(snapshotOutputs, noticeOutPath)
+		for _, notice := range m.EffectiveLicenseFiles() {
+			if _, ok := installedNotices[notice.String()]; !ok {
+				installedNotices[notice.String()] = true
+				snapshotNotices = append(snapshotNotices, notice)
 			}
 		}
 
 	})
 
-	return snapshotOutputs
+	return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices}
 }
 
 // For Bazel / bp2build
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 79d2412..f76529d 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -339,7 +339,7 @@
 	// List of modules for monitoring coverage drops in directories (e.g. "libicu")
 	Target_modules []string `json:"target_modules,omitempty"`
 	// Specifies a bug assignee to replace default ISE assignment
-	Assignee string `json:"assignee,omitempty"`
+	Triage_assignee string `json:"triage_assignee,omitempty"`
 }
 
 type FuzzFrameworks struct {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f5da50e..00adb70 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -940,7 +940,7 @@
 		}
 	}
 
-	tags := android.ApexAvailableTags(m)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 
 	if ctx.ModuleType() == "gensrcs" {
 		// The Output_extension prop is not in an immediately accessible field
diff --git a/go.mod b/go.mod
index a5d9dd5..4a511c5 100644
--- a/go.mod
+++ b/go.mod
@@ -6,4 +6,5 @@
 	github.com/google/blueprint v0.0.0
 	google.golang.org/protobuf v0.0.0
 	prebuilts/bazel/common/proto/analysis_v2 v0.0.0
+	go.starlark.net v0.0.0
 )
diff --git a/go.work b/go.work
index 737a9df..67f6549 100644
--- a/go.work
+++ b/go.work
@@ -4,6 +4,7 @@
 	.
 	../../external/go-cmp
 	../../external/golang-protobuf
+	../../external/starlark-go
 	../../prebuilts/bazel/common/proto/analysis_v2
 	../../prebuilts/bazel/common/proto/build
 	../blueprint
@@ -16,4 +17,5 @@
 	google.golang.org/protobuf v0.0.0 => ../../external/golang-protobuf
 	prebuilts/bazel/common/proto/analysis_v2 v0.0.0 => ../../prebuilts/bazel/common/proto/analysis_v2
 	prebuilts/bazel/common/proto/build v0.0.0 => ../../prebuilts/bazel/common/proto/build
+	go.starlark.net v0.0.0 => ../../external/starlark-go
 )
diff --git a/java/android_manifest.go b/java/android_manifest.go
index dbcf098..f2ebfa6 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -63,9 +63,11 @@
 // 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, targetSdkVersionLevel android.ApiLevel, enforceDefaultTargetSdkVersion bool) bool {
-	if enforceDefaultTargetSdkVersion && ctx.Config().PlatformSdkFinal() {
+	// If this is a REL branch, do not return 10000
+	if ctx.Config().PlatformSdkFinal() {
 		return false
 	}
+	// If this a module targeting an unreleased SDK (MTS or unbundled builds), return 10000
 	return targetSdkVersionLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module()))
 }
 
diff --git a/java/app.go b/java/app.go
index 03e2330..7bb8cdb 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1461,10 +1461,8 @@
 
 // verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build
 // system and returns the path to a copy of the APK.
-func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) {
 	u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file
-	outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
-	return outputFile
 }
 
 // For Bazel / bp2build
diff --git a/java/app_import.go b/java/app_import.go
index 85b35eb..bfd6767 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -49,6 +49,17 @@
 		CommandDeps: []string{"${config.Zip2ZipCmd}"},
 		Description: "Uncompress dex files",
 	})
+
+	checkJniAndDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-and-dex-libs-are-uncompressed", blueprint.RuleParams{
+		// grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
+		Command: "if (zipinfo $in 'lib/*.so' '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
+			"echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
+			"exit 1; " +
+			"else " +
+			"touch $out; " +
+			"fi",
+		Description: "Check for compressed JNI libs or dex files",
+	})
 )
 
 func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
@@ -73,8 +84,6 @@
 
 	usesLibrary usesLibrary
 
-	preprocessed bool
-
 	installPath android.InstallPath
 
 	hideApexVariantFromMake bool
@@ -128,6 +137,13 @@
 
 	// Optional. Install to a subdirectory of the default install path for the module
 	Relative_install_path *string
+
+	// Whether the prebuilt apk can be installed without additional processing. Default is false.
+	Preprocessed *bool
+
+	// Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
+	// JNI libs and dex files. Default is false
+	Skip_preprocessed_apk_checks *bool
 }
 
 func (a *AndroidAppImport) IsInstallable() bool {
@@ -201,7 +217,7 @@
 	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
 	// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
 	// with them may invalidate pre-existing signature data.
-	if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) {
+	if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   android.Cp,
 			Output: outputPath,
@@ -219,7 +235,7 @@
 
 // Returns whether this module should have the dex file stored uncompressed in the APK.
 func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
-	if ctx.Config().UnbundledBuild() || a.preprocessed {
+	if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
 		return false
 	}
 
@@ -297,7 +313,7 @@
 	a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 
 	if a.usesLibrary.enforceUsesLibraries() {
-		srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+		a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
 	}
 
 	a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
@@ -317,8 +333,15 @@
 
 	// Sign or align the package if package has not been preprocessed
 
-	if a.preprocessed {
-		a.outputFile = srcApk
+	if proptools.Bool(a.properties.Preprocessed) {
+		output := srcApk
+		// TODO(b/185811447) Uncomment this after all existing failing apks set skip_preprocessed_apk_checks: true
+		//if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
+		//	writableOutput := android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
+		//	a.validatePreprocessedApk(ctx, srcApk, writableOutput)
+		//	output = writableOutput
+		//}
+		a.outputFile = output
 		a.certificate = PresignedCertificate
 	} else if !Bool(a.properties.Presigned) {
 		// If the certificate property is empty at this point, default_dev_cert must be set to true.
@@ -352,6 +375,30 @@
 	// TODO: androidmk converter jni libs
 }
 
+func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
+	alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   checkZipAlignment,
+		Input:  srcApk,
+		Output: alignmentStamp,
+	})
+	compressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "compression.stamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   checkJniAndDexLibsAreUncompressedRule,
+		Input:  srcApk,
+		Output: compressionStamp,
+	})
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Input:  srcApk,
+		Output: dstApk,
+		Validations: []android.Path{
+			alignmentStamp,
+			compressionStamp,
+		},
+	})
+}
+
 func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
 	return &a.prebuilt
 }
@@ -487,11 +534,6 @@
 	return module
 }
 
-type androidTestImportProperties struct {
-	// Whether the prebuilt apk can be installed without additional processing. Default is false.
-	Preprocessed *bool
-}
-
 type AndroidTestImport struct {
 	AndroidAppImport
 
@@ -508,14 +550,10 @@
 		Per_testcase_directory *bool
 	}
 
-	testImportProperties androidTestImportProperties
-
 	data android.Paths
 }
 
 func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.preprocessed = Bool(a.testImportProperties.Preprocessed)
-
 	a.generateAndroidBuildActions(ctx)
 
 	a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -532,7 +570,6 @@
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.dexpreoptProperties)
 	module.AddProperties(&module.testProperties)
-	module.AddProperties(&module.testImportProperties)
 	module.populateAllVariantStructs()
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
 		module.processVariants(ctx)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 8093024..845a962 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -657,6 +657,30 @@
 	}
 }
 
+// TODO(b/185811447) Uncomment this after all existing failing apks set skip_preprocessed_apk_checks: true
+//func TestAndroidAppImport_Preprocessed(t *testing.T) {
+//	ctx, _ := testJava(t, `
+//		android_app_import {
+//			name: "foo",
+//			apk: "prebuilts/apk/app.apk",
+//			presigned: true,
+//			preprocessed: true,
+//		}
+//		`)
+//
+//	apkName := "foo.apk"
+//	variant := ctx.ModuleForTests("foo", "android_common")
+//	outputBuildParams := variant.Output("validated-prebuilt/" + apkName).BuildParams
+//	if outputBuildParams.Rule.String() != android.Cp.String() {
+//		t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+//	}
+//
+//	// Make sure compression and aligning were validated.
+//	if len(outputBuildParams.Validations) != 2 {
+//		t.Errorf("Expected compression/alignment validation rules, found %d validations", len(outputBuildParams.Validations))
+//	}
+//}
+
 func TestAndroidTestImport_UncompressDex(t *testing.T) {
 	testCases := []struct {
 		name string
diff --git a/java/app_test.go b/java/app_test.go
index 561be68..7e97b0f 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3034,11 +3034,13 @@
 
 func TestTargetSdkVersionManifestFixer(t *testing.T) {
 	platform_sdk_codename := "Tiramisu"
+	platform_sdk_version := 33
 	testCases := []struct {
 		name                     string
 		targetSdkVersionInBp     string
 		targetSdkVersionExpected string
 		unbundledBuild           bool
+		platformSdkFinal         bool
 	}{
 		{
 			name:                     "Non-Unbundled build: Android.bp has targetSdkVersion",
@@ -3075,6 +3077,12 @@
 			targetSdkVersionExpected: "10000",
 			unbundledBuild:           true,
 		},
+		{
+			name:                     "Bundled build in REL branches",
+			targetSdkVersionExpected: "33",
+			unbundledBuild:           false,
+			platformSdkFinal:         true,
+		},
 	}
 	for _, testCase := range testCases {
 		targetSdkVersionTemplate := ""
@@ -3091,8 +3099,12 @@
 		fixture := android.GroupFixturePreparers(
 			prepareForJavaTest,
 			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				if testCase.platformSdkFinal {
+					variables.Platform_sdk_final = proptools.BoolPtr(true)
+				}
 				// explicitly set platform_sdk_codename to make the test deterministic
 				variables.Platform_sdk_codename = &platform_sdk_codename
+				variables.Platform_sdk_version = &platform_sdk_version
 				variables.Platform_version_active_codenames = []string{platform_sdk_codename}
 				// create a non-empty list if unbundledBuild==true
 				if testCase.unbundledBuild {
diff --git a/java/base.go b/java/base.go
index 9911323..374138c 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1923,9 +1923,12 @@
 
 func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
 	switch name {
-	case android.SdkCore.JavaLibraryName(ctx.Config()), "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
+	case android.SdkCore.JavaLibraryName(ctx.Config()),
+		android.JavaApiLibraryName(ctx.Config(), "legacy.core.platform.api.stubs"),
+		android.JavaApiLibraryName(ctx.Config(), "stable.core.platform.api.stubs"),
 		"stub-annotations", "private-stub-annotations-jar",
-		"core-lambda-stubs", "core-generated-annotation-stubs":
+		android.JavaApiLibraryName(ctx.Config(), "core-lambda-stubs"),
+		"core-generated-annotation-stubs":
 		return javaCore, true
 	case android.SdkPublic.JavaLibraryName(ctx.Config()):
 		return javaSdk, true
diff --git a/java/builder.go b/java/builder.go
index 4626267..0c57738 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -246,6 +246,19 @@
 			CommandDeps: []string{"${config.ZipAlign}"},
 		},
 	)
+
+	checkZipAlignment = pctx.AndroidStaticRule("checkzipalign",
+		blueprint.RuleParams{
+			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
+				"echo $in: Improper package alignment >&2; " +
+				"exit 1; " +
+				"else " +
+				"touch $out; " +
+				"fi",
+			CommandDeps: []string{"${config.ZipAlign}"},
+			Description: "Check zip alignment",
+		},
+	)
 )
 
 func init() {
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 273aca0..d383d98 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -28,8 +28,11 @@
 	ctx.Strict("FRAMEWORK_LIBRARIES", strings.Join(FrameworkLibraries, " "))
 
 	// These are used by make when LOCAL_PRIVATE_PLATFORM_APIS is set (equivalent to platform_apis in blueprint):
-	ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES", strings.Join(LegacyCorePlatformBootclasspathLibraries, " "))
-	ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES", LegacyCorePlatformSystemModules)
+	ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES",
+		strings.Join(android.JavaApiLibraryNames(ctx.Config(), LegacyCorePlatformBootclasspathLibraries), " "))
+	ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES",
+		android.JavaApiLibraryName(ctx.Config(), LegacyCorePlatformSystemModules),
+	)
 
 	ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
 	ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index f4827ea..f4c0935 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -507,8 +507,8 @@
 		// No module has enabled dexpreopting, so we assume there will be no boot image to make.
 		return
 	}
-
-	d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
+	archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
+	d.dexpreoptConfigForMake = android.PathForOutput(ctx, toDexpreoptDirName(archType), "dexpreopt.config")
 	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
 
 	global := dexpreopt.GetGlobalConfig(ctx)
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index bc7a55e..9083808 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -58,11 +58,11 @@
 	rule := platformBootclasspath.Output(ruleFile)
 
 	for i := range expectedInputs {
-		expectedInputs[i] = filepath.Join("out/soong/test_device", expectedInputs[i])
+		expectedInputs[i] = filepath.Join("out/soong/dexpreopt_arm64", expectedInputs[i])
 	}
 
 	for i := range expectedOutputs {
-		expectedOutputs[i] = filepath.Join("out/soong/test_device", expectedOutputs[i])
+		expectedOutputs[i] = filepath.Join("out/soong/dexpreopt_arm64", expectedOutputs[i])
 	}
 
 	inputs := rule.Implicits.Strings()
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 8c62c33..8f732cf 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -108,7 +108,8 @@
 func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
 	return ctx.Config().Once(bootImageConfigKey, func() interface{} {
 		targets := dexpreoptTargets(ctx)
-		deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
+		archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
+		deviceDir := android.PathForOutput(ctx, toDexpreoptDirName(archType))
 
 		configs := genBootImageConfigRaw(ctx)
 
@@ -220,8 +221,8 @@
 func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
 	return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
 		apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
-
-		dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "apex_bootjars")
+		archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
+		dir := android.PathForOutput(ctx, toDexpreoptDirName(archType), "apex_bootjars")
 		dexPaths := apexBootJars.BuildPaths(ctx, dir)
 		dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
 
@@ -261,3 +262,7 @@
 func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
 	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
 }
+
+func toDexpreoptDirName(arch android.ArchType) string {
+	return "dexpreopt_" + arch.String()
+}
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 86dd329..6b98ca5 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -207,65 +207,65 @@
 	expected := &expectedConfig{
 		name:                     "art",
 		stem:                     "boot",
-		dir:                      "out/soong/test_device/dex_artjars",
-		symbolsDir:               "out/soong/test_device/dex_artjars_unstripped",
+		dir:                      "out/soong/dexpreopt_arm64/dex_artjars",
+		symbolsDir:               "out/soong/dexpreopt_arm64/dex_artjars_unstripped",
 		installDirOnDevice:       "system/framework",
 		installDirOnHost:         "apex/art_boot_images/javalib",
 		profileInstallPathInApex: "etc/boot-image.prof",
 		modules:                  android.CreateTestConfiguredJarList([]string{"com.android.art:core1", "com.android.art:core2"}),
-		dexPaths:                 []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar"},
-		dexPathsDeps:             []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar"},
-		zip:                      "out/soong/test_device/dex_artjars/art.zip",
+		dexPaths:                 []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar"},
+		dexPathsDeps:             []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar"},
+		zip:                      "out/soong/dexpreopt_arm64/dex_artjars/art.zip",
 		variants: []*expectedVariant{
 			{
 				archType:          android.Arm64,
 				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
 				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
-				imagePathOnHost:   "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
 				imagePathOnDevice: "/system/framework/arm64/boot.art",
 				imagesDeps: []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/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
 						to:   "/apex/art_boot_images/javalib/arm64/boot.art",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
 						to:   "/apex/art_boot_images/javalib/arm64/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
 						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.art",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
 						to:   "/apex/art_boot_images/javalib/arm64/boot.vdex",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat",
 						to:   "/apex/art_boot_images/javalib/arm64/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 					},
 				},
@@ -275,51 +275,51 @@
 				archType:          android.Arm,
 				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
 				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
-				imagePathOnHost:   "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
 				imagePathOnDevice: "/system/framework/arm/boot.art",
 				imagesDeps: []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/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
 						to:   "/apex/art_boot_images/javalib/arm/boot.art",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
 						to:   "/apex/art_boot_images/javalib/arm/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
 						to:   "/apex/art_boot_images/javalib/arm/boot-core2.art",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm/boot-core2.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
 						to:   "/apex/art_boot_images/javalib/arm/boot.vdex",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/arm/boot-core2.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat",
 						to:   "/apex/art_boot_images/javalib/arm/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm/boot-core2.oat",
 					},
 				},
@@ -329,49 +329,49 @@
 				archType:          android.X86_64,
 				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
 				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
-				imagePathOnHost:   "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
 				imagePathOnDevice: "/system/framework/x86_64/boot.art",
 				imagesDeps: []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/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot.art",
 					}, {
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.art",
 					}, {
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot.vdex",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 					},
 				},
@@ -381,49 +381,49 @@
 				archType:          android.X86,
 				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
 				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
-				imagePathOnHost:   "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
 				imagePathOnDevice: "/system/framework/x86/boot.art",
 				imagesDeps: []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/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
 						to:   "/apex/art_boot_images/javalib/x86/boot.art",
 					}, {
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
 						to:   "/apex/art_boot_images/javalib/x86/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
 						to:   "/apex/art_boot_images/javalib/x86/boot-core2.art",
 					}, {
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86/boot-core2.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
 						to:   "/apex/art_boot_images/javalib/x86/boot.vdex",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/x86/boot-core2.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
 						to:   "/apex/art_boot_images/javalib/x86/boot.oat",
 					},
 					{
-						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86/boot-core2.oat",
 					},
 				},
@@ -460,15 +460,15 @@
 	expected := &expectedConfig{
 		name:                     "boot",
 		stem:                     "boot",
-		dir:                      "out/soong/test_device/dex_bootjars",
-		symbolsDir:               "out/soong/test_device/dex_bootjars_unstripped",
+		dir:                      "out/soong/dexpreopt_arm64/dex_bootjars",
+		symbolsDir:               "out/soong/dexpreopt_arm64/dex_bootjars_unstripped",
 		installDirOnDevice:       "system/framework",
 		installDirOnHost:         "system/framework",
 		profileInstallPathInApex: "",
 		modules:                  android.CreateTestConfiguredJarList([]string{"platform:framework"}),
-		dexPaths:                 []string{"out/soong/test_device/dex_bootjars_input/framework.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"},
-		zip:                      "out/soong/test_device/dex_bootjars/boot.zip",
+		dexPaths:                 []string{"out/soong/dexpreopt_arm64/dex_bootjars_input/framework.jar"},
+		dexPathsDeps:             []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/framework.jar"},
+		zip:                      "out/soong/dexpreopt_arm64/dex_bootjars/boot.zip",
 		variants: []*expectedVariant{
 			{
 				archType:     android.Arm64,
@@ -478,41 +478,41 @@
 					"/apex/com.android.art/javalib/core2.jar",
 					"/system/framework/framework.jar",
 				},
-				imagePathOnHost:   "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art",
 				imagePathOnDevice: "/system/framework/arm64/boot-framework.art",
 				imagesDeps: []string{
-					"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",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
 				},
-				baseImages: []string{"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art"},
+				baseImages: []string{"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.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/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art",
 						to:   "/system/framework/arm64/boot-framework.art",
 					},
 					{
-						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
 						to:   "/system/framework/arm64/boot-framework.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
 						to:   "/system/framework/arm64/boot-framework.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat",
 						to:   "/system/framework/arm64/boot-framework.oat",
 					},
 				},
@@ -526,41 +526,41 @@
 					"/apex/com.android.art/javalib/core2.jar",
 					"/system/framework/framework.jar",
 				},
-				imagePathOnHost:   "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art",
 				imagePathOnDevice: "/system/framework/arm/boot-framework.art",
 				imagesDeps: []string{
-					"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",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
 				},
-				baseImages: []string{"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art"},
+				baseImages: []string{"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.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/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art",
 						to:   "/system/framework/arm/boot-framework.art",
 					},
 					{
-						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat",
 						to:   "/system/framework/arm/boot-framework.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
 						to:   "/system/framework/arm/boot-framework.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat",
 						to:   "/system/framework/arm/boot-framework.oat",
 					},
 				},
@@ -574,41 +574,41 @@
 					"host/linux-x86/apex/com.android.art/javalib/core2.jar",
 					"host/linux-x86/system/framework/framework.jar",
 				},
-				imagePathOnHost:   "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
 				imagePathOnDevice: "/system/framework/x86_64/boot-framework.art",
 				imagesDeps: []string{
-					"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",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
 				},
-				baseImages: []string{"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art"},
+				baseImages: []string{"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.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/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
 						to:   "/system/framework/x86_64/boot-framework.art",
 					},
 					{
-						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
 						to:   "/system/framework/x86_64/boot-framework.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
 						to:   "/system/framework/x86_64/boot-framework.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat",
 						to:   "/system/framework/x86_64/boot-framework.oat",
 					},
 				},
@@ -622,41 +622,41 @@
 					"host/linux-x86/apex/com.android.art/javalib/core2.jar",
 					"host/linux-x86/system/framework/framework.jar",
 				},
-				imagePathOnHost:   "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
 				imagePathOnDevice: "/system/framework/x86/boot-framework.art",
 				imagesDeps: []string{
-					"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",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
 				},
-				baseImages: []string{"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art"},
+				baseImages: []string{"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.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/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
 				},
 				installs: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
 						to:   "/system/framework/x86/boot-framework.art",
 					},
 					{
-						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
 						to:   "/system/framework/x86/boot-framework.oat",
 					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
 						to:   "/system/framework/x86/boot-framework.vdex",
 					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
-						from: "out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat",
+						from: "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat",
 						to:   "/system/framework/x86/boot-framework.oat",
 					},
 				},
@@ -664,8 +664,8 @@
 			},
 		},
 		profileInstalls: []normalizedInstall{
-			{from: "out/soong/test_device/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"},
-			{from: "out/soong/test_device/dex_bootjars/boot.prof", to: "/system/etc/boot-image.prof"},
+			{from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"},
+			{from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.prof", to: "/system/etc/boot-image.prof"},
 		},
 		profileLicenseMetadataFile: expectedLicenseMetadataFile,
 	}
@@ -691,8 +691,8 @@
 	expected := &expectedConfig{
 		name:                     "mainline",
 		stem:                     "boot",
-		dir:                      "out/soong/test_device/dex_mainlinejars",
-		symbolsDir:               "out/soong/test_device/dex_mainlinejars_unstripped",
+		dir:                      "out/soong/dexpreopt_arm64/dex_mainlinejars",
+		symbolsDir:               "out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped",
 		installDirOnDevice:       "system/framework",
 		installDirOnHost:         "system/framework",
 		profileInstallPathInApex: "",
@@ -701,17 +701,17 @@
 			"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",
+			"out/soong/dexpreopt_arm64/dex_mainlinejars_input/framework-foo.jar",
+			"out/soong/dexpreopt_arm64/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",
+			"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar",
+			"out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar",
+			"out/soong/dexpreopt_arm64/dex_bootjars_input/framework.jar",
+			"out/soong/dexpreopt_arm64/dex_mainlinejars_input/framework-foo.jar",
+			"out/soong/dexpreopt_arm64/dex_mainlinejars_input/framework-bar.jar",
 		},
-		zip: "out/soong/test_device/dex_mainlinejars/mainline.zip",
+		zip: "out/soong/dexpreopt_arm64/dex_mainlinejars/mainline.zip",
 		variants: []*expectedVariant{
 			{
 				archType: android.Arm64,
@@ -726,47 +726,47 @@
 					"/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",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-foo.oat",
 						to:   "/system/framework/arm64/boot-framework-foo.oat",
 					},
 				},
@@ -785,47 +785,47 @@
 					"/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",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/android/system/framework/arm/boot-framework-foo.oat",
 						to:   "/system/framework/arm/boot-framework-foo.oat",
 					},
 				},
@@ -844,47 +844,47 @@
 					"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",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
 						to:   "/system/framework/x86_64/boot-framework-foo.oat",
 					},
 				},
@@ -903,47 +903,47 @@
 					"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",
+				imagePathOnHost:   "out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art",
+					"out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/dexpreopt_arm64/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",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+					"out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
+					"out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/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",
+						from: "out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-foo.oat",
 						to:   "/system/framework/x86/boot-framework-foo.oat",
 					},
 				},
@@ -1056,34 +1056,34 @@
 		fmt.Fprintf(out, "%s=%s\n", v.Name(), android.StringRelativeToTop(result.Config, v.Value()))
 	}
 	format := `
-DEXPREOPT_BOOTCLASSPATH_DEX_FILES=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
+DEXPREOPT_BOOTCLASSPATH_DEX_FILES=out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar out/soong/dexpreopt_arm64/dex_bootjars_input/framework.jar
 DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS=/apex/com.android.art/javalib/core1.jar /apex/com.android.art/javalib/core2.jar /system/framework/framework.jar
 DEXPREOPT_BOOT_JARS_MODULES=platform:framework
 DEXPREOPT_GEN=out/host/linux-x86/bin/dexpreopt_gen
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/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:/apex/art_boot_images/javalib/arm/boot-core2.oat
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/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:/apex/art_boot_images/javalib/arm64/boot-core2.oat
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/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:/apex/art_boot_images/javalib/x86/boot-core2.oat
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/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:/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-core2.art:/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:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
-DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art:/system/framework/arm/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
-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
-DEXPREOPT_IMAGE_DEPS_art_host_x86_64=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
-DEXPREOPT_IMAGE_DEPS_boot_arm=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
-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_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art:/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art:/system/framework/arm/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art:/system/framework/arm64/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art:/system/framework/x86/boot-framework.art out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art:/system/framework/x86_64/boot-framework.art out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art:/system/framework/arm/boot-framework-foo.art out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art:/system/framework/arm64/boot-framework-foo.art out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art:/system/framework/x86/boot-framework-foo.art out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art:/system/framework/x86_64/boot-framework-foo.art out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_boot_host_x86_64=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_arm=out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_arm64=out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_host_x86=out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_host_x86_64=out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat out/soong/dexpreopt_arm64/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
@@ -1099,51 +1099,51 @@
 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_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_LOCATIONS_ON_HOSTart=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/boot.art
+DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot-framework.art
+DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot-framework.art:out/soong/dexpreopt_arm64/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_BUILT_INSTALLED=out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/dexpreopt_arm64/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
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
-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
-DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/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.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex
-DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex:/system/framework/arm/boot-framework.vdex
-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
-DEXPREOPT_IMAGE_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art
-DEXPREOPT_IMAGE_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art
-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
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex:/system/framework/arm/boot-framework.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/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/dexpreopt_arm64/dex_artjars/art.zip
+DEXPREOPT_IMAGE_ZIP_boot=out/soong/dexpreopt_arm64/dex_bootjars/boot.zip
+DEXPREOPT_IMAGE_ZIP_mainline=out/soong/dexpreopt_arm64/dex_mainlinejars/mainline.zip
+DEXPREOPT_IMAGE_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
+DEXPREOPT_IMAGE_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art
+DEXPREOPT_IMAGE_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art
+DEXPREOPT_IMAGE_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art
+DEXPREOPT_IMAGE_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art
+DEXPREOPT_IMAGE_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art
+DEXPREOPT_IMAGE_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art
+DEXPREOPT_IMAGE_boot_host_x86_64=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art
+DEXPREOPT_IMAGE_mainline_arm=out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_arm64=out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_host_x86=out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_host_x86_64=out/soong/dexpreopt_arm64/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/hiddenapi_modular.go b/java/hiddenapi_modular.go
index c6176e6..96e084a 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -241,7 +241,7 @@
 		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")
+	corePlatformStubModules = append(corePlatformStubModules, android.JavaApiLibraryName(config, "legacy.core.platform.api.stubs"))
 
 	// Allow products to define their own stubs for custom product jars that apps can use.
 	publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
diff --git a/java/java.go b/java/java.go
index 2de4ea9..0da7328 100644
--- a/java/java.go
+++ b/java/java.go
@@ -456,7 +456,9 @@
 		ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
 		ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
 		if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
-			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
+			ctx.AddVariationDependencies(nil, proguardRaiseTag,
+				android.JavaApiLibraryNames(ctx.Config(), config.LegacyCorePlatformBootclasspathLibraries)...,
+			)
 		}
 		if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
 			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
@@ -2837,7 +2839,7 @@
 			return android.IsConvertedToAidlLibrary(ctx, src.OriginalModuleName)
 		})
 
-		apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+		apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 
 		if !aidlSrcs.IsEmpty() {
 			aidlLibName := m.Name() + "_aidl_library"
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 6cb549e..04c6d05 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -93,16 +93,16 @@
 
 func corePlatformSystemModules(ctx android.EarlyModuleContext) string {
 	if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
-		return config.LegacyCorePlatformSystemModules
+		return android.JavaApiLibraryName(ctx.Config(), config.LegacyCorePlatformSystemModules)
 	} else {
-		return config.StableCorePlatformSystemModules
+		return android.JavaApiLibraryName(ctx.Config(), config.StableCorePlatformSystemModules)
 	}
 }
 
 func corePlatformBootclasspathLibraries(ctx android.EarlyModuleContext) []string {
 	if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
-		return config.LegacyCorePlatformBootclasspathLibraries
+		return android.JavaApiLibraryNames(ctx.Config(), config.LegacyCorePlatformBootclasspathLibraries)
 	} else {
-		return config.StableCorePlatformBootclasspathLibraries
+		return android.JavaApiLibraryNames(ctx.Config(), config.StableCorePlatformBootclasspathLibraries)
 	}
 }
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 7267cf3..dee72ed 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -923,7 +923,10 @@
 license_kind {
     name: "SPDX-license-identifier-Linux-syscall-note",
     // expanding visibility requires approval from an OSPO lawyer or pcounsel
-    visibility: ["//external/libbpf:__subpackages__"],
+    visibility: [
+        "//external/libbpf:__subpackages__",
+        "//prebuilts/vsdk:__subpackages__",
+    ],
     conditions: ["permissive"],
     url: "https://spdx.org/licenses/Linux-syscall-note.html",
 }
diff --git a/rust/protobuf.go b/rust/protobuf.go
index e30f25d..0cf6e8c 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -52,6 +52,10 @@
 
 	// List of libraries which export include paths required for this module
 	Header_libs []string `android:"arch_variant,variant_prepend"`
+
+	// Use protobuf version 3.x. This will be deleted once we migrate all current users
+	// of protobuf off of 2.x.
+	Use_protobuf3 *bool
 }
 
 type protobufDecorator struct {
@@ -65,6 +69,10 @@
 	protoFlags     android.ProtoFlags
 }
 
+func (proto *protobufDecorator) useProtobuf3() bool {
+	return Bool(proto.Properties.Use_protobuf3)
+}
+
 func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
 	var protoFlags android.ProtoFlags
 	var grpcProtoFlags android.ProtoFlags
@@ -73,7 +81,13 @@
 	outDir := android.PathForModuleOut(ctx)
 	protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
 	grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
+
+	// For now protobuf2 (the deprecated version) remains the default. This will change in the
+	// future as we update the various users.
 	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust-deprecated")
+	if proto.useProtobuf3() == true {
+		protoPluginPath = ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+	}
 
 	commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
 	commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
@@ -206,10 +220,20 @@
 
 func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
 	deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
-	deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
+	useProtobuf3 := proto.useProtobuf3()
+	if useProtobuf3 == true {
+		deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
+	} else {
+		deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
+	}
 	deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
 
 	if len(proto.Properties.Grpc_protos) > 0 {
+		if useProtobuf3 == true {
+			ctx.PropertyErrorf("protos", "rust_protobuf with grpc_protos defined must currently use "+
+				"`use_protobuf3: false,` in the Android.bp file. This is temporary until the "+
+				"grpcio crate is updated to use the current version of the protobuf crate.")
+		}
 		deps.Rustlibs = append(deps.Rustlibs, "libgrpcio", "libfutures")
 		deps.HeaderLibs = append(deps.HeaderLibs, "libprotobuf-cpp-full")
 	}
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index 0aa4549..b723f3f 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -69,6 +69,55 @@
 	}
 }
 
+func TestRustProtobuf3(t *testing.T) {
+	ctx := testRust(t, `
+		rust_protobuf {
+			name: "librust_proto",
+			protos: ["buf.proto", "proto.proto"],
+			crate_name: "rust_proto",
+			source_stem: "buf",
+            use_protobuf3: true,
+			shared_libs: ["libfoo_shared"],
+			static_libs: ["libfoo_static"],
+		}
+		cc_library_shared {
+			name: "libfoo_shared",
+			export_include_dirs: ["shared_include"],
+		}
+		cc_library_static {
+			name: "libfoo_static",
+			export_include_dirs: ["static_include"],
+		}
+	`)
+	// Check that libprotobuf is added as a dependency.
+	librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
+	if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
+		t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
+	}
+
+	// Make sure the correct plugin is being used.
+	librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
+	cmd := librust_proto_out.RuleParams.Command
+	if w := "protoc-gen-rust"; !strings.Contains(cmd, w) {
+		t.Errorf("expected %q in %q", w, cmd)
+	}
+
+	// Check exported include directories
+	if w := "-Ishared_include"; !strings.Contains(cmd, w) {
+		t.Errorf("expected %q in %q", w, cmd)
+	}
+	if w := "-Istatic_include"; !strings.Contains(cmd, w) {
+		t.Errorf("expected %q in %q", w, cmd)
+	}
+
+	// Check proto.rs, the second protobuf, is listed as an output
+	librust_proto_outputs := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").AllOutputs()
+	if android.InList("proto.rs", librust_proto_outputs) {
+		t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto.rs' in list, got: %#v ",
+			librust_proto_outputs)
+	}
+}
+
 func TestRustGrpc(t *testing.T) {
 	ctx := testRust(t, `
 		rust_protobuf {
diff --git a/rust/testing.go b/rust/testing.go
index a33d948..0a6a870 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -127,6 +127,12 @@
 			min_sdk_version: "29",
 		}
 		rust_library {
+			name: "libprotobuf",
+			crate_name: "protobuf",
+			srcs: ["foo.rs"],
+			host_supported: true,
+		}
+		rust_library {
 			name: "libprotobuf_deprecated",
 			crate_name: "protobuf",
 			srcs: ["foo.rs"],
diff --git a/snapshot/host_snapshot.go b/snapshot/host_snapshot.go
index 9793218..edcc163 100644
--- a/snapshot/host_snapshot.go
+++ b/snapshot/host_snapshot.go
@@ -96,6 +96,7 @@
 	var jsonData []SnapshotJsonFlags
 	var metaPaths android.Paths
 
+	installedNotices := make(map[string]bool)
 	metaZipFile := android.PathForModuleOut(ctx, fileName).OutputPath
 
 	// Create JSON file based on the direct dependencies
@@ -104,12 +105,14 @@
 		if desc != nil {
 			jsonData = append(jsonData, *desc)
 		}
-		if len(dep.EffectiveLicenseFiles()) > 0 {
-			noticeFile := android.PathForModuleOut(ctx, "NOTICE_FILES", dep.Name()+".txt").OutputPath
-			android.CatFileRule(ctx, dep.EffectiveLicenseFiles(), noticeFile)
-			metaPaths = append(metaPaths, noticeFile)
+		for _, notice := range dep.EffectiveLicenseFiles() {
+			if _, ok := installedNotices[notice.String()]; !ok {
+				installedNotices[notice.String()] = true
+				noticeOut := android.PathForModuleOut(ctx, "NOTICE_FILES", notice.String()).OutputPath
+				CopyFileToOutputPathRule(pctx, ctx, notice, noticeOut)
+				metaPaths = append(metaPaths, noticeOut)
+			}
 		}
-
 	})
 	// Sort notice paths and json data for repeatble build
 	sort.Slice(jsonData, func(i, j int) bool {
@@ -220,8 +223,7 @@
 	}
 
 	if path.Valid() && path.String() != "" {
-		return &SnapshotJsonFlags{
-			ModuleName:          m.Name(),
+		props := &SnapshotJsonFlags{
 			ModuleStemName:      moduleStem,
 			Filename:            path.String(),
 			Required:            append(m.HostRequiredModuleNames(), m.RequiredModuleNames()...),
@@ -229,6 +231,8 @@
 			RustProcMacro:       procMacro,
 			CrateName:           crateName,
 		}
+		props.InitBaseSnapshotProps(m)
+		return props
 	}
 	return nil
 }
diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go
index 206ecc9..c95a537 100644
--- a/snapshot/snapshot.go
+++ b/snapshot/snapshot.go
@@ -26,6 +26,10 @@
 
 var pctx = android.NewPackageContext("android/soong/snapshot")
 
+func init() {
+	pctx.Import("android/soong/android")
+}
+
 type SnapshotSingleton struct {
 	// Name, e.g., "vendor", "recovery", "ramdisk".
 	name string
@@ -48,8 +52,18 @@
 	Fake bool
 }
 
+// The output files to be included in the snapshot.
+type SnapshotPaths struct {
+	// All files to be included in the snapshot
+	OutputFiles android.Paths
+
+	// Notice files of the snapshot output files
+	NoticeFiles android.Paths
+}
+
 // Interface of function to capture snapshot from each module
-type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths
+// Returns snapshot ouputs and notice files.
+type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) SnapshotPaths
 
 var snapshotActionList []GenerateSnapshotAction
 
@@ -74,9 +88,19 @@
 		snapshotDir = filepath.Join("fake", snapshotDir)
 	}
 	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+	installedNotices := make(map[string]bool)
 
 	for _, f := range snapshotActionList {
-		snapshotOutputs = append(snapshotOutputs, f(*c, ctx, snapshotArchDir)...)
+		snapshotPaths := f(*c, ctx, snapshotArchDir)
+		snapshotOutputs = append(snapshotOutputs, snapshotPaths.OutputFiles...)
+		for _, notice := range snapshotPaths.NoticeFiles {
+			if _, ok := installedNotices[notice.String()]; !ok {
+				installedNotices[notice.String()] = true
+				snapshotOutputs = append(snapshotOutputs, CopyFileRule(
+					pctx, ctx, notice, filepath.Join(noticeDir, notice.String())))
+			}
+		}
 	}
 
 	// All artifacts are ready. Sort them to normalize ninja and then zip.
diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go
index 809ca3d..fb4ee0c 100644
--- a/snapshot/snapshot_base.go
+++ b/snapshot/snapshot_base.go
@@ -120,4 +120,19 @@
 	// dependencies
 	Required  []string `json:",omitempty"`
 	Overrides []string `json:",omitempty"`
+
+	// license information
+	LicenseKinds []string `json:",omitempty"`
+	LicenseTexts []string `json:",omitempty"`
+}
+
+func (prop *SnapshotJsonFlags) InitBaseSnapshotPropsWithName(m android.Module, name string) {
+	prop.ModuleName = name
+
+	prop.LicenseKinds = m.EffectiveLicenseKinds()
+	prop.LicenseTexts = m.EffectiveLicenseFiles().Strings()
+}
+
+func (prop *SnapshotJsonFlags) InitBaseSnapshotProps(m android.Module) {
+	prop.InitBaseSnapshotPropsWithName(m, m.Name())
 }
diff --git a/snapshot/util.go b/snapshot/util.go
index 806ac90..c87c508 100644
--- a/snapshot/util.go
+++ b/snapshot/util.go
@@ -21,17 +21,25 @@
 	return outPath
 }
 
-func CopyFileRule(pctx android.PackageContext, ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
-	outPath := android.PathForOutput(ctx, out)
+type buildContext interface {
+	Build(pctx android.PackageContext, params android.BuildParams)
+}
+
+func CopyFileToOutputPathRule(pctx android.PackageContext, ctx buildContext, path android.Path, outPath android.OutputPath) {
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        android.Cp,
 		Input:       path,
 		Output:      outPath,
-		Description: "copy " + path.String() + " -> " + out,
+		Description: "copy " + path.String() + " -> " + outPath.String(),
 		Args: map[string]string{
-			"cpFlags": "-f -L",
+			"cpFlags": "-L",
 		},
 	})
+}
+
+func CopyFileRule(pctx android.PackageContext, ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	CopyFileToOutputPathRule(pctx, ctx, path, outPath)
 	return outPath
 }
 
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index a97f71b..4209507 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -99,6 +99,16 @@
 	return PrintDict(valDict, indentLevel)
 }
 
+// PrintStringStringDict returns a Starlark-compatible string formatted as dictionary with
+// string keys and string values.
+func PrintStringStringDict(dict map[string]string, indentLevel int) string {
+	valDict := make(map[string]string, len(dict))
+	for k, v := range dict {
+		valDict[k] = fmt.Sprintf(`"%s"`, v)
+	}
+	return PrintDict(valDict, indentLevel)
+}
+
 // PrintDict returns a starlark-compatible string containing a dictionary with string keys and
 // values printed with no additional formatting.
 func PrintDict(dict map[string]string, indentLevel int) string {
diff --git a/starlark_import/Android.bp b/starlark_import/Android.bp
new file mode 100644
index 0000000..b43217b
--- /dev/null
+++ b/starlark_import/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-starlark",
+    pkgPath: "android/soong/starlark_import",
+    srcs: [
+        "starlark_import.go",
+        "unmarshal.go",
+    ],
+    testSrcs: [
+        "starlark_import_test.go",
+        "unmarshal_test.go",
+    ],
+    deps: [
+        "go-starlark-starlark",
+        "go-starlark-starlarkstruct",
+        "go-starlark-starlarkjson",
+        "go-starlark-starlarktest",
+    ],
+}
diff --git a/starlark_import/README.md b/starlark_import/README.md
new file mode 100644
index 0000000..e444759
--- /dev/null
+++ b/starlark_import/README.md
@@ -0,0 +1,14 @@
+# starlark_import package
+
+This allows soong to read constant information from starlark files. At package initialization
+time, soong will read `build/bazel/constants_exported_to_soong.bzl`, and then make the
+variables from that file available via `starlark_import.GetStarlarkValue()`. So to import
+a new variable, it must be added to `constants_exported_to_soong.bzl` and then it can
+be accessed by name.
+
+Only constant information can be read, since this is not a full bazel execution but a
+standalone starlark interpreter. This means you can't use bazel contructs like `rule`,
+`provider`, `select`, `glob`, etc.
+
+All starlark files that were loaded must be added as ninja deps that cause soong to rerun.
+The loaded files can be retrieved via `starlark_import.GetNinjaDeps()`.
diff --git a/starlark_import/starlark_import.go b/starlark_import/starlark_import.go
new file mode 100644
index 0000000..ebe4247
--- /dev/null
+++ b/starlark_import/starlark_import.go
@@ -0,0 +1,306 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package starlark_import
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+
+	"go.starlark.net/starlark"
+	"go.starlark.net/starlarkjson"
+	"go.starlark.net/starlarkstruct"
+)
+
+func init() {
+	go func() {
+		startTime := time.Now()
+		v, d, err := runStarlarkFile("//build/bazel/constants_exported_to_soong.bzl")
+		endTime := time.Now()
+		//fmt.Fprintf(os.Stderr, "starlark run time: %s\n", endTime.Sub(startTime).String())
+		globalResult.Set(starlarkResult{
+			values:    v,
+			ninjaDeps: d,
+			err:       err,
+			startTime: startTime,
+			endTime:   endTime,
+		})
+	}()
+}
+
+type starlarkResult struct {
+	values    starlark.StringDict
+	ninjaDeps []string
+	err       error
+	startTime time.Time
+	endTime   time.Time
+}
+
+// setOnce wraps a value and exposes Set() and Get() accessors for it.
+// The Get() calls will block until a Set() has been called.
+// A second call to Set() will panic.
+// setOnce must be created using newSetOnce()
+type setOnce[T any] struct {
+	value T
+	lock  sync.Mutex
+	wg    sync.WaitGroup
+	isSet bool
+}
+
+func (o *setOnce[T]) Set(value T) {
+	o.lock.Lock()
+	defer o.lock.Unlock()
+	if o.isSet {
+		panic("Value already set")
+	}
+
+	o.value = value
+	o.isSet = true
+	o.wg.Done()
+}
+
+func (o *setOnce[T]) Get() T {
+	if !o.isSet {
+		o.wg.Wait()
+	}
+	return o.value
+}
+
+func newSetOnce[T any]() *setOnce[T] {
+	result := &setOnce[T]{}
+	result.wg.Add(1)
+	return result
+}
+
+var globalResult = newSetOnce[starlarkResult]()
+
+func GetStarlarkValue[T any](key string) (T, error) {
+	result := globalResult.Get()
+	if result.err != nil {
+		var zero T
+		return zero, result.err
+	}
+	if !result.values.Has(key) {
+		var zero T
+		return zero, fmt.Errorf("a starlark variable by that name wasn't found, did you update //build/bazel/constants_exported_to_soong.bzl?")
+	}
+	return Unmarshal[T](result.values[key])
+}
+
+func GetNinjaDeps() ([]string, error) {
+	result := globalResult.Get()
+	if result.err != nil {
+		return nil, result.err
+	}
+	return result.ninjaDeps, nil
+}
+
+func getTopDir() (string, error) {
+	// It's hard to communicate the top dir to this package in any other way than reading the
+	// arguments directly, because we need to know this at package initialization time. Many
+	// soong constants that we'd like to read from starlark are initialized during package
+	// initialization.
+	for i, arg := range os.Args {
+		if arg == "--top" {
+			if i < len(os.Args)-1 && os.Args[i+1] != "" {
+				return os.Args[i+1], nil
+			}
+		}
+	}
+
+	// When running tests, --top is not passed. Instead, search for the top dir manually
+	cwd, err := os.Getwd()
+	if err != nil {
+		return "", err
+	}
+	for cwd != "/" {
+		if _, err := os.Stat(filepath.Join(cwd, "build/soong/soong_ui.bash")); err == nil {
+			return cwd, nil
+		}
+		cwd = filepath.Dir(cwd)
+	}
+	return "", fmt.Errorf("could not find top dir")
+}
+
+const callerDirKey = "callerDir"
+
+type modentry struct {
+	globals starlark.StringDict
+	err     error
+}
+
+func unsupportedMethod(t *starlark.Thread, fn *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
+	return nil, fmt.Errorf("%sthis file is read by soong, and must therefore be pure starlark and include only constant information. %q is not allowed", t.CallStack().String(), fn.Name())
+}
+
+var builtins = starlark.StringDict{
+	"aspect":     starlark.NewBuiltin("aspect", unsupportedMethod),
+	"glob":       starlark.NewBuiltin("glob", unsupportedMethod),
+	"json":       starlarkjson.Module,
+	"provider":   starlark.NewBuiltin("provider", unsupportedMethod),
+	"rule":       starlark.NewBuiltin("rule", unsupportedMethod),
+	"struct":     starlark.NewBuiltin("struct", starlarkstruct.Make),
+	"select":     starlark.NewBuiltin("select", unsupportedMethod),
+	"transition": starlark.NewBuiltin("transition", unsupportedMethod),
+}
+
+// Takes a module name (the first argument to the load() function) and returns the path
+// it's trying to load, stripping out leading //, and handling leading :s.
+func cleanModuleName(moduleName string, callerDir string) (string, error) {
+	if strings.Count(moduleName, ":") > 1 {
+		return "", fmt.Errorf("at most 1 colon must be present in starlark path: %s", moduleName)
+	}
+
+	// We don't have full support for external repositories, but at least support skylib's dicts.
+	if moduleName == "@bazel_skylib//lib:dicts.bzl" {
+		return "external/bazel-skylib/lib/dicts.bzl", nil
+	}
+
+	localLoad := false
+	if strings.HasPrefix(moduleName, "@//") {
+		moduleName = moduleName[3:]
+	} else if strings.HasPrefix(moduleName, "//") {
+		moduleName = moduleName[2:]
+	} else if strings.HasPrefix(moduleName, ":") {
+		moduleName = moduleName[1:]
+		localLoad = true
+	} else {
+		return "", fmt.Errorf("load path must start with // or :")
+	}
+
+	if ix := strings.LastIndex(moduleName, ":"); ix >= 0 {
+		moduleName = moduleName[:ix] + string(os.PathSeparator) + moduleName[ix+1:]
+	}
+
+	if filepath.Clean(moduleName) != moduleName {
+		return "", fmt.Errorf("load path must be clean, found: %s, expected: %s", moduleName, filepath.Clean(moduleName))
+	}
+	if strings.HasPrefix(moduleName, "../") {
+		return "", fmt.Errorf("load path must not start with ../: %s", moduleName)
+	}
+	if strings.HasPrefix(moduleName, "/") {
+		return "", fmt.Errorf("load path starts with /, use // for a absolute path: %s", moduleName)
+	}
+
+	if localLoad {
+		return filepath.Join(callerDir, moduleName), nil
+	}
+
+	return moduleName, nil
+}
+
+// loader implements load statement. The format of the loaded module URI is
+//
+//	[//path]:base
+//
+// The file path is $ROOT/path/base if path is present, <caller_dir>/base otherwise.
+func loader(thread *starlark.Thread, module string, topDir string, moduleCache map[string]*modentry, moduleCacheLock *sync.Mutex, filesystem map[string]string) (starlark.StringDict, error) {
+	modulePath, err := cleanModuleName(module, thread.Local(callerDirKey).(string))
+	if err != nil {
+		return nil, err
+	}
+	moduleCacheLock.Lock()
+	e, ok := moduleCache[modulePath]
+	if e == nil {
+		if ok {
+			moduleCacheLock.Unlock()
+			return nil, fmt.Errorf("cycle in load graph")
+		}
+
+		// Add a placeholder to indicate "load in progress".
+		moduleCache[modulePath] = nil
+		moduleCacheLock.Unlock()
+
+		childThread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
+
+		// Cheating for the sake of testing:
+		// propagate starlarktest's Reporter key, otherwise testing
+		// the load function may cause panic in starlarktest code.
+		const testReporterKey = "Reporter"
+		if v := thread.Local(testReporterKey); v != nil {
+			childThread.SetLocal(testReporterKey, v)
+		}
+
+		childThread.SetLocal(callerDirKey, filepath.Dir(modulePath))
+
+		if filesystem != nil {
+			globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), filesystem[modulePath], builtins)
+			e = &modentry{globals, err}
+		} else {
+			globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), nil, builtins)
+			e = &modentry{globals, err}
+		}
+
+		// Update the cache.
+		moduleCacheLock.Lock()
+		moduleCache[modulePath] = e
+	}
+	moduleCacheLock.Unlock()
+	return e.globals, e.err
+}
+
+// Run runs the given starlark file and returns its global variables and a list of all starlark
+// files that were loaded. The top dir for starlark's // is found via getTopDir().
+func runStarlarkFile(filename string) (starlark.StringDict, []string, error) {
+	topDir, err := getTopDir()
+	if err != nil {
+		return nil, nil, err
+	}
+	return runStarlarkFileWithFilesystem(filename, topDir, nil)
+}
+
+func runStarlarkFileWithFilesystem(filename string, topDir string, filesystem map[string]string) (starlark.StringDict, []string, error) {
+	if !strings.HasPrefix(filename, "//") && !strings.HasPrefix(filename, ":") {
+		filename = "//" + filename
+	}
+	filename, err := cleanModuleName(filename, "")
+	if err != nil {
+		return nil, nil, err
+	}
+	moduleCache := make(map[string]*modentry)
+	moduleCache[filename] = nil
+	moduleCacheLock := &sync.Mutex{}
+	mainThread := &starlark.Thread{
+		Name: "main",
+		Print: func(_ *starlark.Thread, msg string) {
+			// Ignore prints
+		},
+		Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
+			return loader(thread, module, topDir, moduleCache, moduleCacheLock, filesystem)
+		},
+	}
+	mainThread.SetLocal(callerDirKey, filepath.Dir(filename))
+
+	var result starlark.StringDict
+	if filesystem != nil {
+		result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), filesystem[filename], builtins)
+	} else {
+		result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), nil, builtins)
+	}
+	return result, sortedStringKeys(moduleCache), err
+}
+
+func sortedStringKeys(m map[string]*modentry) []string {
+	s := make([]string, 0, len(m))
+	for k := range m {
+		s = append(s, k)
+	}
+	sort.Strings(s)
+	return s
+}
diff --git a/starlark_import/starlark_import_test.go b/starlark_import/starlark_import_test.go
new file mode 100644
index 0000000..8a58e3b
--- /dev/null
+++ b/starlark_import/starlark_import_test.go
@@ -0,0 +1,122 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package starlark_import
+
+import (
+	"strings"
+	"testing"
+
+	"go.starlark.net/starlark"
+)
+
+func TestBasic(t *testing.T) {
+	globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+		"a.bzl": `
+my_string = "hello, world!"
+`})
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	if globals["my_string"].(starlark.String) != "hello, world!" {
+		t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+	}
+}
+
+func TestLoad(t *testing.T) {
+	globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+		"a.bzl": `
+load("//b.bzl", _b_string = "my_string")
+my_string = "hello, " + _b_string
+`,
+		"b.bzl": `
+my_string = "world!"
+`})
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	if globals["my_string"].(starlark.String) != "hello, world!" {
+		t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+	}
+}
+
+func TestLoadRelative(t *testing.T) {
+	globals, ninjaDeps, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+		"a.bzl": `
+load(":b.bzl", _b_string = "my_string")
+load("//foo/c.bzl", _c_string = "my_string")
+my_string = "hello, " + _b_string
+c_string = _c_string
+`,
+		"b.bzl": `
+my_string = "world!"
+`,
+		"foo/c.bzl": `
+load(":d.bzl", _d_string = "my_string")
+my_string = "hello, " + _d_string
+`,
+		"foo/d.bzl": `
+my_string = "world!"
+`})
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	if globals["my_string"].(starlark.String) != "hello, world!" {
+		t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+	}
+
+	expectedNinjaDeps := []string{
+		"a.bzl",
+		"b.bzl",
+		"foo/c.bzl",
+		"foo/d.bzl",
+	}
+	if !slicesEqual(ninjaDeps, expectedNinjaDeps) {
+		t.Errorf("Expected %v ninja deps, got %v", expectedNinjaDeps, ninjaDeps)
+	}
+}
+
+func TestLoadCycle(t *testing.T) {
+	_, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+		"a.bzl": `
+load(":b.bzl", _b_string = "my_string")
+my_string = "hello, " + _b_string
+`,
+		"b.bzl": `
+load(":a.bzl", _a_string = "my_string")
+my_string = "hello, " + _a_string
+`})
+	if err == nil || !strings.Contains(err.Error(), "cycle in load graph") {
+		t.Errorf("Expected cycle in load graph, got: %v", err)
+		return
+	}
+}
+
+func slicesEqual[T comparable](a []T, b []T) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i := range a {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}
diff --git a/starlark_import/unmarshal.go b/starlark_import/unmarshal.go
new file mode 100644
index 0000000..1b54437
--- /dev/null
+++ b/starlark_import/unmarshal.go
@@ -0,0 +1,288 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package starlark_import
+
+import (
+	"fmt"
+	"math"
+	"reflect"
+	"unsafe"
+
+	"go.starlark.net/starlark"
+	"go.starlark.net/starlarkstruct"
+)
+
+func Unmarshal[T any](value starlark.Value) (T, error) {
+	var zero T
+	x, err := UnmarshalReflect(value, reflect.TypeOf(zero))
+	return x.Interface().(T), err
+}
+
+func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) {
+	zero := reflect.Zero(ty)
+	var result reflect.Value
+	if ty.Kind() == reflect.Interface {
+		var err error
+		ty, err = typeOfStarlarkValue(value)
+		if err != nil {
+			return zero, err
+		}
+	}
+	if ty.Kind() == reflect.Map {
+		result = reflect.MakeMap(ty)
+	} else {
+		result = reflect.Indirect(reflect.New(ty))
+	}
+
+	switch v := value.(type) {
+	case starlark.String:
+		if result.Type().Kind() != reflect.String {
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+		result.SetString(v.GoString())
+	case starlark.Int:
+		signedValue, signedOk := v.Int64()
+		unsignedValue, unsignedOk := v.Uint64()
+		switch result.Type().Kind() {
+		case reflect.Int64:
+			if !signedOk {
+				return zero, fmt.Errorf("starlark int didn't fit in go int64")
+			}
+			result.SetInt(signedValue)
+		case reflect.Int32:
+			if !signedOk || signedValue > math.MaxInt32 || signedValue < math.MinInt32 {
+				return zero, fmt.Errorf("starlark int didn't fit in go int32")
+			}
+			result.SetInt(signedValue)
+		case reflect.Int16:
+			if !signedOk || signedValue > math.MaxInt16 || signedValue < math.MinInt16 {
+				return zero, fmt.Errorf("starlark int didn't fit in go int16")
+			}
+			result.SetInt(signedValue)
+		case reflect.Int8:
+			if !signedOk || signedValue > math.MaxInt8 || signedValue < math.MinInt8 {
+				return zero, fmt.Errorf("starlark int didn't fit in go int8")
+			}
+			result.SetInt(signedValue)
+		case reflect.Int:
+			if !signedOk || signedValue > math.MaxInt || signedValue < math.MinInt {
+				return zero, fmt.Errorf("starlark int didn't fit in go int")
+			}
+			result.SetInt(signedValue)
+		case reflect.Uint64:
+			if !unsignedOk {
+				return zero, fmt.Errorf("starlark int didn't fit in go uint64")
+			}
+			result.SetUint(unsignedValue)
+		case reflect.Uint32:
+			if !unsignedOk || unsignedValue > math.MaxUint32 {
+				return zero, fmt.Errorf("starlark int didn't fit in go uint32")
+			}
+			result.SetUint(unsignedValue)
+		case reflect.Uint16:
+			if !unsignedOk || unsignedValue > math.MaxUint16 {
+				return zero, fmt.Errorf("starlark int didn't fit in go uint16")
+			}
+			result.SetUint(unsignedValue)
+		case reflect.Uint8:
+			if !unsignedOk || unsignedValue > math.MaxUint8 {
+				return zero, fmt.Errorf("starlark int didn't fit in go uint8")
+			}
+			result.SetUint(unsignedValue)
+		case reflect.Uint:
+			if !unsignedOk || unsignedValue > math.MaxUint {
+				return zero, fmt.Errorf("starlark int didn't fit in go uint")
+			}
+			result.SetUint(unsignedValue)
+		default:
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+	case starlark.Float:
+		f := float64(v)
+		switch result.Type().Kind() {
+		case reflect.Float64:
+			result.SetFloat(f)
+		case reflect.Float32:
+			if f > math.MaxFloat32 || f < -math.MaxFloat32 {
+				return zero, fmt.Errorf("starlark float didn't fit in go float32")
+			}
+			result.SetFloat(f)
+		default:
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+	case starlark.Bool:
+		if result.Type().Kind() != reflect.Bool {
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+		result.SetBool(bool(v))
+	case starlark.Tuple:
+		if result.Type().Kind() != reflect.Slice {
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+		elemType := result.Type().Elem()
+		// TODO: Add this grow call when we're on go 1.20
+		//result.Grow(v.Len())
+		for i := 0; i < v.Len(); i++ {
+			elem, err := UnmarshalReflect(v.Index(i), elemType)
+			if err != nil {
+				return zero, err
+			}
+			result = reflect.Append(result, elem)
+		}
+	case *starlark.List:
+		if result.Type().Kind() != reflect.Slice {
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+		elemType := result.Type().Elem()
+		// TODO: Add this grow call when we're on go 1.20
+		//result.Grow(v.Len())
+		for i := 0; i < v.Len(); i++ {
+			elem, err := UnmarshalReflect(v.Index(i), elemType)
+			if err != nil {
+				return zero, err
+			}
+			result = reflect.Append(result, elem)
+		}
+	case *starlark.Dict:
+		if result.Type().Kind() != reflect.Map {
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+		keyType := result.Type().Key()
+		valueType := result.Type().Elem()
+		for _, pair := range v.Items() {
+			key := pair.Index(0)
+			value := pair.Index(1)
+
+			unmarshalledKey, err := UnmarshalReflect(key, keyType)
+			if err != nil {
+				return zero, err
+			}
+			unmarshalledValue, err := UnmarshalReflect(value, valueType)
+			if err != nil {
+				return zero, err
+			}
+
+			result.SetMapIndex(unmarshalledKey, unmarshalledValue)
+		}
+	case *starlarkstruct.Struct:
+		if result.Type().Kind() != reflect.Struct {
+			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+		}
+		if result.NumField() != len(v.AttrNames()) {
+			return zero, fmt.Errorf("starlark struct and go struct have different number of fields (%d and %d)", len(v.AttrNames()), result.NumField())
+		}
+		for _, attrName := range v.AttrNames() {
+			attr, err := v.Attr(attrName)
+			if err != nil {
+				return zero, err
+			}
+
+			// TODO(b/279787235): this should probably support tags to rename the field
+			resultField := result.FieldByName(attrName)
+			if resultField == (reflect.Value{}) {
+				return zero, fmt.Errorf("starlark struct had field %s, but requested struct type did not", attrName)
+			}
+			// This hack allows us to change unexported fields
+			resultField = reflect.NewAt(resultField.Type(), unsafe.Pointer(resultField.UnsafeAddr())).Elem()
+			x, err := UnmarshalReflect(attr, resultField.Type())
+			if err != nil {
+				return zero, err
+			}
+			resultField.Set(x)
+		}
+	default:
+		return zero, fmt.Errorf("unimplemented starlark type: %s", value.Type())
+	}
+
+	return result, nil
+}
+
+func typeOfStarlarkValue(value starlark.Value) (reflect.Type, error) {
+	var err error
+	switch v := value.(type) {
+	case starlark.String:
+		return reflect.TypeOf(""), nil
+	case *starlark.List:
+		innerType := reflect.TypeOf("")
+		if v.Len() > 0 {
+			innerType, err = typeOfStarlarkValue(v.Index(0))
+			if err != nil {
+				return nil, err
+			}
+		}
+		for i := 1; i < v.Len(); i++ {
+			innerTypeI, err := typeOfStarlarkValue(v.Index(i))
+			if err != nil {
+				return nil, err
+			}
+			if innerType != innerTypeI {
+				return nil, fmt.Errorf("List must contain elements of entirely the same type, found %v and %v", innerType, innerTypeI)
+			}
+		}
+		return reflect.SliceOf(innerType), nil
+	case *starlark.Dict:
+		keyType := reflect.TypeOf("")
+		valueType := reflect.TypeOf("")
+		keys := v.Keys()
+		if v.Len() > 0 {
+			firstKey := keys[0]
+			keyType, err = typeOfStarlarkValue(firstKey)
+			if err != nil {
+				return nil, err
+			}
+			firstValue, found, err := v.Get(firstKey)
+			if !found {
+				err = fmt.Errorf("value not found")
+			}
+			if err != nil {
+				return nil, err
+			}
+			valueType, err = typeOfStarlarkValue(firstValue)
+			if err != nil {
+				return nil, err
+			}
+		}
+		for _, key := range keys {
+			keyTypeI, err := typeOfStarlarkValue(key)
+			if err != nil {
+				return nil, err
+			}
+			if keyType != keyTypeI {
+				return nil, fmt.Errorf("dict must contain elements of entirely the same type, found %v and %v", keyType, keyTypeI)
+			}
+			value, found, err := v.Get(key)
+			if !found {
+				err = fmt.Errorf("value not found")
+			}
+			if err != nil {
+				return nil, err
+			}
+			valueTypeI, err := typeOfStarlarkValue(value)
+			if valueType.Kind() != reflect.Interface && valueTypeI != valueType {
+				// If we see conflicting value types, change the result value type to an empty interface
+				valueType = reflect.TypeOf([]interface{}{}).Elem()
+			}
+		}
+		return reflect.MapOf(keyType, valueType), nil
+	case starlark.Int:
+		return reflect.TypeOf(0), nil
+	case starlark.Float:
+		return reflect.TypeOf(0.0), nil
+	case starlark.Bool:
+		return reflect.TypeOf(true), nil
+	default:
+		return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type())
+	}
+}
diff --git a/starlark_import/unmarshal_test.go b/starlark_import/unmarshal_test.go
new file mode 100644
index 0000000..ee7a9e3
--- /dev/null
+++ b/starlark_import/unmarshal_test.go
@@ -0,0 +1,133 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package starlark_import
+
+import (
+	"reflect"
+	"testing"
+
+	"go.starlark.net/starlark"
+)
+
+func createStarlarkValue(t *testing.T, code string) starlark.Value {
+	t.Helper()
+	result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, builtins)
+	if err != nil {
+		panic(err)
+	}
+	return result["x"]
+}
+
+func TestUnmarshallConcreteType(t *testing.T) {
+	x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if x != "foo" {
+		t.Errorf(`Expected "foo", got %q`, x)
+	}
+}
+
+func TestUnmarshallConcreteTypeWithInterfaces(t *testing.T) {
+	x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t,
+		`{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	expected := map[string]map[string]interface{}{
+		"foo": {"foo2": "foo3"},
+		"bar": {"bar2": []string{"bar3"}},
+	}
+	if !reflect.DeepEqual(x, expected) {
+		t.Errorf(`Expected %v, got %v`, expected, x)
+	}
+}
+
+func TestUnmarshall(t *testing.T) {
+	testCases := []struct {
+		input    string
+		expected interface{}
+	}{
+		{
+			input:    `"foo"`,
+			expected: "foo",
+		},
+		{
+			input:    `5`,
+			expected: 5,
+		},
+		{
+			input:    `["foo", "bar"]`,
+			expected: []string{"foo", "bar"},
+		},
+		{
+			input:    `("foo", "bar")`,
+			expected: []string{"foo", "bar"},
+		},
+		{
+			input:    `("foo",5)`,
+			expected: []interface{}{"foo", 5},
+		},
+		{
+			input:    `{"foo": 5, "bar": 10}`,
+			expected: map[string]int{"foo": 5, "bar": 10},
+		},
+		{
+			input:    `{"foo": ["qux"], "bar": []}`,
+			expected: map[string][]string{"foo": {"qux"}, "bar": nil},
+		},
+		{
+			input: `struct(Foo="foo", Bar=5)`,
+			expected: struct {
+				Foo string
+				Bar int
+			}{Foo: "foo", Bar: 5},
+		},
+		{
+			// Unexported fields version of the above
+			input: `struct(foo="foo", bar=5)`,
+			expected: struct {
+				foo string
+				bar int
+			}{foo: "foo", bar: 5},
+		},
+		{
+			input: `{"foo": "foo2", "bar": ["bar2"], "baz": 5, "qux": {"qux2": "qux3"}, "quux": {"quux2": "quux3", "quux4": 5}}`,
+			expected: map[string]interface{}{
+				"foo": "foo2",
+				"bar": []string{"bar2"},
+				"baz": 5,
+				"qux": map[string]string{"qux2": "qux3"},
+				"quux": map[string]interface{}{
+					"quux2": "quux3",
+					"quux4": 5,
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		x, err := UnmarshalReflect(createStarlarkValue(t, tc.input), reflect.TypeOf(tc.expected))
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		if !reflect.DeepEqual(x.Interface(), tc.expected) {
+			t.Errorf(`Expected %#v, got %#v`, tc.expected, x.Interface())
+		}
+	}
+}
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 68d7f8d..71e6af0 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -53,6 +53,20 @@
   if [[ "$buildfile_mtime1" != "$buildfile_mtime2" ]]; then
     fail "BUILD.bazel was updated even though contents are same"
   fi
+
+  # Force bp2build to rerun by updating the timestamp of the constants_exported_to_soong.bzl file.
+  touch build/bazel/constants_exported_to_soong.bzl
+
+  run_soong bp2build
+  local -r buildfile_mtime3=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
+  local -r marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+
+  if [[ "$marker_mtime2" == "$marker_mtime3" ]]; then
+    fail "Expected bp2build marker file to change"
+  fi
+  if [[ "$buildfile_mtime2" != "$buildfile_mtime3" ]]; then
+    fail "BUILD.bazel was updated even though contents are same"
+  fi
 }
 
 # Tests that blueprint files that are deleted are not present when the
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index 05d3a66..ca63fdf 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -eu
+#!/bin/bash
 
 set -o pipefail
 
@@ -88,12 +88,12 @@
     fail "Bazel actions not found for force-enabled module"
   fi
 
-  local exit_code=`run_soong --bazel-force-enabled-modules=unenabled-touch-file nothing`
+  unused=`run_soong --bazel-force-enabled-modules=unenabled-touch-file --ensure-allowlist-integrity nothing >/dev/null`
 
-  if [[ $exit_code -ne 1 ]]; then
+  if [[ $? -ne 1 ]]; then
     fail "Expected failure due to force-enabling an unenabled module "
   fi
 }
 
 
-scan_and_run_tests
\ No newline at end of file
+scan_and_run_tests
diff --git a/tests/persistent_bazel_test.sh b/tests/persistent_bazel_test.sh
index 4e2982a..9b7b58f 100755
--- a/tests/persistent_bazel_test.sh
+++ b/tests/persistent_bazel_test.sh
@@ -73,8 +73,8 @@
 
   USE_PERSISTENT_BAZEL=1 run_soong nothing 1>out/failurelog.txt 2>&1 && fail "Expected build failure" || true
 
-  if ! grep -sq "'build/bazel/rules' is not a package" out/failurelog.txt ; then
-    fail "Expected error to contain 'build/bazel/rules' is not a package, instead got:\n$(cat out/failurelog.txt)"
+  if ! grep -sq "cannot load //build/bazel/rules/common/api_constants.bzl" out/failurelog.txt ; then
+    fail "Expected error to contain 'cannot load //build/bazel/rules/common/api_constants.bzl', instead got:\n$(cat out/failurelog.txt)"
   fi
 
   kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
diff --git a/tradefed/suite_harness/tradefed_binary.go b/tradefed/suite_harness/tradefed_binary.go
index a421d8b..1ce94bc 100644
--- a/tradefed/suite_harness/tradefed_binary.go
+++ b/tradefed/suite_harness/tradefed_binary.go
@@ -78,7 +78,6 @@
 		// Add dependencies required by all tradefed_binary modules.
 		props.Libs = []string{
 			"tradefed",
-			"tradefed-test-framework",
 			"loganalysis",
 			"compatibility-host-util",
 		}
diff --git a/ui/build/config.go b/ui/build/config.go
index bf4aec9..2dda52a 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -67,28 +67,29 @@
 	logsPrefix    string
 
 	// From the arguments
-	parallel          int
-	keepGoing         int
-	verbose           bool
-	checkbuild        bool
-	dist              bool
-	jsonModuleGraph   bool
-	apiBp2build       bool // Generate BUILD files for Soong modules that contribute APIs
-	bp2build          bool
-	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
-	skipSoong         bool
-	skipNinja         bool
-	skipSoongTests    bool
-	searchApiDir      bool // Scan the Android.bp files generated in out/api_surfaces
-	skipMetricsUpload bool
-	buildStartedTime  int64 // For metrics-upload-only - manually specify a build-started time
-	buildFromTextStub bool
+	parallel                 int
+	keepGoing                int
+	verbose                  bool
+	checkbuild               bool
+	dist                     bool
+	jsonModuleGraph          bool
+	apiBp2build              bool // Generate BUILD files for Soong modules that contribute APIs
+	bp2build                 bool
+	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
+	skipSoong                bool
+	skipNinja                bool
+	skipSoongTests           bool
+	searchApiDir             bool // Scan the Android.bp files generated in out/api_surfaces
+	skipMetricsUpload        bool
+	buildStartedTime         int64 // For metrics-upload-only - manually specify a build-started time
+	buildFromTextStub        bool
+	ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
 
 	// From the product config
 	katiArgs        []string
@@ -813,9 +814,6 @@
 			//   by a previous build.
 			c.skipConfig = true
 			c.skipKati = true
-		} else if arg == "--skip-kati" {
-			// TODO: remove --skip-kati once module builds have been migrated to --song-only
-			c.skipKati = true
 		} else if arg == "--soong-only" {
 			c.skipKati = true
 			c.skipKatiNinja = true
@@ -883,6 +881,8 @@
 			} else {
 				ctx.Fatalf("Error parsing build-time-started-unix-millis", err)
 			}
+		} else if arg == "--ensure-allowlist-integrity" {
+			c.ensureAllowlistIntegrity = true
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -1710,6 +1710,10 @@
 	return c.skipMetricsUpload
 }
 
+func (c *configImpl) EnsureAllowlistIntegrity() bool {
+	return c.ensureAllowlistIntegrity
+}
+
 // Returns a Time object if one was passed via a command-line flag.
 // Otherwise returns the passed default.
 func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 9287731..563199b 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -288,6 +288,9 @@
 	if config.buildFromTextStub {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-text-stub")
 	}
+	if config.ensureAllowlistIntegrity {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--ensure-allowlist-integrity")
+	}
 
 	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/bazel_metrics_proto/bazel_metrics.pb.go b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
index f8b8fd6..bf5e80b 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
@@ -14,8 +14,8 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.0
-// 	protoc        v3.21.7
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
 // source: bazel_metrics.proto
 
 package bazel_metrics_proto
@@ -41,6 +41,7 @@
 
 	PhaseTimings []*PhaseTiming `protobuf:"bytes,1,rep,name=phase_timings,json=phaseTimings,proto3" json:"phase_timings,omitempty"`
 	Total        *int64         `protobuf:"varint,2,opt,name=total,proto3,oneof" json:"total,omitempty"`
+	ExitCode     *int32         `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"`
 }
 
 func (x *BazelMetrics) Reset() {
@@ -89,6 +90,13 @@
 	return 0
 }
 
+func (x *BazelMetrics) GetExitCode() int32 {
+	if x != nil && x.ExitCode != nil {
+		return *x.ExitCode
+	}
+	return 0
+}
+
 type PhaseTiming struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -161,15 +169,18 @@
 	0x0a, 0x13, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
 	0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x22, 0x80, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x22, 0xb0, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
 	0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e,
 	0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
 	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74,
 	0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67,
 	0x52, 0x0c, 0x70, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19,
 	0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
-	0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f,
-	0x74, 0x61, 0x6c, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
+	0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x78, 0x69,
+	0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x08,
+	0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f,
+	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63,
+	0x6f, 0x64, 0x65, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
 	0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
 	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65,
 	0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74,
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
index 57eed4c..9073080 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
@@ -20,6 +20,7 @@
 message BazelMetrics {
   repeated PhaseTiming phase_timings = 1;
   optional int64 total = 2;
+  optional int32 exit_code = 3;
 }
 
 message PhaseTiming {