Merge "Fix the way manifest fixer detects optional <uses-library> entries."
diff --git a/android/bazel.go b/android/bazel.go
index e3d017f..fa19e52 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -148,11 +148,12 @@
 		// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
 		// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
 		"external/bazelbuild-rules_android":/* recursive = */ true,
+		"external/bazel-skylib":/* recursive = */ true,
 
 		"prebuilts/sdk":/* recursive = */ false,
 		"prebuilts/sdk/tools":/* recursive = */ false,
 		"prebuilts/r8":/* recursive = */ false,
-		"packages/apps/Music":/* recursive = */ false,
+		"packages/apps/Music":/* recursive = */ true,
 	}
 
 	// Configure modules in these directories to enable bp2build_available: true or false by default.
@@ -166,9 +167,10 @@
 		"system/logging/liblog":           Bp2BuildDefaultTrueRecursively,
 		"system/timezone/apex":            Bp2BuildDefaultTrueRecursively,
 		"system/timezone/output_data":     Bp2BuildDefaultTrueRecursively,
-		"external/jemalloc_new":           Bp2BuildDefaultTrueRecursively,
-		"external/fmtlib":                 Bp2BuildDefaultTrueRecursively,
 		"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
+		"external/fmtlib":                 Bp2BuildDefaultTrueRecursively,
+		"external/jemalloc_new":           Bp2BuildDefaultTrueRecursively,
+		"external/libcxxabi":              Bp2BuildDefaultTrueRecursively,
 		"external/scudo":                  Bp2BuildDefaultTrueRecursively,
 		"prebuilts/clang/host/linux-x86":  Bp2BuildDefaultTrueRecursively,
 	}
@@ -231,7 +233,10 @@
 
 	// Per-module denylist to opt modules out of mixed builds. Such modules will
 	// still be generated via bp2build.
-	mixedBuildsDisabledList = []string{}
+	mixedBuildsDisabledList = []string{
+		"libc++abi",      // http://b/195970501, cc_library_static, duplicate symbols because it propagates libc objects.
+		"libc++demangle", // http://b/195970501, cc_library_static, duplicate symbols because it propagates libc objects.
+	}
 
 	// Used for quicker lookups
 	bp2buildModuleDoNotConvert  = map[string]bool{}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 341d500..0e7c944 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -57,6 +57,17 @@
 	archType    ArchType
 }
 
+// bazelHandler is the interface for a helper object related to deferring to Bazel for
+// processing a module (during Bazel mixed builds). Individual module types should define
+// their own bazel handler if they support deferring to Bazel.
+type BazelHandler interface {
+	// Issue query to Bazel to retrieve information about Bazel's view of the current module.
+	// If Bazel returns this information, set module properties on the current module to reflect
+	// the returned information.
+	// Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
+	GenerateBazelBuildActions(ctx ModuleContext, label string) bool
+}
+
 type BazelContext interface {
 	// The below methods involve queuing cquery requests to be later invoked
 	// by bazel. If any of these methods return (_, false), then the request
@@ -69,6 +80,9 @@
 	// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
 	GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error)
 
+	// Returns the executable binary resultant from building together the python sources
+	GetPythonBinary(label string, archType ArchType) (string, bool)
+
 	// ** End cquery methods
 
 	// Issues commands to Bazel to receive results for all cquery requests
@@ -123,8 +137,9 @@
 type MockBazelContext struct {
 	OutputBaseDir string
 
-	LabelToOutputFiles map[string][]string
-	LabelToCcInfo      map[string]cquery.CcInfo
+	LabelToOutputFiles  map[string][]string
+	LabelToCcInfo       map[string]cquery.CcInfo
+	LabelToPythonBinary map[string]string
 }
 
 func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
@@ -137,6 +152,11 @@
 	return result, ok, nil
 }
 
+func (m MockBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
+	result, ok := m.LabelToPythonBinary[label]
+	return result, ok
+}
+
 func (m MockBazelContext) InvokeBazel() error {
 	panic("unimplemented")
 }
@@ -174,6 +194,16 @@
 	return ret, ok, err
 }
 
+func (bazelCtx *bazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
+	rawString, ok := bazelCtx.cquery(label, cquery.GetPythonBinary, archType)
+	var ret string
+	if ok {
+		bazelOutput := strings.TrimSpace(rawString)
+		ret = cquery.GetPythonBinary.ParseResult(bazelOutput)
+	}
+	return ret, ok
+}
+
 func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
 	panic("unimplemented")
 }
@@ -182,6 +212,10 @@
 	panic("unimplemented")
 }
 
+func (n noopBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
+	panic("unimplemented")
+}
+
 func (n noopBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
 	panic("unimplemented")
 }
diff --git a/android/config.go b/android/config.go
index b3b8f3c..e3d05a6 100644
--- a/android/config.go
+++ b/android/config.go
@@ -209,6 +209,20 @@
 		Bool(configurable.GcovCoverage) ||
 			Bool(configurable.ClangCoverage))
 
+	// when Platform_sdk_final is true (or PLATFORM_VERSION_CODENAME is REL), use Platform_sdk_version;
+	// if false (pre-released version, for example), use Platform_sdk_codename.
+	if Bool(configurable.Platform_sdk_final) {
+		if configurable.Platform_sdk_version != nil {
+			configurable.Platform_sdk_version_or_codename =
+				proptools.StringPtr(strconv.Itoa(*(configurable.Platform_sdk_version)))
+		} else {
+			return fmt.Errorf("Platform_sdk_version cannot be pointed by a NULL pointer")
+		}
+	} else {
+		configurable.Platform_sdk_version_or_codename =
+			proptools.StringPtr(String(configurable.Platform_sdk_codename))
+	}
+
 	return saveToBazelConfigFile(configurable, filepath.Dir(filename))
 }
 
diff --git a/android/filegroup.go b/android/filegroup.go
index e207412..97dd136 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,8 +15,9 @@
 package android
 
 import (
-	"android/soong/bazel"
 	"strings"
+
+	"android/soong/bazel"
 )
 
 func init() {
@@ -108,7 +109,7 @@
 	return module
 }
 
-func (fg *fileGroup) generateBazelBuildActions(ctx ModuleContext) bool {
+func (fg *fileGroup) GenerateBazelBuildActions(ctx ModuleContext) bool {
 	if !fg.MixedBuildsEnabled(ctx) {
 		return false
 	}
@@ -131,7 +132,7 @@
 }
 
 func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
-	if fg.generateBazelBuildActions(ctx) {
+	if fg.GenerateBazelBuildActions(ctx) {
 		return
 	}
 
diff --git a/android/module.go b/android/module.go
index 5e2e06a..7451e09 100644
--- a/android/module.go
+++ b/android/module.go
@@ -235,8 +235,8 @@
 
 	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
 	// direct dependencies on the same module visit will be called multiple times on that module
-	// and OtherModuleDependencyTag will return a different tag for each.  It skips any
-	// dependencies that are not an android.Module.
+	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the
+	// dependencies are not an android.Module.
 	//
 	// The Module passed to the visit function should not be retained outside of the visit
 	// function, it may be invalidated by future mutators.
diff --git a/android/variable.go b/android/variable.go
index 0fb9078..5cf9aa8 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -42,6 +42,10 @@
 			Cflags  []string
 		}
 
+		Platform_sdk_version_or_codename struct {
+			Java_resource_dirs []string
+		}
+
 		// unbundled_build is a catch-all property to annotate modules that don't build in one or
 		// more unbundled branches, usually due to dependencies missing from the manifest.
 		Unbundled_build struct {
@@ -164,6 +168,7 @@
 	Platform_version_name                     *string  `json:",omitempty"`
 	Platform_sdk_version                      *int     `json:",omitempty"`
 	Platform_sdk_codename                     *string  `json:",omitempty"`
+	Platform_sdk_version_or_codename          *string  `json:",omitempty"`
 	Platform_sdk_final                        *bool    `json:",omitempty"`
 	Platform_version_active_codenames         []string `json:",omitempty"`
 	Platform_vndk_version                     *string  `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index e525aff..add506f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1587,6 +1587,7 @@
 	JacocoReportClassesFile() android.Path
 	Certificate() java.Certificate
 	BaseModuleName() string
+	LintDepSets() java.LintDepSets
 }
 
 var _ androidApp = (*java.AndroidApp)(nil)
@@ -1601,6 +1602,7 @@
 	fileToCopy := aapp.OutputFile()
 	af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp)
 	af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
+	af.lintDepSets = aapp.LintDepSets()
 	af.certificate = aapp.Certificate()
 
 	if app, ok := aapp.(interface {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 41bfcea..f07bf63 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4663,6 +4663,7 @@
 
 			prebuilt_bootclasspath_fragment {
 				name: "art-bootclasspath-fragment",
+				image_name: "art",
 				contents: ["core-oj"],
 				hidden_api: {
 					annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
@@ -4871,7 +4872,7 @@
 
 func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
 	preparer := android.GroupFixturePreparers(
-		java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar"),
+		java.FixtureConfigureApexBootJars("myapex:libfoo", "myapex:libbar"),
 		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
 		// is disabled.
 		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
@@ -4949,6 +4950,7 @@
 			name: "libfoo",
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
 		}
 
 		java_sdk_library_import {
@@ -4958,6 +4960,7 @@
 			},
 			apex_available: ["myapex"],
 			shared_library: false,
+			permitted_packages: ["bar"],
 		}
 	`
 
@@ -4998,6 +5001,7 @@
 			name: "libfoo",
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
 		}
 
 		java_sdk_library_import {
@@ -5007,6 +5011,7 @@
 			},
 			apex_available: ["myapex"],
 			shared_library: false,
+			permitted_packages: ["bar"],
 		}
 	`
 
@@ -5120,6 +5125,7 @@
 			prefer: true,
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
 		}
 
 		java_library {
@@ -5136,6 +5142,7 @@
 			},
 			apex_available: ["myapex"],
 			shared_library: false,
+			permitted_packages: ["bar"],
 		}
 
 		java_sdk_library {
@@ -5209,6 +5216,7 @@
 			name: "libfoo",
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
 		}
 
 		java_sdk_library_import {
@@ -5225,6 +5233,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			unsafe_ignore_missing_latest_api: true,
 			apex_available: ["myapex"],
+			permitted_packages: ["bar"],
 		}
 	`
 
@@ -5286,6 +5295,7 @@
 			prefer: true,
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
 		}
 
 		java_library {
@@ -5302,6 +5312,7 @@
 			},
 			apex_available: ["myapex"],
 			shared_library: false,
+			permitted_packages: ["bar"],
 		}
 
 		java_sdk_library {
@@ -6899,6 +6910,7 @@
 			apex_available: [
 				"some-updatable-apex",
 			],
+			permitted_packages: ["some.updatable.apex.lib"],
 		}
 
 		java_library {
@@ -6908,6 +6920,7 @@
 				"some-non-updatable-apex",
 			],
 			compile_dex: true,
+			permitted_packages: ["some.non.updatable.apex.lib"],
 		}
 
 		bootclasspath_fragment {
@@ -7118,7 +7131,9 @@
 				"myapex",
 			],
 		}
-	`)
+	`,
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
+	)
 }
 
 func TestNoUpdatableJarsInBootImage(t *testing.T) {
@@ -7148,18 +7163,30 @@
 	}
 
 	t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
-		preparer := java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib")
-		fragment := java.ApexVariantReference{
-			Apex:   proptools.StringPtr("com.android.art.debug"),
-			Module: proptools.StringPtr("art-bootclasspath-fragment"),
+		preparer := android.GroupFixturePreparers(
+			java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib"),
+			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+		)
+		fragments := []java.ApexVariantReference{
+			{
+				Apex:   proptools.StringPtr("com.android.art.debug"),
+				Module: proptools.StringPtr("art-bootclasspath-fragment"),
+			},
+			{
+				Apex:   proptools.StringPtr("some-non-updatable-apex"),
+				Module: proptools.StringPtr("some-non-updatable-fragment"),
+			},
 		}
-		testNoUpdatableJarsInBootImage(t, "", preparer, fragment)
+		testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
 	})
 
 	t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
 		err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image`
 		// Update the dexpreopt BootJars directly.
-		preparer := prepareSetBootJars("com.android.art.debug:some-art-lib")
+		preparer := android.GroupFixturePreparers(
+			prepareSetBootJars("com.android.art.debug:some-art-lib"),
+			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+		)
 		testNoUpdatableJarsInBootImage(t, err, preparer)
 	})
 
@@ -7179,12 +7206,15 @@
 
 	t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
 		err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
-		preparer := java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib")
+		preparer := android.GroupFixturePreparers(
+			java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib"),
+			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+		)
 		testNoUpdatableJarsInBootImage(t, err, preparer)
 	})
 
 	t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
-		preparer := java.FixtureConfigureBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+		preparer := java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
 		fragment := java.ApexVariantReference{
 			Apex:   proptools.StringPtr("some-non-updatable-apex"),
 			Module: proptools.StringPtr("some-non-updatable-fragment"),
@@ -7212,13 +7242,22 @@
 	})
 
 	t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
-		preparer := java.FixtureConfigureBootJars("platform:some-platform-lib")
-		testNoUpdatableJarsInBootImage(t, "", preparer)
+		preparer := android.GroupFixturePreparers(
+			java.FixtureConfigureBootJars("platform:some-platform-lib"),
+			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+		)
+		fragments := []java.ApexVariantReference{
+			{
+				Apex:   proptools.StringPtr("some-non-updatable-apex"),
+				Module: proptools.StringPtr("some-non-updatable-fragment"),
+			},
+		}
+		testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
 	})
 }
 
 func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
-	preparer := java.FixtureConfigureBootJars("myapex:libfoo")
+	preparer := java.FixtureConfigureApexBootJars("myapex:libfoo")
 	t.Run("prebuilt no source", func(t *testing.T) {
 		fragment := java.ApexVariantReference{
 			Apex:   proptools.StringPtr("myapex"),
@@ -7256,6 +7295,7 @@
 				name: "libfoo",
 				jars: ["libfoo.jar"],
 				apex_available: ["myapex"],
+				permitted_packages: ["libfoo"],
 			}
 		`, "", preparer, fragment)
 	})
@@ -8168,6 +8208,8 @@
 		java.PrepareForTestWithJavaDefaultModules,
 		android.PrepareForTestWithAndroidBuildComponents,
 		android.FixtureWithRootAndroidBp(bp),
+		dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"),
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"),
 		android.FixtureMergeEnv(map[string]string{
 			"EMMA_INSTRUMENT": "true",
 		}),
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 6098989..3e19014 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -130,7 +130,8 @@
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
 		// Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
-		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
+		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+		java.FixtureConfigureApexBootJars("someapex:foo", "someapex:bar"),
 		prepareForTestWithArtApex,
 
 		java.PrepareForTestWithJavaSdkLibraryFiles,
@@ -642,7 +643,7 @@
 		prepareForTestWithBootclasspathFragment,
 		prepareForTestWithMyapex,
 		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
-		java.FixtureConfigureBootJars("myapex:foo", "myapex:bar"),
+		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
 		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
 		// is disabled.
 		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
@@ -893,7 +894,8 @@
 		prepareForTestWithArtApex,
 		prepareForTestWithMyapex,
 		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
-		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
+		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
 		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
 		// is disabled.
 		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
@@ -1062,7 +1064,8 @@
 		prepareForTestWithArtApex,
 		prepareForTestWithMyapex,
 		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
-		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
+		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
 		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
 		// is disabled.
 		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
diff --git a/apex/builder.go b/apex/builder.go
index 148f42f..5baa5c0 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -75,7 +75,7 @@
 	// by default set to (uid/gid/mode) = (1000/1000/0644)
 	// TODO(b/113082813) make this configurable using config.fs syntax
 	generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{
-		Command: `( echo '/ 1000 1000 0755' ` +
+		Command: `( set -e; echo '/ 1000 1000 0755' ` +
 			`&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` +
 			`&& for i in  ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` +
 			`&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`,
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index 0193127..e2d8465 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -58,6 +58,7 @@
 		}),
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
+		java.FixtureConfigureApexBootJars("myapex:bar"),
 		android.FixtureWithRootAndroidBp(`
 		apex {
 			name: "com.android.art",
@@ -79,6 +80,7 @@
 
 		bootclasspath_fragment {
 			name: "art-bootclasspath-fragment",
+			image_name: "art",
 			apex_available: [
 				"com.android.art",
 			],
@@ -193,6 +195,10 @@
 					apex: "com.android.art",
 					module: "art-bootclasspath-fragment",
 				},
+				{
+					apex: "myapex",
+					module: "mybootclasspath-fragment",
+				},
 			],
 		}
 	`),
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 3066c79..e0421f6 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -39,7 +39,7 @@
 		prepareForTestWithMyapex,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo"),
-		java.FixtureConfigureBootJars("myapex:bar"),
+		java.FixtureConfigureApexBootJars("myapex:bar"),
 		android.FixtureWithRootAndroidBp(`
 			platform_bootclasspath {
 				name: "platform-bootclasspath",
@@ -163,8 +163,8 @@
 	android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
 	android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/index.csv"}, info.IndexPaths)
 
-	android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
-	android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/all-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
+	android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
+	android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
 }
 
 func TestPlatformBootclasspathDependencies(t *testing.T) {
@@ -195,6 +195,7 @@
 
 		bootclasspath_fragment {
 			name: "art-bootclasspath-fragment",
+			image_name: "art",
 			apex_available: [
 				"com.android.art",
 			],
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index 537f51d..a64c6f4 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -15,6 +15,7 @@
 package apex
 
 import (
+	"android/soong/dexpreopt"
 	"testing"
 
 	"android/soong/android"
@@ -30,6 +31,7 @@
 	result := android.GroupFixturePreparers(
 		prepareForTestWithSystemserverclasspathFragment,
 		prepareForTestWithMyapex,
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
@@ -81,6 +83,7 @@
 	result := android.GroupFixturePreparers(
 		prepareForTestWithSystemserverclasspathFragment,
 		prepareForTestWithMyapex,
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 52c6c2f..131f0ec 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -6,8 +6,9 @@
 )
 
 var (
-	GetOutputFiles = &getOutputFilesRequestType{}
-	GetCcInfo      = &getCcInfoType{}
+	GetOutputFiles  = &getOutputFilesRequestType{}
+	GetPythonBinary = &getPythonBinaryRequestType{}
+	GetCcInfo       = &getCcInfoType{}
 )
 
 type CcInfo struct {
@@ -28,6 +29,8 @@
 
 type getOutputFilesRequestType struct{}
 
+type getPythonBinaryRequestType struct{}
+
 // Name returns a string name for this request type. Such request type names must be unique,
 // and must only consist of alphanumeric characters.
 func (g getOutputFilesRequestType) Name() string {
@@ -53,6 +56,31 @@
 	return splitOrEmpty(rawString, ", ")
 }
 
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
+func (g getPythonBinaryRequestType) Name() string {
+	return "getPythonBinary"
+}
+
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information.
+// The function should have the following properties:
+//   - `target` is the only parameter to this function (a configured target).
+//   - The return value must be a string.
+//   - The function body should not be indented outside of its own scope.
+func (g getPythonBinaryRequestType) StarlarkFunctionBody() string {
+	return "return providers(target)['FilesToRunProvider'].executable.path"
+}
+
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getPythonBinaryRequestType) ParseResult(rawString string) string {
+	return rawString
+}
+
 type getCcInfoType struct{}
 
 // Name returns a string name for this request type. Such request type names must be unique,
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 035544e..49019ab 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -37,6 +37,31 @@
 	}
 }
 
+func TestGetPythonBinaryParseResults(t *testing.T) {
+	testCases := []struct {
+		description    string
+		input          string
+		expectedOutput string
+	}{
+		{
+			description:    "no result",
+			input:          "",
+			expectedOutput: "",
+		},
+		{
+			description:    "one result",
+			input:          "test",
+			expectedOutput: "test",
+		},
+	}
+	for _, tc := range testCases {
+		actualOutput := GetPythonBinary.ParseResult(tc.input)
+		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+		}
+	}
+}
+
 func TestGetCcInfoParseResults(t *testing.T) {
 	testCases := []struct {
 		description          string
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 9ec637a..78e3a74 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -39,6 +39,7 @@
         "cc_library_static_conversion_test.go",
         "cc_object_conversion_test.go",
         "conversion_test.go",
+        "performance_test.go",
         "prebuilt_etc_conversion_test.go",
         "python_binary_conversion_test.go",
         "sh_conversion_test.go",
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index e5dbda6..eb3a73f 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -334,9 +334,7 @@
 		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
 		ctx := android.NewTestContext(config)
 
-		ctx.RegisterModuleType("custom", customModuleFactory)
-		ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator)
-		ctx.RegisterForBazelConversion()
+		registerCustomModuleForBp2buildConversion(ctx)
 
 		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
 		if errored(t, "", errs) {
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 204c519..9e0c0a1 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -85,6 +85,7 @@
         "soong_module_variant": attr.string(),
         "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
         "arch_paths": attr.string_list(),
+        "arch_paths_exclude": attr.string_list(),
         # bazel_module start
 #         "label": attr.string(),
 #         "bp2build_available": attr.bool(),
@@ -114,6 +115,7 @@
         "soong_module_variant": attr.string(),
         "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
         "arch_paths": attr.string_list(),
+        "arch_paths_exclude": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
@@ -139,6 +141,7 @@
         "soong_module_variant": attr.string(),
         "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
         "arch_paths": attr.string_list(),
+        "arch_paths_exclude": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go
new file mode 100644
index 0000000..3283952
--- /dev/null
+++ b/bp2build/performance_test.go
@@ -0,0 +1,175 @@
+// Copyright 2021 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 bp2build
+
+// to run the benchmarks in this file, you must run go test with the -bench.
+// The benchmarked portion will run for the specified time (can be set via -benchtime)
+// This can mean if you are benchmarking a faster portion of a larger operation, it will take
+// longer.
+// If you are seeing a small number of iterations for a specific run, the data is less reliable, to
+// run for longer, set -benchtime to a larger value.
+
+import (
+	"android/soong/android"
+	"fmt"
+	"math"
+	"strings"
+	"testing"
+)
+
+func genCustomModule(i int, convert bool) string {
+	var conversionString string
+	if convert {
+		conversionString = `bazel_module: { bp2build_available: true },`
+	}
+	return fmt.Sprintf(`
+custom {
+    name: "arch_paths_%[1]d",
+    string_list_prop: ["\t", "\n"],
+    string_prop: "a\t\n\r",
+    arch_paths: ["outer", ":outer_dep_%[1]d"],
+    arch: {
+      x86: {
+        arch_paths: ["abc", ":x86_dep_%[1]d"],
+      },
+      x86_64: {
+        arch_paths: ["64bit"],
+        arch_paths_exclude: ["outer"],
+      },
+    },
+		%[2]s
+}
+
+custom {
+    name: "outer_dep_%[1]d",
+		%[2]s
+}
+
+custom {
+    name: "x86_dep_%[1]d",
+		%[2]s
+}
+`, i, conversionString)
+}
+
+func genCustomModuleBp(pctConverted float64) string {
+	modules := 100
+
+	bp := make([]string, 0, modules)
+	toConvert := int(math.Round(float64(modules) * pctConverted))
+
+	for i := 0; i < modules; i++ {
+		bp = append(bp, genCustomModule(i, i < toConvert))
+	}
+	return strings.Join(bp, "\n\n")
+}
+
+var pctToConvert = []float64{0.0, 0.01, 0.05, 0.10, 0.25, 0.5, 0.75, 1.0}
+
+func BenchmarkManyModulesFull(b *testing.B) {
+	dir := "."
+	for _, tcSize := range pctToConvert {
+
+		b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
+			for n := 0; n < b.N; n++ {
+				b.StopTimer()
+				// setup we don't want to measure
+				config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
+				ctx := android.NewTestContext(config)
+
+				registerCustomModuleForBp2buildConversion(ctx)
+				codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+
+				b.StartTimer()
+				_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+				if len(errs) > 0 {
+					b.Fatalf("Unexpected errors: %s", errs)
+				}
+
+				_, errs = ctx.ResolveDependencies(config)
+				if len(errs) > 0 {
+					b.Fatalf("Unexpected errors: %s", errs)
+				}
+
+				generateBazelTargetsForDir(codegenCtx, dir)
+				b.StopTimer()
+			}
+		})
+	}
+}
+
+func BenchmarkManyModulesResolveDependencies(b *testing.B) {
+	dir := "."
+	for _, tcSize := range pctToConvert {
+
+		b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
+			for n := 0; n < b.N; n++ {
+				b.StopTimer()
+				// setup we don't want to measure
+				config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
+				ctx := android.NewTestContext(config)
+
+				registerCustomModuleForBp2buildConversion(ctx)
+				codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+
+				_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+				if len(errs) > 0 {
+					b.Fatalf("Unexpected errors: %s", errs)
+				}
+
+				b.StartTimer()
+				_, errs = ctx.ResolveDependencies(config)
+				b.StopTimer()
+				if len(errs) > 0 {
+					b.Fatalf("Unexpected errors: %s", errs)
+				}
+
+				generateBazelTargetsForDir(codegenCtx, dir)
+			}
+		})
+	}
+}
+
+func BenchmarkManyModulesGenerateBazelTargetsForDir(b *testing.B) {
+	dir := "."
+	for _, tcSize := range pctToConvert {
+
+		b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
+			for n := 0; n < b.N; n++ {
+				b.StopTimer()
+				// setup we don't want to measure
+				config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
+				ctx := android.NewTestContext(config)
+
+				registerCustomModuleForBp2buildConversion(ctx)
+				codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+
+				_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+				if len(errs) > 0 {
+					b.Fatalf("Unexpected errors: %s", errs)
+				}
+
+				_, errs = ctx.ResolveDependencies(config)
+				if len(errs) > 0 {
+					b.Fatalf("Unexpected errors: %s", errs)
+				}
+
+				b.StartTimer()
+				generateBazelTargetsForDir(codegenCtx, dir)
+				b.StopTimer()
+			}
+		})
+	}
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index f3cd7f0..faf1a44 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -33,7 +33,8 @@
 	Nested_props     nestedProps
 	Nested_props_ptr *nestedProps
 
-	Arch_paths []string `android:"path,arch_variant"`
+	Arch_paths         []string `android:"path,arch_variant"`
+	Arch_paths_exclude []string `android:"path,arch_variant"`
 }
 
 type customModule struct {
@@ -155,16 +156,18 @@
 			return
 		}
 
-		paths := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.props.Arch_paths))
+		paths := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.props.Arch_paths, m.props.Arch_paths_exclude))
 
 		for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
 			for config, props := range configToProps {
 				if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
-					paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, archProps.Arch_paths))
+					paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude))
 				}
 			}
 		}
 
+		paths.ResolveExcludes()
+
 		attrs := &customBazelModuleAttributes{
 			String_prop:      m.props.String_prop,
 			String_list_prop: m.props.String_list_prop,
@@ -216,3 +219,9 @@
 	buildFileToTargets, _, _ := GenerateBazelTargets(codegenCtx, false)
 	return buildFileToTargets[dir]
 }
+
+func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
+	ctx.RegisterModuleType("custom", customModuleFactory)
+	ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator)
+	ctx.RegisterForBazelConversion()
+}
diff --git a/cc/Android.bp b/cc/Android.bp
index 164d32b..bff2761 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -13,6 +13,7 @@
         "soong-bazel",
         "soong-cc-config",
         "soong-etc",
+        "soong-fuzz",
         "soong-genrule",
         "soong-snapshot",
         "soong-tradefed",
@@ -59,7 +60,6 @@
         "binary.go",
         "binary_sdk_member.go",
         "fuzz.go",
-        "fuzz_common.go",
         "library.go",
         "library_headers.go",
         "library_sdk_member.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 7a57477..1706d72 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -240,6 +240,8 @@
 	// C++ options and sources
 	cppFlags bazel.StringListAttribute
 	srcs     bazel.LabelListAttribute
+
+	rtti bazel.BoolAttribute
 }
 
 // bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
@@ -249,6 +251,7 @@
 	var asFlags bazel.StringListAttribute
 	var conlyFlags bazel.StringListAttribute
 	var cppFlags bazel.StringListAttribute
+	var rtti bazel.BoolAttribute
 
 	// Creates the -I flags for a directory, while making the directory relative
 	// to the exec root for Bazel to work.
@@ -302,6 +305,7 @@
 			asFlags.Value = parseCommandLineFlags(baseCompilerProps.Asflags)
 			conlyFlags.Value = parseCommandLineFlags(baseCompilerProps.Conlyflags)
 			cppFlags.Value = parseCommandLineFlags(baseCompilerProps.Cppflags)
+			rtti.Value = baseCompilerProps.Rtti
 
 			for _, dir := range parseLocalIncludeDirs(baseCompilerProps) {
 				copts.Value = append(copts.Value, includeFlags(dir)...)
@@ -345,6 +349,7 @@
 				asFlags.SetSelectValue(axis, config, archVariantAsflags)
 				conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(baseCompilerProps.Conlyflags))
 				cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(baseCompilerProps.Cppflags))
+				rtti.SetSelectValue(axis, config, baseCompilerProps.Rtti)
 			}
 		}
 	}
@@ -380,6 +385,7 @@
 		cSrcs:      cSrcs,
 		conlyFlags: conlyFlags,
 		cppFlags:   cppFlags,
+		rtti:       rtti,
 	}
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index 39d89e5..f65af30 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -29,6 +29,7 @@
 
 	"android/soong/android"
 	"android/soong/cc/config"
+	"android/soong/fuzz"
 	"android/soong/genrule"
 )
 
@@ -589,17 +590,6 @@
 	installInRoot() bool
 }
 
-// bazelHandler is the interface for a helper object related to deferring to Bazel for
-// processing a module (during Bazel mixed builds). Individual module types should define
-// their own bazel handler if they support deferring to Bazel.
-type bazelHandler interface {
-	// Issue query to Bazel to retrieve information about Bazel's view of the current module.
-	// If Bazel returns this information, set module properties on the current module to reflect
-	// the returned information.
-	// Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
-	generateBazelBuildActions(ctx android.ModuleContext, label string) bool
-}
-
 type xref interface {
 	XrefCcFiles() android.Paths
 }
@@ -773,7 +763,7 @@
 // members of the cc.Module to this decorator. Thus, a cc_binary module has custom linker and
 // installer logic.
 type Module struct {
-	FuzzModule
+	fuzz.FuzzModule
 
 	android.SdkBase
 	android.BazelModuleBase
@@ -796,7 +786,7 @@
 	compiler     compiler
 	linker       linker
 	installer    installer
-	bazelHandler bazelHandler
+	bazelHandler android.BazelHandler
 
 	features []feature
 	stl      *stl
@@ -1696,7 +1686,7 @@
 	bazelModuleLabel := c.GetBazelLabel(actx, c)
 	bazelActionsUsed := false
 	if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil {
-		bazelActionsUsed = c.bazelHandler.generateBazelBuildActions(actx, bazelModuleLabel)
+		bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel)
 	}
 	return bazelActionsUsed
 }
@@ -3426,7 +3416,7 @@
 		&TestProperties{},
 		&TestBinaryProperties{},
 		&BenchmarkProperties{},
-		&FuzzProperties{},
+		&fuzz.FuzzProperties{},
 		&StlProperties{},
 		&SanitizeProperties{},
 		&StripProperties{},
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 812a245..2d6bcb8 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -96,31 +96,25 @@
 	pctx.SourcePathVariable("Arm64GccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/aarch64/aarch64-linux-android-${arm64GccVersion}")
 
-	pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
-	pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " "))
+	exportStringListStaticVariable("Arm64Ldflags", arm64Ldflags)
+	exportStringListStaticVariable("Arm64Lldflags", arm64Lldflags)
 
-	pctx.StaticVariable("Arm64Cflags", strings.Join(arm64Cflags, " "))
-	pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
+	exportStringListStaticVariable("Arm64Cflags", arm64Cflags)
+	exportStringListStaticVariable("Arm64Cppflags", arm64Cppflags)
+
+	exportedStringListDictVars.Set("Arm64ArchVariantCflags", arm64ArchVariantCflags)
+	exportedStringListDictVars.Set("Arm64CpuVariantCflags", arm64CpuVariantCflags)
 
 	pctx.StaticVariable("Arm64Armv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
 	pctx.StaticVariable("Arm64Armv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " "))
 	pctx.StaticVariable("Arm64Armv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
 	pctx.StaticVariable("Arm64Armv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
 
-	pctx.StaticVariable("Arm64CortexA53Cflags",
-		strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
-
-	pctx.StaticVariable("Arm64CortexA55Cflags",
-		strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
-
-	pctx.StaticVariable("Arm64KryoCflags",
-		strings.Join(arm64CpuVariantCflags["kryo"], " "))
-
-	pctx.StaticVariable("Arm64ExynosM1Cflags",
-		strings.Join(arm64CpuVariantCflags["exynos-m1"], " "))
-
-	pctx.StaticVariable("Arm64ExynosM2Cflags",
-		strings.Join(arm64CpuVariantCflags["exynos-m2"], " "))
+	pctx.StaticVariable("Arm64CortexA53Cflags", strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
+	pctx.StaticVariable("Arm64CortexA55Cflags", strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
+	pctx.StaticVariable("Arm64KryoCflags", strings.Join(arm64CpuVariantCflags["kryo"], " "))
+	pctx.StaticVariable("Arm64ExynosM1Cflags", strings.Join(arm64CpuVariantCflags["exynos-m1"], " "))
+	pctx.StaticVariable("Arm64ExynosM2Cflags", strings.Join(arm64CpuVariantCflags["exynos-m2"], " "))
 }
 
 var (
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index b5afe40..0fe5e68 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -188,6 +188,9 @@
 	exportStringListStaticVariable("ArmArmCflags", armArmCflags)
 	exportStringListStaticVariable("ArmThumbCflags", armThumbCflags)
 
+	exportedStringListDictVars.Set("ArmArchVariantCflags", armArchVariantCflags)
+	exportedStringListDictVars.Set("ArmCpuVariantCflags", armCpuVariantCflags)
+
 	// Clang arch variant cflags
 	exportStringListStaticVariable("ArmArmv7ACflags", armArchVariantCflags["armv7-a"])
 	exportStringListStaticVariable("ArmArmv7ANeonCflags", armArchVariantCflags["armv7-a-neon"])
diff --git a/cc/config/bp2build.go b/cc/config/bp2build.go
index e7e94a8..d19f5ac 100644
--- a/cc/config/bp2build.go
+++ b/cc/config/bp2build.go
@@ -15,98 +15,182 @@
 package config
 
 import (
-	"android/soong/android"
 	"fmt"
 	"regexp"
+	"sort"
 	"strings"
 )
 
+const (
+	bazelIndent = 4
+)
+
+type bazelVarExporter interface {
+	asBazel(exportedStringVariables, exportedStringListVariables) []bazelConstant
+}
+
 // Helpers for exporting cc configuration information to Bazel.
 var (
 	// Map containing toolchain variables that are independent of the
 	// environment variables of the build.
-	exportedStringListVars = exportedStringListVariables{}
-	exportedStringVars     = exportedStringVariables{}
+	exportedStringListVars     = exportedStringListVariables{}
+	exportedStringVars         = exportedStringVariables{}
+	exportedStringListDictVars = exportedStringListDictVariables{}
 )
 
+// Ensure that string s has no invalid characters to be generated into the bzl file.
+func validateCharacters(s string) string {
+	for _, c := range []string{`\n`, `"`, `\`} {
+		if strings.Contains(s, c) {
+			panic(fmt.Errorf("%s contains illegal character %s", s, c))
+		}
+	}
+	return s
+}
+
+type bazelConstant struct {
+	variableName       string
+	internalDefinition string
+}
+
 type exportedStringVariables map[string]string
-type exportedStringListVariables map[string][]string
 
 func (m exportedStringVariables) Set(k string, v string) {
 	m[k] = v
 }
 
+func bazelIndention(level int) string {
+	return strings.Repeat(" ", level*bazelIndent)
+}
+
+func printBazelList(items []string, indentLevel int) string {
+	list := make([]string, 0, len(items)+2)
+	list = append(list, "[")
+	innerIndent := bazelIndention(indentLevel + 1)
+	for _, item := range items {
+		list = append(list, fmt.Sprintf(`%s"%s",`, innerIndent, item))
+	}
+	list = append(list, bazelIndention(indentLevel)+"]")
+	return strings.Join(list, "\n")
+}
+
+func (m exportedStringVariables) asBazel(stringScope exportedStringVariables, stringListScope exportedStringListVariables) []bazelConstant {
+	ret := make([]bazelConstant, 0, len(m))
+	for k, variableValue := range m {
+		expandedVar := expandVar(variableValue, exportedStringVars, exportedStringListVars)
+		if len(expandedVar) > 1 {
+			panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
+		}
+		ret = append(ret, bazelConstant{
+			variableName:       k,
+			internalDefinition: fmt.Sprintf(`"%s"`, validateCharacters(expandedVar[0])),
+		})
+	}
+	return ret
+}
+
 // Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
 func exportStringStaticVariable(name string, value string) {
 	pctx.StaticVariable(name, value)
 	exportedStringVars.Set(name, value)
 }
 
+type exportedStringListVariables map[string][]string
+
 func (m exportedStringListVariables) Set(k string, v []string) {
 	m[k] = v
 }
 
+func (m exportedStringListVariables) asBazel(stringScope exportedStringVariables, stringListScope exportedStringListVariables) []bazelConstant {
+	ret := make([]bazelConstant, 0, len(m))
+	// For each exported variable, recursively expand elements in the variableValue
+	// list to ensure that interpolated variables are expanded according to their values
+	// in the variable scope.
+	for k, variableValue := range m {
+		var expandedVars []string
+		for _, v := range variableValue {
+			expandedVars = append(expandedVars, expandVar(v, stringScope, stringListScope)...)
+		}
+		// Assign the list as a bzl-private variable; this variable will be exported
+		// out through a constants struct later.
+		ret = append(ret, bazelConstant{
+			variableName:       k,
+			internalDefinition: printBazelList(expandedVars, 0),
+		})
+	}
+	return ret
+}
+
 // Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
 func exportStringListStaticVariable(name string, value []string) {
 	pctx.StaticVariable(name, strings.Join(value, " "))
 	exportedStringListVars.Set(name, value)
 }
 
+type exportedStringListDictVariables map[string]map[string][]string
+
+func (m exportedStringListDictVariables) Set(k string, v map[string][]string) {
+	m[k] = v
+}
+
+func printBazelStringListDict(dict map[string][]string) string {
+	bazelDict := make([]string, 0, len(dict)+2)
+	bazelDict = append(bazelDict, "{")
+	for k, v := range dict {
+		bazelDict = append(bazelDict,
+			fmt.Sprintf(`%s"%s": %s,`, bazelIndention(1), k, printBazelList(v, 1)))
+	}
+	bazelDict = append(bazelDict, "}")
+	return strings.Join(bazelDict, "\n")
+}
+
+// Since dictionaries are not supported in Ninja, we do not expand variables for dictionaries
+func (m exportedStringListDictVariables) asBazel(_ exportedStringVariables, _ exportedStringListVariables) []bazelConstant {
+	ret := make([]bazelConstant, 0, len(m))
+	for k, dict := range m {
+		ret = append(ret, bazelConstant{
+			variableName:       k,
+			internalDefinition: printBazelStringListDict(dict),
+		})
+	}
+	return ret
+}
+
 // BazelCcToolchainVars generates bzl file content containing variables for
 // Bazel's cc_toolchain configuration.
 func BazelCcToolchainVars() string {
+	return bazelToolchainVars(
+		exportedStringListDictVars,
+		exportedStringListVars,
+		exportedStringVars)
+}
+
+func bazelToolchainVars(vars ...bazelVarExporter) string {
 	ret := "# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.\n\n"
 
-	// Ensure that string s has no invalid characters to be generated into the bzl file.
-	validateCharacters := func(s string) string {
-		for _, c := range []string{`\n`, `"`, `\`} {
-			if strings.Contains(s, c) {
-				panic(fmt.Errorf("%s contains illegal character %s", s, c))
-			}
-		}
-		return s
+	results := []bazelConstant{}
+	for _, v := range vars {
+		results = append(results, v.asBazel(exportedStringVars, exportedStringListVars)...)
 	}
 
-	// For each exported variable, recursively expand elements in the variableValue
-	// list to ensure that interpolated variables are expanded according to their values
-	// in the variable scope.
-	for _, k := range android.SortedStringKeys(exportedStringListVars) {
-		variableValue := exportedStringListVars[k]
-		var expandedVars []string
-		for _, v := range variableValue {
-			expandedVars = append(expandedVars, expandVar(v, exportedStringVars, exportedStringListVars)...)
-		}
-		// Build the list for this variable.
-		list := "["
-		for _, flag := range expandedVars {
-			list += fmt.Sprintf("\n    \"%s\",", validateCharacters(flag))
-		}
-		list += "\n]"
-		// Assign the list as a bzl-private variable; this variable will be exported
-		// out through a constants struct later.
-		ret += fmt.Sprintf("_%s = %s\n", k, list)
-		ret += "\n"
-	}
+	sort.Slice(results, func(i, j int) bool { return results[i].variableName < results[j].variableName })
 
-	for _, k := range android.SortedStringKeys(exportedStringVars) {
-		variableValue := exportedStringVars[k]
-		expandedVar := expandVar(variableValue, exportedStringVars, exportedStringListVars)
-		if len(expandedVar) > 1 {
-			panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
-		}
-		ret += fmt.Sprintf("_%s = \"%s\"\n", k, validateCharacters(expandedVar[0]))
-		ret += "\n"
+	definitions := make([]string, 0, len(results))
+	constants := make([]string, 0, len(results))
+	for _, b := range results {
+		definitions = append(definitions,
+			fmt.Sprintf("_%s = %s", b.variableName, b.internalDefinition))
+		constants = append(constants,
+			fmt.Sprintf("%[1]s%[2]s = _%[2]s,", bazelIndention(1), b.variableName))
 	}
 
 	// Build the exported constants struct.
+	ret += strings.Join(definitions, "\n\n")
+	ret += "\n\n"
 	ret += "constants = struct(\n"
-	for _, k := range android.SortedStringKeys(exportedStringVars) {
-		ret += fmt.Sprintf("    %s = _%s,\n", k, k)
-	}
-	for _, k := range android.SortedStringKeys(exportedStringListVars) {
-		ret += fmt.Sprintf("    %s = _%s,\n", k, k)
-	}
-	ret += ")"
+	ret += strings.Join(constants, "\n")
+	ret += "\n)"
+
 	return ret
 }
 
diff --git a/cc/config/bp2build_test.go b/cc/config/bp2build_test.go
index a4745e6..883597a 100644
--- a/cc/config/bp2build_test.go
+++ b/cc/config/bp2build_test.go
@@ -115,3 +115,143 @@
 		})
 	}
 }
+
+func TestBazelToolchainVars(t *testing.T) {
+	testCases := []struct {
+		name        string
+		vars        []bazelVarExporter
+		expectedOut string
+	}{
+		{
+			name: "exports strings",
+			vars: []bazelVarExporter{
+				exportedStringVariables{
+					"a": "b",
+					"c": "d",
+				},
+			},
+			expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = "b"
+
+_c = "d"
+
+constants = struct(
+    a = _a,
+    c = _c,
+)`,
+		},
+		{
+			name: "exports string lists",
+			vars: []bazelVarExporter{
+				exportedStringListVariables{
+					"a": []string{"b1", "b2"},
+					"c": []string{"d1", "d2"},
+				},
+			},
+			expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = [
+    "b1",
+    "b2",
+]
+
+_c = [
+    "d1",
+    "d2",
+]
+
+constants = struct(
+    a = _a,
+    c = _c,
+)`,
+		},
+		{
+			name: "exports string lists dicts",
+			vars: []bazelVarExporter{
+				exportedStringListDictVariables{
+					"a": map[string][]string{"b1": []string{"b2"}},
+					"c": map[string][]string{"d1": []string{"d2"}},
+				},
+			},
+			expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = {
+    "b1": [
+        "b2",
+    ],
+}
+
+_c = {
+    "d1": [
+        "d2",
+    ],
+}
+
+constants = struct(
+    a = _a,
+    c = _c,
+)`,
+		},
+		{
+			name: "sorts across types",
+			vars: []bazelVarExporter{
+				exportedStringVariables{
+					"b": "b-val",
+					"d": "d-val",
+				},
+				exportedStringListVariables{
+					"c": []string{"c-val"},
+					"e": []string{"e-val"},
+				},
+				exportedStringListDictVariables{
+					"a": map[string][]string{"a1": []string{"a2"}},
+					"f": map[string][]string{"f1": []string{"f2"}},
+				},
+			},
+			expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = {
+    "a1": [
+        "a2",
+    ],
+}
+
+_b = "b-val"
+
+_c = [
+    "c-val",
+]
+
+_d = "d-val"
+
+_e = [
+    "e-val",
+]
+
+_f = {
+    "f1": [
+        "f2",
+    ],
+}
+
+constants = struct(
+    a = _a,
+    b = _b,
+    c = _c,
+    d = _d,
+    e = _e,
+    f = _f,
+)`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			out := bazelToolchainVars(tc.vars...)
+			if out != tc.expectedOut {
+				t.Errorf("Expected \n%s, got \n%s", tc.expectedOut, out)
+			}
+		})
+	}
+}
diff --git a/cc/config/global.go b/cc/config/global.go
index 3daee38..248822f 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -228,6 +228,8 @@
 		"-Wno-non-c-typedef-for-linkage", // http://b/161304145
 		// New warnings to be fixed after clang-r407598
 		"-Wno-string-concatenation", // http://b/175068488
+		// New warnings to be fixed after clang-r428724
+		"-Wno-align-mismatch", // http://b/193679946
 	}
 
 	// Extra cflags for external third-party projects to disable warnings that
@@ -266,8 +268,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r416183b1"
-	ClangDefaultShortVersion = "12.0.7"
+	ClangDefaultVersion      = "clang-r428724"
+	ClangDefaultShortVersion = "13.0.1"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index c4f47a7..00f07ff 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -77,6 +77,14 @@
 		"popcnt": []string{"-mpopcnt"},
 		"aes_ni": []string{"-maes"},
 	}
+
+	x86_64DefaultArchVariantFeatures = []string{
+		"ssse3",
+		"sse4",
+		"sse4_1",
+		"sse4_2",
+		"popcnt",
+	}
 )
 
 const (
@@ -84,37 +92,38 @@
 )
 
 func init() {
-	android.RegisterDefaultArchVariantFeatures(android.Android, android.X86_64,
-		"ssse3",
-		"sse4",
-		"sse4_1",
-		"sse4_2",
-		"popcnt")
+	android.RegisterDefaultArchVariantFeatures(android.Android, android.X86_64, x86_64DefaultArchVariantFeatures...)
+	exportedStringListVars.Set("X86_64DefaultArchVariantFeatures", x86_64DefaultArchVariantFeatures)
 
 	pctx.StaticVariable("x86_64GccVersion", x86_64GccVersion)
 
 	pctx.SourcePathVariable("X86_64GccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86_64GccVersion}")
 
-	pctx.StaticVariable("X86_64ToolchainCflags", "-m64")
-	pctx.StaticVariable("X86_64ToolchainLdflags", "-m64")
+	exportStringListStaticVariable("X86_64ToolchainCflags", []string{"-m64"})
+	exportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"})
 
-	pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
-	pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Ldflags, " "))
+	exportStringListStaticVariable("X86_64Ldflags", x86_64Ldflags)
+	exportStringListStaticVariable("X86_64Lldflags", x86_64Ldflags)
 
 	// Clang cflags
-	pctx.StaticVariable("X86_64Cflags", strings.Join(x86_64Cflags, " "))
-	pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " "))
+	exportStringListStaticVariable("X86_64Cflags", x86_64Cflags)
+	exportStringListStaticVariable("X86_64Cppflags", x86_64Cppflags)
 
 	// Yasm flags
-	pctx.StaticVariable("X86_64YasmFlags", "-f elf64 -m amd64")
+	exportStringListStaticVariable("X86_64YasmFlags", []string{
+		"-f elf64",
+		"-m amd64",
+	})
 
 	// Extended cflags
 
+	exportedStringListDictVars.Set("X86_64ArchVariantCflags", x86_64ArchVariantCflags)
+	exportedStringListDictVars.Set("X86_64ArchFeatureCflags", x86_64ArchFeatureCflags)
+
 	// Architecture variant cflags
 	for variant, cflags := range x86_64ArchVariantCflags {
-		pctx.StaticVariable("X86_64"+variant+"VariantCflags",
-			strings.Join(cflags, " "))
+		pctx.StaticVariable("X86_64"+variant+"VariantCflags", strings.Join(cflags, " "))
 	}
 }
 
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 5e510a4..29f0593 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -97,25 +97,29 @@
 	pctx.SourcePathVariable("X86GccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86GccVersion}")
 
-	pctx.StaticVariable("X86ToolchainCflags", "-m32")
-	pctx.StaticVariable("X86ToolchainLdflags", "-m32")
+	exportStringListStaticVariable("X86ToolchainCflags", []string{"-m32"})
+	exportStringListStaticVariable("X86ToolchainLdflags", []string{"-m32"})
 
-	pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
-	pctx.StaticVariable("X86Lldflags", strings.Join(x86Ldflags, " "))
+	exportStringListStaticVariable("X86Ldflags", x86Ldflags)
+	exportStringListStaticVariable("X86Lldflags", x86Ldflags)
 
 	// Clang cflags
-	pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " "))
-	pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " "))
+	exportStringListStaticVariable("X86Cflags", x86Cflags)
+	exportStringListStaticVariable("X86Cppflags", x86Cppflags)
 
 	// Yasm flags
-	pctx.StaticVariable("X86YasmFlags", "-f elf32 -m x86")
+	exportStringListStaticVariable("X86YasmFlags", []string{
+		"-f elf32",
+		"-m x86",
+	})
 
 	// Extended cflags
+	exportedStringListDictVars.Set("X86ArchVariantCflags", x86ArchVariantCflags)
+	exportedStringListDictVars.Set("X86ArchFeatureCflags", x86ArchFeatureCflags)
 
 	// Architecture variant cflags
 	for variant, cflags := range x86ArchVariantCflags {
-		pctx.StaticVariable("X86"+variant+"VariantCflags",
-			strings.Join(cflags, " "))
+		pctx.StaticVariable("X86"+variant+"VariantCflags", strings.Join(cflags, " "))
 	}
 }
 
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 1d66cb7..e7fcfed 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -110,7 +110,7 @@
 	muslCrtBeginSharedBinary, muslCrtEndSharedBinary   = []string{"libc_musl_crtbegin_dynamic", "musl_linker_script"}, []string{"libc_musl_crtend"}
 	muslCrtBeginSharedLibrary, muslCrtEndSharedLibrary = []string{"libc_musl_crtbegin_so"}, []string{"libc_musl_crtend_so"}
 
-	muslDefaultSharedLibraries = []string{"libjemalloc5", "libc_musl"}
+	muslDefaultSharedLibraries = []string{"libc_musl"}
 )
 
 const (
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 8b0f93e..fbef12b 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -15,7 +15,6 @@
 package cc
 
 import (
-	"encoding/json"
 	"path/filepath"
 	"sort"
 	"strings"
@@ -24,55 +23,9 @@
 
 	"android/soong/android"
 	"android/soong/cc/config"
+	"android/soong/fuzz"
 )
 
-type FuzzConfig struct {
-	// Email address of people to CC on bugs or contact about this fuzz target.
-	Cc []string `json:"cc,omitempty"`
-	// Specify whether to enable continuous fuzzing on devices. Defaults to true.
-	Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
-	// Specify whether to enable continuous fuzzing on host. Defaults to true.
-	Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
-	// Component in Google's bug tracking system that bugs should be filed to.
-	Componentid *int64 `json:"componentid,omitempty"`
-	// Hotlists in Google's bug tracking system that bugs should be marked with.
-	Hotlists []string `json:"hotlists,omitempty"`
-	// Specify whether this fuzz target was submitted by a researcher. Defaults
-	// to false.
-	Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
-	// Specify who should be acknowledged for CVEs in the Android Security
-	// Bulletin.
-	Acknowledgement []string `json:"acknowledgement,omitempty"`
-	// Additional options to be passed to libfuzzer when run in Haiku.
-	Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
-	// Additional options to be passed to HWASAN when running on-device in Haiku.
-	Hwasan_options []string `json:"hwasan_options,omitempty"`
-	// Additional options to be passed to HWASAN when running on host in Haiku.
-	Asan_options []string `json:"asan_options,omitempty"`
-}
-
-func (f *FuzzConfig) String() string {
-	b, err := json.Marshal(f)
-	if err != nil {
-		panic(err)
-	}
-
-	return string(b)
-}
-
-type FuzzProperties struct {
-	// Optional list of seed files to be installed to the fuzz target's output
-	// directory.
-	Corpus []string `android:"path"`
-	// Optional list of data files to be installed to the fuzz target's output
-	// directory. Directory structure relative to the module is preserved.
-	Data []string `android:"path"`
-	// Optional dictionary to be installed to the fuzz target's output directory.
-	Dictionary *string `android:"path"`
-	// Config for running the target on fuzzing infrastructure.
-	Fuzz_config *FuzzConfig
-}
-
 func init() {
 	android.RegisterModuleType("cc_fuzz", FuzzFactory)
 	android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
@@ -94,7 +47,7 @@
 	*binaryDecorator
 	*baseCompiler
 
-	fuzzPackagedModule FuzzPackagedModule
+	fuzzPackagedModule fuzz.FuzzPackagedModule
 
 	installedSharedDeps []string
 }
@@ -355,7 +308,7 @@
 // Responsible for generating GNU Make rules that package fuzz targets into
 // their architecture & target/host specific zip file.
 type ccFuzzPackager struct {
-	FuzzPackager
+	fuzz.FuzzPackager
 	sharedLibInstallStrings []string
 }
 
@@ -367,7 +320,7 @@
 	// Map between each architecture + host/device combination, and the files that
 	// need to be packaged (in the tuple of {source file, destination folder in
 	// archive}).
-	archDirs := make(map[ArchOs][]FileToZip)
+	archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
 
 	// Map tracking whether each shared library has an install rule to avoid duplicate install rules from
 	// multiple fuzzers that depend on the same shared library.
@@ -384,7 +337,7 @@
 		}
 
 		// Discard non-fuzz targets.
-		if ok := IsValid(ccModule.FuzzModule); !ok {
+		if ok := fuzz.IsValid(ccModule.FuzzModule); !ok {
 			return
 		}
 
@@ -400,12 +353,12 @@
 
 		archString := ccModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
-		archOs := ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
+		archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
 
 		// Grab the list of required shared libraries.
 		sharedLibraries := collectAllSharedDependencies(ctx, module)
 
-		var files []FileToZip
+		var files []fuzz.FileToZip
 		builder := android.NewRuleBuilder(pctx, ctx)
 
 		// Package the corpus, data, dict and config into a zipfile.
@@ -414,7 +367,7 @@
 		// Find and mark all the transiently-dependent shared libraries for
 		// packaging.
 		for _, library := range sharedLibraries {
-			files = append(files, FileToZip{library, "lib"})
+			files = append(files, fuzz.FileToZip{library, "lib"})
 
 			// For each architecture-specific shared library dependency, we need to
 			// install it to the output directory. Setup the install destination here,
@@ -446,7 +399,7 @@
 		}
 
 		// The executable.
-		files = append(files, FileToZip{ccModule.UnstrippedOutputFile(), ""})
+		files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""})
 
 		archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
 		if !ok {
@@ -454,7 +407,7 @@
 		}
 	})
 
-	s.CreateFuzzPackage(ctx, archDirs, Cc)
+	s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
 
 }
 
diff --git a/cc/library.go b/cc/library.go
index 1478a16..b2360e9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -236,6 +236,7 @@
 	Includes            bazel.StringListAttribute
 	Linkopts            bazel.StringListAttribute
 	Use_libcrt          bazel.BoolAttribute
+	Rtti                bazel.BoolAttribute
 
 	// This is shared only.
 	Version_script bazel.LabelAttribute
@@ -323,6 +324,7 @@
 		Includes:            exportedIncludes,
 		Linkopts:            linkerAttrs.linkopts,
 		Use_libcrt:          linkerAttrs.useLibcrt,
+		Rtti:                compilerAttrs.rtti,
 
 		Version_script: linkerAttrs.versionScript,
 
@@ -554,7 +556,7 @@
 }
 
 type ccLibraryBazelHandler struct {
-	bazelHandler
+	android.BazelHandler
 
 	module *Module
 }
@@ -640,7 +642,7 @@
 	return android.OptionalPathForPath(android.PathForBazelOut(ctx, tocFile))
 }
 
-func (handler *ccLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (handler *ccLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
 	bazelCtx := ctx.Config().BazelContext
 	ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
 	if err != nil {
@@ -2335,6 +2337,7 @@
 	Linkopts            bazel.StringListAttribute
 	Linkstatic          bool
 	Use_libcrt          bazel.BoolAttribute
+	Rtti                bazel.BoolAttribute
 	Includes            bazel.StringListAttribute
 	Hdrs                bazel.LabelListAttribute
 
@@ -2396,6 +2399,7 @@
 		Linkopts:   linkerAttrs.linkopts,
 		Linkstatic: true,
 		Use_libcrt: linkerAttrs.useLibcrt,
+		Rtti:       compilerAttrs.rtti,
 		Includes:   exportedIncludes,
 
 		Cppflags:   compilerAttrs.cppFlags,
diff --git a/cc/library_headers.go b/cc/library_headers.go
index e596ff7..1a276f4 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -44,13 +44,13 @@
 }
 
 type libraryHeaderBazelHander struct {
-	bazelHandler
+	android.BazelHandler
 
 	module  *Module
 	library *libraryDecorator
 }
 
-func (h *libraryHeaderBazelHander) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (h *libraryHeaderBazelHander) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
 	bazelCtx := ctx.Config().BazelContext
 	ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
 	if err != nil {
diff --git a/cc/object.go b/cc/object.go
index bd9f228..5952f1e 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -47,12 +47,12 @@
 }
 
 type objectBazelHandler struct {
-	bazelHandler
+	android.BazelHandler
 
 	module *Module
 }
 
-func (handler *objectBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (handler *objectBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
 	bazelCtx := ctx.Config().BazelContext
 	objPaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType)
 	if ok {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index f7154ec..d324241 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -15,9 +15,10 @@
 package cc
 
 import (
-	"android/soong/android"
 	"path/filepath"
 	"strings"
+
+	"android/soong/android"
 )
 
 func init() {
@@ -321,13 +322,13 @@
 }
 
 type prebuiltStaticLibraryBazelHandler struct {
-	bazelHandler
+	android.BazelHandler
 
 	module  *Module
 	library *libraryDecorator
 }
 
-func (h *prebuiltStaticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (h *prebuiltStaticLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
 	bazelCtx := ctx.Config().BazelContext
 	ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
 	if err != nil {
diff --git a/cc/testing.go b/cc/testing.go
index e8f3481..071f1ec 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -451,16 +451,6 @@
 			name: "note_memtag_heap_sync",
 		}
 
-
-		cc_library {
-			name: "libjemalloc5",
-			host_supported: true,
-			no_libcrt: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-		}
-
 		cc_library {
 			name: "libc_musl",
 			host_supported: true,
diff --git a/cc/tidy.go b/cc/tidy.go
index b2382e8..fefa7f0 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -146,6 +146,8 @@
 	tidyChecks = tidyChecks + ",-bugprone-signed-char-misuse"
 	// http://b/155034972
 	tidyChecks = tidyChecks + ",-bugprone-branch-clone"
+	// http://b/193716442
+	tidyChecks = tidyChecks + ",-bugprone-implicit-widening-of-multiplication-result"
 	flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
 
 	if ctx.Config().IsEnvTrue("WITH_TIDY") {
diff --git a/cmd/extract_linker/main.go b/cmd/extract_linker/main.go
index f1f7bc7..1280553 100644
--- a/cmd/extract_linker/main.go
+++ b/cmd/extract_linker/main.go
@@ -26,7 +26,7 @@
 	"io/ioutil"
 	"log"
 	"os"
-	"strings"
+	"strconv"
 )
 
 func main() {
@@ -59,20 +59,16 @@
 	fmt.Fprintln(script, "ENTRY(__dlwrap__start)")
 	fmt.Fprintln(script, "SECTIONS {")
 
+	progsWithFlagsCount := make(map[string]int)
+
 	for _, prog := range ef.Progs {
 		if prog.Type != elf.PT_LOAD {
 			continue
 		}
 
-		var progName string
-		progSection := progToFirstSection(prog, ef.Sections)
-		if progSection != nil {
-			progName = progSection.Name
-		} else {
-			progName = fmt.Sprintf(".sect%d", load)
-		}
-		sectionName := ".linker" + progName
-		symName := "__dlwrap_linker" + strings.ReplaceAll(progName, ".", "_")
+		progName := progNameFromFlags(prog.Flags, progsWithFlagsCount)
+		sectionName := ".linker_" + progName
+		symName := "__dlwrap_linker_" + progName
 
 		flags := ""
 		if prog.Flags&elf.PF_W != 0 {
@@ -83,6 +79,12 @@
 		}
 		fmt.Fprintf(asm, ".section %s, \"a%s\"\n", sectionName, flags)
 
+		if load == 0 {
+			fmt.Fprintln(asm, ".globl __dlwrap_linker")
+			fmt.Fprintln(asm, "__dlwrap_linker:")
+			fmt.Fprintln(asm)
+		}
+
 		fmt.Fprintf(asm, ".globl %s\n%s:\n\n", symName, symName)
 
 		fmt.Fprintf(script, "  %s 0x%x : {\n", sectionName, baseLoadAddr+prog.Vaddr)
@@ -106,6 +108,10 @@
 		load += 1
 	}
 
+	fmt.Fprintln(asm, ".globl __dlwrap_linker_end")
+	fmt.Fprintln(asm, "__dlwrap_linker_end:")
+	fmt.Fprintln(asm)
+
 	fmt.Fprintln(asm, `.section .note.android.embedded_linker,"a",%note`)
 
 	fmt.Fprintln(script, "}")
@@ -139,11 +145,25 @@
 	fmt.Fprintln(asm)
 }
 
-func progToFirstSection(prog *elf.Prog, sections []*elf.Section) *elf.Section {
-	for _, section := range sections {
-		if section.Addr == prog.Vaddr {
-			return section
-		}
+func progNameFromFlags(flags elf.ProgFlag, progsWithFlagsCount map[string]int) string {
+	s := ""
+	if flags&elf.PF_R != 0 {
+		s += "r"
 	}
-	return nil
+	if flags&elf.PF_W != 0 {
+		s += "w"
+	}
+	if flags&elf.PF_X != 0 {
+		s += "x"
+	}
+
+	count := progsWithFlagsCount[s]
+	count++
+	progsWithFlagsCount[s] = count
+
+	if count > 1 {
+		s += strconv.Itoa(count)
+	}
+
+	return s
 }
diff --git a/cmd/multiproduct_kati/Android.bp b/cmd/multiproduct_kati/Android.bp
index 21d8e21..e5be6c0 100644
--- a/cmd/multiproduct_kati/Android.bp
+++ b/cmd/multiproduct_kati/Android.bp
@@ -19,8 +19,8 @@
 blueprint_go_binary {
     name: "multiproduct_kati",
     deps: [
-        "soong-ui-build",
         "soong-ui-logger",
+        "soong-ui-signal",
         "soong-ui-terminal",
         "soong-ui-tracer",
         "soong-zip",
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 55a5470..2846387 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -15,22 +15,24 @@
 package main
 
 import (
+	"bufio"
 	"context"
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
+	"log"
 	"os"
+	"os/exec"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"strings"
 	"sync"
 	"syscall"
 	"time"
 
-	"android/soong/finder"
-	"android/soong/ui/build"
 	"android/soong/ui/logger"
+	"android/soong/ui/signal"
 	"android/soong/ui/status"
 	"android/soong/ui/terminal"
 	"android/soong/ui/tracer"
@@ -74,36 +76,6 @@
 	return nil
 }
 
-const errorLeadingLines = 20
-const errorTrailingLines = 20
-
-func errMsgFromLog(filename string) string {
-	if filename == "" {
-		return ""
-	}
-
-	data, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return ""
-	}
-
-	lines := strings.Split(strings.TrimSpace(string(data)), "\n")
-	if len(lines) > errorLeadingLines+errorTrailingLines+1 {
-		lines[errorLeadingLines] = fmt.Sprintf("... skipping %d lines ...",
-			len(lines)-errorLeadingLines-errorTrailingLines)
-
-		lines = append(lines[:errorLeadingLines+1],
-			lines[len(lines)-errorTrailingLines:]...)
-	}
-	var buf strings.Builder
-	for _, line := range lines {
-		buf.WriteString("> ")
-		buf.WriteString(line)
-		buf.WriteString("\n")
-	}
-	return buf.String()
-}
-
 // TODO(b/70370883): This tool uses a lot of open files -- over the default
 // soft limit of 1024 on some systems. So bump up to the hard limit until I fix
 // the algorithm.
@@ -155,28 +127,59 @@
 }
 
 type mpContext struct {
-	Context context.Context
-	Logger  logger.Logger
-	Status  status.ToolStatus
-	Tracer  tracer.Tracer
-	Finder  *finder.Finder
-	Config  build.Config
+	Logger logger.Logger
+	Status status.ToolStatus
 
-	LogsDir string
+	SoongUi     string
+	MainOutDir  string
+	MainLogsDir string
+}
+
+func detectTotalRAM() uint64 {
+	var info syscall.Sysinfo_t
+	err := syscall.Sysinfo(&info)
+	if err != nil {
+		panic(err)
+	}
+	return info.Totalram * uint64(info.Unit)
+}
+
+func findNamedProducts(soongUi string, log logger.Logger) []string {
+	cmd := exec.Command(soongUi, "--dumpvars-mode", "--vars=all_named_products")
+	output, err := cmd.Output()
+	if err != nil {
+		log.Fatalf("Cannot determine named products: %v", err)
+	}
+
+	rx := regexp.MustCompile(`^all_named_products='(.*)'$`)
+	match := rx.FindStringSubmatch(strings.TrimSpace(string(output)))
+	return strings.Fields(match[1])
+}
+
+// ensureEmptyFileExists ensures that the containing directory exists, and the
+// specified file exists. If it doesn't exist, it will write an empty file.
+func ensureEmptyFileExists(file string, log logger.Logger) {
+	if _, err := os.Stat(file); os.IsNotExist(err) {
+		f, err := os.Create(file)
+		if err != nil {
+			log.Fatalf("Error creating %s: %q\n", file, err)
+		}
+		f.Close()
+	} else if err != nil {
+		log.Fatalf("Error checking %s: %q\n", file, err)
+	}
 }
 
 func main() {
 	stdio := terminal.StdioImpl{}
 
-	output := terminal.NewStatusOutput(stdio.Stdout(), "", false,
-		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
-
+	output := terminal.NewStatusOutput(stdio.Stdout(), "", false, false)
 	log := logger.New(output)
 	defer log.Cleanup()
 
 	flag.Parse()
 
-	ctx, cancel := context.WithCancel(context.Background())
+	_, cancel := context.WithCancel(context.Background())
 	defer cancel()
 
 	trace := tracer.New(log)
@@ -189,61 +192,59 @@
 	var failures failureCount
 	stat.AddOutput(&failures)
 
-	build.SetupSignals(log, cancel, func() {
+	signal.SetupSignals(log, cancel, func() {
 		trace.Close()
 		log.Cleanup()
 		stat.Finish()
 	})
 
-	buildCtx := build.Context{ContextImpl: &build.ContextImpl{
-		Context: ctx,
-		Logger:  log,
-		Tracer:  trace,
-		Writer:  output,
-		Status:  stat,
-	}}
+	soongUi := "build/soong/soong_ui.bash"
 
-	args := ""
-	if *alternateResultDir {
-		args = "dist"
-	}
-	config := build.NewConfig(buildCtx, args)
-	if *outDir == "" {
+	var outputDir string
+	if *outDir != "" {
+		outputDir = *outDir
+	} else {
 		name := "multiproduct"
 		if !*incremental {
 			name += "-" + time.Now().Format("20060102150405")
 		}
 
-		*outDir = filepath.Join(config.OutDir(), name)
-
-		// Ensure the empty files exist in the output directory
-		// containing our output directory too. This is mostly for
-		// safety, but also triggers the ninja_build file so that our
-		// build servers know that they can parse the output as if it
-		// was ninja output.
-		build.SetupOutDir(buildCtx, config)
-
-		if err := os.MkdirAll(*outDir, 0777); err != nil {
-			log.Fatalf("Failed to create tempdir: %v", err)
+		outDirBase := os.Getenv("OUT_DIR")
+		if outDirBase == "" {
+			outDirBase = "out"
 		}
-	}
-	config.Environment().Set("OUT_DIR", *outDir)
-	log.Println("Output directory:", *outDir)
 
-	logsDir := filepath.Join(config.OutDir(), "logs")
+		outputDir = filepath.Join(outDirBase, name)
+	}
+
+	log.Println("Output directory:", outputDir)
+
+	// The ninja_build file is used by our buildbots to understand that the output
+	// can be parsed as ninja output.
+	if err := os.MkdirAll(outputDir, 0777); err != nil {
+		log.Fatalf("Failed to create output directory: %v", err)
+	}
+	ensureEmptyFileExists(filepath.Join(outputDir, "ninja_build"), log)
+
+	logsDir := filepath.Join(outputDir, "logs")
 	os.MkdirAll(logsDir, 0777)
 
-	build.SetupOutDir(buildCtx, config)
+	var configLogsDir string
+	if *alternateResultDir {
+		configLogsDir = filepath.Join(outputDir, "dist/logs")
+	} else {
+		configLogsDir = outputDir
+	}
 
-	os.MkdirAll(config.LogsDir(), 0777)
-	log.SetOutput(filepath.Join(config.LogsDir(), "soong.log"))
-	trace.SetOutput(filepath.Join(config.LogsDir(), "build.trace"))
+	os.MkdirAll(configLogsDir, 0777)
+	log.SetOutput(filepath.Join(configLogsDir, "soong.log"))
+	trace.SetOutput(filepath.Join(configLogsDir, "build.trace"))
 
 	var jobs = *numJobs
 	if jobs < 1 {
 		jobs = runtime.NumCPU() / 4
 
-		ramGb := int(config.TotalRAM() / 1024 / 1024 / 1024)
+		ramGb := int(detectTotalRAM() / (1024 * 1024 * 1024))
 		if ramJobs := ramGb / 25; ramGb > 0 && jobs > ramJobs {
 			jobs = ramJobs
 		}
@@ -256,17 +257,8 @@
 
 	setMaxFiles(log)
 
-	finder := build.NewSourceFinder(buildCtx, config)
-	defer finder.Shutdown()
-
-	build.FindSources(buildCtx, config, finder)
-
-	vars, err := build.DumpMakeVars(buildCtx, config, nil, []string{"all_named_products"})
-	if err != nil {
-		log.Fatal(err)
-	}
+	allProducts := findNamedProducts(soongUi, log)
 	var productsList []string
-	allProducts := strings.Fields(vars["all_named_products"])
 
 	if len(includeProducts) > 0 {
 		var missingProducts []string
@@ -314,19 +306,15 @@
 
 	log.Verbose("Got product list: ", finalProductsList)
 
-	s := buildCtx.Status.StartTool()
+	s := stat.StartTool()
 	s.SetTotalActions(len(finalProductsList))
 
 	mpCtx := &mpContext{
-		Context: ctx,
-		Logger:  log,
-		Status:  s,
-		Tracer:  trace,
-
-		Finder: finder,
-		Config: config,
-
-		LogsDir: logsDir,
+		Logger:      log,
+		Status:      s,
+		SoongUi:     soongUi,
+		MainOutDir:  outputDir,
+		MainLogsDir: logsDir,
 	}
 
 	products := make(chan string, len(productsList))
@@ -348,7 +336,7 @@
 					if product == "" {
 						return
 					}
-					buildProduct(mpCtx, product)
+					runSoongUiForProduct(mpCtx, product)
 				}
 			}
 		}()
@@ -360,7 +348,7 @@
 			FileArgs: []zip.FileArg{
 				{GlobDir: logsDir, SourcePrefixToStrip: logsDir},
 			},
-			OutputFilePath:   filepath.Join(config.RealDistDir(), "logs.zip"),
+			OutputFilePath:   filepath.Join(outputDir, "dist/logs.zip"),
 			NumParallelJobs:  runtime.NumCPU(),
 			CompressionLevel: 5,
 		}
@@ -380,11 +368,33 @@
 	}
 }
 
-func buildProduct(mpctx *mpContext, product string) {
-	var stdLog string
+func cleanupAfterProduct(outDir, productZip string) {
+	if *keepArtifacts {
+		args := zip.ZipArgs{
+			FileArgs: []zip.FileArg{
+				{
+					GlobDir:             outDir,
+					SourcePrefixToStrip: outDir,
+				},
+			},
+			OutputFilePath:   productZip,
+			NumParallelJobs:  runtime.NumCPU(),
+			CompressionLevel: 5,
+		}
+		if err := zip.Zip(args); err != nil {
+			log.Fatalf("Error zipping artifacts: %v", err)
+		}
+	}
+	if !*incremental {
+		os.RemoveAll(outDir)
+	}
+}
 
-	outDir := filepath.Join(mpctx.Config.OutDir(), product)
-	logsDir := filepath.Join(mpctx.LogsDir, product)
+func runSoongUiForProduct(mpctx *mpContext, product string) {
+	outDir := filepath.Join(mpctx.MainOutDir, product)
+	logsDir := filepath.Join(mpctx.MainLogsDir, product)
+	productZip := filepath.Join(mpctx.MainOutDir, product+".zip")
+	consoleLogPath := filepath.Join(logsDir, "std.log")
 
 	if err := os.MkdirAll(outDir, 0777); err != nil {
 		mpctx.Logger.Fatalf("Error creating out directory: %v", err)
@@ -393,98 +403,65 @@
 		mpctx.Logger.Fatalf("Error creating log directory: %v", err)
 	}
 
-	stdLog = filepath.Join(logsDir, "std.log")
-	f, err := os.Create(stdLog)
+	consoleLogFile, err := os.Create(consoleLogPath)
 	if err != nil {
-		mpctx.Logger.Fatalf("Error creating std.log: %v", err)
+		mpctx.Logger.Fatalf("Error creating console log file: %v", err)
 	}
-	defer f.Close()
+	defer consoleLogFile.Close()
 
-	log := logger.New(f)
-	defer log.Cleanup()
-	log.SetOutput(filepath.Join(logsDir, "soong.log"))
+	consoleLogWriter := bufio.NewWriter(consoleLogFile)
+	defer consoleLogWriter.Flush()
+
+	args := []string{"--make-mode", "--skip-soong-tests", "--skip-ninja"}
+
+	if !*keepArtifacts {
+		args = append(args, "--empty-ninja-file")
+	}
+
+	if *onlyConfig {
+		args = append(args, "--config-only")
+	} else if *onlySoong {
+		args = append(args, "--soong-only")
+	}
+
+	if *alternateResultDir {
+		args = append(args, "dist")
+	}
+
+	cmd := exec.Command(mpctx.SoongUi, args...)
+	cmd.Stdout = consoleLogWriter
+	cmd.Stderr = consoleLogWriter
+	cmd.Env = append(os.Environ(),
+		"OUT_DIR="+outDir,
+		"TARGET_PRODUCT="+product,
+		"TARGET_BUILD_VARIANT="+*buildVariant,
+		"TARGET_BUILD_TYPE=release",
+		"TARGET_BUILD_APPS=",
+		"TARGET_BUILD_UNBUNDLED=")
 
 	action := &status.Action{
 		Description: product,
 		Outputs:     []string{product},
 	}
+
 	mpctx.Status.StartAction(action)
-	defer logger.Recover(func(err error) {
-		mpctx.Status.FinishAction(status.ActionResult{
-			Action: action,
-			Error:  err,
-			Output: errMsgFromLog(stdLog),
-		})
-	})
-
-	ctx := build.Context{ContextImpl: &build.ContextImpl{
-		Context: mpctx.Context,
-		Logger:  log,
-		Tracer:  mpctx.Tracer,
-		Writer:  f,
-		Thread:  mpctx.Tracer.NewThread(product),
-		Status:  &status.Status{},
-	}}
-	ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "", false,
-		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
-
-	args := append([]string(nil), flag.Args()...)
-	args = append(args, "--skip-soong-tests")
-	config := build.NewConfig(ctx, args...)
-	config.Environment().Set("OUT_DIR", outDir)
-	if !*keepArtifacts {
-		config.SetEmptyNinjaFile(true)
-	}
-	build.FindSources(ctx, config, mpctx.Finder)
-	config.Lunch(ctx, product, *buildVariant)
-
-	defer func() {
-		if *keepArtifacts {
-			args := zip.ZipArgs{
-				FileArgs: []zip.FileArg{
-					{
-						GlobDir:             outDir,
-						SourcePrefixToStrip: outDir,
-					},
-				},
-				OutputFilePath:   filepath.Join(mpctx.Config.OutDir(), product+".zip"),
-				NumParallelJobs:  runtime.NumCPU(),
-				CompressionLevel: 5,
-			}
-			if err := zip.Zip(args); err != nil {
-				log.Fatalf("Error zipping artifacts: %v", err)
-			}
-		}
-		if !*incremental {
-			os.RemoveAll(outDir)
-		}
-	}()
-
-	config.SetSkipNinja(true)
-
-	buildWhat := build.RunProductConfig
-	if !*onlyConfig {
-		buildWhat |= build.RunSoong
-		if !*onlySoong {
-			buildWhat |= build.RunKati
-		}
-	}
+	defer cleanupAfterProduct(outDir, productZip)
 
 	before := time.Now()
-	build.Build(ctx, config)
+	err = cmd.Run()
 
-	// Save std_full.log if Kati re-read the makefiles
-	if buildWhat&build.RunKati != 0 {
-		if after, err := os.Stat(config.KatiBuildNinjaFile()); err == nil && after.ModTime().After(before) {
-			err := copyFile(stdLog, filepath.Join(filepath.Dir(stdLog), "std_full.log"))
+	if !*onlyConfig && !*onlySoong {
+		katiBuildNinjaFile := filepath.Join(outDir, "build-"+product+".ninja")
+		if after, err := os.Stat(katiBuildNinjaFile); err == nil && after.ModTime().After(before) {
+			err := copyFile(consoleLogPath, filepath.Join(filepath.Dir(consoleLogPath), "std_full.log"))
 			if err != nil {
 				log.Fatalf("Error copying log file: %s", err)
 			}
 		}
 	}
-
 	mpctx.Status.FinishAction(status.ActionResult{
 		Action: action,
+		Error:  err,
 	})
 }
 
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 0336fb6..0099e87 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -469,6 +469,12 @@
 	ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bp2buildCtx.Context, configuration)
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
+	// Generate out/soong/.bootstrap/build-globs.ninja with the actions to generate flattened globfiles
+	// containing the globs seen during bp2build conversion
+	if blueprintArgs.GlobFile != "" {
+		bootstrap.WriteBuildGlobsNinjaFile(bootstrap.StageMain, bp2buildCtx.Context, blueprintArgs, configuration)
+	}
+	// Add the depfile on the expanded globs in out/soong/.primary/globs
 	ninjaDeps = append(ninjaDeps, bootstrap.GlobFileListFiles(configuration)...)
 
 	// Run the code-generation phase to convert BazelTargetModules to BUILD files
diff --git a/cmd/soong_ui/Android.bp b/cmd/soong_ui/Android.bp
index 4f5eea9..9f10b82 100644
--- a/cmd/soong_ui/Android.bp
+++ b/cmd/soong_ui/Android.bp
@@ -20,6 +20,7 @@
     name: "soong_ui",
     deps: [
         "soong-ui-build",
+        "soong-ui-signal",
         "soong-ui-logger",
         "soong-ui-terminal",
         "soong-ui-tracer",
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 02c5229..d709787 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -30,6 +30,7 @@
 	"android/soong/ui/build"
 	"android/soong/ui/logger"
 	"android/soong/ui/metrics"
+	"android/soong/ui/signal"
 	"android/soong/ui/status"
 	"android/soong/ui/terminal"
 	"android/soong/ui/tracer"
@@ -190,7 +191,7 @@
 	stat.AddOutput(trace.StatusTracer())
 
 	// Set up a cleanup procedure in case the normal termination process doesn't work.
-	build.SetupSignals(log, cancel, func() {
+	signal.SetupSignals(log, cancel, func() {
 		trace.Close()
 		log.Cleanup()
 		stat.Finish()
diff --git a/cuj/Android.bp b/cuj/Android.bp
index a2da6e6..f9cfdc1 100644
--- a/cuj/Android.bp
+++ b/cuj/Android.bp
@@ -7,6 +7,7 @@
     deps: [
         "soong-ui-build",
         "soong-ui-logger",
+        "soong-ui-signal",
         "soong-ui-terminal",
         "soong-ui-tracer",
     ],
diff --git a/cuj/cuj.go b/cuj/cuj.go
index b4ae9a2..413f423 100644
--- a/cuj/cuj.go
+++ b/cuj/cuj.go
@@ -27,6 +27,7 @@
 	"android/soong/ui/build"
 	"android/soong/ui/logger"
 	"android/soong/ui/metrics"
+	"android/soong/ui/signal"
 	"android/soong/ui/status"
 	"android/soong/ui/terminal"
 	"android/soong/ui/tracer"
@@ -65,7 +66,7 @@
 	stat.AddOutput(output)
 	stat.AddOutput(trace.StatusTracer())
 
-	build.SetupSignals(log, cancel, func() {
+	signal.SetupSignals(log, cancel, func() {
 		trace.Close()
 		log.Cleanup()
 		stat.Finish()
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 2f99655..8f5c315 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -125,6 +125,20 @@
 	})
 }
 
+// FixtureSetSystemServerJars sets the SystemServerJars property.
+func FixtureSetSystemServerJars(jars ...string) android.FixturePreparer {
+	return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+		dexpreoptConfig.SystemServerJars = android.CreateTestConfiguredJarList(jars)
+	})
+}
+
+// FixtureSetApexSystemServerJars sets the ApexSystemServerJars property in the global config.
+func FixtureSetApexSystemServerJars(jars ...string) android.FixturePreparer {
+	return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+		dexpreoptConfig.ApexSystemServerJars = android.CreateTestConfiguredJarList(jars)
+	})
+}
+
 // FixtureSetPreoptWithUpdatableBcp sets the PreoptWithUpdatableBcp property in the global config.
 func FixtureSetPreoptWithUpdatableBcp(value bool) android.FixturePreparer {
 	return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
diff --git a/fuzz/Android.bp b/fuzz/Android.bp
new file mode 100644
index 0000000..9d96e48
--- /dev/null
+++ b/fuzz/Android.bp
@@ -0,0 +1,15 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-fuzz",
+    pkgPath: "android/soong/fuzz",
+    deps: [
+        "soong-android",
+    ],
+    srcs: [
+        "fuzz_common.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/cc/fuzz_common.go b/fuzz/fuzz_common.go
similarity index 73%
rename from cc/fuzz_common.go
rename to fuzz/fuzz_common.go
index 98ed7f4..ccadc0f 100644
--- a/cc/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -12,14 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cc
+package fuzz
 
 // This file contains the common code for compiling C/C++ and Rust fuzzers for Android.
 
 import (
+	"encoding/json"
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 )
 
@@ -30,6 +33,8 @@
 	Rust Lang = "rust"
 )
 
+var BoolDefault = proptools.BoolDefault
+
 type FuzzModule struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -52,6 +57,44 @@
 	Dir          string
 }
 
+type FuzzConfig struct {
+	// Email address of people to CC on bugs or contact about this fuzz target.
+	Cc []string `json:"cc,omitempty"`
+	// Specify whether to enable continuous fuzzing on devices. Defaults to true.
+	Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
+	// Specify whether to enable continuous fuzzing on host. Defaults to true.
+	Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
+	// Component in Google's bug tracking system that bugs should be filed to.
+	Componentid *int64 `json:"componentid,omitempty"`
+	// Hotlists in Google's bug tracking system that bugs should be marked with.
+	Hotlists []string `json:"hotlists,omitempty"`
+	// Specify whether this fuzz target was submitted by a researcher. Defaults
+	// to false.
+	Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
+	// Specify who should be acknowledged for CVEs in the Android Security
+	// Bulletin.
+	Acknowledgement []string `json:"acknowledgement,omitempty"`
+	// Additional options to be passed to libfuzzer when run in Haiku.
+	Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
+	// Additional options to be passed to HWASAN when running on-device in Haiku.
+	Hwasan_options []string `json:"hwasan_options,omitempty"`
+	// Additional options to be passed to HWASAN when running on host in Haiku.
+	Asan_options []string `json:"asan_options,omitempty"`
+}
+
+type FuzzProperties struct {
+	// Optional list of seed files to be installed to the fuzz target's output
+	// directory.
+	Corpus []string `android:"path"`
+	// Optional list of data files to be installed to the fuzz target's output
+	// directory. Directory structure relative to the module is preserved.
+	Data []string `android:"path"`
+	// Optional dictionary to be installed to the fuzz target's output directory.
+	Dictionary *string `android:"path"`
+	// Config for running the target on fuzzing infrastructure.
+	Fuzz_config *FuzzConfig
+}
+
 type FuzzPackagedModule struct {
 	FuzzProperties        FuzzProperties
 	Dictionary            android.Path
@@ -151,7 +194,16 @@
 	return archDirs[archOs], true
 }
 
-func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang) {
+func (f *FuzzConfig) String() string {
+	b, err := json.Marshal(f)
+	if err != nil {
+		panic(err)
+	}
+
+	return string(b)
+}
+
+func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang, pctx android.PackageContext) {
 	var archOsList []ArchOs
 	for archOs := range archDirs {
 		archOsList = append(archOsList, archOs)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 71a8780..fdb3618 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -240,7 +240,7 @@
 }
 
 // Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
-func (c *Module) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (c *Module) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
 	bazelCtx := ctx.Config().BazelContext
 	filePaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType)
 	if ok {
@@ -560,7 +560,7 @@
 	bazelModuleLabel := g.GetBazelLabel(ctx, g)
 	bazelActionsUsed := false
 	if g.MixedBuildsEnabled(ctx) {
-		bazelActionsUsed = g.generateBazelBuildActions(ctx, bazelModuleLabel)
+		bazelActionsUsed = g.GenerateBazelBuildActions(ctx, bazelModuleLabel)
 	}
 	if !bazelActionsUsed {
 		// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
diff --git a/java/app_import.go b/java/app_import.go
index 5a87b07..b5a6084 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -410,6 +410,10 @@
 	return android.SdkSpecPrivate
 }
 
+func (a *AndroidAppImport) LintDepSets() LintDepSets {
+	return LintDepSets{}
+}
+
 var _ android.ApexModule = (*AndroidAppImport)(nil)
 
 // Implements android.ApexModule
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 3d0e155..d3de675 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -164,6 +164,7 @@
 		prepareForTestWithBootclasspathFragment,
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"),
+		FixtureConfigureApexBootJars("someapex:mybootlib"),
 		prepareWithBp,
 	)
 
@@ -186,6 +187,7 @@
 		prepareForTestWithBootclasspathFragment,
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
+		FixtureConfigureApexBootJars("someapex:mysdklibrary"),
 	).RunTestWithBp(t, `
 		bootclasspath_fragment {
 			name: "myfragment",
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 8a06a99..8e39f40 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -948,6 +948,22 @@
 	return patternsFile
 }
 
+// buildRuleRemoveBlockedFlag creates a rule that will remove entries from the input path which
+// only have blocked flags. It will not remove entries that have blocked as well as other flags,
+// e.g. blocked,core-platform-api.
+func buildRuleRemoveBlockedFlag(ctx android.BuilderContext, name string, desc string, inputPath android.Path, filteredPath android.WritablePath) {
+	rule := android.NewRuleBuilder(pctx, ctx)
+	rule.Command().
+		Text(`grep -vE "^[^,]+,blocked$"`).Input(inputPath).Text(">").Output(filteredPath).
+		// Grep's exit code depends on whether it finds anything. It is 0 (build success) when it finds
+		// something and 1 (build failure) when it does not and 2 (when it encounters an error).
+		// However, while it is unlikely it is not an error if this does not find any matches. The
+		// following will only run if the grep does not find something and in that case it will treat
+		// an exit code of 1 as success and anything else as failure.
+		Text("|| test $? -eq 1")
+	rule.Build(name, desc)
+}
+
 // buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
 // by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
 func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets) android.WritablePath {
@@ -1036,14 +1052,24 @@
 		encodedBootDexJarsByModule[name] = encodedDex
 	}
 
+	// Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
+	// compared against the monolithic stub flags.
+	filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
+	buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredStubFlags", "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV)
+
+	// Generate the filtered-flags.csv file which contains the filtered flags that will be compared
+	// against the monolithic flags.
+	filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
+	buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredFlags", "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV)
+
 	// Store the paths in the info for use by other modules and sdk snapshot generation.
 	output := HiddenAPIOutput{
 		HiddenAPIFlagOutput: HiddenAPIFlagOutput{
-			StubFlagsPath:       stubFlagsCSV,
+			StubFlagsPath:       filteredStubFlagsCSV,
 			AnnotationFlagsPath: annotationFlagsCSV,
 			MetadataPath:        metadataCSV,
 			IndexPath:           indexCSV,
-			AllFlagsPath:        allFlagsCSV,
+			AllFlagsPath:        filteredFlagsCSV,
 		},
 		EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
 	}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 3470e51..be9e71e 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
 	defaultBindgenFlags = []string{""}
 
 	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
-	bindgenClangVersion = "clang-r416183b"
+	bindgenClangVersion = "clang-r428724"
 
 	_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
diff --git a/rust/builder.go b/rust/builder.go
index a5b3ab9..426a569 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -269,6 +269,17 @@
 
 	envVars = append(envVars, "ANDROID_RUST_VERSION="+config.RustDefaultVersion)
 
+	if ctx.RustModule().compiler.CargoEnvCompat() {
+		if _, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
+			envVars = append(envVars, "CARGO_BIN_NAME="+strings.TrimSuffix(outputFile.Base(), outputFile.Ext()))
+		}
+		envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
+		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
+		if pkgVersion != "" {
+			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+		}
+	}
+
 	if flags.Clippy {
 		clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
 		ctx.Build(pctx, android.BuildParams{
diff --git a/rust/compiler.go b/rust/compiler.go
index de59f39..d9e21ff 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -65,7 +65,11 @@
 )
 
 type BaseCompilerProperties struct {
-	// path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
+	// path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs).
+	// Only a single source file can be defined. Modules which generate source can be included by prefixing
+	// the module name with ":", for example ":libfoo_bindgen"
+	//
+	// If no source file is defined, a single generated source module can be defined to be used as the main source.
 	Srcs []string `android:"path,arch_variant"`
 
 	// name of the lint set that should be used to validate this module.
@@ -154,6 +158,14 @@
 	// linkage if all dependencies of the root binary module do not link against libstd\
 	// the same way.
 	Prefer_rlib *bool `android:"arch_variant"`
+
+	// Enables emitting certain Cargo environment variables. Only intended to be used for compatibility purposes.
+	// Will set CARGO_CRATE_NAME to the crate_name property's value.
+	// Will set CARGO_BIN_NAME to the output filename value without the extension.
+	Cargo_env_compat *bool
+
+	// If cargo_env_compat is true, sets the CARGO_PKG_VERSION env var to this value.
+	Cargo_pkg_version *string
 }
 
 type baseCompiler struct {
@@ -309,6 +321,14 @@
 	return android.OptionalPathForPath(compiler.cargoOutDir)
 }
 
+func (compiler *baseCompiler) CargoEnvCompat() bool {
+	return Bool(compiler.Properties.Cargo_env_compat)
+}
+
+func (compiler *baseCompiler) CargoPkgVersion() string {
+	return String(compiler.Properties.Cargo_pkg_version)
+}
+
 func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath {
 	return compiler.strippedOutputFile
 }
@@ -346,7 +366,9 @@
 	} else {
 		deps.SharedLibs = append(deps.SharedLibs, bionicLibs...)
 	}
-
+	if ctx.RustModule().StaticExecutable() {
+		deps.StaticLibs = append(deps.StaticLibs, "libunwind")
+	}
 	if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" {
 		deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins)
 	}
@@ -420,12 +442,18 @@
 			srcIndex = i
 		}
 	}
-	if numSrcs != 1 {
+	if numSrcs > 1 {
 		ctx.PropertyErrorf("srcs", incorrectSourcesError)
 	}
+
+	// If a main source file is not provided we expect only a single SourceProvider module to be defined
+	// within srcs, with the expectation that the first source it provides is the entry point.
 	if srcIndex != 0 {
 		ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
+	} else if numSrcs > 1 {
+		ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.")
 	}
+
 	paths := android.PathsForModuleSrc(ctx, srcs)
 	return paths[srcIndex], paths[1:]
 }
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index c331b4c..f589b69 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -98,6 +98,30 @@
 		}`)
 }
 
+// Test environment vars for Cargo compat are set.
+func TestCargoCompat(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary {
+			name: "fizz",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			cargo_env_compat: true,
+			cargo_pkg_version: "1.0.0"
+		}`)
+
+	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
+
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") {
+		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"])
+	}
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") {
+		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"])
+	}
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") {
+		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"])
+	}
+}
+
 func TestInstallDir(t *testing.T) {
 	ctx := testRust(t, `
 		rust_library_dylib {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index e527aea..926d2ac 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -12,6 +12,7 @@
 		"external/libchromeos-rs",
 		"external/minijail",
 		"external/rust",
+		"external/selinux/libselinux",
 		"external/vm_tools/p9",
 		"frameworks/native/libs/binder/rust",
 		"frameworks/proto_logging/stats",
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 18b2513..5fb56ff 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -21,6 +21,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/fuzz"
 	"android/soong/rust/config"
 )
 
@@ -32,7 +33,7 @@
 type fuzzDecorator struct {
 	*binaryDecorator
 
-	fuzzPackagedModule cc.FuzzPackagedModule
+	fuzzPackagedModule fuzz.FuzzPackagedModule
 }
 
 var _ compiler = (*binaryDecorator)(nil)
@@ -96,7 +97,7 @@
 // Responsible for generating GNU Make rules that package fuzz targets into
 // their architecture & target/host specific zip file.
 type rustFuzzPackager struct {
-	cc.FuzzPackager
+	fuzz.FuzzPackager
 }
 
 func rustFuzzPackagingFactory() android.Singleton {
@@ -105,7 +106,7 @@
 
 func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
 	// Map between each architecture + host/device combination.
-	archDirs := make(map[cc.ArchOs][]cc.FileToZip)
+	archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
 
 	// List of individual fuzz targets.
 	s.FuzzTargets = make(map[string]bool)
@@ -117,7 +118,7 @@
 			return
 		}
 
-		if ok := cc.IsValid(rustModule.FuzzModule); !ok || rustModule.Properties.PreventInstall {
+		if ok := fuzz.IsValid(rustModule.FuzzModule); !ok || rustModule.Properties.PreventInstall {
 			return
 		}
 
@@ -133,16 +134,16 @@
 
 		archString := rustModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
-		archOs := cc.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
+		archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
 
-		var files []cc.FileToZip
+		var files []fuzz.FileToZip
 		builder := android.NewRuleBuilder(pctx, ctx)
 
 		// Package the artifacts (data, corpus, config and dictionary into a zipfile.
 		files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
 
 		// The executable.
-		files = append(files, cc.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
+		files = append(files, fuzz.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
 
 		archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
 		if !ok {
@@ -150,7 +151,7 @@
 		}
 
 	})
-	s.CreateFuzzPackage(ctx, archDirs, cc.Rust)
+	s.CreateFuzzPackage(ctx, archDirs, fuzz.Rust, pctx)
 }
 
 func (s *rustFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
diff --git a/rust/project_json.go b/rust/project_json.go
index e15ec0f..faa7db5 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -54,7 +54,6 @@
 }
 
 type rustProjectJson struct {
-	// Roots  []string           `json:"roots"`
 	Crates []rustProjectCrate `json:"crates"`
 }
 
@@ -248,9 +247,6 @@
 	idx := len(singleton.project.Crates)
 	singleton.knownCrates[rModule.Name()] = crateInfo{Idx: idx, Deps: deps}
 	singleton.project.Crates = append(singleton.project.Crates, crate)
-	// rust-analyzer requires that all crates belong to at least one root:
-	// https://github.com/rust-analyzer/rust-analyzer/issues/4735.
-	// singleton.project.Roots = append(singleton.project.Roots, path.Dir(crate.RootModule))
 	return idx, true
 }
 
diff --git a/rust/rust.go b/rust/rust.go
index 80be496..4ceeef1 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -25,6 +25,7 @@
 	"android/soong/bloaty"
 	"android/soong/cc"
 	cc_config "android/soong/cc/config"
+	"android/soong/fuzz"
 	"android/soong/rust/config"
 )
 
@@ -123,7 +124,7 @@
 }
 
 type Module struct {
-	cc.FuzzModule
+	fuzz.FuzzModule
 
 	VendorProperties cc.VendorProperties
 
@@ -433,6 +434,12 @@
 	// copied. This is equivalent to Cargo's OUT_DIR variable.
 	CargoOutDir() android.OptionalPath
 
+	// CargoPkgVersion returns the value of the Cargo_pkg_version property.
+	CargoPkgVersion() string
+
+	// CargoEnvCompat returns whether Cargo environment variables should be used.
+	CargoEnvCompat() bool
+
 	inData() bool
 	install(ctx ModuleContext)
 	relativeInstallPath() string
diff --git a/scripts/get_clang_version.py b/scripts/get_clang_version.py
index 622fca1..f6efc5f 100755
--- a/scripts/get_clang_version.py
+++ b/scripts/get_clang_version.py
@@ -30,7 +30,7 @@
   with open(global_go) as infile:
     contents = infile.read()
 
-  regex_rev = r'\tClangDefaultVersion\s+= "clang-(?P<rev>r\d+[a-z]?\d?)"'
+  regex_rev = r'\tClangDefaultVersion\s+= "(?P<rev>clang-r\d+[a-z]?\d?)"'
   match_rev = re.search(regex_rev, contents)
   if match_rev is None:
     raise RuntimeError('Parsing clang info failed')
diff --git a/scripts/hiddenapi/signature_patterns.py b/scripts/hiddenapi/signature_patterns.py
index 91328e6..a7c5bb4 100755
--- a/scripts/hiddenapi/signature_patterns.py
+++ b/scripts/hiddenapi/signature_patterns.py
@@ -30,11 +30,21 @@
         return produce_patterns_from_stream(f)
 
 def produce_patterns_from_stream(stream):
-    patterns = []
-    allFlagsReader = dict_reader(stream)
-    for row in allFlagsReader:
+    # Read in all the signatures into a list and remove member names.
+    patterns = set()
+    for row in dict_reader(stream):
         signature = row['signature']
-        patterns.append(signature)
+        text = signature.removeprefix("L")
+        # Remove the class specific member signature
+        pieces = text.split(";->")
+        qualifiedClassName = pieces[0]
+            # Remove inner class names as they cannot be separated from the containing outer class.
+        pieces = qualifiedClassName.split("$", maxsplit=1)
+        pattern = pieces[0]
+        patterns.add(pattern)
+
+    patterns = list(patterns)
+    patterns.sort()
     return patterns
 
 def main(args):
diff --git a/scripts/hiddenapi/signature_patterns_test.py b/scripts/hiddenapi/signature_patterns_test.py
index 83c9db2..0431f45 100755
--- a/scripts/hiddenapi/signature_patterns_test.py
+++ b/scripts/hiddenapi/signature_patterns_test.py
@@ -28,12 +28,15 @@
 
     def test_generate(self):
         patterns = self.produce_patterns_from_string('''
+Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked
+Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,public-api
 Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
 Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
 ''')
         expected = [
-            "Ljava/lang/Object;->hashCode()I",
-            "Ljava/lang/Object;->toString()Ljava/lang/String;",
+            "java/lang/Character",
+            "java/lang/Object",
+            "java/lang/ProcessBuilder",
         ]
         self.assertEqual(expected, patterns)
 
diff --git a/scripts/hiddenapi/verify_overlaps.py b/scripts/hiddenapi/verify_overlaps.py
index a4a423e..6432bf1 100755
--- a/scripts/hiddenapi/verify_overlaps.py
+++ b/scripts/hiddenapi/verify_overlaps.py
@@ -331,8 +331,11 @@
     for signature in allSignatures:
         monolithicRow = monolithicFlagsDict.get(signature, {})
         monolithicFlags = monolithicRow.get(None, [])
-        modularRow = modularFlagsDict.get(signature, {})
-        modularFlags = modularRow.get(None, [])
+        if signature in modularFlagsDict:
+            modularRow = modularFlagsDict.get(signature, {})
+            modularFlags = modularRow.get(None, [])
+        else:
+            modularFlags = ["blocked"]
         if monolithicFlags != modularFlags:
             mismatchingSignatures.append((signature, modularFlags, monolithicFlags))
     return mismatchingSignatures
diff --git a/scripts/hiddenapi/verify_overlaps_test.py b/scripts/hiddenapi/verify_overlaps_test.py
index 7477254..00c0611 100755
--- a/scripts/hiddenapi/verify_overlaps_test.py
+++ b/scripts/hiddenapi/verify_overlaps_test.py
@@ -298,7 +298,7 @@
         ]
         self.assertEqual(expected, mismatches)
 
-    def test_missing_from_monolithic(self):
+    def test_match_treat_missing_from_modular_as_blocked(self):
         monolithic = self.read_signature_csv_from_string_as_dict('')
         modular = self.read_signature_csv_from_string_as_dict('''
 Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
@@ -313,7 +313,7 @@
         ]
         self.assertEqual(expected, mismatches)
 
-    def test_missing_from_modular(self):
+    def test_mismatch_treat_missing_from_modular_as_blocked(self):
         monolithic = self.read_signature_csv_from_string_as_dict('''
 Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
 ''')
@@ -322,7 +322,7 @@
         expected = [
             (
                 'Ljava/lang/Object;->hashCode()I',
-                [],
+                ['blocked'],
                 ['public-api', 'system-api', 'test-api'],
             ),
         ]
@@ -334,13 +334,7 @@
 ''')
         modular = {}
         mismatches = compare_signature_flags(monolithic, modular)
-        expected = [
-            (
-                'Ljava/lang/Object;->hashCode()I',
-                [],
-                ['blocked'],
-            ),
-        ]
+        expected = []
         self.assertEqual(expected, mismatches)
 
 if __name__ == '__main__':
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 9166109..bed2ecf 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -138,8 +138,8 @@
         metadata: "hiddenapi/metadata.csv",
         index: "hiddenapi/index.csv",
         signature_patterns: "hiddenapi/signature-patterns.csv",
-        stub_flags: "hiddenapi/stub-flags.csv",
-        all_flags: "hiddenapi/all-flags.csv",
+        stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        all_flags: "hiddenapi/filtered-flags.csv",
     },
 }
 
@@ -166,8 +166,8 @@
         metadata: "hiddenapi/metadata.csv",
         index: "hiddenapi/index.csv",
         signature_patterns: "hiddenapi/signature-patterns.csv",
-        stub_flags: "hiddenapi/stub-flags.csv",
-        all_flags: "hiddenapi/all-flags.csv",
+        stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        all_flags: "hiddenapi/filtered-flags.csv",
     },
 }
 
@@ -191,8 +191,8 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 		`),
 		snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
@@ -339,8 +339,8 @@
         metadata: "hiddenapi/metadata.csv",
         index: "hiddenapi/index.csv",
         signature_patterns: "hiddenapi/signature-patterns.csv",
-        stub_flags: "hiddenapi/stub-flags.csv",
-        all_flags: "hiddenapi/all-flags.csv",
+        stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        all_flags: "hiddenapi/filtered-flags.csv",
     },
 }
 
@@ -424,8 +424,8 @@
         metadata: "hiddenapi/metadata.csv",
         index: "hiddenapi/index.csv",
         signature_patterns: "hiddenapi/signature-patterns.csv",
-        stub_flags: "hiddenapi/stub-flags.csv",
-        all_flags: "hiddenapi/all-flags.csv",
+        stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        all_flags: "hiddenapi/filtered-flags.csv",
     },
 }
 
@@ -503,8 +503,8 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
@@ -546,13 +546,13 @@
 			android.AssertStringEquals(t, "updatable-bcp-packages.txt", expectedContents, rule.Args["content"])
 
 			rule = module.Output("out/soong/hiddenapi/hiddenapi-flags.csv.valid")
-			android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " snapshot/hiddenapi/all-flags.csv:snapshot/hiddenapi/signature-patterns.csv ")
+			android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " snapshot/hiddenapi/filtered-flags.csv:snapshot/hiddenapi/signature-patterns.csv ")
 		}),
 		snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
 		snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
 			module := result.ModuleForTests("platform-bootclasspath", "android_common")
 			rule := module.Output("out/soong/hiddenapi/hiddenapi-flags.csv.valid")
-			android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/all-flags.csv:out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv ")
+			android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv ")
 		}),
 		snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
 	)
@@ -566,6 +566,7 @@
 		java.PrepareForTestWithJavaDefaultModules,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary"),
+		java.FixtureConfigureApexBootJars("someapex:mysdklibrary", "myotherapex:myotherlib"),
 		prepareForSdkTestWithApex,
 
 		// Some additional files needed for the myotherapex.
@@ -654,8 +655,8 @@
         metadata: "hiddenapi/metadata.csv",
         index: "hiddenapi/index.csv",
         signature_patterns: "hiddenapi/signature-patterns.csv",
-        stub_flags: "hiddenapi/stub-flags.csv",
-        all_flags: "hiddenapi/all-flags.csv",
+        stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        all_flags: "hiddenapi/filtered-flags.csv",
     },
 }
 
@@ -857,8 +858,8 @@
         metadata: "hiddenapi/metadata.csv",
         index: "hiddenapi/index.csv",
         signature_patterns: "hiddenapi/signature-patterns.csv",
-        stub_flags: "hiddenapi/stub-flags.csv",
-        all_flags: "hiddenapi/all-flags.csv",
+        stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        all_flags: "hiddenapi/filtered-flags.csv",
     },
 }
 
@@ -901,8 +902,8 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index e357710..b5c6863 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -8,6 +8,100 @@
 
 readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
 
+function test_bp2build_null_build() {
+  setup
+  run_bp2build
+  local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+  run_bp2build
+  local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
+    fail "Output bp2build marker file changed on null build"
+  fi
+}
+
+test_bp2build_null_build
+
+function test_bp2build_null_build_with_globs() {
+  setup
+
+  mkdir -p foo/bar
+  cat > foo/bar/Android.bp <<'EOF'
+filegroup {
+    name: "globs",
+    srcs: ["*.txt"],
+  }
+EOF
+  touch foo/bar/a.txt foo/bar/b.txt
+
+  run_bp2build
+  local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+  run_bp2build
+  local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
+    fail "Output bp2build marker file changed on null build"
+  fi
+}
+
+test_bp2build_null_build_with_globs
+
+function test_soong_after_bp2build_regenerates_build_globs_ninja() {
+  setup
+
+  mkdir -p foo/bar
+  cat > foo/bar/Android.bp <<'EOF'
+filegroup {
+    name: "bp2build-files",
+    srcs: ["bp2build.*"],
+    bazel_module: { bp2build_available: true },
+}
+
+filegroup {
+    name: "soong-files",
+    srcs: ["soong.*"],
+}
+EOF
+  touch foo/bar/bp2build.txt foo/bar/soong.txt
+
+  build_globs_file="out/soong/.bootstrap/build-globs.ninja"
+
+  # Test: the build-globs file for bp2build should only contain the bp2build-files
+  # glob, whereas the build-globs file for soong should contain both bp2build-files
+  # and soong-files globs.
+
+  run_bp2build
+  local output_mtime1=$(stat -c "%y" "${build_globs_file}")
+
+  if ! grep "\"foo/bar/bp2build.*\"" "${build_globs_file}"; then
+    fail "bp2build filegroup globs not found in bp2build's globs file"
+  fi
+
+  if grep "\"foo/bar/soong.*\"" "${build_globs_file}"; then
+    fail "soong filegroup globs unexpectedly found in bp2build's globs file"
+  fi
+
+  run_soong
+  local output_mtime2=$(stat -c "%y" "${build_globs_file}")
+
+  if [[ "$output_mtime1" == "$output_mtime2" ]]; then
+    fail "Output build-globs.ninja file did not change"
+  fi
+
+  if ! grep "\"foo/bar/bp2build.*\"" "${build_globs_file}"; then
+    fail "bp2build filegroup globs not found in bp2build's globs file"
+  fi
+
+  if ! grep "\"foo/bar/soong.*\"" "${build_globs_file}"; then
+    fail "soong filegroup globs not found in bp2build's globs file"
+  fi
+
+}
+
+test_soong_after_bp2build_regenerates_build_globs_ninja
+
 function test_bp2build_generates_all_buildfiles {
   setup
   create_mock_bazel
diff --git a/tests/lib.sh b/tests/lib.sh
index 1d9b8d4..813a9dd 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -113,6 +113,7 @@
 
   symlink_directory prebuilts/bazel
   symlink_directory prebuilts/jdk
+  symlink_directory external/bazel-skylib
 
   symlink_file WORKSPACE
   symlink_file BUILD
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 8399573..6304a11 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -6,3 +6,4 @@
 "$TOP/build/soong/tests/bootstrap_test.sh"
 "$TOP/build/soong/tests/mixed_mode_test.sh"
 "$TOP/build/soong/tests/bp2build_bazel_test.sh"
+"$TOP/build/soong/tests/soong_test.sh"
diff --git a/tests/soong_test.sh b/tests/soong_test.sh
new file mode 100755
index 0000000..905d708
--- /dev/null
+++ b/tests/soong_test.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Tests of Soong functionality
+
+source "$(dirname "$0")/lib.sh"
+
+function test_m_clean_works {
+  setup
+
+  # Create a directory with files that cannot be removed
+  mkdir -p out/bad_directory_permissions
+  touch out/bad_directory_permissions/unremovable_file
+  # File permissions are fine but directory permissions are bad
+  chmod a+rwx out/bad_directory_permissions/unremovable_file
+  chmod a-rwx out/bad_directory_permissions
+
+  run_soong clean
+}
+
+test_m_clean_works
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 37940ba..3dc87f5 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -61,7 +61,6 @@
         "proc_sync.go",
         "rbe.go",
         "sandbox_config.go",
-        "signal.go",
         "soong.go",
         "test_build.go",
         "upload.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 1ed9014..d869bf0 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -238,6 +238,11 @@
 		ctx.Verboseln("Skipping use of Kati ninja as requested")
 		what = what &^ RunKatiNinja
 	}
+	if config.SkipSoong() {
+		ctx.Verboseln("Skipping use of Soong as requested")
+		what = what &^ RunSoong
+	}
+
 	if config.SkipNinja() {
 		ctx.Verboseln("Skipping Ninja as requested")
 		what = what &^ RunNinja
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 19b5690..65b91bc 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -17,6 +17,7 @@
 import (
 	"bytes"
 	"fmt"
+	"io/fs"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -46,9 +47,49 @@
 	}
 }
 
+// Based on https://stackoverflow.com/questions/28969455/how-to-properly-instantiate-os-filemode
+// Because Go doesn't provide a nice way to set bits on a filemode
+const (
+	FILEMODE_READ         = 04
+	FILEMODE_WRITE        = 02
+	FILEMODE_EXECUTE      = 01
+	FILEMODE_USER_SHIFT   = 6
+	FILEMODE_USER_READ    = FILEMODE_READ << FILEMODE_USER_SHIFT
+	FILEMODE_USER_WRITE   = FILEMODE_WRITE << FILEMODE_USER_SHIFT
+	FILEMODE_USER_EXECUTE = FILEMODE_EXECUTE << FILEMODE_USER_SHIFT
+)
+
+// Ensures that files and directories in the out dir can be deleted.
+// For example, Bazen can generate output directories where the write bit isn't set, causing 'm' clean' to fail.
+func ensureOutDirRemovable(ctx Context, config Config) {
+	err := filepath.WalkDir(config.OutDir(), func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			return err
+		}
+		if d.IsDir() {
+			info, err := d.Info()
+			if err != nil {
+				return err
+			}
+			// Equivalent to running chmod u+rwx on each directory
+			newMode := info.Mode() | FILEMODE_USER_READ | FILEMODE_USER_WRITE | FILEMODE_USER_EXECUTE
+			if err := os.Chmod(path, newMode); err != nil {
+				return err
+			}
+		}
+		// Continue walking the out dir...
+		return nil
+	})
+	if err != nil && !os.IsNotExist(err) {
+		// Display the error, but don't crash.
+		ctx.Println(err.Error())
+	}
+}
+
 // Remove everything under the out directory. Don't remove the out directory
 // itself in case it's a symlink.
 func clean(ctx Context, config Config) {
+	ensureOutDirRemovable(ctx, config)
 	removeGlobs(ctx, filepath.Join(config.OutDir(), "*"))
 	ctx.Println("Entire build directory removed.")
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index 918a956..9768a44 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -49,6 +49,7 @@
 	skipConfig     bool
 	skipKati       bool
 	skipKatiNinja  bool
+	skipSoong      bool
 	skipNinja      bool
 	skipSoongTests bool
 
@@ -582,6 +583,8 @@
 		arg := strings.TrimSpace(args[i])
 		if arg == "showcommands" {
 			c.verbose = true
+		} else if arg == "--empty-ninja-file" {
+			c.emptyNinjaFile = true
 		} else if arg == "--skip-ninja" {
 			c.skipNinja = true
 		} else if arg == "--skip-make" {
@@ -596,6 +599,10 @@
 		} else if arg == "--soong-only" {
 			c.skipKati = true
 			c.skipKatiNinja = true
+		} else if arg == "--config-only" {
+			c.skipKati = true
+			c.skipKatiNinja = true
+			c.skipSoong = true
 		} else if arg == "--skip-config" {
 			c.skipConfig = true
 		} else if arg == "--skip-soong-tests" {
@@ -690,54 +697,6 @@
 	}
 }
 
-// Lunch configures the environment for a specific product similarly to the
-// `lunch` bash function.
-func (c *configImpl) Lunch(ctx Context, product, variant string) {
-	if variant != "eng" && variant != "userdebug" && variant != "user" {
-		ctx.Fatalf("Invalid variant %q. Must be one of 'user', 'userdebug' or 'eng'", variant)
-	}
-
-	c.environ.Set("TARGET_PRODUCT", product)
-	c.environ.Set("TARGET_BUILD_VARIANT", variant)
-	c.environ.Set("TARGET_BUILD_TYPE", "release")
-	c.environ.Unset("TARGET_BUILD_APPS")
-	c.environ.Unset("TARGET_BUILD_UNBUNDLED")
-}
-
-// Tapas configures the environment to build one or more unbundled apps,
-// similarly to the `tapas` bash function.
-func (c *configImpl) Tapas(ctx Context, apps []string, arch, variant string) {
-	if len(apps) == 0 {
-		apps = []string{"all"}
-	}
-	if variant == "" {
-		variant = "eng"
-	}
-
-	if variant != "eng" && variant != "userdebug" && variant != "user" {
-		ctx.Fatalf("Invalid variant %q. Must be one of 'user', 'userdebug' or 'eng'", variant)
-	}
-
-	var product string
-	switch arch {
-	case "arm", "":
-		product = "aosp_arm"
-	case "arm64":
-		product = "aosm_arm64"
-	case "x86":
-		product = "aosp_x86"
-	case "x86_64":
-		product = "aosp_x86_64"
-	default:
-		ctx.Fatalf("Invalid architecture: %q", arch)
-	}
-
-	c.environ.Set("TARGET_PRODUCT", product)
-	c.environ.Set("TARGET_BUILD_VARIANT", variant)
-	c.environ.Set("TARGET_BUILD_TYPE", "release")
-	c.environ.Set("TARGET_BUILD_APPS", strings.Join(apps, " "))
-}
-
 func (c *configImpl) Environment() *Environment {
 	return c.environ
 }
@@ -817,6 +776,10 @@
 	return c.skipKatiNinja
 }
 
+func (c *configImpl) SkipSoong() bool {
+	return c.skipSoong
+}
+
 func (c *configImpl) SkipNinja() bool {
 	return c.skipNinja
 }
diff --git a/ui/signal/Android.bp b/ui/signal/Android.bp
new file mode 100644
index 0000000..08933a1
--- /dev/null
+++ b/ui/signal/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2021 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-ui-signal",
+    pkgPath: "android/soong/ui/signal",
+    srcs: [
+        "signal.go",
+    ],
+    deps: [
+        "soong-ui-logger",
+    ],
+}
diff --git a/ui/build/signal.go b/ui/signal/signal.go
similarity index 99%
rename from ui/build/signal.go
rename to ui/signal/signal.go
index 6643e2f..4929a7b 100644
--- a/ui/build/signal.go
+++ b/ui/signal/signal.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package build
+package signal
 
 import (
 	"os"