Merge "Revert "Disable stripping for riscv64""
diff --git a/.gitignore b/.gitignore
index 45884c4..5d2bc0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
 /.idea
 *.iml
+*.ipr
+*.iws
+
diff --git a/README.md b/README.md
index 87d6948..18cf7b2 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,33 @@
 # Soong
 
-Soong is the replacement for the old Android make-based build system.  It
-replaces Android.mk files with Android.bp files, which are JSON-like simple
-declarative descriptions of modules to build.
+Soong is one of the build systems used in Android. There are altogether three:
+* The legacy Make-based build system that is controlled by files called
+  `Android.mk`.
+* Soong, which is controlled by files called `Android.bp`.
+* The upcoming Bazel-based build system that is controlled by files called
+  `BUILD.bazel`.
+
+`Android.bp` file are JSON-like declarative descriptions of "modules" to build;
+a "module" is the basic unit of building that Soong understands, similarly to
+how "target" is the basic unit of building for Bazel (and Make, although the
+two kinds of "targets" are very different)
 
 See [Simple Build
 Configuration](https://source.android.com/compatibility/tests/development/blueprints)
 on source.android.com to read how Soong is configured for testing.
 
+### Contributing
+
+Code reviews are handled through the usual code review system of Android,
+available [here](https://android-review.googlesource.com/dashboard/self).
+
+For simple changes (fixing typos, obvious optimizations, etc.), sending a code
+review request is enough. For more substantial changes, file a bug in our
+[bug tracker](https://issuetracker.google.com/issues/new?component=381517) or
+or write us at android-building@googlegroups.com .
+
+For Googlers, see our [internal documentation](http://go/soong).
+
 ## Android.bp file format
 
 By design, Android.bp files are very simple.  There are no conditionals or
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index b09b923..16f144e 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -33,6 +33,10 @@
 	// all modules in this package (not recursively) default to bp2build_available: false.
 	// allows modules to opt-in.
 	Bp2BuildDefaultFalse
+
+	// all modules in this package and subpackages default to bp2build_available: false.
+	// allows modules to opt-in.
+	Bp2BuildDefaultFalseRecursively
 )
 
 var (
@@ -45,6 +49,7 @@
 		"art/runtime":                           Bp2BuildDefaultTrueRecursively,
 		"art/tools":                             Bp2BuildDefaultTrue,
 		"bionic":                                Bp2BuildDefaultTrueRecursively,
+		"bootable/recovery/applypatch":          Bp2BuildDefaultTrue,
 		"bootable/recovery/minadbd":             Bp2BuildDefaultTrue,
 		"bootable/recovery/minui":               Bp2BuildDefaultTrue,
 		"bootable/recovery/recovery_utils":      Bp2BuildDefaultTrue,
@@ -52,6 +57,7 @@
 
 		"build/bazel":                        Bp2BuildDefaultTrueRecursively,
 		"build/make/target/product/security": Bp2BuildDefaultTrue,
+		"build/make/tools/releasetools":      Bp2BuildDefaultTrue,
 		"build/make/tools/signapk":           Bp2BuildDefaultTrue,
 		"build/make/tools/zipalign":          Bp2BuildDefaultTrueRecursively,
 		"build/soong":                        Bp2BuildDefaultTrue,
@@ -63,6 +69,9 @@
 		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
 
 		"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
+
+		"dalvik/tools/dexdeps": Bp2BuildDefaultTrueRecursively,
+
 		"development/apps/DevelopmentSettings":        Bp2BuildDefaultTrue,
 		"development/apps/Fallback":                   Bp2BuildDefaultTrue,
 		"development/apps/WidgetPreview":              Bp2BuildDefaultTrue,
@@ -102,13 +111,15 @@
 
 		"external/aac":                           Bp2BuildDefaultTrueRecursively,
 		"external/arm-optimized-routines":        Bp2BuildDefaultTrueRecursively,
-		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
 		"external/auto":                          Bp2BuildDefaultTrue,
+		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
 		"external/auto/common":                   Bp2BuildDefaultTrueRecursively,
 		"external/auto/service":                  Bp2BuildDefaultTrueRecursively,
 		"external/boringssl":                     Bp2BuildDefaultTrueRecursively,
 		"external/bouncycastle":                  Bp2BuildDefaultTrue,
 		"external/brotli":                        Bp2BuildDefaultTrue,
+		"external/bsdiff":                        Bp2BuildDefaultTrueRecursively,
+		"external/bzip2":                         Bp2BuildDefaultTrueRecursively,
 		"external/conscrypt":                     Bp2BuildDefaultTrue,
 		"external/e2fsprogs":                     Bp2BuildDefaultTrueRecursively,
 		"external/eigen":                         Bp2BuildDefaultTrueRecursively,
@@ -138,6 +149,7 @@
 		"external/libcap":                        Bp2BuildDefaultTrueRecursively,
 		"external/libcxx":                        Bp2BuildDefaultTrueRecursively,
 		"external/libcxxabi":                     Bp2BuildDefaultTrueRecursively,
+		"external/libdivsufsort":                 Bp2BuildDefaultTrueRecursively,
 		"external/libdrm":                        Bp2BuildDefaultTrue,
 		"external/libevent":                      Bp2BuildDefaultTrueRecursively,
 		"external/libgav1":                       Bp2BuildDefaultTrueRecursively,
@@ -148,6 +160,7 @@
 		"external/libvpx":                        Bp2BuildDefaultTrueRecursively,
 		"external/libyuv":                        Bp2BuildDefaultTrueRecursively,
 		"external/lz4/lib":                       Bp2BuildDefaultTrue,
+		"external/lz4/programs":                  Bp2BuildDefaultTrue,
 		"external/lzma/C":                        Bp2BuildDefaultTrueRecursively,
 		"external/mdnsresponder":                 Bp2BuildDefaultTrueRecursively,
 		"external/minijail":                      Bp2BuildDefaultTrueRecursively,
@@ -166,18 +179,19 @@
 		"external/zopfli":                        Bp2BuildDefaultTrueRecursively,
 		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
 
-		"frameworks/av":                                      Bp2BuildDefaultTrue,
-		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
+		"frameworks/av": Bp2BuildDefaultTrue,
 		"frameworks/av/media/codec2/components/aom":          Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/module/minijail":                Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
 		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
 		"frameworks/base/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
 		"frameworks/base/startop/apps/test":                  Bp2BuildDefaultTrue,
 		"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/tools/aapt2":                        Bp2BuildDefaultTrue,
+		"frameworks/base/tools/streaming_proto":              Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/adbd_auth":                   Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/arect":                       Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/gui":                         Bp2BuildDefaultTrue,
@@ -190,17 +204,17 @@
 		"frameworks/native/opengl/tests/testPauseResume":     Bp2BuildDefaultTrue,
 		"frameworks/native/opengl/tests/testViewport":        Bp2BuildDefaultTrue,
 		"frameworks/native/services/batteryservice":          Bp2BuildDefaultTrue,
-		"frameworks/proto_logging/stats/stats_log_api_gen":   Bp2BuildDefaultTrueRecursively,
+		"frameworks/proto_logging/stats":                     Bp2BuildDefaultTrueRecursively,
 
 		"hardware/interfaces":                          Bp2BuildDefaultTrue,
 		"hardware/interfaces/common/aidl":              Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/1.0":          Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/1.1":          Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/utils":        Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/aidl":  Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/2.0":   Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/3.0":   Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/4.0":   Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/aidl":  Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/bufferqueue/1.0": Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/bufferqueue/2.0": Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/common/1.0":      Bp2BuildDefaultTrue,
@@ -238,6 +252,7 @@
 		"packages/apps/Protips":                            Bp2BuildDefaultTrue,
 		"packages/apps/SafetyRegulatoryInfo":               Bp2BuildDefaultTrue,
 		"packages/apps/WallpaperPicker":                    Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/driver/cache":     Bp2BuildDefaultTrueRecursively,
 		"packages/modules/StatsD/lib/libstatssocket":       Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb":                             Bp2BuildDefaultTrue,
 		"packages/modules/adb/apex":                        Bp2BuildDefaultTrue,
@@ -248,7 +263,6 @@
 		"packages/modules/adb/proto":                       Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb/tls":                         Bp2BuildDefaultTrueRecursively,
 		"packages/providers/MediaProvider/tools/dialogs":   Bp2BuildDefaultFalse, // TODO(b/242834374)
-		"packages/modules/NeuralNetworks/driver/cache":     Bp2BuildDefaultTrueRecursively,
 		"packages/screensavers/Basic":                      Bp2BuildDefaultTrue,
 		"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
 
@@ -261,6 +275,9 @@
 		"prebuilts/tools":                          Bp2BuildDefaultTrue,
 		"prebuilts/tools/common/m2":                Bp2BuildDefaultTrue,
 
+		"sdk/dumpeventlog":  Bp2BuildDefaultTrue,
+		"sdk/eventanalyzer": Bp2BuildDefaultTrue,
+
 		"system/apex":                                            Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
 		"system/apex/apexer":                                     Bp2BuildDefaultTrue,
 		"system/apex/libs":                                       Bp2BuildDefaultTrueRecursively,
@@ -282,6 +299,7 @@
 		"system/core/libsysutils":                                Bp2BuildDefaultTrueRecursively,
 		"system/core/libutils":                                   Bp2BuildDefaultTrueRecursively,
 		"system/core/libvndksupport":                             Bp2BuildDefaultTrueRecursively,
+		"system/core/mkbootfs":                                   Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoparser":     Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoserializer": Bp2BuildDefaultTrueRecursively,
 		"system/extras/toolchain-extras":                         Bp2BuildDefaultTrue,
@@ -315,11 +333,10 @@
 		"system/timezone/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/timezone/output_data":                            Bp2BuildDefaultTrueRecursively,
 		"system/tools/aidl/build/tests_bp2build":                 Bp2BuildDefaultTrue,
+		"system/tools/mkbootimg":                                 Bp2BuildDefaultTrueRecursively,
 		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/unwinding/libunwindstack":                        Bp2BuildDefaultTrueRecursively,
 
-		"frameworks/proto_logging/stats": Bp2BuildDefaultTrueRecursively,
-
 		"tools/apksig": Bp2BuildDefaultTrue,
 		"tools/platform-compat/java/android/compat":  Bp2BuildDefaultTrueRecursively,
 		"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
@@ -387,8 +404,10 @@
 		"com.android.neuralnetworks.certificate",
 		"com.android.neuralnetworks.key",
 		"flatbuffer_headers",
+		"framework-connectivity-protos",
 		"gemmlowp_headers",
 		"gl_headers",
+		"ipconnectivity-proto-src",
 		"libaidlcommonsupport",
 		"libandroid_runtime_lazy",
 		"libandroid_runtime_vm_headers",
@@ -464,6 +483,7 @@
 		"philox_random",
 		"philox_random_headers",
 		"server_configurable_flags",
+		"service-permission-streaming-proto-sources",
 		"statslog_neuralnetworks.cpp",
 		"statslog_neuralnetworks.h",
 		"tensorflow_headers",
@@ -472,8 +492,10 @@
 		"libstagefright_bufferpool@2.0.1",
 		"libSurfaceFlingerProp",
 
+		// prebuilts
+		"prebuilt_stats-log-api-gen",
+
 		// fastboot
-		"bootimg_headers",
 		"fastboot",
 		"libfastboot",
 		"liblp",
@@ -506,6 +528,7 @@
 
 		//system/extras/verity/fec
 		"fec",
+		"boot_signer",
 
 		//packages/apps/Car/libs/car-ui-lib/car-ui-androidx
 		// genrule dependencies for java_imports
@@ -589,8 +612,6 @@
 		"libEGL_getProcAddress",
 		"libEGL_blobCache",
 
-		"protoc-gen-cppstream",
-
 		"mediaswcodec",
 		"libmedia_headers",
 		"libmedia_codecserviceregistrant",
@@ -1244,6 +1265,33 @@
 		"launcherprotosnano",
 		"datastallprotosnano",
 		"devicepolicyprotosnano",
+		"ota_metadata_proto_java",
+		"merge_ota",
+
+		// releasetools
+		"releasetools_fsverity_metadata_generator",
+		"verity_utils",
+		"check_ota_package_signature",
+		"check_target_files_vintf",
+		"releasetools_check_target_files_vintf",
+		"releasetools_verity_utils",
+		"build_image",
+		"ota_from_target_files",
+		"releasetools_ota_from_target_files",
+		"releasetools_build_image",
+		"add_img_to_target_files",
+		"releasetools_add_img_to_target_files",
+		"fsverity_metadata_generator",
+		"sign_target_files_apks",
+
+		// depends on the support of yacc file
+		"libapplypatch",
+		"libapplypatch_modes",
+		"applypatch",
+
+		// TODO(b/254476335): disable the following due to this bug
+		"libapexinfo",
+		"libapexinfo_tests",
 	}
 
 	Bp2buildCcLibraryStaticOnlyList = []string{}
@@ -1292,23 +1340,14 @@
 		"prebuilt_platform-robolectric-4.4-prebuilt",
 		"prebuilt_platform-robolectric-4.5.1-prebuilt",
 		"prebuilt_currysrc_org.eclipse",
-
-		// TODO(b/247782695 and/or b/242847534) Fix mixed build between unconverted gensrcs and converted filegroup
-		"libstats_atom_enum_protos",
-		"data_stall_event_proto",
-		"device_policy_proto",
-		"dns_resolver_proto",
-		"launcher_proto",
-		"network_stack_proto",
-		"srcs_bluetooth_protos",
-		"srcs_bluetooth_leaudio_protos",
-		"style_proto",
-		"tethering_proto",
-		"text_classifier_proto",
-		"libstats_atom_message_protos",
 	}
 
-	ProdMixedBuildsEnabledList = []string{
-		"com.android.adbd",
-	}
+	// Bazel prod-mode allowlist. Modules in this list are built by Bazel
+	// in either prod mode or staging mode.
+	ProdMixedBuildsEnabledList = []string{}
+
+	// Staging-mode allowlist. Modules in this list are only built
+	// by Bazel with --bazel-mode-staging. This list should contain modules
+	// which will soon be added to the prod allowlist.
+	StagingMixedBuildsEnabledList = []string{"com.android.tzdata"}
 )
diff --git a/android/api_domain.go b/android/api_domain.go
index 7876654..3265148 100644
--- a/android/api_domain.go
+++ b/android/api_domain.go
@@ -70,13 +70,11 @@
 	return m
 }
 
+// Do not create any dependency edges in Soong for now to skip visibility checks for some systemapi libraries.
+// Currently, all api_domain modules reside in build/orchestrator/apis/Android.bp
+// However, cc libraries like libsigchain (com.android.art) restrict their visibility to art/*
+// When the api_domain module types are collocated with their contributions, this dependency edge can be restored
 func (a *apiDomain) DepsMutator(ctx BottomUpMutatorContext) {
-	for _, cc := range a.properties.Cc_api_contributions {
-		// Use FarVariationDependencies since the variants of api_domain is a subset of the variants of the dependency cc module
-		// Creating a dependency on the first variant is ok since this is a no-op in Soong
-		// The primary function of this dependency is to create a connected graph in the corresponding bp2build workspace
-		ctx.AddFarVariationDependencies([]blueprint.Variation{}, nil, cc)
-	}
 }
 
 // API domain does not have any builld actions yet
diff --git a/android/arch.go b/android/arch.go
index 75ee922..086e945 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1687,14 +1687,12 @@
 	abi         []string
 }
 
-// getNdkAbisConfig returns the list of archConfigs that are used for bulding
-// the API stubs and static libraries that are included in the NDK. These are
-// built *without Neon*, because non-Neon is still supported and building these
-// with Neon will break those users.
+// getNdkAbisConfig returns the list of archConfigs that are used for building
+// the API stubs and static libraries that are included in the NDK.
 func getNdkAbisConfig() []archConfig {
 	return []archConfig{
 		{"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
-		{"arm", "armv7-a", "", []string{"armeabi-v7a"}},
+		{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
 		{"x86_64", "", "", []string{"x86_64"}},
 		{"x86", "", "", []string{"x86"}},
 	}
diff --git a/android/bazel.go b/android/bazel.go
index 7b227bd..d30cb80 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -489,21 +489,27 @@
 	// Check if the package path has an exact match in the config.
 	if config[packagePath] == allowlists.Bp2BuildDefaultTrue || config[packagePath] == allowlists.Bp2BuildDefaultTrueRecursively {
 		return true, packagePath
-	} else if config[packagePath] == allowlists.Bp2BuildDefaultFalse {
+	} else if config[packagePath] == allowlists.Bp2BuildDefaultFalse || config[packagePath] == allowlists.Bp2BuildDefaultFalseRecursively {
 		return false, packagePath
 	}
 
 	// If not, check for the config recursively.
-	packagePrefix := ""
-	// e.g. for x/y/z, iterate over x, x/y, then x/y/z, taking the final value from the allowlist.
-	for _, part := range strings.Split(packagePath, "/") {
-		packagePrefix += part
-		if config[packagePrefix] == allowlists.Bp2BuildDefaultTrueRecursively {
+	packagePrefix := packagePath
+
+	// e.g. for x/y/z, iterate over x/y, then x, taking the most-specific value from the allowlist.
+	for strings.Contains(packagePrefix, "/") {
+		dirIndex := strings.LastIndex(packagePrefix, "/")
+		packagePrefix = packagePrefix[:dirIndex]
+		switch value := config[packagePrefix]; value {
+		case allowlists.Bp2BuildDefaultTrueRecursively:
 			// package contains this prefix and this prefix should convert all modules
 			return true, packagePrefix
+		case allowlists.Bp2BuildDefaultFalseRecursively:
+			//package contains this prefix and this prefix should NOT convert any modules
+			return false, packagePrefix
 		}
 		// Continue to the next part of the package dir.
-		packagePrefix += "/"
+
 	}
 
 	return false, packagePath
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index e81086d..eec78d2 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -142,7 +142,10 @@
 	GetPythonBinary(label string, cfgKey configKey) (string, error)
 
 	// Returns the results of the GetApexInfo query (including output files)
-	GetApexInfo(label string, cfgkey configKey) (cquery.ApexCqueryInfo, error)
+	GetApexInfo(label string, cfgkey configKey) (cquery.ApexInfo, error)
+
+	// Returns the results of the GetCcUnstrippedInfo query
+	GetCcUnstrippedInfo(label string, cfgkey configKey) (cquery.CcUnstrippedInfo, error)
 
 	// ** end Cquery Results Retrieval Functions
 
@@ -172,12 +175,13 @@
 }
 
 type bazelPaths struct {
-	homeDir      string
-	bazelPath    string
-	outputBase   string
-	workspaceDir string
-	soongOutDir  string
-	metricsDir   string
+	homeDir       string
+	bazelPath     string
+	outputBase    string
+	workspaceDir  string
+	soongOutDir   string
+	metricsDir    string
+	bazelDepsFile string
 }
 
 // A context object which tracks queued requests that need to be made to Bazel,
@@ -222,7 +226,8 @@
 	LabelToOutputFiles  map[string][]string
 	LabelToCcInfo       map[string]cquery.CcInfo
 	LabelToPythonBinary map[string]string
-	LabelToApexInfo     map[string]cquery.ApexCqueryInfo
+	LabelToApexInfo     map[string]cquery.ApexInfo
+	LabelToCcBinary     map[string]cquery.CcUnstrippedInfo
 }
 
 func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
@@ -244,8 +249,14 @@
 	return result, nil
 }
 
-func (n MockBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
-	panic("unimplemented")
+func (m MockBazelContext) GetApexInfo(label string, _ configKey) (cquery.ApexInfo, error) {
+	result, _ := m.LabelToApexInfo[label]
+	return result, nil
+}
+
+func (m MockBazelContext) GetCcUnstrippedInfo(label string, _ configKey) (cquery.CcUnstrippedInfo, error) {
+	result, _ := m.LabelToCcBinary[label]
+	return result, nil
 }
 
 func (m MockBazelContext) InvokeBazel(_ Config) error {
@@ -303,12 +314,20 @@
 	return "", fmt.Errorf("no bazel response found for %v", key)
 }
 
-func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) {
+func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexInfo, error) {
 	key := makeCqueryKey(label, cquery.GetApexInfo, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
-		return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString)), nil
+		return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString))
 	}
-	return cquery.ApexCqueryInfo{}, fmt.Errorf("no bazel response found for %v", key)
+	return cquery.ApexInfo{}, fmt.Errorf("no bazel response found for %v", key)
+}
+
+func (bazelCtx *bazelContext) GetCcUnstrippedInfo(label string, cfgKey configKey) (cquery.CcUnstrippedInfo, error) {
+	key := makeCqueryKey(label, cquery.GetCcUnstrippedInfo, cfgKey)
+	if rawString, ok := bazelCtx.results[key]; ok {
+		return cquery.GetCcUnstrippedInfo.ParseResult(strings.TrimSpace(rawString))
+	}
+	return cquery.CcUnstrippedInfo{}, fmt.Errorf("no bazel response for %s", key)
 }
 
 func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
@@ -327,10 +346,15 @@
 	panic("unimplemented")
 }
 
-func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexInfo, error) {
 	panic("unimplemented")
 }
 
+func (n noopBazelContext) GetCcUnstrippedInfo(_ string, _ configKey) (cquery.CcUnstrippedInfo, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
 func (n noopBazelContext) InvokeBazel(_ Config) error {
 	panic("unimplemented")
 }
@@ -363,6 +387,15 @@
 		for _, enabledProdModule := range allowlists.ProdMixedBuildsEnabledList {
 			enabledModules[enabledProdModule] = true
 		}
+	case BazelStagingMode:
+		modulesDefaultToBazel = false
+		// Staging mode includes all prod modules plus all staging modules.
+		for _, enabledProdModule := range allowlists.ProdMixedBuildsEnabledList {
+			enabledModules[enabledProdModule] = true
+		}
+		for _, enabledStagingMode := range allowlists.StagingMixedBuildsEnabledList {
+			enabledModules[enabledStagingMode] = true
+		}
 	case BazelDevMode:
 		modulesDefaultToBazel = true
 
@@ -424,6 +457,11 @@
 	} else {
 		missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR")
 	}
+	if len(c.Getenv("BAZEL_DEPS_FILE")) > 1 {
+		p.bazelDepsFile = c.Getenv("BAZEL_DEPS_FILE")
+	} else {
+		missingEnvVars = append(missingEnvVars, "BAZEL_DEPS_FILE")
+	}
 	if len(missingEnvVars) > 0 {
 		return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
 	} else {
@@ -523,9 +561,7 @@
 		//
 		// The actual platform values here may be overridden by configuration
 		// transitions from the buildroot.
-		fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_target"),
 		fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"),
-
 		// This should be parameterized on the host OS, but let's restrict to linux
 		// to keep things simple for now.
 		fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"),
@@ -535,7 +571,9 @@
 
 		// Suppress noise
 		"--ui_event_filters=-INFO",
-		"--noshow_progress"}
+		"--noshow_progress",
+		"--norun_validations",
+	}
 	cmdFlags = append(cmdFlags, extraFlags...)
 
 	bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
@@ -544,7 +582,7 @@
 		"HOME=" + paths.homeDir,
 		pwdPrefix(),
 		"BUILD_DIR=" + absolutePath(paths.soongOutDir),
-		// Make OUT_DIR absolute here so tools/bazel.sh uses the correct
+		// Make OUT_DIR absolute here so build/bazel/bin/bazel uses the correct
 		// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
 		"OUT_DIR=" + absolutePath(paths.outDir()),
 		// Disables local host detection of gcc; toolchain information is defined
@@ -894,7 +932,7 @@
 	//
 	// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
 	// proto sources, which would add a number of unnecessary dependencies.
-	extraFlags := []string{"--output=jsonproto", "--include_file_write_contents"}
+	extraFlags := []string{"--output=proto", "--include_file_write_contents"}
 	if Bool(config.productVariables.ClangCoverage) {
 		extraFlags = append(extraFlags, "--collect_code_coverage")
 		paths := make([]string, 0, 2)
@@ -1050,7 +1088,7 @@
 
 	// Remove old outputs, as some actions might not rerun if the outputs are detected.
 	if len(buildStatement.OutputPaths) > 0 {
-		cmd.Text("rm -f")
+		cmd.Text("rm -rf") // -r because outputs can be Bazel dir/tree artifacts.
 		for _, outputPath := range buildStatement.OutputPaths {
 			cmd.Text(fmt.Sprintf("'%s'", outputPath))
 		}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index dc2261c..6e3acd5 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -1,6 +1,7 @@
 package android
 
 import (
+	"encoding/json"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -8,6 +9,9 @@
 	"testing"
 
 	"android/soong/bazel/cquery"
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
+	"google.golang.org/protobuf/proto"
 )
 
 var testConfig = TestConfig("out", nil, "", nil)
@@ -65,52 +69,56 @@
 	var testCases = []testCase{
 		{`
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [1],
-    "primaryOutputId": 1
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 2] }],
-  "pathFragments": [
-    { "id": 1, "label": "one" },
-    { "id": 2, "label": "two" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+   "target_Id": 1,
+   "action_Key": "x",
+   "mnemonic": "x",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [1],
+   "output_Ids": [1],
+   "primary_output_id": 1
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1, 2] }],
+ "path_fragments": [
+   { "id": 1, "label": "one" },
+   { "id": 2, "label": "two" }]
 }`,
-			"cd 'test/exec_root' && rm -f 'one' && touch foo",
+			"cd 'test/exec_root' && rm -rf 'one' && touch foo",
 		}, {`
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 10 },
-    { "id": 2, "pathFragmentId": 20 }],
-  "actions": [{
-    "targetId": 100,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["bogus", "command"],
-    "outputIds": [1, 2],
-    "primaryOutputId": 1
-  }],
-  "pathFragments": [
-    { "id": 10, "label": "one", "parentId": 30 },
-    { "id": 20, "label": "one.d", "parentId": 30 },
-    { "id": 30, "label": "parent" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 10 },
+   { "id": 2, "path_fragment_id": 20 }],
+ "actions": [{
+   "target_Id": 100,
+   "action_Key": "x",
+   "mnemonic": "x",
+   "arguments": ["bogus", "command"],
+   "output_Ids": [1, 2],
+   "primary_output_id": 1
+ }],
+ "path_fragments": [
+   { "id": 10, "label": "one", "parent_id": 30 },
+   { "id": 20, "label": "one.d", "parent_id": 30 },
+   { "id": 30, "label": "parent" }]
 }`,
-			`cd 'test/exec_root' && rm -f 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
+			`cd 'test/exec_root' && rm -rf 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
 		},
 	}
 
 	for i, testCase := range testCases {
+		data, err := JsonToActionGraphContainer(testCase.input)
+		if err != nil {
+			t.Error(err)
+		}
 		bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
-			bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: testCase.input})
+			bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: string(data)})
 
-		err := bazelContext.InvokeBazel(testConfig)
+		err = bazelContext.InvokeBazel(testConfig)
 		if err != nil {
 			t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
 		}
@@ -194,3 +202,14 @@
 		requests:    map[cqueryKey]bool{},
 	}, p.soongOutDir
 }
+
+// Transform the json format to ActionGraphContainer
+func JsonToActionGraphContainer(inputString string) ([]byte, error) {
+	var aqueryProtoResult analysis_v2_proto.ActionGraphContainer
+	err := json.Unmarshal([]byte(inputString), &aqueryProtoResult)
+	if err != nil {
+		return []byte(""), err
+	}
+	data, _ := proto.Marshal(&aqueryProtoResult)
+	return data, err
+}
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 9c50098..b2ea22f 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -534,3 +534,55 @@
 	}
 	return outs
 }
+
+// BazelStringOrLabelFromProp splits a Soong module property that can be
+// either a string literal, path (with android:path tag) or a module reference
+// into separate bazel string or label attributes. Bazel treats string and label
+// attributes as distinct types, so this function categorizes a string property
+// into either one of them.
+//
+// e.g. apex.private_key = "foo.pem" can either refer to:
+//
+// 1. "foo.pem" in the current directory -> file target
+// 2. "foo.pem" module -> rule target
+// 3. "foo.pem" file in a different directory, prefixed by a product variable handled
+// in a bazel macro. -> string literal
+//
+// For the first two cases, they are defined using the label attribute. For the third case,
+// it's defined with the string attribute.
+func BazelStringOrLabelFromProp(
+	ctx TopDownMutatorContext,
+	propToDistinguish *string) (bazel.LabelAttribute, bazel.StringAttribute) {
+
+	var labelAttr bazel.LabelAttribute
+	var strAttr bazel.StringAttribute
+
+	if propToDistinguish == nil {
+		// nil pointer
+		return labelAttr, strAttr
+	}
+
+	prop := String(propToDistinguish)
+	if SrcIsModule(prop) != "" {
+		// If it's a module (SrcIsModule will return the module name), set the
+		// resolved label to the label attribute.
+		labelAttr.SetValue(BazelLabelForModuleDepSingle(ctx, prop))
+	} else {
+		// Not a module name. This could be a string literal or a file target in
+		// the current dir. Check if the path exists:
+		path := ExistentPathForSource(ctx, ctx.ModuleDir(), prop)
+
+		if path.Valid() && parentDir(path.String()) == ctx.ModuleDir() {
+			// If it exists and the path is relative to the current dir, resolve the bazel label
+			// for the _file target_ and set it to the label attribute.
+			//
+			// Resolution is necessary because this could be a file in a subpackage.
+			labelAttr.SetValue(BazelLabelForModuleSrcSingle(ctx, prop))
+		} else {
+			// Otherwise, treat it as a string literal and assign to the string attribute.
+			strAttr.Value = propToDistinguish
+		}
+	}
+
+	return labelAttr, strAttr
+}
diff --git a/android/bazel_test.go b/android/bazel_test.go
index dbe6067..7b38b6a 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -71,6 +71,20 @@
 			},
 			packageDir: "a",
 		},
+		{
+			prefixes: allowlists.Bp2BuildConfig{
+				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
+				"a/b": allowlists.Bp2BuildDefaultTrue,
+			},
+			packageDir: "a/b",
+		},
+		{
+			prefixes: allowlists.Bp2BuildConfig{
+				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
+				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
+			},
+			packageDir: "a/b/c",
+		},
 	}
 
 	for _, test := range testCases {
@@ -133,6 +147,20 @@
 			},
 			packageDir: "a",
 		},
+		{
+			prefixes: allowlists.Bp2BuildConfig{
+				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
+				"a/b": allowlists.Bp2BuildDefaultTrue,
+			},
+			packageDir: "a/b/c",
+		},
+		{
+			prefixes: allowlists.Bp2BuildConfig{
+				"a":   allowlists.Bp2BuildDefaultTrueRecursively,
+				"a/b": allowlists.Bp2BuildDefaultFalseRecursively,
+			},
+			packageDir: "a/b/c",
+		},
 	}
 
 	for _, test := range testCases {
@@ -395,3 +423,21 @@
 		}
 	}
 }
+
+func TestShouldKeepExistingBuildFileForDir(t *testing.T) {
+	allowlist := NewBp2BuildAllowlist()
+	// entry "a/b2/c2" is moot because of its parent "a/b2"
+	allowlist.SetKeepExistingBuildFile(map[string]bool{"a": false, "a/b1": false, "a/b2": true, "a/b1/c1": true, "a/b2/c2": false})
+	truths := []string{"a", "a/b1", "a/b2", "a/b1/c1", "a/b2/c", "a/b2/c2", "a/b2/c2/d"}
+	falsities := []string{"a1", "a/b", "a/b1/c"}
+	for _, dir := range truths {
+		if !allowlist.ShouldKeepExistingBuildFileForDir(dir) {
+			t.Errorf("%s expected TRUE but was FALSE", dir)
+		}
+	}
+	for _, dir := range falsities {
+		if allowlist.ShouldKeepExistingBuildFileForDir(dir) {
+			t.Errorf("%s expected FALSE but was TRUE", dir)
+		}
+	}
+}
diff --git a/android/config.go b/android/config.go
index 4992882..1deb7d4 100644
--- a/android/config.go
+++ b/android/config.go
@@ -75,6 +75,9 @@
 	// Don't use bazel at all during module analysis.
 	AnalysisNoBazel SoongBuildMode = iota
 
+	// Symlink fores mode: merge two directory trees into a symlink forest
+	SymlinkForest
+
 	// Bp2build mode: Generate BUILD files from blueprint files and exit.
 	Bp2build
 
@@ -97,6 +100,11 @@
 	// allowlisted on an experimental basis.
 	BazelDevMode
 
+	// Use bazel during analysis of a few allowlisted build modules. The allowlist
+	// is considered "staging, as these are modules being prepared to be released
+	// into prod mode shortly after.
+	BazelStagingMode
+
 	// Use bazel during analysis of build modules from an allowlist carefully
 	// curated by the build team to be proven stable.
 	BazelProdMode
@@ -528,7 +536,7 @@
 // Returns true if "Bazel builds" is enabled. In this mode, part of build
 // analysis is handled by Bazel.
 func (c *config) IsMixedBuildsEnabled() bool {
-	return c.BuildMode == BazelProdMode || c.BuildMode == BazelDevMode
+	return c.BuildMode == BazelProdMode || c.BuildMode == BazelDevMode || c.BuildMode == BazelStagingMode
 }
 
 func (c *config) SetAllowMissingDependencies() {
@@ -1101,7 +1109,7 @@
 	return c.config.productVariables.WithDexpreopt
 }
 
-func (c *config) FrameworksBaseDirExists(ctx PathContext) bool {
+func (c *config) FrameworksBaseDirExists(ctx PathGlobContext) bool {
 	return ExistentPathForSource(ctx, "frameworks", "base", "Android.bp").Valid()
 }
 
@@ -1264,10 +1272,6 @@
 	return coverage
 }
 
-func (c *deviceConfig) AfdoAdditionalProfileDirs() []string {
-	return c.config.productVariables.AfdoAdditionalProfileDirs
-}
-
 func (c *deviceConfig) PgoAdditionalProfileDirs() []string {
 	return c.config.productVariables.PgoAdditionalProfileDirs
 }
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index d6b2bcf..2beeb51 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -69,6 +69,7 @@
 	ret = append(ret, ev.exportedStringListDictVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
 	// Note: ExportedVariableReferenceDictVars collections can only contain references to other variables and must be printed last
 	ret = append(ret, ev.exportedVariableReferenceDictVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
+	ret = append(ret, ev.exportedConfigDependingVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
 	return ret
 }
 
@@ -141,6 +142,33 @@
 	m[k] = v
 }
 
+func (m ExportedConfigDependingVariables) asBazel(config Config,
+	stringVars ExportedStringVariables, stringListVars ExportedStringListVariables, cfgDepVars ExportedConfigDependingVariables) []bazelConstant {
+	ret := make([]bazelConstant, 0, len(m))
+	for variable, unevaluatedVar := range m {
+		evalFunc := reflect.ValueOf(unevaluatedVar)
+		validateVariableMethod(variable, evalFunc)
+		evaluatedResult := evalFunc.Call([]reflect.Value{reflect.ValueOf(config)})
+		evaluatedValue := evaluatedResult[0].Interface().(string)
+		expandedVars, err := expandVar(config, evaluatedValue, stringVars, stringListVars, cfgDepVars)
+		if err != nil {
+			panic(fmt.Errorf("error expanding config variable %s: %s", variable, err))
+		}
+		if len(expandedVars) > 1 {
+			ret = append(ret, bazelConstant{
+				variableName:       variable,
+				internalDefinition: starlark_fmt.PrintStringList(expandedVars, 0),
+			})
+		} else {
+			ret = append(ret, bazelConstant{
+				variableName:       variable,
+				internalDefinition: fmt.Sprintf(`"%s"`, validateCharacters(expandedVars[0])),
+			})
+		}
+	}
+	return ret
+}
+
 // 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`, `"`, `\`} {
diff --git a/android/filegroup.go b/android/filegroup.go
index 6b11172..af4d89a 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -234,7 +234,8 @@
 }
 
 func (fg *fileGroup) IsMixedBuildSupported(ctx BaseModuleContext) bool {
-	return true
+	// TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups
+	return false
 }
 
 func (fg *fileGroup) ProcessBazelQueryResponse(ctx ModuleContext) {
diff --git a/android/filegroup_test.go b/android/filegroup_test.go
index a7ea805..8292d5e 100644
--- a/android/filegroup_test.go
+++ b/android/filegroup_test.go
@@ -6,6 +6,8 @@
 )
 
 func TestFileGroupWithPathProp(t *testing.T) {
+	// TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups
+	t.Skip("Re-enable once filegroups are corrected for mixed builds")
 	outBaseDir := "outputbase"
 	pathPrefix := outBaseDir + "/execroot/__main__"
 	expectedOutputfile := filepath.Join(pathPrefix, "a/b/c/d/test.aidl")
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 4ee5bf7..18b63d3 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -98,6 +98,11 @@
 	var orderOnlyDeps Paths
 	var args []string
 
+	if n := ctx.ModuleName(); n != "" {
+		args = append(args,
+			"-mn "+proptools.NinjaAndShellEscape(n))
+	}
+
 	if t := ctx.ModuleType(); t != "" {
 		args = append(args,
 			"-mt "+proptools.NinjaAndShellEscape(t))
diff --git a/android/licenses.go b/android/licenses.go
index c47b3e6..c6b3243 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -340,4 +340,5 @@
 	ctx.Strict("COMPLIANCENOTICE_SHIPPEDLIBS", ctx.Config().HostToolPath(ctx, "compliancenotice_shippedlibs").String())
 	ctx.Strict("COMPLIANCE_LISTSHARE", ctx.Config().HostToolPath(ctx, "compliance_listshare").String())
 	ctx.Strict("COMPLIANCE_CHECKSHARE", ctx.Config().HostToolPath(ctx, "compliance_checkshare").String())
+	ctx.Strict("COMPLIANCE_SBOM", ctx.Config().HostToolPath(ctx, "compliance_sbom").String())
 }
diff --git a/android/makevars.go b/android/makevars.go
index 5165a55..0800190 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -471,7 +471,7 @@
 			fmt.Fprintf(buf, " %s", dep.String())
 		}
 		fmt.Fprintln(buf)
-		fmt.Fprintln(buf, "\t@echo \"Install $@\"")
+		fmt.Fprintln(buf, "\t@echo \"Install: $@\"")
 		fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag)
 		if install.executable {
 			fmt.Fprintf(buf, "\tchmod +x $@\n")
@@ -515,7 +515,7 @@
 			fromStr = symlink.absFrom
 		}
 
-		fmt.Fprintln(buf, "\t@echo \"Symlink $@\"")
+		fmt.Fprintln(buf, "\t@echo \"Symlink: $@\"")
 		fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
 		fmt.Fprintln(buf)
 		fmt.Fprintln(buf)
diff --git a/android/metrics.go b/android/metrics.go
index ecda026..3d41a1d 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -62,7 +62,7 @@
 	})
 }
 
-func collectMetrics(config Config, eventHandler metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
+func collectMetrics(config Config, eventHandler *metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
 	metrics := &soong_metrics_proto.SoongBuildMetrics{}
 
 	soongMetrics, ok := readSoongMetrics(config)
@@ -107,7 +107,7 @@
 	return metrics
 }
 
-func WriteMetrics(config Config, eventHandler metrics.EventHandler, metricsFile string) error {
+func WriteMetrics(config Config, eventHandler *metrics.EventHandler, metricsFile string) error {
 	metrics := collectMetrics(config, eventHandler)
 
 	buf, err := proto.Marshal(metrics)
diff --git a/android/module.go b/android/module.go
index 68d9f8e..b41a898 100644
--- a/android/module.go
+++ b/android/module.go
@@ -915,12 +915,21 @@
 type CommonAttributes struct {
 	// Soong nameProperties -> Bazel name
 	Name string
+
 	// Data mapped from: Required
 	Data bazel.LabelListAttribute
 
+	// SkipData is neither a Soong nor Bazel target attribute
+	// If true, this will not fill the data attribute automatically
+	// This is useful for Soong modules that have 1:many Bazel targets
+	// Some of the generated Bazel targets might not have a data attribute
+	SkipData *bool
+
 	Tags bazel.StringListAttribute
 
 	Applicable_licenses bazel.LabelListAttribute
+
+	Testonly *bool
 }
 
 // constraintAttributes represents Bazel attributes pertaining to build constraints,
@@ -1239,12 +1248,14 @@
 	// when generated as the 'data' label list attribute in Bazel. Remove it if
 	// it exists. See b/247985196.
 	_, requiredWithoutCycles := RemoveFromList(ctx.ModuleName(), mod.commonProperties.Required)
+	requiredWithoutCycles = FirstUniqueStrings(requiredWithoutCycles)
 	required := depsToLabelList(requiredWithoutCycles)
 	archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
 	for axis, configToProps := range archVariantProps {
 		for config, _props := range configToProps {
 			if archProps, ok := _props.(*commonProperties); ok {
 				_, requiredWithoutCycles := RemoveFromList(ctx.ModuleName(), archProps.Required)
+				requiredWithoutCycles = FirstUniqueStrings(requiredWithoutCycles)
 				required.SetSelectValue(axis, config, depsToLabelList(requiredWithoutCycles).Value)
 				if !neitherHostNorDevice {
 					if archProps.Enabled != nil {
@@ -1305,7 +1316,12 @@
 		platformEnabledAttribute.Add(&l)
 	}
 
-	attrs.Data.Append(required)
+	if !proptools.Bool(attrs.SkipData) {
+		attrs.Data.Append(required)
+	}
+	// SkipData is not an attribute of any Bazel target
+	// Set this to nil so that it does not appear in the generated build file
+	attrs.SkipData = nil
 
 	moduleEnableConstraints := bazel.LabelListAttribute{}
 	moduleEnableConstraints.Append(platformEnabledAttribute)
diff --git a/android/neverallow.go b/android/neverallow.go
index 2745238..d288439 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -58,7 +58,7 @@
 	AddNeverAllowRules(createMakefileGoalRules()...)
 	AddNeverAllowRules(createInitFirstStageRules()...)
 	AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
-	AddNeverAllowRules(createBp2BuildRules()...)
+	AddNeverAllowRules(createBp2BuildRule())
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -66,22 +66,12 @@
 	neverallows = append(neverallows, rules...)
 }
 
-func createBp2BuildRules() []Rule {
-	rules := []Rule{}
-	bp2buildAvailableAllowedDirs := []string{
-		// Can we just allowlist these modules in allowlists.go?
-		"bionic/libc",
-	}
-
-	for _, dir := range bp2buildAvailableAllowedDirs {
-		rule := NeverAllow().
-			With("bazel_module.bp2build_available", "true").
-			NotIn(dir).
-			Because("disallowed usages of bp2build_available for custom conversion")
-		rules = append(rules, rule)
-	}
-
-	return rules
+func createBp2BuildRule() Rule {
+	return NeverAllow().
+		With("bazel_module.bp2build_available", "true").
+		NotIn("soong_tests"). // only used in tests
+		Because("setting bp2build_available in Android.bp is not " +
+			"supported for custom conversion, use allowlists.go instead.")
 }
 
 func createIncludeDirsRules() []Rule {
@@ -173,6 +163,7 @@
 		"development/build",
 		"external/guava",
 		"external/robolectric-shadows",
+		"external/robolectric",
 		"frameworks/layoutlib",
 	}
 
diff --git a/android/ninja_deps_test.go b/android/ninja_deps_test.go
index 947c257..d6afcc0 100644
--- a/android/ninja_deps_test.go
+++ b/android/ninja_deps_test.go
@@ -18,21 +18,6 @@
 	"testing"
 )
 
-func init() {
-	// This variable uses ExistentPathForSource on a PackageVarContext, which is a PathContext
-	// that is not a PathGlobContext.  That requires the deps to be stored in the Config.
-	pctx.VariableFunc("test_ninja_deps_variable", func(ctx PackageVarContext) string {
-		// Using ExistentPathForSource to look for a file that does not exist in a directory that
-		// does exist (test_ninja_deps) from a PackageVarContext adds a dependency from build.ninja
-		// to the directory.
-		if ExistentPathForSource(ctx, "test_ninja_deps/does_not_exist").Valid() {
-			return "true"
-		} else {
-			return "false"
-		}
-	})
-}
-
 func testNinjaDepsSingletonFactory() Singleton {
 	return testNinjaDepsSingleton{}
 }
@@ -40,33 +25,19 @@
 type testNinjaDepsSingleton struct{}
 
 func (testNinjaDepsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	// Reference the test_ninja_deps_variable in a build statement so Blueprint is forced to
-	// evaluate it.
-	ctx.Build(pctx, BuildParams{
-		Rule:   Cp,
-		Input:  PathForTesting("foo"),
-		Output: PathForOutput(ctx, "test_ninja_deps_out"),
-		Args: map[string]string{
-			"cpFlags": "${test_ninja_deps_variable}",
-		},
-	})
+	ctx.Config().addNinjaFileDeps("foo")
 }
 
 func TestNinjaDeps(t *testing.T) {
-	fs := MockFS{
-		"test_ninja_deps/exists": nil,
-	}
-
 	result := GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterSingletonType("test_ninja_deps_singleton", testNinjaDepsSingletonFactory)
 			ctx.RegisterSingletonType("ninja_deps_singleton", ninjaDepsSingletonFactory)
 		}),
-		fs.AddToFixture(),
 	).RunTest(t)
 
 	// Verify that the ninja file has a dependency on the test_ninja_deps directory.
-	if g, w := result.NinjaDeps, "test_ninja_deps"; !InList(w, g) {
+	if g, w := result.NinjaDeps, "foo"; !InList(w, g) {
 		t.Errorf("expected %q in %q", w, g)
 	}
 }
diff --git a/android/package_ctx.go b/android/package_ctx.go
index f354db8..c348c82 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -48,7 +48,7 @@
 
 var _ PathContext = &configErrorWrapper{}
 var _ errorfContext = &configErrorWrapper{}
-var _ PackageVarContext = &configErrorWrapper{}
+var _ PackageVarContext = &variableFuncContextWrapper{}
 var _ PackagePoolContext = &configErrorWrapper{}
 var _ PackageRuleContext = &configErrorWrapper{}
 
@@ -62,21 +62,33 @@
 	e.config.addNinjaFileDeps(deps...)
 }
 
-type PackageVarContext interface {
+type variableFuncContextWrapper struct {
+	configErrorWrapper
+	blueprint.VariableFuncContext
+}
+
+type PackagePoolContext interface {
 	PathContext
 	errorfContext
 }
 
-type PackagePoolContext PackageVarContext
-type PackageRuleContext PackageVarContext
+type PackageRuleContext PackagePoolContext
+
+type PackageVarContext interface {
+	PackagePoolContext
+	PathGlobContext
+}
 
 // VariableFunc wraps blueprint.PackageContext.VariableFunc, converting the interface{} config
 // argument to a PackageVarContext.
 func (p PackageContext) VariableFunc(name string,
 	f func(PackageVarContext) string) blueprint.Variable {
 
-	return p.PackageContext.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), nil}
+	return p.PackageContext.VariableFunc(name, func(bpctx blueprint.VariableFuncContext, config interface{}) (string, error) {
+		ctx := &variableFuncContextWrapper{
+			configErrorWrapper:  configErrorWrapper{p, config.(Config), nil},
+			VariableFuncContext: bpctx,
+		}
 		ret := f(ctx)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
diff --git a/android/paths.go b/android/paths.go
index dbcdb23..a6a54fa 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -39,6 +39,7 @@
 }
 
 type PathGlobContext interface {
+	PathContext
 	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
 }
 
@@ -56,7 +57,6 @@
 // EarlyModulePathContext is a subset of EarlyModuleContext methods required by the
 // Path methods. These path methods can be called before any mutators have run.
 type EarlyModulePathContext interface {
-	PathContext
 	PathGlobContext
 
 	ModuleDir() string
@@ -375,7 +375,7 @@
 // ExistentPathsForSources returns a list of Paths rooted from SrcDir, *not* rooted from the
 // module's local source directory, that are found in the tree. If any are not found, they are
 // omitted from the list, and dependencies are added so that we're re-run when they are added.
-func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
+func ExistentPathsForSources(ctx PathGlobContext, paths []string) Paths {
 	ret := make(Paths, 0, len(paths))
 	for _, path := range paths {
 		p := ExistentPathForSource(ctx, path)
@@ -1087,21 +1087,12 @@
 
 // existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
 // path does not exist.
-func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err error) {
+func existsWithDependencies(ctx PathGlobContext, path SourcePath) (exists bool, err error) {
 	var files []string
 
-	if gctx, ok := ctx.(PathGlobContext); ok {
-		// Use glob to produce proper dependencies, even though we only want
-		// a single file.
-		files, err = gctx.GlobWithDeps(path.String(), nil)
-	} else {
-		var result pathtools.GlobResult
-		// We cannot add build statements in this context, so we fall back to
-		// AddNinjaFileDeps
-		result, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
-		ctx.AddNinjaFileDeps(result.Deps...)
-		files = result.Matches
-	}
+	// Use glob to produce proper dependencies, even though we only want
+	// a single file.
+	files, err = ctx.GlobWithDeps(path.String(), nil)
 
 	if err != nil {
 		return false, fmt.Errorf("glob: %s", err.Error())
@@ -1124,7 +1115,7 @@
 	}
 
 	if modCtx, ok := ctx.(ModuleMissingDepsPathContext); ok && ctx.Config().AllowMissingDependencies() {
-		exists, err := existsWithDependencies(ctx, path)
+		exists, err := existsWithDependencies(modCtx, path)
 		if err != nil {
 			reportPathError(ctx, err)
 		}
@@ -1139,11 +1130,26 @@
 	return path
 }
 
+// MaybeExistentPathForSource joins the provided path components and validates that the result
+// neither escapes the source dir nor is in the out dir.
+// It does not validate whether the path exists.
+func MaybeExistentPathForSource(ctx PathContext, pathComponents ...string) SourcePath {
+	path, err := pathForSource(ctx, pathComponents...)
+	if err != nil {
+		reportPathError(ctx, err)
+	}
+
+	if pathtools.IsGlob(path.String()) {
+		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
+	}
+	return path
+}
+
 // ExistentPathForSource returns an OptionalPath with the SourcePath, rooted from SrcDir, *not*
 // rooted from the module's local source directory, if the path exists, or an empty OptionalPath if
 // it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state
 // of the path changes.
-func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
+func ExistentPathForSource(ctx PathGlobContext, pathComponents ...string) OptionalPath {
 	path, err := pathForSource(ctx, pathComponents...)
 	if err != nil {
 		reportPathError(ctx, err)
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 7d21b75..1519f60 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -642,9 +642,13 @@
 // Extracts an interface from values containing the properties to apply based on config.
 // If config does not match a value with a non-nil property set, the default value will be returned.
 func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
+	configValue := config.String(s.variable)
+	if configValue != "" && !InList(configValue, s.values) {
+		return nil, fmt.Errorf("Soong config property %q must be one of %v, found %q", s.variable, s.values, configValue)
+	}
 	for j, v := range s.values {
 		f := values.Field(j)
-		if config.String(s.variable) == v && !f.Elem().IsNil() {
+		if configValue == v && !f.Elem().IsNil() {
 			return f.Interface(), nil
 		}
 	}
@@ -861,3 +865,13 @@
 }
 
 var emptyInterfaceType = reflect.TypeOf(emptyInterfaceStruct{}).Field(0).Type
+
+// InList checks if the string belongs to the list
+func InList(s string, list []string) bool {
+	for _, s2 := range list {
+		if s2 == s {
+			return true
+		}
+	}
+	return false
+}
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index a7800e8..d5d87ef 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -303,6 +303,10 @@
 	Bool_var interface{}
 }
 
+type stringSoongConfigVars struct {
+	String_var interface{}
+}
+
 func Test_PropertiesToApply(t *testing.T) {
 	mt, _ := newModuleType(&ModuleTypeProperties{
 		Module_type:      "foo",
@@ -365,6 +369,51 @@
 	}
 }
 
+func Test_PropertiesToApply_String_Error(t *testing.T) {
+	mt, _ := newModuleType(&ModuleTypeProperties{
+		Module_type:      "foo",
+		Config_namespace: "bar",
+		Variables:        []string{"string_var"},
+		Properties:       []string{"a", "b"},
+	})
+	mt.Variables = append(mt.Variables, &stringVariable{
+		baseVariable: baseVariable{
+			variable: "string_var",
+		},
+		values: []string{"a", "b", "c"},
+	})
+	stringVarPositive := &properties{
+		A: proptools.StringPtr("A"),
+		B: true,
+	}
+	conditionsDefault := &properties{
+		A: proptools.StringPtr("default"),
+		B: false,
+	}
+	actualProps := &struct {
+		Soong_config_variables stringSoongConfigVars
+	}{
+		Soong_config_variables: stringSoongConfigVars{
+			String_var: &boolVarProps{
+				A:                  stringVarPositive.A,
+				B:                  stringVarPositive.B,
+				Conditions_default: conditionsDefault,
+			},
+		},
+	}
+	props := reflect.ValueOf(actualProps)
+
+	_, err := PropertiesToApply(mt, props, Config(map[string]string{
+		"string_var": "x",
+	}))
+	expected := `Soong config property "string_var" must be one of [a b c], found "x"`
+	if err == nil {
+		t.Fatalf("Expected an error, got nil")
+	} else if err.Error() != expected {
+		t.Fatalf("Error message was not correct, expected %q, got %q", expected, err.Error())
+	}
+}
+
 func Test_Bp2BuildSoongConfigDefinitions(t *testing.T) {
 	testCases := []struct {
 		desc     string
diff --git a/android/testing.go b/android/testing.go
index f9f9670..2256c96 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -1120,6 +1120,7 @@
 }
 
 func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) []AndroidMkEntries {
+	t.Helper()
 	var p AndroidMkEntriesProvider
 	var ok bool
 	if p, ok = mod.(AndroidMkEntriesProvider); !ok {
@@ -1134,6 +1135,7 @@
 }
 
 func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData {
+	t.Helper()
 	var p AndroidMkDataProvider
 	var ok bool
 	if p, ok = mod.(AndroidMkDataProvider); !ok {
diff --git a/android/variable.go b/android/variable.go
index 37ecab5..28f22c9 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -336,8 +336,7 @@
 
 	NamespacesToExport []string `json:",omitempty"`
 
-	AfdoAdditionalProfileDirs []string `json:",omitempty"`
-	PgoAdditionalProfileDirs  []string `json:",omitempty"`
+	PgoAdditionalProfileDirs []string `json:",omitempty"`
 
 	VndkUseCoreVariant         *bool `json:",omitempty"`
 	VndkSnapshotBuildArtifacts *bool `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 4247db4..72403f9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -17,13 +17,14 @@
 package apex
 
 import (
-	"android/soong/bazel/cquery"
 	"fmt"
 	"path/filepath"
 	"regexp"
 	"sort"
 	"strings"
 
+	"android/soong/bazel/cquery"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
@@ -47,7 +48,7 @@
 
 func registerApexBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("apex", BundleFactory)
-	ctx.RegisterModuleType("apex_test", testApexBundleFactory)
+	ctx.RegisterModuleType("apex_test", TestApexBundleFactory)
 	ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
 	ctx.RegisterModuleType("apex_defaults", defaultsFactory)
 	ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
@@ -224,7 +225,7 @@
 	// List of JNI libraries that are embedded inside this APEX.
 	Jni_libs []string
 
-	// List of rust dyn libraries
+	// List of rust dyn libraries that are embedded inside this APEX.
 	Rust_dyn_libs []string
 
 	// List of native executables that are embedded inside this APEX.
@@ -235,6 +236,41 @@
 
 	// List of filesystem images that are embedded inside this APEX bundle.
 	Filesystems []string
+
+	// List of native libraries to exclude from this APEX.
+	Exclude_native_shared_libs []string
+
+	// List of JNI libraries to exclude from this APEX.
+	Exclude_jni_libs []string
+
+	// List of rust dyn libraries to exclude from this APEX.
+	Exclude_rust_dyn_libs []string
+
+	// List of native executables to exclude from this APEX.
+	Exclude_binaries []string
+
+	// List of native tests to exclude from this APEX.
+	Exclude_tests []string
+
+	// List of filesystem images to exclude from this APEX bundle.
+	Exclude_filesystems []string
+}
+
+// Merge combines another ApexNativeDependencies into this one
+func (a *ApexNativeDependencies) Merge(b ApexNativeDependencies) {
+	a.Native_shared_libs = append(a.Native_shared_libs, b.Native_shared_libs...)
+	a.Jni_libs = append(a.Jni_libs, b.Jni_libs...)
+	a.Rust_dyn_libs = append(a.Rust_dyn_libs, b.Rust_dyn_libs...)
+	a.Binaries = append(a.Binaries, b.Binaries...)
+	a.Tests = append(a.Tests, b.Tests...)
+	a.Filesystems = append(a.Filesystems, b.Filesystems...)
+
+	a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...)
+	a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...)
+	a.Exclude_rust_dyn_libs = append(a.Exclude_rust_dyn_libs, b.Exclude_rust_dyn_libs...)
+	a.Exclude_binaries = append(a.Exclude_binaries, b.Exclude_binaries...)
+	a.Exclude_tests = append(a.Exclude_tests, b.Exclude_tests...)
+	a.Exclude_filesystems = append(a.Exclude_filesystems, b.Exclude_filesystems...)
 }
 
 type apexMultilibProperties struct {
@@ -674,12 +710,18 @@
 	// Use *FarVariation* to be able to depend on modules having conflicting variations with
 	// this module. This is required since arch variant of an APEX bundle is 'common' but it is
 	// 'arm' or 'arm64' for native shared libs.
-	ctx.AddFarVariationDependencies(binVariations, executableTag, nativeModules.Binaries...)
-	ctx.AddFarVariationDependencies(binVariations, testTag, nativeModules.Tests...)
-	ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
-	ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
-	ctx.AddFarVariationDependencies(rustLibVariations, sharedLibTag, nativeModules.Rust_dyn_libs...)
-	ctx.AddFarVariationDependencies(target.Variations(), fsTag, nativeModules.Filesystems...)
+	ctx.AddFarVariationDependencies(binVariations, executableTag,
+		android.RemoveListFromList(nativeModules.Binaries, nativeModules.Exclude_binaries)...)
+	ctx.AddFarVariationDependencies(binVariations, testTag,
+		android.RemoveListFromList(nativeModules.Tests, nativeModules.Exclude_tests)...)
+	ctx.AddFarVariationDependencies(libVariations, jniLibTag,
+		android.RemoveListFromList(nativeModules.Jni_libs, nativeModules.Exclude_jni_libs)...)
+	ctx.AddFarVariationDependencies(libVariations, sharedLibTag,
+		android.RemoveListFromList(nativeModules.Native_shared_libs, nativeModules.Exclude_native_shared_libs)...)
+	ctx.AddFarVariationDependencies(rustLibVariations, sharedLibTag,
+		android.RemoveListFromList(nativeModules.Rust_dyn_libs, nativeModules.Exclude_rust_dyn_libs)...)
+	ctx.AddFarVariationDependencies(target.Variations(), fsTag,
+		android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -747,12 +789,12 @@
 			continue
 		}
 
-		var depsList []ApexNativeDependencies
+		var deps ApexNativeDependencies
 
 		// Add native modules targeting both ABIs. When multilib.* is omitted for
 		// native_shared_libs/jni_libs/tests, it implies multilib.both
-		depsList = append(depsList, a.properties.Multilib.Both)
-		depsList = append(depsList, ApexNativeDependencies{
+		deps.Merge(a.properties.Multilib.Both)
+		deps.Merge(ApexNativeDependencies{
 			Native_shared_libs: a.properties.Native_shared_libs,
 			Tests:              a.properties.Tests,
 			Jni_libs:           a.properties.Jni_libs,
@@ -763,8 +805,8 @@
 		// binaries, it implies multilib.first
 		isPrimaryAbi := i == 0
 		if isPrimaryAbi {
-			depsList = append(depsList, a.properties.Multilib.First)
-			depsList = append(depsList, ApexNativeDependencies{
+			deps.Merge(a.properties.Multilib.First)
+			deps.Merge(ApexNativeDependencies{
 				Native_shared_libs: nil,
 				Tests:              nil,
 				Jni_libs:           nil,
@@ -775,34 +817,32 @@
 		// Add native modules targeting either 32-bit or 64-bit ABI
 		switch target.Arch.ArchType.Multilib {
 		case "lib32":
-			depsList = append(depsList, a.properties.Multilib.Lib32)
-			depsList = append(depsList, a.properties.Multilib.Prefer32)
+			deps.Merge(a.properties.Multilib.Lib32)
+			deps.Merge(a.properties.Multilib.Prefer32)
 		case "lib64":
-			depsList = append(depsList, a.properties.Multilib.Lib64)
+			deps.Merge(a.properties.Multilib.Lib64)
 			if !has32BitTarget {
-				depsList = append(depsList, a.properties.Multilib.Prefer32)
+				deps.Merge(a.properties.Multilib.Prefer32)
 			}
 		}
 
 		// Add native modules targeting a specific arch variant
 		switch target.Arch.ArchType {
 		case android.Arm:
-			depsList = append(depsList, a.archProperties.Arch.Arm.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.Arm.ApexNativeDependencies)
 		case android.Arm64:
-			depsList = append(depsList, a.archProperties.Arch.Arm64.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.Arm64.ApexNativeDependencies)
 		case android.Riscv64:
-			depsList = append(depsList, a.archProperties.Arch.Riscv64.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.Riscv64.ApexNativeDependencies)
 		case android.X86:
-			depsList = append(depsList, a.archProperties.Arch.X86.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.X86.ApexNativeDependencies)
 		case android.X86_64:
-			depsList = append(depsList, a.archProperties.Arch.X86_64.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.X86_64.ApexNativeDependencies)
 		default:
 			panic(fmt.Errorf("unsupported arch %v\n", ctx.Arch().ArchType))
 		}
 
-		for _, d := range depsList {
-			addDependenciesForNativeModules(ctx, d, target, imageVariation)
-		}
+		addDependenciesForNativeModules(ctx, deps, target, imageVariation)
 		ctx.AddFarVariationDependencies([]blueprint.Variation{
 			{Mutator: "os", Variation: target.OsVariation()},
 			{Mutator: "arch", Variation: target.ArchVariation()},
@@ -1853,24 +1893,24 @@
 	a.outputFile = a.outputApexFile
 	a.setCompression(ctx)
 
-	a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[0])
-	a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[1])
-	a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[0])
-	a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[1])
+	// TODO(b/257829940): These are used by the apex_keys_text singleton; would probably be a clearer
+	// interface if these were set in a provider rather than the module itself
+	a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[0])
+	a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[1])
+	a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[0])
+	a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[1])
+
 	apexType := a.properties.ApexType
 	switch apexType {
 	case imageApex:
-		// TODO(asmundak): Bazel does not create these files yet.
-		// b/190817312
+
+		// TODO(b/190817312): Generate the notice file from the apex rule.
 		a.htmlGzNotice = android.PathForBazelOut(ctx, "NOTICE.html.gz")
-		// b/239081457
-		a.bundleModuleFile = android.PathForBazelOut(ctx, a.Name()+apexType.suffix()+"-base.zip")
-		// b/239081455
-		a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.txt"))
-		// b/239081456
-		a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_backing.txt"))
-		// b/239084755
-		a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.xml"))
+		a.bundleModuleFile = android.PathForBazelOut(ctx, outputs.BundleFile)
+		a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.SymbolsUsedByApex))
+		a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.BackingLibs))
+		// TODO(b/239084755): Generate the java api using.xml file from Bazel.
+		a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.JavaSymbolsUsedByApex))
 		installSuffix := imageApexSuffix
 		if a.isCompressed {
 			installSuffix = imageCapexSuffix
@@ -2563,7 +2603,7 @@
 
 // apex_test is an APEX for testing. The difference from the ordinary apex module type is that
 // certain compatibility checks such as apex_available are not done for apex_test.
-func testApexBundleFactory() android.Module {
+func TestApexBundleFactory() android.Module {
 	bundle := newApexBundle()
 	bundle.testApex = true
 	return bundle
@@ -2592,6 +2632,7 @@
 	module.AddProperties(
 		&apexBundleProperties{},
 		&apexTargetBundleProperties{},
+		&apexArchBundleProperties{},
 		&overridableProperties{},
 	)
 
@@ -2665,12 +2706,13 @@
 
 		// Certificate
 		if overridableProperties.Certificate == nil {
-			// delegated to the rule attr default
-			attrs.Certificate = nil
+			// If overridableProperties.Certificate is nil, clear this out as
+			// well with zeroed structs, so the override_apex does not use the
+			// base apex's certificate.
+			attrs.Certificate = bazel.LabelAttribute{}
+			attrs.Certificate_name = bazel.StringAttribute{}
 		} else {
-			certificateName, certificate := java.ParseCertificateToAttribute(ctx, overridableProperties.Certificate)
-			attrs.Certificate_name = certificateName
-			attrs.Certificate = certificate
+			attrs.Certificate, attrs.Certificate_name = android.BazelStringOrLabelFromProp(ctx, overridableProperties.Certificate)
 		}
 
 		// Prebuilts
@@ -2740,11 +2782,6 @@
 		return ""
 	}
 
-	archMinApiLevel := cc.MinApiForArch(ctx, a.MultiTargets()[0].Arch.ArchType)
-	if !archMinApiLevel.IsNone() && archMinApiLevel.CompareTo(minApiLevel) > 0 {
-		minApiLevel = archMinApiLevel
-	}
-
 	overrideMinSdkValue := ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride()
 	overrideApiLevel := minSdkVersionFromValue(ctx, overrideMinSdkValue)
 	if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(minApiLevel) > 0 {
@@ -3351,8 +3388,8 @@
 	Android_manifest      bazel.LabelAttribute
 	File_contexts         bazel.LabelAttribute
 	Key                   bazel.LabelAttribute
-	Certificate           *bazel.Label // used when the certificate prop is a module
-	Certificate_name      *string      // used when the certificate prop is a string
+	Certificate           bazel.LabelAttribute  // used when the certificate prop is a module
+	Certificate_name      bazel.StringAttribute // used when the certificate prop is a string
 	Min_sdk_version       *string
 	Updatable             bazel.BoolAttribute
 	Installable           bazel.BoolAttribute
@@ -3363,6 +3400,7 @@
 	Compressible          bazel.BoolAttribute
 	Package_name          *string
 	Logging_parent        *string
+	Tests                 bazel.LabelListAttribute
 }
 
 type convertedNativeSharedLibs struct {
@@ -3372,13 +3410,19 @@
 
 // ConvertWithBp2build performs bp2build conversion of an apex
 func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	// We do not convert apex_test modules at this time
-	if ctx.ModuleType() != "apex" {
+	// We only convert apex and apex_test modules at this time
+	if ctx.ModuleType() != "apex" && ctx.ModuleType() != "apex_test" {
 		return
 	}
 
 	attrs, props := convertWithBp2build(a, ctx)
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, &attrs)
+	commonAttrs := android.CommonAttributes{
+		Name: a.Name(),
+	}
+	if a.testApex {
+		commonAttrs.Testonly = proptools.BoolPtr(a.testApex)
+	}
+	ctx.CreateBazelTargetModule(props, commonAttrs, &attrs)
 }
 
 func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (bazelApexBundleAttributes, bazel.BazelTargetModuleProperties) {
@@ -3414,13 +3458,19 @@
 		keyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Key))
 	}
 
-	certificateName, certificate := java.ParseCertificateToAttribute(ctx, a.overridableProperties.Certificate)
+	// Certificate
+	certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableProperties.Certificate)
 
 	nativeSharedLibs := &convertedNativeSharedLibs{
 		Native_shared_libs_32: bazel.LabelListAttribute{},
 		Native_shared_libs_64: bazel.LabelListAttribute{},
 	}
-	compileMultilib := "both"
+
+	// https://cs.android.com/android/platform/superproject/+/master:build/soong/android/arch.go;l=698;drc=f05b0d35d2fbe51be9961ce8ce8031f840295c68
+	// https://cs.android.com/android/platform/superproject/+/master:build/soong/apex/apex.go;l=2549;drc=ec731a83e3e2d80a1254e32fd4ad7ef85e262669
+	// In Soong, decodeMultilib, used to get multilib, return "first" if defaultMultilib is set to "common".
+	// Since apex sets defaultMultilib to be "common", equivalent compileMultilib in bp2build for apex should be "first"
+	compileMultilib := "first"
 	if a.CompileMultilib() != nil {
 		compileMultilib = *a.CompileMultilib()
 	}
@@ -3439,6 +3489,12 @@
 	binaries := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Binaries)
 	binariesLabelListAttribute := bazel.MakeLabelListAttribute(binaries)
 
+	var testsAttrs bazel.LabelListAttribute
+	if a.testApex && len(a.properties.ApexNativeDependencies.Tests) > 0 {
+		tests := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Tests)
+		testsAttrs = bazel.MakeLabelListAttribute(tests)
+	}
+
 	var updatableAttribute bazel.BoolAttribute
 	if a.properties.Updatable != nil {
 		updatableAttribute.Value = a.properties.Updatable
@@ -3481,6 +3537,7 @@
 		Compressible:          compressibleAttribute,
 		Package_name:          packageName,
 		Logging_parent:        loggingParent,
+		Tests:                 testsAttrs,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e130fcc..985ad59 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"os"
 	"path"
 	"path/filepath"
 	"reflect"
@@ -30,6 +29,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel/cquery"
 	"android/soong/bpf"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
@@ -2191,6 +2191,38 @@
 	`)
 }
 
+func TestApexMinSdkVersion_MinApiForArch(t *testing.T) {
+	// Tests that an apex dependency with min_sdk_version higher than the
+	// min_sdk_version of the apex is allowed as long as the dependency's
+	// min_sdk_version is less than or equal to the api level that the
+	// architecture was introduced in.  In this case, arm64 didn't exist
+	// until api level 21, so the arm64 code will never need to run on
+	// an api level 20 device, even if other architectures of the apex
+	// will.
+	testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+			min_sdk_version: "20",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libfoo",
+			srcs: ["mylib.cpp"],
+			apex_available: ["myapex"],
+			min_sdk_version: "21",
+			stl: "none",
+		}
+	`)
+}
+
 func TestJavaStableSdkVersion(t *testing.T) {
 	testCases := []struct {
 		name          string
@@ -4098,6 +4130,76 @@
 	ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
 }
 
+func TestCompileMultilibProp(t *testing.T) {
+	testCases := []struct {
+		compileMultiLibProp string
+		containedLibs       []string
+		notContainedLibs    []string
+	}{
+		{
+			containedLibs: []string{
+				"image.apex/lib64/mylib.so",
+				"image.apex/lib/mylib.so",
+			},
+			compileMultiLibProp: `compile_multilib: "both",`,
+		},
+		{
+			containedLibs:       []string{"image.apex/lib64/mylib.so"},
+			notContainedLibs:    []string{"image.apex/lib/mylib.so"},
+			compileMultiLibProp: `compile_multilib: "first",`,
+		},
+		{
+			containedLibs:    []string{"image.apex/lib64/mylib.so"},
+			notContainedLibs: []string{"image.apex/lib/mylib.so"},
+			// compile_multilib, when unset, should result to the same output as when compile_multilib is "first"
+		},
+		{
+			containedLibs:       []string{"image.apex/lib64/mylib.so"},
+			notContainedLibs:    []string{"image.apex/lib/mylib.so"},
+			compileMultiLibProp: `compile_multilib: "64",`,
+		},
+		{
+			containedLibs:       []string{"image.apex/lib/mylib.so"},
+			notContainedLibs:    []string{"image.apex/lib64/mylib.so"},
+			compileMultiLibProp: `compile_multilib: "32",`,
+		},
+	}
+	for _, testCase := range testCases {
+		ctx := testApex(t, fmt.Sprintf(`
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				%s
+				native_shared_libs: ["mylib"],
+				updatable: false,
+			}
+			apex_key {
+				name: "myapex.key",
+				public_key: "testkey.avbpubkey",
+				private_key: "testkey.pem",
+			}
+			cc_library {
+				name: "mylib",
+				srcs: ["mylib.cpp"],
+				apex_available: [
+					"//apex_available:platform",
+					"myapex",
+			],
+			}
+		`, testCase.compileMultiLibProp),
+		)
+		module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+		apexRule := module.Rule("apexRule")
+		copyCmds := apexRule.Args["copy_commands"]
+		for _, containedLib := range testCase.containedLibs {
+			ensureContains(t, copyCmds, containedLib)
+		}
+		for _, notContainedLib := range testCase.notContainedLibs {
+			ensureNotContains(t, copyCmds, notContainedLib)
+		}
+	}
+}
+
 func TestNonTestApex(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -4297,12 +4399,15 @@
 			name: "myapex",
 			key: "myapex.key",
 			updatable: false,
+			native_shared_libs: ["mylib.generic"],
 			arch: {
 				arm64: {
 					native_shared_libs: ["mylib.arm64"],
+					exclude_native_shared_libs: ["mylib.generic"],
 				},
 				x86_64: {
 					native_shared_libs: ["mylib.x64"],
+					exclude_native_shared_libs: ["mylib.generic"],
 				},
 			}
 		}
@@ -4314,6 +4419,18 @@
 		}
 
 		cc_library {
+			name: "mylib.generic",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
+
+		cc_library {
 			name: "mylib.arm64",
 			srcs: ["mylib.cpp"],
 			system_shared_libs: [],
@@ -4343,6 +4460,7 @@
 
 	// Ensure that apex variant is created for the direct dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib.arm64"), "android_arm64_armv8-a_shared_apex10000")
+	ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib.generic"), "android_arm64_armv8-a_shared_apex10000")
 	ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib.x64"), "android_arm64_armv8-a_shared_apex10000")
 
 	// Ensure that both direct and indirect deps are copied into apex
@@ -9628,6 +9746,86 @@
 	android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
 }
 
-func TestMain(m *testing.M) {
-	os.Exit(m.Run())
+func TestApexImageInMixedBuilds(t *testing.T) {
+	bp := `
+apex_key{
+	name: "foo_key",
+}
+apex {
+	name: "foo",
+	key: "foo_key",
+	updatable: true,
+	min_sdk_version: "31",
+	file_contexts: ":myapex-file_contexts",
+	bazel_module: { label: "//:foo" },
+}`
+
+	outputBaseDir := "out/bazel"
+	result := android.GroupFixturePreparers(
+		prepareForApexTest,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: outputBaseDir,
+				LabelToApexInfo: map[string]cquery.ApexInfo{
+					"//:foo": cquery.ApexInfo{
+						SignedOutput:          "signed_out.apex",
+						UnsignedOutput:        "unsigned_out.apex",
+						BundleKeyInfo:         []string{"public_key", "private_key"},
+						ContainerKeyInfo:      []string{"container_cert", "container_private"},
+						SymbolsUsedByApex:     "foo_using.txt",
+						JavaSymbolsUsedByApex: "foo_using.xml",
+						BundleFile:            "apex_bundle.zip",
+
+						// unused
+						PackageName:  "pkg_name",
+						ProvidesLibs: []string{"a", "b"},
+						RequiresLibs: []string{"c", "d"},
+					},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp)
+
+	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
+	ab, ok := m.(*apexBundle)
+	if !ok {
+		t.Fatalf("Expected module to be an apexBundle, was not")
+	}
+
+	if w, g := "out/bazel/execroot/__main__/public_key", ab.publicKeyFile.String(); w != g {
+		t.Errorf("Expected public key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/private_key", ab.privateKeyFile.String(); w != g {
+		t.Errorf("Expected private key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/container_cert", ab.containerCertificateFile.String(); w != g {
+		t.Errorf("Expected public container key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/container_private", ab.containerPrivateKeyFile.String(); w != g {
+		t.Errorf("Expected private container key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/signed_out.apex", ab.outputFile.String(); w != g {
+		t.Errorf("Expected output file %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
+		t.Errorf("Expected output file %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
+		t.Errorf("Expected output file %q, got %q", w, g)
+	}
+
+	mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
+	var builder strings.Builder
+	mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
+
+	data := builder.String()
+	if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/apex_bundle.zip"; !strings.Contains(data, w) {
+		t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
+	}
 }
diff --git a/apex/builder.go b/apex/builder.go
index ad8075b..e4c1673 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -922,10 +922,16 @@
 				installedSymlinks = append(installedSymlinks,
 					ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
 			} else {
-				target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
-				for _, sym := range fi.symlinks {
-					installedSymlinks = append(installedSymlinks,
-						ctx.InstallSymlink(installDir, sym, target))
+				if fi.class == appSet {
+					as := fi.module.(*java.AndroidAppSet)
+					ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk",
+						as.OutputFile(), as.PackedAdditionalOutputs())
+				} else {
+					target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
+					for _, sym := range fi.symlinks {
+						installedSymlinks = append(installedSymlinks,
+							ctx.InstallSymlink(installDir, sym, target))
+					}
 				}
 			}
 		}
diff --git a/apex/key.go b/apex/key.go
index 2b09f1d..0a7e80f 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -201,10 +201,10 @@
 
 type bazelApexKeyAttributes struct {
 	Public_key      bazel.LabelAttribute
-	Public_key_name bazel.LabelAttribute
+	Public_key_name bazel.StringAttribute
 
 	Private_key      bazel.LabelAttribute
-	Private_key_name bazel.LabelAttribute
+	Private_key_name bazel.StringAttribute
 }
 
 // ConvertWithBp2build performs conversion apexKey for bp2build
@@ -213,27 +213,11 @@
 }
 
 func apexKeyBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexKey) {
-	var privateKeyLabelAttribute bazel.LabelAttribute
-	var privateKeyNameAttribute bazel.LabelAttribute
-	if module.properties.Private_key != nil {
-		m := String(module.properties.Private_key)
-		if android.SrcIsModule(m) == "" {
-			privateKeyNameAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.Private_key))
-		} else {
-			privateKeyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.properties.Private_key))
-		}
-	}
+	privateKeyLabelAttribute, privateKeyNameAttribute :=
+		android.BazelStringOrLabelFromProp(ctx, module.properties.Private_key)
 
-	var publicKeyLabelAttribute bazel.LabelAttribute
-	var publicKeyNameAttribute bazel.LabelAttribute
-	if module.properties.Public_key != nil {
-		m := String(module.properties.Public_key)
-		if android.SrcIsModule(m) == "" {
-			publicKeyNameAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.Public_key))
-		} else {
-			publicKeyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.properties.Public_key))
-		}
-	}
+	publicKeyLabelAttribute, publicKeyNameAttribute :=
+		android.BazelStringOrLabelFromProp(ctx, module.properties.Public_key)
 
 	attrs := &bazelApexKeyAttributes{
 		Private_key:      privateKeyLabelAttribute,
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 0f57911..39446a1 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -500,6 +500,9 @@
 		Arm64 struct {
 			Src *string `android:"path"`
 		}
+		Riscv64 struct {
+			Src *string `android:"path"`
+		}
 		X86 struct {
 			Src *string `android:"path"`
 		}
@@ -527,6 +530,12 @@
 		src = String(p.Arch.Arm.Src)
 	case android.Arm64:
 		src = String(p.Arch.Arm64.Src)
+	case android.Riscv64:
+		src = String(p.Arch.Riscv64.Src)
+		// HACK: fall back to arm64 prebuilts, the riscv64 ones don't exist yet.
+		if src == "" {
+			src = String(p.Arch.Arm64.Src)
+		}
 	case android.X86:
 		src = String(p.Arch.X86.Src)
 	case android.X86_64:
diff --git a/bazel/Android.bp b/bazel/Android.bp
index 9e7edc7..d11c78b 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -20,6 +20,7 @@
         "soong_build",
     ],
     deps: [
+        "bazel_analysis_v2_proto",
         "blueprint",
     ],
 }
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 05f6ed4..bc823b3 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -17,7 +17,6 @@
 import (
 	"crypto/sha256"
 	"encoding/base64"
-	"encoding/json"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -25,6 +24,8 @@
 	"strings"
 
 	"github.com/google/blueprint/proptools"
+	"google.golang.org/protobuf/proto"
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 )
 
 type artifactId int
@@ -312,11 +313,79 @@
 // BuildStatements are one-to-one with actions in the given action graph, and AqueryDepsets
 // are one-to-one with Bazel's depSetOfFiles objects.
 func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, []AqueryDepset, error) {
-	var aqueryResult actionGraphContainer
-	err := json.Unmarshal(aqueryJsonProto, &aqueryResult)
+	aqueryProto := &analysis_v2_proto.ActionGraphContainer{}
+	err := proto.Unmarshal(aqueryJsonProto, aqueryProto)
 	if err != nil {
 		return nil, nil, err
 	}
+	aqueryResult := actionGraphContainer{}
+
+	for _, protoArtifact := range aqueryProto.Artifacts {
+		aqueryResult.Artifacts = append(aqueryResult.Artifacts, artifact{artifactId(protoArtifact.Id),
+			pathFragmentId(protoArtifact.PathFragmentId)})
+	}
+
+	for _, protoAction := range aqueryProto.Actions {
+		var environmentVariable []KeyValuePair
+		var inputDepSetIds []depsetId
+		var outputIds []artifactId
+		var substitutions []KeyValuePair
+
+		for _, protoEnvironmentVariable := range protoAction.EnvironmentVariables {
+			environmentVariable = append(environmentVariable, KeyValuePair{
+				protoEnvironmentVariable.Key, protoEnvironmentVariable.Value,
+			})
+		}
+		for _, protoInputDepSetIds := range protoAction.InputDepSetIds {
+			inputDepSetIds = append(inputDepSetIds, depsetId(protoInputDepSetIds))
+		}
+		for _, protoOutputIds := range protoAction.OutputIds {
+			outputIds = append(outputIds, artifactId(protoOutputIds))
+		}
+		for _, protoSubstitutions := range protoAction.Substitutions {
+			substitutions = append(substitutions, KeyValuePair{
+				protoSubstitutions.Key, protoSubstitutions.Value,
+			})
+		}
+
+		aqueryResult.Actions = append(aqueryResult.Actions,
+			action{
+				Arguments:            protoAction.Arguments,
+				EnvironmentVariables: environmentVariable,
+				InputDepSetIds:       inputDepSetIds,
+				Mnemonic:             protoAction.Mnemonic,
+				OutputIds:            outputIds,
+				TemplateContent:      protoAction.TemplateContent,
+				Substitutions:        substitutions,
+				FileContents:         protoAction.FileContents})
+	}
+
+	for _, protoDepSetOfFiles := range aqueryProto.DepSetOfFiles {
+		var directArtifactIds []artifactId
+		var transitiveDepSetIds []depsetId
+
+		for _, protoDirectArtifactIds := range protoDepSetOfFiles.DirectArtifactIds {
+			directArtifactIds = append(directArtifactIds, artifactId(protoDirectArtifactIds))
+		}
+		for _, protoTransitiveDepSetIds := range protoDepSetOfFiles.TransitiveDepSetIds {
+			transitiveDepSetIds = append(transitiveDepSetIds, depsetId(protoTransitiveDepSetIds))
+		}
+		aqueryResult.DepSetOfFiles = append(aqueryResult.DepSetOfFiles,
+			depSetOfFiles{
+				Id:                  depsetId(protoDepSetOfFiles.Id),
+				DirectArtifactIds:   directArtifactIds,
+				TransitiveDepSetIds: transitiveDepSetIds})
+
+	}
+
+	for _, protoPathFragments := range aqueryProto.PathFragments {
+		aqueryResult.PathFragments = append(aqueryResult.PathFragments,
+			pathFragment{
+				Id:       pathFragmentId(protoPathFragments.Id),
+				Label:    protoPathFragments.Label,
+				ParentId: pathFragmentId(protoPathFragments.ParentId)})
+
+	}
 	aqueryHandler, err := newAqueryHandler(aqueryResult)
 	if err != nil {
 		return nil, nil, err
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 5810364..2eacafa 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -15,118 +15,128 @@
 package bazel
 
 import (
+	"encoding/json"
 	"fmt"
 	"reflect"
 	"sort"
 	"testing"
+
+	"google.golang.org/protobuf/proto"
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 )
 
 func TestAqueryMultiArchGenrule(t *testing.T) {
 	// This input string is retrieved from a real build of bionic-related genrules.
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 6 },
-    { "id": 3, "pathFragmentId": 8 },
-    { "id": 4, "pathFragmentId": 12 },
-    { "id": 5, "pathFragmentId": 19 },
-    { "id": 6, "pathFragmentId": 20 },
-    { "id": 7, "pathFragmentId": 21 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
-    "mnemonic": "Genrule",
-    "configurationId": 1,
-    "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm.S"],
-    "environmentVariables": [{
-      "key": "PATH",
-      "value": "/bin:/usr/bin:/usr/local/bin"
-    }],
-    "inputDepSetIds": [1],
-    "outputIds": [4],
-    "primaryOutputId": 4
-  }, {
-    "targetId": 2,
-    "actionKey": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826",
-    "mnemonic": "Genrule",
-    "configurationId": 1,
-    "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86.S"],
-    "environmentVariables": [{
-      "key": "PATH",
-      "value": "/bin:/usr/bin:/usr/local/bin"
-    }],
-    "inputDepSetIds": [2],
-    "outputIds": [5],
-    "primaryOutputId": 5
-  }, {
-    "targetId": 3,
-    "actionKey": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342",
-    "mnemonic": "Genrule",
-    "configurationId": 1,
-    "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86_64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86_64.S"],
-    "environmentVariables": [{
-      "key": "PATH",
-      "value": "/bin:/usr/bin:/usr/local/bin"
-    }],
-    "inputDepSetIds": [3],
-    "outputIds": [6],
-    "primaryOutputId": 6
-  }, {
-    "targetId": 4,
-    "actionKey": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa",
-    "mnemonic": "Genrule",
-    "configurationId": 1,
-    "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm64.S"],
-    "environmentVariables": [{
-      "key": "PATH",
-      "value": "/bin:/usr/bin:/usr/local/bin"
-    }],
-    "inputDepSetIds": [4],
-    "outputIds": [7],
-    "primaryOutputId": 7
-  }],
-  "targets": [
-    { "id": 1, "label": "@sourceroot//bionic/libc:syscalls-arm", "ruleClassId": 1 },
-    { "id": 2, "label": "@sourceroot//bionic/libc:syscalls-x86", "ruleClassId": 1 },
-    { "id": 3, "label": "@sourceroot//bionic/libc:syscalls-x86_64", "ruleClassId": 1 },
-    { "id": 4, "label": "@sourceroot//bionic/libc:syscalls-arm64", "ruleClassId": 1 }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 2, 3] },
-    { "id": 2, "directArtifactIds": [1, 2, 3] },
-    { "id": 3, "directArtifactIds": [1, 2, 3] },
-    { "id": 4, "directArtifactIds": [1, 2, 3] }],
-  "configuration": [{
-    "id": 1,
-    "mnemonic": "k8-fastbuild",
-    "platformName": "k8",
-    "checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
-  }],
-  "ruleClasses": [{ "id": 1, "name": "genrule"}],
-  "pathFragments": [
-    { "id": 5, "label": ".." },
-    { "id": 4, "label": "sourceroot", "parentId": 5 },
-    { "id": 3, "label": "bionic", "parentId": 4 },
-    { "id": 2, "label": "libc", "parentId": 3 },
-    { "id": 1, "label": "SYSCALLS.TXT", "parentId": 2 },
-    { "id": 7, "label": "tools", "parentId": 2 },
-    { "id": 6, "label": "gensyscalls.py", "parentId": 7 },
-    { "id": 11, "label": "bazel_tools", "parentId": 5 },
-    { "id": 10, "label": "tools", "parentId": 11 },
-    { "id": 9, "label": "genrule", "parentId": 10 },
-    { "id": 8, "label": "genrule-setup.sh", "parentId": 9 },
-    { "id": 18, "label": "bazel-out" },
-    { "id": 17, "label": "sourceroot", "parentId": 18 },
-    { "id": 16, "label": "k8-fastbuild", "parentId": 17 },
-    { "id": 15, "label": "bin", "parentId": 16 },
-    { "id": 14, "label": "bionic", "parentId": 15 },
-    { "id": 13, "label": "libc", "parentId": 14 },
-    { "id": 12, "label": "syscalls-arm.S", "parentId": 13 },
-    { "id": 19, "label": "syscalls-x86.S", "parentId": 13 },
-    { "id": 20, "label": "syscalls-x86_64.S", "parentId": 13 },
-    { "id": 21, "label": "syscalls-arm64.S", "parentId": 13 }]
-}`
-	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
+ "Artifacts": [
+   { "Id": 1, "path_fragment_id": 1 },
+   { "Id": 2, "path_fragment_id": 6 },
+   { "Id": 3, "path_fragment_id": 8 },
+   { "Id": 4, "path_fragment_id": 12 },
+   { "Id": 5, "path_fragment_id": 19 },
+   { "Id": 6, "path_fragment_id": 20 },
+   { "Id": 7, "path_fragment_id": 21 }],
+ "Actions": [{
+   "target_id": 1,
+   "action_key": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
+   "Mnemonic": "Genrule",
+   "configuration_id": 1,
+   "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm.S"],
+   "environment_variables": [{
+     "Key": "PATH",
+     "Value": "/bin:/usr/bin:/usr/local/bin"
+   }],
+   "input_dep_set_ids": [1],
+   "output_ids": [4],
+   "primary_output_id": 4
+ }, {
+   "target_id": 2,
+   "action_key": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826",
+   "Mnemonic": "Genrule",
+   "configuration_id": 1,
+   "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86.S"],
+   "environment_variables": [{
+     "Key": "PATH",
+     "Value": "/bin:/usr/bin:/usr/local/bin"
+   }],
+   "input_dep_set_ids": [2],
+   "output_ids": [5],
+   "primary_output_id": 5
+ }, {
+   "target_id": 3,
+   "action_key": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342",
+   "Mnemonic": "Genrule",
+   "configuration_id": 1,
+   "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86_64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86_64.S"],
+   "environment_variables": [{
+     "Key": "PATH",
+     "Value": "/bin:/usr/bin:/usr/local/bin"
+   }],
+   "input_dep_set_ids": [3],
+   "output_ids": [6],
+   "primary_output_id": 6
+ }, {
+   "target_id": 4,
+   "action_key": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa",
+   "Mnemonic": "Genrule",
+   "configuration_id": 1,
+   "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm64.S"],
+   "environment_variables": [{
+     "Key": "PATH",
+     "Value": "/bin:/usr/bin:/usr/local/bin"
+   }],
+   "input_dep_set_ids": [4],
+   "output_ids": [7],
+   "primary_output_id": 7
+ }],
+ "Targets": [
+   { "Id": 1, "Label": "@sourceroot//bionic/libc:syscalls-arm", "rule_class_id": 1 },
+   { "Id": 2, "Label": "@sourceroot//bionic/libc:syscalls-x86", "rule_class_id": 1 },
+   { "Id": 3, "Label": "@sourceroot//bionic/libc:syscalls-x86_64", "rule_class_id": 1 },
+   { "Id": 4, "Label": "@sourceroot//bionic/libc:syscalls-arm64", "rule_class_id": 1 }],
+ "dep_set_of_files": [
+   { "Id": 1, "direct_artifact_ids": [1, 2, 3] },
+   { "Id": 2, "direct_artifact_ids": [1, 2, 3] },
+   { "Id": 3, "direct_artifact_ids": [1, 2, 3] },
+   { "Id": 4, "direct_artifact_ids": [1, 2, 3] }],
+ "Configuration": [{
+   "Id": 1,
+   "Mnemonic": "k8-fastbuild",
+   "platform_name": "k8",
+   "Checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
+ }],
+ "rule_classes": [{ "Id": 1, "Name": "genrule"}],
+ "path_fragments": [
+   { "Id": 5, "Label": ".." },
+   { "Id": 4, "Label": "sourceroot", "parent_id": 5 },
+   { "Id": 3, "Label": "bionic", "parent_id": 4 },
+   { "Id": 2, "Label": "libc", "parent_id": 3 },
+   { "Id": 1, "Label": "SYSCALLS.TXT", "parent_id": 2 },
+   { "Id": 7, "Label": "tools", "parent_id": 2 },
+   { "Id": 6, "Label": "gensyscalls.py", "parent_id": 7 },
+   { "Id": 11, "Label": "bazel_tools", "parent_id": 5 },
+   { "Id": 10, "Label": "tools", "parent_id": 11 },
+   { "Id": 9, "Label": "genrule", "parent_id": 10 },
+   { "Id": 8, "Label": "genrule-setup.sh", "parent_id": 9 },
+   { "Id": 18, "Label": "bazel-out" },
+   { "Id": 17, "Label": "sourceroot", "parent_id": 18 },
+   { "Id": 16, "Label": "k8-fastbuild", "parent_id": 17 },
+   { "Id": 15, "Label": "bin", "parent_id": 16 },
+   { "Id": 14, "Label": "bionic", "parent_id": 15 },
+   { "Id": 13, "Label": "libc", "parent_id": 14 },
+   { "Id": 12, "Label": "syscalls-arm.S", "parent_id": 13 },
+   { "Id": 19, "Label": "syscalls-x86.S", "parent_id": 13 },
+   { "Id": 20, "Label": "syscalls-x86_64.S", "parent_id": 13 },
+   { "Id": 21, "Label": "syscalls-arm64.S", "parent_id": 13 }]
+}
+`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
 	var expectedBuildStatements []BuildStatement
 	for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
 		expectedBuildStatements = append(expectedBuildStatements,
@@ -161,130 +171,155 @@
 func TestInvalidOutputId(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [3],
-    "primaryOutputId": 3
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 2] }],
-  "pathFragments": [
-    { "id": 1, "label": "one" },
-    { "id": 2, "label": "two" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "x",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [1],
+   "output_ids": [3],
+   "primary_output_id": 3
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1, 2] }],
+ "path_fragments": [
+   { "id": 1, "label": "one" },
+   { "id": 2, "label": "two" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, "undefined outputId 3")
 }
 
 func TestInvalidInputDepsetIdFromAction(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [2],
-    "outputIds": [1],
-    "primaryOutputId": 1
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 2] }],
-  "pathFragments": [
-    { "id": 1, "label": "one" },
-    { "id": 2, "label": "two" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "x",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [2],
+   "output_ids": [1],
+   "primary_output_id": 1
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1, 2] }],
+ "path_fragments": [
+   { "id": 1, "label": "one" },
+   { "id": 2, "label": "two" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, "undefined input depsetId 2")
 }
 
 func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [1],
-    "primaryOutputId": 1
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 2], "transitiveDepSetIds": [42] }],
-  "pathFragments": [
-    { "id": 1, "label": "one"},
-    { "id": 2, "label": "two" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "x",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [1],
+   "output_ids": [1],
+   "primary_output_id": 1
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1, 2], "transitive_dep_set_ids": [42] }],
+ "path_fragments": [
+   { "id": 1, "label": "one"},
+   { "id": 2, "label": "two" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, "undefined input depsetId 42 (referenced by depsetId 1)")
 }
 
 func TestInvalidInputArtifactId(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [1],
-    "primaryOutputId": 1
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 3] }],
-  "pathFragments": [
-    { "id": 1, "label": "one" },
-    { "id": 2, "label": "two" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "x",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [1],
+   "output_ids": [1],
+   "primary_output_id": 1
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1, 3] }],
+ "path_fragments": [
+   { "id": 1, "label": "one" },
+   { "id": 2, "label": "two" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, "undefined input artifactId 3")
 }
 
 func TestInvalidPathFragmentId(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [1],
-    "primaryOutputId": 1
-  }],
-  "depSetOfFiles": [
-     { "id": 1, "directArtifactIds": [1, 2] }],
-  "pathFragments": [
-    {  "id": 1, "label": "one" },
-    {  "id": 2, "label": "two", "parentId": 3 }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "x",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [1],
+   "output_ids": [1],
+   "primary_output_id": 1
+ }],
+ "dep_set_of_files": [
+    { "id": 1, "direct_artifact_ids": [1, 2] }],
+ "path_fragments": [
+   {  "id": 1, "label": "one" },
+   {  "id": 2, "label": "two", "parent_id": 3 }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, "undefined path fragment id 3")
 }
 
@@ -292,27 +327,32 @@
 	const inputString = `
 {
   "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 },
-    { "id": 3, "pathFragmentId": 3 }],
+    { "id": 1, "path_fragment_id": 1 },
+    { "id": 2, "path_fragment_id": 2 },
+    { "id": 3, "path_fragment_id": 3 }],
   "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
+    "target_Id": 1,
+    "action_Key": "x",
     "mnemonic": "x",
     "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [2, 3],
-    "primaryOutputId": 2
+    "input_dep_set_ids": [1],
+    "output_ids": [2, 3],
+    "primary_output_id": 2
   }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 2, 3] }],
-  "pathFragments": [
+  "dep_set_of_files": [
+    { "id": 1, "direct_Artifact_Ids": [1, 2, 3] }],
+  "path_fragments": [
     { "id": 1, "label": "one" },
     { "id": 2, "label": "two" },
     { "id": 3, "label": "two.d" }]
 }`
 
-	actual, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data)
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -332,32 +372,37 @@
 func TestMultipleDepfiles(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 },
-    { "id": 3, "pathFragmentId": 3 },
-    { "id": 4, "pathFragmentId": 4 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "x",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [2,3,4],
-    "primaryOutputId": 2
-  }],
-  "depSetOfFiles": [{
-    "id": 1,
-    "directArtifactIds": [1, 2, 3, 4]
-  }],
-  "pathFragments": [
-    { "id": 1, "label": "one" },
-    { "id": 2, "label": "two" },
-    { "id": 3, "label": "two.d" },
-    { "id": 4, "label": "other.d" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 },
+   { "id": 3, "path_fragment_id": 3 },
+   { "id": 4, "path_fragment_id": 4 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "x",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [1],
+   "output_ids": [2,3,4],
+   "primary_output_id": 2
+ }],
+ "dep_set_of_files": [{
+   "id": 1,
+   "direct_artifact_ids": [1, 2, 3, 4]
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "one" },
+   { "id": 2, "label": "two" },
+   { "id": 3, "label": "two.d" },
+   { "id": 4, "label": "other.d" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
 }
 
@@ -366,74 +411,79 @@
 	// a single action with many inputs given via a deep depset.
 	const inputString = `
 {
-  "artifacts": [
-   { "id": 1, "pathFragmentId": 1 },
-   { "id": 2, "pathFragmentId": 7 },
-   { "id": 3, "pathFragmentId": 8 },
-   { "id": 4, "pathFragmentId": 9 },
-   { "id": 5, "pathFragmentId": 10 },
-   { "id": 6, "pathFragmentId": 11 },
-   { "id": 7, "pathFragmentId": 12 },
-   { "id": 8, "pathFragmentId": 13 },
-   { "id": 9, "pathFragmentId": 14 },
-   { "id": 10, "pathFragmentId": 15 },
-   { "id": 11, "pathFragmentId": 16 },
-   { "id": 12, "pathFragmentId": 17 },
-   { "id": 13, "pathFragmentId": 18 },
-   { "id": 14, "pathFragmentId": 19 },
-   { "id": 15, "pathFragmentId": 20 },
-   { "id": 16, "pathFragmentId": 21 },
-   { "id": 17, "pathFragmentId": 22 },
-   { "id": 18, "pathFragmentId": 23 },
-   { "id": 19, "pathFragmentId": 24 },
-   { "id": 20, "pathFragmentId": 25 },
-   { "id": 21, "pathFragmentId": 26 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
-    "mnemonic": "Action",
-    "configurationId": 1,
-    "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
-    "inputDepSetIds": [1],
-    "outputIds": [21],
-    "primaryOutputId": 21
-  }],
-  "depSetOfFiles": [
-    { "id": 3, "directArtifactIds": [1, 2, 3, 4, 5] },
-    { "id": 4, "directArtifactIds": [6, 7, 8, 9, 10] },
-    { "id": 2, "transitiveDepSetIds": [3, 4], "directArtifactIds": [11, 12, 13, 14, 15] },
-    { "id": 5, "directArtifactIds": [16, 17, 18, 19] },
-    { "id": 1, "transitiveDepSetIds": [2, 5], "directArtifactIds": [20] }],
-  "pathFragments": [
-    { "id": 6, "label": "bazel-out" },
-    { "id": 5, "label": "sourceroot", "parentId": 6 },
-    { "id": 4, "label": "k8-fastbuild", "parentId": 5 },
-    { "id": 3, "label": "bin", "parentId": 4 },
-    { "id": 2, "label": "testpkg", "parentId": 3 },
-    { "id": 1, "label": "test_1", "parentId": 2 },
-    { "id": 7, "label": "test_2", "parentId": 2 },
-    { "id": 8, "label": "test_3", "parentId": 2 },
-    { "id": 9, "label": "test_4", "parentId": 2 },
-    { "id": 10, "label": "test_5", "parentId": 2 },
-    { "id": 11, "label": "test_6", "parentId": 2 },
-    { "id": 12, "label": "test_7", "parentId": 2 },
-    { "id": 13, "label": "test_8", "parentId": 2 },
-    { "id": 14, "label": "test_9", "parentId": 2 },
-    { "id": 15, "label": "test_10", "parentId": 2 },
-    { "id": 16, "label": "test_11", "parentId": 2 },
-    { "id": 17, "label": "test_12", "parentId": 2 },
-    { "id": 18, "label": "test_13", "parentId": 2 },
-    { "id": 19, "label": "test_14", "parentId": 2 },
-    { "id": 20, "label": "test_15", "parentId": 2 },
-    { "id": 21, "label": "test_16", "parentId": 2 },
-    { "id": 22, "label": "test_17", "parentId": 2 },
-    { "id": 23, "label": "test_18", "parentId": 2 },
-    { "id": 24, "label": "test_19", "parentId": 2 },
-    { "id": 25, "label": "test_root", "parentId": 2 },
-    { "id": 26,"label": "test_out", "parentId": 2 }]
+ "artifacts": [
+  { "id": 1, "path_fragment_id": 1 },
+  { "id": 2, "path_fragment_id": 7 },
+  { "id": 3, "path_fragment_id": 8 },
+  { "id": 4, "path_fragment_id": 9 },
+  { "id": 5, "path_fragment_id": 10 },
+  { "id": 6, "path_fragment_id": 11 },
+  { "id": 7, "path_fragment_id": 12 },
+  { "id": 8, "path_fragment_id": 13 },
+  { "id": 9, "path_fragment_id": 14 },
+  { "id": 10, "path_fragment_id": 15 },
+  { "id": 11, "path_fragment_id": 16 },
+  { "id": 12, "path_fragment_id": 17 },
+  { "id": 13, "path_fragment_id": 18 },
+  { "id": 14, "path_fragment_id": 19 },
+  { "id": 15, "path_fragment_id": 20 },
+  { "id": 16, "path_fragment_id": 21 },
+  { "id": 17, "path_fragment_id": 22 },
+  { "id": 18, "path_fragment_id": 23 },
+  { "id": 19, "path_fragment_id": 24 },
+  { "id": 20, "path_fragment_id": 25 },
+  { "id": 21, "path_fragment_id": 26 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
+   "mnemonic": "Action",
+   "configuration_id": 1,
+   "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
+   "input_dep_set_ids": [1],
+   "output_ids": [21],
+   "primary_output_id": 21
+ }],
+ "dep_set_of_files": [
+   { "id": 3, "direct_artifact_ids": [1, 2, 3, 4, 5] },
+   { "id": 4, "direct_artifact_ids": [6, 7, 8, 9, 10] },
+   { "id": 2, "transitive_dep_set_ids": [3, 4], "direct_artifact_ids": [11, 12, 13, 14, 15] },
+   { "id": 5, "direct_artifact_ids": [16, 17, 18, 19] },
+   { "id": 1, "transitive_dep_set_ids": [2, 5], "direct_artifact_ids": [20] }],
+ "path_fragments": [
+   { "id": 6, "label": "bazel-out" },
+   { "id": 5, "label": "sourceroot", "parent_id": 6 },
+   { "id": 4, "label": "k8-fastbuild", "parent_id": 5 },
+   { "id": 3, "label": "bin", "parent_id": 4 },
+   { "id": 2, "label": "testpkg", "parent_id": 3 },
+   { "id": 1, "label": "test_1", "parent_id": 2 },
+   { "id": 7, "label": "test_2", "parent_id": 2 },
+   { "id": 8, "label": "test_3", "parent_id": 2 },
+   { "id": 9, "label": "test_4", "parent_id": 2 },
+   { "id": 10, "label": "test_5", "parent_id": 2 },
+   { "id": 11, "label": "test_6", "parent_id": 2 },
+   { "id": 12, "label": "test_7", "parent_id": 2 },
+	 { "id": 13, "label": "test_8", "parent_id": 2 },
+   { "id": 14, "label": "test_9", "parent_id": 2 },
+   { "id": 15, "label": "test_10", "parent_id": 2 },
+   { "id": 16, "label": "test_11", "parent_id": 2 },
+   { "id": 17, "label": "test_12", "parent_id": 2 },
+   { "id": 18, "label": "test_13", "parent_id": 2 },
+   { "id": 19, "label": "test_14", "parent_id": 2 },
+   { "id": 20, "label": "test_15", "parent_id": 2 },
+   { "id": 21, "label": "test_16", "parent_id": 2 },
+   { "id": 22, "label": "test_17", "parent_id": 2 },
+   { "id": 23, "label": "test_18", "parent_id": 2 },
+   { "id": 24, "label": "test_19", "parent_id": 2 },
+   { "id": 25, "label": "test_root", "parent_id": 2 },
+   { "id": 26,"label": "test_out", "parent_id": 2 }]
 }`
 
-	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
 
 	expectedBuildStatements := []BuildStatement{
 		{
@@ -463,27 +513,32 @@
 func TestSymlinkTree(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "SymlinkTree",
-    "configurationId": 1,
-    "inputDepSetIds": [1],
-    "outputIds": [2],
-    "primaryOutputId": 2,
-    "executionPlatform": "//build/bazel/platforms:linux_x86_64"
-  }],
-  "pathFragments": [
-    { "id": 1, "label": "foo.manifest" },
-    { "id": 2, "label": "foo.runfiles/MANIFEST" }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1] }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "SymlinkTree",
+   "configuration_id": 1,
+   "input_dep_set_ids": [1],
+   "output_ids": [2],
+   "primary_output_id": 2,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "foo.manifest" },
+   { "id": 2, "label": "foo.runfiles/MANIFEST" }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1] }]
 }
 `
-	actual, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data)
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -499,37 +554,42 @@
 
 func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
 	const inputString = `{
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 10 },
-    { "id": 2, "pathFragmentId": 20 },
-    { "id": 3, "pathFragmentId": 30 },
-    { "id": 4, "pathFragmentId": 40 }],
-  "depSetOfFiles": [{
-    "id": 1111,
-    "directArtifactIds": [3 , 4]
-  }, {
-    "id": 2222,
-    "directArtifactIds": [3]
-  }],
-  "actions": [{
-    "targetId": 100,
-    "actionKey": "x",
-    "inputDepSetIds": [1111, 2222],
-    "mnemonic": "x",
-    "arguments": ["bogus", "command"],
-    "outputIds": [2],
-    "primaryOutputId": 1
-  }],
-  "pathFragments": [
-    { "id": 10, "label": "input" },
-    { "id": 20, "label": "output" },
-    { "id": 30, "label": "dep1", "parentId": 50 },
-    { "id": 40, "label": "dep2", "parentId": 60 },
-    { "id": 50, "label": "bazel_tools", "parentId": 60 },
-    { "id": 60, "label": ".."}
-  ]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 10 },
+   { "id": 2, "path_fragment_id": 20 },
+   { "id": 3, "path_fragment_id": 30 },
+   { "id": 4, "path_fragment_id": 40 }],
+ "dep_set_of_files": [{
+   "id": 1111,
+   "direct_artifact_ids": [3 , 4]
+ }, {
+   "id": 2222,
+   "direct_artifact_ids": [3]
+ }],
+ "actions": [{
+   "target_id": 100,
+   "action_key": "x",
+   "input_dep_set_ids": [1111, 2222],
+   "mnemonic": "x",
+   "arguments": ["bogus", "command"],
+   "output_ids": [2],
+   "primary_output_id": 1
+ }],
+ "path_fragments": [
+   { "id": 10, "label": "input" },
+   { "id": 20, "label": "output" },
+   { "id": 30, "label": "dep1", "parent_id": 50 },
+   { "id": 40, "label": "dep2", "parent_id": 60 },
+   { "id": 50, "label": "bazel_tools", "parent_id": 60 },
+   { "id": 60, "label": ".."}
+ ]
 }`
-	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
 	if len(actualDepsets) != 2 {
 		t.Errorf("expected 1 depset but found %#v", actualDepsets)
 		return
@@ -567,43 +627,47 @@
 func TestMiddlemenAction(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 },
-    { "id": 3, "pathFragmentId": 3 },
-    { "id": 4, "pathFragmentId": 4 },
-    { "id": 5, "pathFragmentId": 5 },
-    { "id": 6, "pathFragmentId": 6 }],
-  "pathFragments": [
-    { "id": 1, "label": "middleinput_one" },
-    { "id": 2, "label": "middleinput_two" },
-    { "id": 3, "label": "middleman_artifact" },
-    { "id": 4, "label": "maininput_one" },
-    { "id": 5, "label": "maininput_two" },
-    { "id": 6, "label": "output" }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1, 2] },
-    { "id": 2, "directArtifactIds": [3, 4, 5] }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "Middleman",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [1],
-    "outputIds": [3],
-    "primaryOutputId": 3
-  }, {
-    "targetId": 2,
-    "actionKey": "y",
-    "mnemonic": "Main action",
-    "arguments": ["touch", "foo"],
-    "inputDepSetIds": [2],
-    "outputIds": [6],
-    "primaryOutputId": 6
-  }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 },
+   { "id": 3, "path_fragment_id": 3 },
+   { "id": 4, "path_fragment_id": 4 },
+   { "id": 5, "path_fragment_id": 5 },
+   { "id": 6, "path_fragment_id": 6 }],
+ "path_fragments": [
+   { "id": 1, "label": "middleinput_one" },
+   { "id": 2, "label": "middleinput_two" },
+   { "id": 3, "label": "middleman_artifact" },
+   { "id": 4, "label": "maininput_one" },
+   { "id": 5, "label": "maininput_two" },
+   { "id": 6, "label": "output" }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1, 2] },
+   { "id": 2, "direct_artifact_ids": [3, 4, 5] }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "Middleman",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [1],
+   "output_ids": [3],
+   "primary_output_id": 3
+ }, {
+   "target_id": 2,
+   "action_key": "y",
+   "mnemonic": "Main action",
+   "arguments": ["touch", "foo"],
+   "input_dep_set_ids": [2],
+   "output_ids": [6],
+   "primary_output_id": 6
+ }]
 }`
-
-	actualBuildStatements, actualDepsets, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data)
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -675,28 +739,32 @@
 func TestSimpleSymlink(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 3 },
-    { "id": 2, "pathFragmentId": 5 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "Symlink",
-    "inputDepSetIds": [1],
-    "outputIds": [2],
-    "primaryOutputId": 2
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1] }],
-  "pathFragments": [
-    { "id": 1, "label": "one" },
-    { "id": 2, "label": "file_subdir", "parentId": 1 },
-    { "id": 3, "label": "file", "parentId": 2 },
-    { "id": 4, "label": "symlink_subdir", "parentId": 1 },
-    { "id": 5, "label": "symlink", "parentId": 4 }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 3 },
+   { "id": 2, "path_fragment_id": 5 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "Symlink",
+   "input_dep_set_ids": [1],
+   "output_ids": [2],
+   "primary_output_id": 2
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1] }],
+ "path_fragments": [
+   { "id": 1, "label": "one" },
+   { "id": 2, "label": "file_subdir", "parent_id": 1 },
+   { "id": 3, "label": "file", "parent_id": 2 },
+   { "id": 4, "label": "symlink_subdir", "parent_id": 1 },
+   { "id": 5, "label": "symlink", "parent_id": 4 }]
 }`
-
-	actual, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data)
 
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
@@ -719,29 +787,33 @@
 func TestSymlinkQuotesPaths(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 3 },
-    { "id": 2, "pathFragmentId": 5 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "SolibSymlink",
-    "inputDepSetIds": [1],
-    "outputIds": [2],
-    "primaryOutputId": 2
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1] }],
-  "pathFragments": [
-    { "id": 1, "label": "one" },
-    { "id": 2, "label": "file subdir", "parentId": 1 },
-    { "id": 3, "label": "file", "parentId": 2 },
-    { "id": 4, "label": "symlink subdir", "parentId": 1 },
-    { "id": 5, "label": "symlink", "parentId": 4 }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 3 },
+   { "id": 2, "path_fragment_id": 5 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "SolibSymlink",
+   "input_dep_set_ids": [1],
+   "output_ids": [2],
+   "primary_output_id": 2
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1] }],
+ "path_fragments": [
+   { "id": 1, "label": "one" },
+   { "id": 2, "label": "file subdir", "parent_id": 1 },
+   { "id": 3, "label": "file", "parent_id": 2 },
+   { "id": 4, "label": "symlink subdir", "parent_id": 1 },
+   { "id": 5, "label": "symlink", "parent_id": 4 }]
 }`
 
-	actual, _, err := AqueryBuildStatements([]byte(inputString))
-
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data)
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -763,82 +835,95 @@
 func TestSymlinkMultipleInputs(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 },
-    { "id": 3, "pathFragmentId": 3 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "Symlink",
-    "inputDepSetIds": [1],
-    "outputIds": [3],
-    "primaryOutputId": 3
-  }],
-  "depSetOfFiles": [{ "id": 1, "directArtifactIds": [1,2] }],
-  "pathFragments": [
-    { "id": 1, "label": "file" },
-    { "id": 2, "label": "other_file" },
-    { "id": 3, "label": "symlink" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 2, "path_fragment_id": 2 },
+   { "id": 3, "path_fragment_id": 3 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "Symlink",
+   "input_dep_set_ids": [1],
+   "output_ids": [3],
+   "primary_output_id": 3
+ }],
+ "dep_set_of_files": [{ "id": 1, "direct_artifact_ids": [1,2] }],
+ "path_fragments": [
+   { "id": 1, "label": "file" },
+   { "id": 2, "label": "other_file" },
+   { "id": 3, "label": "symlink" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
 }
 
 func TestSymlinkMultipleOutputs(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 },
-    { "id": 2, "pathFragmentId": 2 },
-    { "id": 3, "pathFragmentId": 3 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "Symlink",
-    "inputDepSetIds": [1],
-    "outputIds": [2,3],
-    "primaryOutputId": 2
-  }],
-  "depSetOfFiles": [
-    { "id": 1, "directArtifactIds": [1] }],
-  "pathFragments": [
-    { "id": 1, "label": "file" },
-    { "id": 2, "label": "symlink" },
-    { "id": 3,  "label": "other_symlink" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 },
+   { "id": 3, "path_fragment_id": 3 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "Symlink",
+   "input_dep_set_ids": [1],
+   "output_ids": [2,3],
+   "primary_output_id": 2
+ }],
+ "dep_set_of_files": [
+   { "id": 1, "direct_artifact_ids": [1] }],
+ "path_fragments": [
+   { "id": 1, "label": "file" },
+   { "id": 2, "label": "symlink" },
+   { "id": 3,  "label": "other_symlink" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
-	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
+	assertError(t, err, "undefined outputId 2")
 }
 
 func TestTemplateExpandActionSubstitutions(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [{
-    "id": 1,
-    "pathFragmentId": 1
-  }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "TemplateExpand",
-    "configurationId": 1,
-    "outputIds": [1],
-    "primaryOutputId": 1,
-    "executionPlatform": "//build/bazel/platforms:linux_x86_64",
-    "templateContent": "Test template substitutions: %token1%, %python_binary%",
-    "substitutions": [
-      { "key": "%token1%", "value": "abcd" },
-      { "key": "%python_binary%", "value": "python3" }]
-  }],
-  "pathFragments": [
-    { "id": 1, "label": "template_file" }]
+ "artifacts": [{
+   "id": 1,
+   "path_fragment_id": 1
+ }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "TemplateExpand",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "template_content": "Test template substitutions: %token1%, %python_binary%",
+   "substitutions": [
+     { "key": "%token1%", "value": "abcd" },
+     { "key": "%python_binary%", "value": "python3" }]
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "template_file" }]
 }`
 
-	actual, _, err := AqueryBuildStatements([]byte(inputString))
-
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data)
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -857,48 +942,58 @@
 func TestTemplateExpandActionNoOutput(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "TemplateExpand",
-    "configurationId": 1,
-    "primaryOutputId": 1,
-    "executionPlatform": "//build/bazel/platforms:linux_x86_64",
-    "templateContent": "Test template substitutions: %token1%, %python_binary%",
-    "substitutions": [
-      { "key": "%token1%", "value": "abcd" },
-      { "key": "%python_binary%", "value": "python3" }]
-  }],
-  "pathFragments": [
-    { "id": 1, "label": "template_file" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "TemplateExpand",
+   "configuration_id": 1,
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "templateContent": "Test template substitutions: %token1%, %python_binary%",
+   "substitutions": [
+     { "key": "%token1%", "value": "abcd" },
+     { "key": "%python_binary%", "value": "python3" }]
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "template_file" }]
 }`
 
-	_, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	_, _, err = AqueryBuildStatements(data)
 	assertError(t, err, `Expect 1 output to template expand action, got: output []`)
 }
 
 func TestFileWrite(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "FileWrite",
-    "configurationId": 1,
-    "outputIds": [1],
-    "primaryOutputId": 1,
-    "executionPlatform": "//build/bazel/platforms:linux_x86_64",
-    "fileContents": "file data\n"
-  }],
-  "pathFragments": [
-    { "id": 1, "label": "foo.manifest" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "FileWrite",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "file_contents": "file data\n"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "foo.manifest" }]
 }
 `
-	actual, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data)
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -914,23 +1009,28 @@
 func TestSourceSymlinkManifest(t *testing.T) {
 	const inputString = `
 {
-  "artifacts": [
-    { "id": 1, "pathFragmentId": 1 }],
-  "actions": [{
-    "targetId": 1,
-    "actionKey": "x",
-    "mnemonic": "SourceSymlinkManifest",
-    "configurationId": 1,
-    "outputIds": [1],
-    "primaryOutputId": 1,
-    "executionPlatform": "//build/bazel/platforms:linux_x86_64",
-    "fileContents": "symlink target\n"
-  }],
-  "pathFragments": [
-    { "id": 1, "label": "foo.manifest" }]
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "SourceSymlinkManifest",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "file_contents": "symlink target\n"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "foo.manifest" }]
 }
 `
-	actual, _, err := AqueryBuildStatements([]byte(inputString))
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data)
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -1011,3 +1111,14 @@
 	sort.Strings(sorted)
 	return sorted
 }
+
+// Transform the json format to ActionGraphContainer
+func JsonToActionGraphContainer(inputString string) ([]byte, error) {
+	var aqueryProtoResult analysis_v2_proto.ActionGraphContainer
+	err := json.Unmarshal([]byte(inputString), &aqueryProtoResult)
+	if err != nil {
+		return []byte(""), err
+	}
+	data, _ := proto.Marshal(&aqueryProtoResult)
+	return data, err
+}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index e35b531..eb44dd1 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -7,10 +7,11 @@
 )
 
 var (
-	GetOutputFiles  = &getOutputFilesRequestType{}
-	GetPythonBinary = &getPythonBinaryRequestType{}
-	GetCcInfo       = &getCcInfoType{}
-	GetApexInfo     = &getApexInfoType{}
+	GetOutputFiles      = &getOutputFilesRequestType{}
+	GetPythonBinary     = &getPythonBinaryRequestType{}
+	GetCcInfo           = &getCcInfoType{}
+	GetApexInfo         = &getApexInfoType{}
+	GetCcUnstrippedInfo = &getCcUnstippedInfoType{}
 )
 
 type CcInfo struct {
@@ -29,7 +30,9 @@
 	// be a subset of OutputFiles. (or shared libraries, this will be equal to OutputFiles,
 	// but general cc_library will also have dynamic libraries in output files).
 	RootDynamicLibraries []string
+	TidyFiles            []string
 	TocFile              string
+	UnstrippedOutput     string
 }
 
 type getOutputFilesRequestType struct{}
@@ -135,12 +138,17 @@
 rootSharedLibraries = []
 
 shared_info_tag = "//build/bazel/rules/cc:cc_library_shared.bzl%CcSharedLibraryOutputInfo"
+unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
+unstripped = ""
 
 if shared_info_tag in providers(target):
   shared_info = providers(target)[shared_info_tag]
   path = shared_info.output_file.path
   sharedLibraries.append(path)
   rootSharedLibraries += [path]
+  unstripped = path
+  if unstripped_tag in providers(target):
+    unstripped = providers(target)[unstripped_tag].unstripped.path
 else:
   for linker_input in linker_inputs:
     for library in linker_input.libraries:
@@ -158,6 +166,12 @@
   # NOTE: It's OK if there's no ToC, as Soong just uses it for optimization
   pass
 
+tidy_files = []
+p = providers(target)
+clang_tidy_info = p.get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
+if clang_tidy_info:
+  tidy_files = [v.path for v in clang_tidy_info.tidy_files.to_list()]
+
 return json_encode({
 	"OutputFiles": outputFiles,
 	"CcObjectFiles": ccObjectFiles,
@@ -168,7 +182,9 @@
 	"Headers": headers,
 	"RootStaticArchives": rootStaticArchives,
 	"RootDynamicLibraries": rootSharedLibraries,
-	"TocFile": toc_file
+	"TidyFiles": tidy_files,
+	"TocFile": toc_file,
+	"UnstrippedOutput": unstripped,
 })`
 
 }
@@ -178,13 +194,10 @@
 // Starlark given in StarlarkFunctionBody.
 func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
 	var ccInfo CcInfo
-	decoder := json.NewDecoder(strings.NewReader(rawString))
-	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
-	err := decoder.Decode(&ccInfo)
-	if err != nil {
-		return ccInfo, fmt.Errorf("error parsing CcInfo result. %s RAW STRING: %s", err, rawString)
+	if err := parseJson(rawString, &ccInfo); err != nil {
+		return ccInfo, err
 	}
-	return ccInfo, err
+	return ccInfo, nil
 }
 
 // Query Bazel for the artifacts generated by the apex modules.
@@ -205,36 +218,81 @@
 //   - The function body should not be indented outside of its own scope.
 func (g getApexInfoType) StarlarkFunctionBody() string {
 	return `info = providers(target)["//build/bazel/rules/apex:apex.bzl%ApexInfo"]
+bundle_key_info = info.bundle_key_info
+container_key_info = info.container_key_info
 return json_encode({
     "signed_output": info.signed_output.path,
     "unsigned_output": info.unsigned_output.path,
     "provides_native_libs": [str(lib) for lib in info.provides_native_libs],
     "requires_native_libs": [str(lib) for lib in info.requires_native_libs],
-    "bundle_key_pair": [f.path for f in info.bundle_key_pair],
-    "container_key_pair": [f.path for f in info.container_key_pair]
+    "bundle_key_info": [bundle_key_info.public_key.path, bundle_key_info.private_key.path],
+    "container_key_info": [container_key_info.pem.path, container_key_info.pk8.path, container_key_info.key_name],
+    "package_name": info.package_name,
+    "symbols_used_by_apex": info.symbols_used_by_apex.path,
+    "java_symbols_used_by_apex": info.java_symbols_used_by_apex.path,
+    "backing_libs": info.backing_libs.path,
+    "bundle_file": info.base_with_config_zip.path,
 })`
 }
 
-type ApexCqueryInfo struct {
-	SignedOutput     string   `json:"signed_output"`
-	UnsignedOutput   string   `json:"unsigned_output"`
-	ProvidesLibs     []string `json:"provides_native_libs"`
-	RequiresLibs     []string `json:"requires_native_libs"`
-	BundleKeyPair    []string `json:"bundle_key_pair"`
-	ContainerKeyPair []string `json:"container_key_pair"`
+type ApexInfo struct {
+	SignedOutput          string   `json:"signed_output"`
+	UnsignedOutput        string   `json:"unsigned_output"`
+	ProvidesLibs          []string `json:"provides_native_libs"`
+	RequiresLibs          []string `json:"requires_native_libs"`
+	BundleKeyInfo         []string `json:"bundle_key_info"`
+	ContainerKeyInfo      []string `json:"container_key_info"`
+	PackageName           string   `json:"package_name"`
+	SymbolsUsedByApex     string   `json:"symbols_used_by_apex"`
+	JavaSymbolsUsedByApex string   `json:"java_symbols_used_by_apex"`
+	BackingLibs           string   `json:"backing_libs"`
+	BundleFile            string   `json:"bundle_file"`
 }
 
 // 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 getApexInfoType) ParseResult(rawString string) ApexCqueryInfo {
-	var info ApexCqueryInfo
-	decoder := json.NewDecoder(strings.NewReader(rawString))
-	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
-	if err := decoder.Decode(&info); err != nil {
-		panic(fmt.Errorf("cannot parse cquery result '%s': %s", rawString, err))
-	}
-	return info
+func (g getApexInfoType) ParseResult(rawString string) (ApexInfo, error) {
+	var info ApexInfo
+	err := parseJson(rawString, &info)
+	return info, err
+}
+
+// getCcUnstrippedInfoType implements cqueryRequest interface. It handles the
+// interaction with `bazel cquery` to retrieve CcUnstrippedInfo provided
+// by the` cc_binary` and `cc_shared_library` rules.
+type getCcUnstippedInfoType struct{}
+
+func (g getCcUnstippedInfoType) Name() string {
+	return "getCcUnstrippedInfo"
+}
+
+func (g getCcUnstippedInfoType) StarlarkFunctionBody() string {
+	return `unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
+p = providers(target)
+output_path = target.files.to_list()[0].path
+unstripped = output_path
+if unstripped_tag in p:
+    unstripped = p[unstripped_tag].unstripped.files.to_list()[0].path
+return json_encode({
+    "OutputFile":  output_path,
+    "UnstrippedOutput": unstripped,
+})
+`
+}
+
+// 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 getCcUnstippedInfoType) ParseResult(rawString string) (CcUnstrippedInfo, error) {
+	var info CcUnstrippedInfo
+	err := parseJson(rawString, &info)
+	return info, err
+}
+
+type CcUnstrippedInfo struct {
+	OutputFile       string
+	UnstrippedOutput string
 }
 
 // splitOrEmpty is a modification of strings.Split() that returns an empty list
@@ -246,3 +304,15 @@
 		return strings.Split(s, sep)
 	}
 }
+
+// parseJson decodes json string into the fields of the receiver.
+// Unknown attribute name causes panic.
+func parseJson(jsonString string, info interface{}) error {
+	decoder := json.NewDecoder(strings.NewReader(jsonString))
+	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
+	err := decoder.Decode(info)
+	if err != nil {
+		return fmt.Errorf("cannot parse cquery result '%s': %s", jsonString, err)
+	}
+	return nil
+}
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index afe478b..a0a993f 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -3,10 +3,12 @@
 import (
 	"encoding/json"
 	"reflect"
+	"strings"
 	"testing"
 )
 
 func TestGetOutputFilesParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		input          string
@@ -29,14 +31,17 @@
 		},
 	}
 	for _, tc := range testCases {
-		actualOutput := GetOutputFiles.ParseResult(tc.input)
-		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput := GetOutputFiles.ParseResult(tc.input)
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
 	}
 }
 
 func TestGetPythonBinaryParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		input          string
@@ -54,14 +59,17 @@
 		},
 	}
 	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)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput := GetPythonBinary.ParseResult(tc.input)
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
 	}
 }
 
 func TestGetCcInfoParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		inputCcInfo    CcInfo
@@ -73,24 +81,6 @@
 			expectedOutput: CcInfo{},
 		},
 		{
-			description: "only output",
-			inputCcInfo: CcInfo{
-				OutputFiles: []string{"test", "test3"},
-			},
-			expectedOutput: CcInfo{
-				OutputFiles: []string{"test", "test3"},
-			},
-		},
-		{
-			description: "only ToC",
-			inputCcInfo: CcInfo{
-				TocFile: "test",
-			},
-			expectedOutput: CcInfo{
-				TocFile: "test",
-			},
-		},
-		{
 			description: "all items set",
 			inputCcInfo: CcInfo{
 				OutputFiles:          []string{"out1", "out2"},
@@ -119,49 +109,194 @@
 		},
 	}
 	for _, tc := range testCases {
-		jsonInput, _ := json.Marshal(tc.inputCcInfo)
-		actualOutput, err := GetCcInfo.ParseResult(string(jsonInput))
-		if err != nil {
-			t.Errorf("%q:\n test case get error: %q", tc.description, err)
-		} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q:\n expected %#v\n!= actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			jsonInput, _ := json.Marshal(tc.inputCcInfo)
+			actualOutput, err := GetCcInfo.ParseResult(string(jsonInput))
+			if err != nil {
+				t.Errorf("error parsing result: %q", err)
+			} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v\n!= actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
+	}
+}
+
+func TestGetCcInfoParseResultsError(t *testing.T) {
+	t.Parallel()
+	testCases := []struct {
+		description   string
+		input         string
+		expectedError string
+	}{
+		{
+			description:   "not json",
+			input:         ``,
+			expectedError: `cannot parse cquery result '': EOF`,
+		},
+		{
+			description: "invalid field",
+			input: `{
+	"toc_file": "dir/file.so.toc"
+}`,
+			expectedError: `json: unknown field "toc_file"`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			_, err := GetCcInfo.ParseResult(tc.input)
+			if !strings.Contains(err.Error(), tc.expectedError) {
+				t.Errorf("expected string %q in error message, got %q", tc.expectedError, err)
+			}
+		})
 	}
 }
 
 func TestGetApexInfoParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		input          string
-		expectedOutput ApexCqueryInfo
+		expectedOutput ApexInfo
 	}{
 		{
 			description:    "no result",
 			input:          "{}",
-			expectedOutput: ApexCqueryInfo{},
+			expectedOutput: ApexInfo{},
 		},
 		{
 			description: "one result",
-			input: `{"signed_output":"my.apex",` +
-				`"unsigned_output":"my.apex.unsigned",` +
-				`"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],` +
-				`"bundle_key_pair":["foo.pem","foo.privkey"],` +
-				`"container_key_pair":["foo.x509.pem", "foo.pk8"],` +
-				`"provides_native_libs":[]}`,
-			expectedOutput: ApexCqueryInfo{
-				SignedOutput:     "my.apex",
-				UnsignedOutput:   "my.apex.unsigned",
-				RequiresLibs:     []string{"//bionic/libc:libc", "//bionic/libdl:libdl"},
-				ProvidesLibs:     []string{},
-				BundleKeyPair:    []string{"foo.pem", "foo.privkey"},
-				ContainerKeyPair: []string{"foo.x509.pem", "foo.pk8"},
+			input: `{
+	"signed_output":"my.apex",
+	"unsigned_output":"my.apex.unsigned",
+	"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],
+	"bundle_key_info":["foo.pem", "foo.privkey"],
+	"container_key_info":["foo.x509.pem", "foo.pk8", "foo"],
+	"package_name":"package.name",
+	"symbols_used_by_apex": "path/to/my.apex_using.txt",
+	"backing_libs":"path/to/backing.txt",
+	"bundle_file": "dir/bundlefile.zip",
+	"provides_native_libs":[]
+}`,
+			expectedOutput: ApexInfo{
+				SignedOutput:      "my.apex",
+				UnsignedOutput:    "my.apex.unsigned",
+				RequiresLibs:      []string{"//bionic/libc:libc", "//bionic/libdl:libdl"},
+				ProvidesLibs:      []string{},
+				BundleKeyInfo:     []string{"foo.pem", "foo.privkey"},
+				ContainerKeyInfo:  []string{"foo.x509.pem", "foo.pk8", "foo"},
+				PackageName:       "package.name",
+				SymbolsUsedByApex: "path/to/my.apex_using.txt",
+				BackingLibs:       "path/to/backing.txt",
+				BundleFile:        "dir/bundlefile.zip",
 			},
 		},
 	}
 	for _, tc := range testCases {
-		actualOutput := GetApexInfo.ParseResult(tc.input)
-		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput, err := GetApexInfo.ParseResult(tc.input)
+			if err != nil {
+				t.Errorf("Unexpected error %q", err)
+			}
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
+	}
+}
+
+func TestGetApexInfoParseResultsError(t *testing.T) {
+	t.Parallel()
+	testCases := []struct {
+		description   string
+		input         string
+		expectedError string
+	}{
+		{
+			description:   "not json",
+			input:         ``,
+			expectedError: `cannot parse cquery result '': EOF`,
+		},
+		{
+			description: "invalid field",
+			input: `{
+	"fake_field": "path/to/file"
+}`,
+			expectedError: `json: unknown field "fake_field"`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			_, err := GetApexInfo.ParseResult(tc.input)
+			if !strings.Contains(err.Error(), tc.expectedError) {
+				t.Errorf("expected string %q in error message, got %q", tc.expectedError, err)
+			}
+		})
+	}
+}
+
+func TestGetCcUnstrippedParseResults(t *testing.T) {
+	t.Parallel()
+	testCases := []struct {
+		description    string
+		input          string
+		expectedOutput CcUnstrippedInfo
+	}{
+		{
+			description:    "no result",
+			input:          "{}",
+			expectedOutput: CcUnstrippedInfo{},
+		},
+		{
+			description: "one result",
+			input:       `{"OutputFile":"myapp", "UnstrippedOutput":"myapp_unstripped"}`,
+			expectedOutput: CcUnstrippedInfo{
+				OutputFile:       "myapp",
+				UnstrippedOutput: "myapp_unstripped",
+			},
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput, err := GetCcUnstrippedInfo.ParseResult(tc.input)
+			if err != nil {
+				t.Errorf("Unexpected error %q", err)
+			}
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
+	}
+}
+
+func TestGetCcUnstrippedParseResultsErrors(t *testing.T) {
+	t.Parallel()
+	testCases := []struct {
+		description   string
+		input         string
+		expectedError string
+	}{
+		{
+			description:   "not json",
+			input:         ``,
+			expectedError: `cannot parse cquery result '': EOF`,
+		},
+		{
+			description: "invalid field",
+			input: `{
+	"fake_field": "path/to/file"
+}`,
+			expectedError: `json: unknown field "fake_field"`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			_, err := GetCcUnstrippedInfo.ParseResult(tc.input)
+			if !strings.Contains(err.Error(), tc.expectedError) {
+				t.Errorf("expected string %q in error message, got %q", tc.expectedError, err)
+			}
+		})
 	}
 }
diff --git a/bazel/properties.go b/bazel/properties.go
index c329e41..823cda8 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -73,6 +73,17 @@
 	}
 }
 
+// MakeLabelListFromTargetNames creates a LabelList from unqualified target names
+// This is a utiltity function for bp2build converters of Soong modules that have 1:many generated targets
+func MakeLabelListFromTargetNames(targetNames []string) LabelList {
+	labels := []Label{}
+	for _, name := range targetNames {
+		label := Label{Label: ":" + name}
+		labels = append(labels, label)
+	}
+	return MakeLabelList(labels)
+}
+
 func (ll *LabelList) Equals(other LabelList) bool {
 	if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
 		return false
@@ -1178,6 +1189,11 @@
 	ConfigurableValues configurableStringLists
 }
 
+// IsEmpty returns true if the attribute has no values under any configuration.
+func (sla StringListAttribute) IsEmpty() bool {
+	return len(sla.Value) == 0 && !sla.HasConfigurableValues()
+}
+
 type configurableStringLists map[ConfigurationAxis]stringListSelectValues
 
 func (csl configurableStringLists) Append(other configurableStringLists) {
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index e112be3..2b35521 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -27,6 +27,7 @@
 }
 
 func registerAndroidAppModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 }
 
 func TestMinimalAndroidApp(t *testing.T) {
@@ -76,6 +77,7 @@
         manifest: "manifest/AndroidManifest.xml",
         static_libs: ["static_lib_dep"],
         java_version: "7",
+        certificate: "foocert",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -86,9 +88,10 @@
         "resa/res.png",
         "resb/res.png",
     ]`,
-				"custom_package": `"com.google"`,
-				"deps":           `[":static_lib_dep"]`,
-				"javacopts":      `["-source 1.7 -target 1.7"]`,
+				"custom_package":   `"com.google"`,
+				"deps":             `[":static_lib_dep"]`,
+				"javacopts":        `["-source 1.7 -target 1.7"]`,
+				"certificate_name": `"foocert"`,
 			}),
 		}})
 }
@@ -130,3 +133,70 @@
 			}),
 		}})
 }
+
+func TestAndroidAppCertIsModule(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app - cert is module",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+android_app {
+        name: "TestApp",
+        certificate: ":foocert",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
+				"certificate":    `":foocert"`,
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `[]`,
+			}),
+		}})
+}
+
+func TestAndroidAppCertIsSrcFile(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app - cert is src file",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem: map[string]string{
+			"foocert": "",
+		},
+		Blueprint: `
+android_app {
+        name: "TestApp",
+        certificate: "foocert",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
+				"certificate":    `"foocert"`,
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `[]`,
+			}),
+		}})
+}
+
+func TestAndroidAppCertIsNotSrcOrModule(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app - cert is not src or module",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem:                 map[string]string{
+			// deliberate empty
+		},
+		Blueprint: `
+android_app {
+        name: "TestApp",
+        certificate: "foocert",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
+				"certificate_name": `"foocert"`,
+				"manifest":         `"AndroidManifest.xml"`,
+				"resource_files":   `[]`,
+			}),
+		}})
+}
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 4fd6e43..b6061e4 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -22,6 +22,7 @@
 	"android/soong/java"
 	"android/soong/sh"
 
+	"fmt"
 	"testing"
 )
 
@@ -41,6 +42,7 @@
 	ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
+	ctx.RegisterModuleType("cc_test", cc.TestFactory)
 }
 
 func runOverrideApexTestCase(t *testing.T, tc Bp2buildTestCase) {
@@ -153,10 +155,17 @@
 				"key":             `":com.android.apogee.key"`,
 				"manifest":        `"apogee_manifest.json"`,
 				"min_sdk_version": `"29"`,
-				"native_shared_libs_32": `[
-        ":native_shared_lib_1",
-        ":native_shared_lib_2",
-    ]`,
+				"native_shared_libs_32": `select({
+        "//build/bazel/platforms/arch:arm": [
+            ":native_shared_lib_1",
+            ":native_shared_lib_2",
+        ],
+        "//build/bazel/platforms/arch:x86": [
+            ":native_shared_lib_1",
+            ":native_shared_lib_2",
+        ],
+        "//conditions:default": [],
+    })`,
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
             ":native_shared_lib_1",
@@ -273,10 +282,11 @@
 }
 `,
 		},
-		Blueprint: createMultilibBlueprint("both"),
+		Blueprint: createMultilibBlueprint(`compile_multilib: "both",`),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `[
+        ":unnested_native_shared_lib",
         ":native_shared_lib_for_both",
         ":native_shared_lib_for_lib32",
     ] + select({
@@ -286,11 +296,13 @@
     })`,
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
             ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86_64": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
             ":native_shared_lib_for_first",
@@ -303,53 +315,69 @@
 		}})
 }
 
-func TestApexBundleCompileMultilibFirst(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - example with compile_multilib=first",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: createMultilibBlueprint("first"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"native_shared_libs_32": `select({
+func TestApexBundleCompileMultilibFirstAndDefaultValue(t *testing.T) {
+	expectedBazelTargets := []string{
+		MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
+			"native_shared_libs_32": `select({
         "//build/bazel/platforms/arch:arm": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib32",
             ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib32",
             ":native_shared_lib_for_first",
         ],
         "//conditions:default": [],
     })`,
-				"native_shared_libs_64": `select({
+			"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
             ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86_64": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
             ":native_shared_lib_for_first",
         ],
         "//conditions:default": [],
     })`,
-				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":      `"apex_manifest.json"`,
-			}),
-		}})
+			"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+			"manifest":      `"apex_manifest.json"`,
+		}),
+	}
+
+	// "first" is the default value of compile_multilib prop so `compile_multilib_: "first"` and unset compile_multilib
+	// should result to the same bp2build output
+	compileMultiLibPropValues := []string{`compile_multilib: "first",`, ""}
+	for _, compileMultiLibProp := range compileMultiLibPropValues {
+		descriptionSuffix := compileMultiLibProp
+		if descriptionSuffix == "" {
+			descriptionSuffix = "compile_multilib unset"
+		}
+		runApexTestCase(t, Bp2buildTestCase{
+			Description:                "apex - example with " + compileMultiLibProp,
+			ModuleTypeUnderTest:        "apex",
+			ModuleTypeUnderTestFactory: apex.BundleFactory,
+			Filesystem: map[string]string{
+				"system/sepolicy/apex/Android.bp": `
+    filegroup {
+        name: "com.android.apogee-file_contexts",
+        srcs: [ "apogee-file_contexts", ],
+        bazel_module: { bp2build_available: false },
+    }
+    `,
+			},
+			Blueprint:            createMultilibBlueprint(compileMultiLibProp),
+			ExpectedBazelTargets: expectedBazelTargets,
+		})
+	}
 }
 
 func TestApexBundleCompileMultilib32(t *testing.T) {
@@ -366,10 +394,11 @@
 }
 `,
 		},
-		Blueprint: createMultilibBlueprint("32"),
+		Blueprint: createMultilibBlueprint(`compile_multilib: "32",`),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `[
+        ":unnested_native_shared_lib",
         ":native_shared_lib_for_both",
         ":native_shared_lib_for_lib32",
     ] + select({
@@ -397,16 +426,18 @@
 }
 `,
 		},
-		Blueprint: createMultilibBlueprint("64"),
+		Blueprint: createMultilibBlueprint(`compile_multilib: "64",`),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
             ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86_64": [
+            ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
             ":native_shared_lib_for_first",
@@ -420,7 +451,7 @@
 }
 
 func createMultilibBlueprint(compile_multilib string) string {
-	return `
+	return fmt.Sprintf(`
 cc_library {
 	name: "native_shared_lib_for_both",
 	bazel_module: { bp2build_available: false },
@@ -441,9 +472,15 @@
 	bazel_module: { bp2build_available: false },
 }
 
+cc_library {
+	name: "unnested_native_shared_lib",
+	bazel_module: { bp2build_available: false },
+}
+
 apex {
 	name: "com.android.apogee",
-	compile_multilib: "` + compile_multilib + `",
+	%s
+	native_shared_libs: ["unnested_native_shared_lib"],
 	multilib: {
 		both: {
 			native_shared_libs: [
@@ -466,7 +503,7 @@
 			],
 		},
 	},
-}`
+}`, compile_multilib)
 }
 
 func TestApexBundleDefaultPropertyValues(t *testing.T) {
@@ -636,10 +673,17 @@
 				"key":             `":com.google.android.apogee.key"`,
 				"manifest":        `"apogee_manifest.json"`,
 				"min_sdk_version": `"29"`,
-				"native_shared_libs_32": `[
-        ":native_shared_lib_1",
-        ":native_shared_lib_2",
-    ]`,
+				"native_shared_libs_32": `select({
+        "//build/bazel/platforms/arch:arm": [
+            ":native_shared_lib_1",
+            ":native_shared_lib_2",
+        ],
+        "//build/bazel/platforms/arch:x86": [
+            ":native_shared_lib_1",
+            ":native_shared_lib_2",
+        ],
+        "//conditions:default": [],
+    })`,
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
             ":native_shared_lib_1",
@@ -1206,3 +1250,28 @@
 			}),
 		}})
 }
+
+func TestApexTestBundleSimple(t *testing.T) {
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex_test - simple",
+		ModuleTypeUnderTest:        "apex_test",
+		ModuleTypeUnderTestFactory: apex.TestApexBundleFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
+cc_test { name: "cc_test_1", bazel_module: { bp2build_available: false } }
+
+apex_test {
+	name: "test_com.android.apogee",
+	file_contexts: "file_contexts_file",
+	tests: ["cc_test_1"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("apex", "test_com.android.apogee", AttrNameToString{
+				"file_contexts": `"file_contexts_file"`,
+				"manifest":      `"apex_manifest.json"`,
+				"testonly":      `True`,
+				"tests":         `[":cc_test_1"]`,
+			}),
+		}})
+}
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index 79b1d89..f9a68c9 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -30,12 +30,37 @@
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 }
 
-func TestApexKeySimple_KeysAreSrcFiles(t *testing.T) {
+func TestApexKeySimple_KeysAreSrcFilesInSameDir(t *testing.T) {
 	runApexKeyTestCase(t, Bp2buildTestCase{
-		Description:                "apex key - keys are src files, use key_name attributes",
+		Description:                "apex key - keys are src files, use key attributes",
 		ModuleTypeUnderTest:        "apex_key",
 		ModuleTypeUnderTestFactory: apex.ApexKeyFactory,
-		Filesystem:                 map[string]string{},
+		Filesystem: map[string]string{
+			"com.android.apogee.avbpubkey": "",
+			"com.android.apogee.pem":       "",
+		},
+		Blueprint: `
+apex_key {
+        name: "com.android.apogee.key",
+        public_key: "com.android.apogee.avbpubkey",
+        private_key: "com.android.apogee.pem",
+}
+`,
+		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
+			"private_key": `"com.android.apogee.pem"`,
+			"public_key":  `"com.android.apogee.avbpubkey"`,
+		}),
+		}})
+}
+
+func TestApexKeySimple_KeysAreSrcFilesNotInDir(t *testing.T) {
+	runApexKeyTestCase(t, Bp2buildTestCase{
+		Description:                "apex key - keys are not src or module, use key_name attributes",
+		ModuleTypeUnderTest:        "apex_key",
+		ModuleTypeUnderTestFactory: apex.ApexKeyFactory,
+		Filesystem:                 map[string]string{
+			// deliberately left empty
+		},
 		Blueprint: `
 apex_key {
         name: "com.android.apogee.key",
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 0e3d2a5..a75a84e 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -26,7 +26,7 @@
 // Codegen is the backend of bp2build. The code generator is responsible for
 // writing .bzl files that are equivalent to Android.bp files that are capable
 // of being built with Bazel.
-func Codegen(ctx *CodegenContext) CodegenMetrics {
+func Codegen(ctx *CodegenContext) *CodegenMetrics {
 	// This directory stores BUILD files that could be eventually checked-in.
 	bp2buildDir := android.PathForOutput(ctx, "bp2build")
 	if err := android.RemoveAllOutputDir(bp2buildDir); err != nil {
@@ -48,7 +48,7 @@
 	soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
 	writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(ctx.Config(), res.metrics))
 
-	return res.metrics
+	return &res.metrics
 }
 
 // Get the output directory and create it if it doesn't exist.
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 82ce115..5ab54e3 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -28,7 +28,6 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/starlark_fmt"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -137,7 +136,7 @@
 
 type CodegenContext struct {
 	config             android.Config
-	context            android.Context
+	context            *android.Context
 	mode               CodegenMode
 	additionalDeps     []string
 	unconvertedDepMode unconvertedDepsMode
@@ -204,12 +203,12 @@
 	return ctx.additionalDeps
 }
 
-func (ctx *CodegenContext) Config() android.Config   { return ctx.config }
-func (ctx *CodegenContext) Context() android.Context { return ctx.context }
+func (ctx *CodegenContext) Config() android.Config    { return ctx.config }
+func (ctx *CodegenContext) Context() *android.Context { return ctx.context }
 
 // NewCodegenContext creates a wrapper context that conforms to PathContext for
 // writing BUILD files in the output directory.
-func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) *CodegenContext {
+func NewCodegenContext(config android.Config, context *android.Context, mode CodegenMode) *CodegenContext {
 	var unconvertedDeps unconvertedDepsMode
 	if config.IsEnvTrue("BP2BUILD_ERROR_UNCONVERTED") {
 		unconvertedDeps = errorModulesUnconvertedDeps
@@ -245,12 +244,7 @@
 	buildFileToTargets := make(map[string]BazelTargets)
 
 	// Simple metrics tracking for bp2build
-	metrics := CodegenMetrics{
-		ruleClassCount:           make(map[string]uint64),
-		convertedModulePathMap:   make(map[string]string),
-		convertedModuleTypeCount: make(map[string]uint64),
-		totalModuleTypeCount:     make(map[string]uint64),
-	}
+	metrics := CreateCodegenMetrics()
 
 	dirs := make(map[string]bool)
 
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 7c24a94..c40c45a 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -209,7 +209,7 @@
 			_, errs = ctx.PrepareBuildActions(config)
 			android.FailIfErrored(t, errs)
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, QueryView)
+			codegenCtx := NewCodegenContext(config, ctx.Context, QueryView)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 			if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
@@ -530,7 +530,7 @@
 				return
 			}
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 
@@ -903,7 +903,7 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 		bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 		android.FailIfErrored(t, err)
 		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
@@ -1156,7 +1156,7 @@
 			_, errs = ctx.ResolveDependencies(config)
 			android.FailIfErrored(t, errs)
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 			if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
@@ -1263,7 +1263,7 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 
 		// For each directory, test that the expected number of generated targets is correct.
 		for dir, expectedCount := range testCase.expectedCount {
@@ -1398,7 +1398,7 @@
 			if testCase.Dir != "" {
 				checkDir = testCase.Dir
 			}
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
 			android.FailIfErrored(t, err)
 			bazelTargets.sort()
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index d4461b6..4c86374 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -2743,6 +2743,205 @@
 	)
 }
 
+func TestCcApiContributionsWithHdrs(t *testing.T) {
+	bp := `
+	cc_library {
+		name: "libfoo",
+		stubs: { symbol_file: "libfoo.map.txt", versions: ["28", "29", "current"] },
+		llndk: { symbol_file: "libfoo.map.txt", override_export_include_dirs: ["dir2"]},
+		export_include_dirs: ["dir1"],
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"cc_api_library_headers",
+			"libfoo.systemapi.headers",
+			AttrNameToString{
+				"export_includes": `["dir1"]`,
+			}),
+		MakeBazelTarget(
+			"cc_api_library_headers",
+			"libfoo.vendorapi.headers",
+			AttrNameToString{
+				"export_includes": `["dir2"]`,
+			}),
+		MakeBazelTarget(
+			"cc_api_contribution",
+			"libfoo.contribution",
+			AttrNameToString{
+				"api":          `"libfoo.map.txt"`,
+				"library_name": `"libfoo"`,
+				"api_surfaces": `[
+        "systemapi",
+        "vendorapi",
+    ]`,
+				"hdrs": `[
+        ":libfoo.systemapi.headers",
+        ":libfoo.vendorapi.headers",
+    ]`,
+			}),
+	}
+	RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
+		Blueprint:            bp,
+		Description:          "cc API contributions to systemapi and vendorapi",
+		ExpectedBazelTargets: expectedBazelTargets,
+	})
+}
+
+func TestCcApiSurfaceCombinations(t *testing.T) {
+	testCases := []struct {
+		bp                  string
+		expectedApi         string
+		expectedApiSurfaces string
+		description         string
+	}{
+		{
+			bp: `
+			cc_library {
+				name: "a",
+				stubs: {symbol_file: "a.map.txt"},
+			}`,
+			expectedApi:         `"a.map.txt"`,
+			expectedApiSurfaces: `["systemapi"]`,
+			description:         "Library that contributes to systemapi",
+		},
+		{
+			bp: `
+			cc_library {
+				name: "a",
+				llndk: {symbol_file: "a.map.txt"},
+			}`,
+			expectedApi:         `"a.map.txt"`,
+			expectedApiSurfaces: `["vendorapi"]`,
+			description:         "Library that contributes to vendorapi",
+		},
+		{
+			bp: `
+			cc_library {
+				name: "a",
+				llndk: {symbol_file: "a.map.txt"},
+				stubs: {symbol_file: "a.map.txt"},
+			}`,
+			expectedApi: `"a.map.txt"`,
+			expectedApiSurfaces: `[
+        "systemapi",
+        "vendorapi",
+    ]`,
+			description: "Library that contributes to systemapi and vendorapi",
+		},
+	}
+	for _, testCase := range testCases {
+		expectedBazelTargets := []string{
+			MakeBazelTarget(
+				"cc_api_contribution",
+				"a.contribution",
+				AttrNameToString{
+					"library_name": `"a"`,
+					"hdrs":         `[]`,
+					"api":          testCase.expectedApi,
+					"api_surfaces": testCase.expectedApiSurfaces,
+				},
+			),
+		}
+		RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
+			Blueprint:            testCase.bp,
+			Description:          testCase.description,
+			ExpectedBazelTargets: expectedBazelTargets,
+		})
+	}
+}
+
+// llndk struct property in Soong provides users with several options to configure the exported include dirs
+// Test the generated bazel targets for the different configurations
+func TestCcVendorApiHeaders(t *testing.T) {
+	testCases := []struct {
+		bp                     string
+		expectedIncludes       string
+		expectedSystemIncludes string
+		description            string
+	}{
+		{
+			bp: `
+			cc_library {
+				name: "a",
+				export_include_dirs: ["include"],
+				export_system_include_dirs: ["base_system_include"],
+				llndk: {
+					symbol_file: "a.map.txt",
+					export_headers_as_system: true,
+				},
+			}
+			`,
+			expectedIncludes: "",
+			expectedSystemIncludes: `[
+        "base_system_include",
+        "include",
+    ]`,
+			description: "Headers are exported as system to API surface",
+		},
+		{
+			bp: `
+			cc_library {
+				name: "a",
+				export_include_dirs: ["include"],
+				export_system_include_dirs: ["base_system_include"],
+				llndk: {
+					symbol_file: "a.map.txt",
+					override_export_include_dirs: ["llndk_include"],
+				},
+			}
+			`,
+			expectedIncludes:       `["llndk_include"]`,
+			expectedSystemIncludes: `["base_system_include"]`,
+			description:            "Non-system Headers are ovverriden before export to API surface",
+		},
+		{
+			bp: `
+			cc_library {
+				name: "a",
+				export_include_dirs: ["include"],
+				export_system_include_dirs: ["base_system_include"],
+				llndk: {
+					symbol_file: "a.map.txt",
+					override_export_include_dirs: ["llndk_include"],
+					export_headers_as_system: true,
+				},
+			}
+			`,
+			expectedIncludes: "", // includes are set to nil
+			expectedSystemIncludes: `[
+        "base_system_include",
+        "llndk_include",
+    ]`,
+			description: "System Headers are extended before export to API surface",
+		},
+	}
+	for _, testCase := range testCases {
+		attrs := AttrNameToString{}
+		if testCase.expectedIncludes != "" {
+			attrs["export_includes"] = testCase.expectedIncludes
+		}
+		if testCase.expectedSystemIncludes != "" {
+			attrs["export_system_includes"] = testCase.expectedSystemIncludes
+		}
+
+		expectedBazelTargets := []string{
+			MakeBazelTarget("cc_api_library_headers", "a.vendorapi.headers", attrs),
+			// Create a target for cc_api_contribution target
+			MakeBazelTarget("cc_api_contribution", "a.contribution", AttrNameToString{
+				"api":          `"a.map.txt"`,
+				"api_surfaces": `["vendorapi"]`,
+				"hdrs":         `[":a.vendorapi.headers"]`,
+				"library_name": `"a"`,
+			}),
+		}
+		RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
+			Blueprint:            testCase.bp,
+			ExpectedBazelTargets: expectedBazelTargets,
+		})
+	}
+}
+
 func TestCcLibraryStubsAcrossConfigsDuplicatesRemoved(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
 		Description:                "stub target generation of the same lib across configs should not result in duplicates",
@@ -3309,3 +3508,38 @@
 		},
 	})
 }
+
+func TestCcLibraryWithTidy(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library uses tidy properties",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+    name: "foo",
+    srcs: ["foo.cpp"],
+	tidy: true,
+	tidy_checks: ["check1", "check2"],
+	tidy_checks_as_errors: ["check1error", "check2error"],
+	tidy_disabled_srcs: ["bar.cpp"],
+	tidy_timeout_srcs: ["baz.cpp"],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"local_includes": `["."]`,
+				"srcs":           `["foo.cpp"]`,
+				"tidy":           `True`,
+				"tidy_checks": `[
+        "check1",
+        "check2",
+    ]`,
+				"tidy_checks_as_errors": `[
+        "check1error",
+        "check2error",
+    ]`,
+				"tidy_disabled_srcs": `["bar.cpp"]`,
+				"tidy_timeout_srcs":  `["baz.cpp"]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 5fa7cac..7d9db6f 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -123,6 +123,69 @@
 	})
 }
 
+func TestCcApiHeaders(t *testing.T) {
+	fs := map[string]string{
+		"bar/Android.bp": `cc_library_headers { name: "bar_headers", }`,
+	}
+	bp := `
+	cc_library_headers {
+		name: "foo_headers",
+		export_include_dirs: ["dir1", "dir2"],
+		export_header_lib_headers: ["bar_headers"],
+
+		arch: {
+			arm: {
+				export_include_dirs: ["dir_arm"],
+			},
+			x86: {
+				export_include_dirs: ["dir_x86"],
+			},
+		},
+
+		target: {
+			android: {
+				export_include_dirs: ["dir1", "dir_android"],
+			},
+			windows: {
+				export_include_dirs: ["dir_windows"],
+			},
+		}
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.arm", AttrNameToString{
+			"export_includes": `["dir_arm"]`,
+			"arch":            `"arm"`,
+		}),
+		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.x86", AttrNameToString{
+			"export_includes": `["dir_x86"]`,
+			"arch":            `"x86"`,
+		}),
+		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.androidos", AttrNameToString{
+			"export_includes": `["dir_android"]`, // common includes are deduped
+		}),
+		// Windows headers are not exported
+		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution", AttrNameToString{
+			"export_includes": `[
+        "dir1",
+        "dir2",
+    ]`,
+			"deps": `[
+        "//bar:bar_headers.contribution",
+        ":foo_headers.contribution.arm",
+        ":foo_headers.contribution.x86",
+        ":foo_headers.contribution.androidos",
+    ]`,
+		}),
+	}
+	RunApiBp2BuildTestCase(t, cc.RegisterLibraryHeadersBuildComponents, Bp2buildTestCase{
+		Blueprint:            bp,
+		Description:          "Header library contributions to API surfaces",
+		ExpectedBazelTargets: expectedBazelTargets,
+		Filesystem:           fs,
+	})
+}
+
 func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) {
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:                "cc_library_headers test with os-specific header_libs props",
diff --git a/bp2build/cc_prebuilt_binary_conversion_test.go b/bp2build/cc_prebuilt_binary_conversion_test.go
new file mode 100644
index 0000000..0e8048c
--- /dev/null
+++ b/bp2build/cc_prebuilt_binary_conversion_test.go
@@ -0,0 +1,125 @@
+// Copyright 2022 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
+
+import (
+	"fmt"
+	"testing"
+
+	"android/soong/cc"
+)
+
+func runCcPrebuiltBinaryTestCase(t *testing.T, testCase Bp2buildTestCase) {
+	t.Helper()
+	description := fmt.Sprintf("cc_prebuilt_binary: %s", testCase.Description)
+	testCase.ModuleTypeUnderTest = "cc_prebuilt_binary"
+	testCase.ModuleTypeUnderTestFactory = cc.PrebuiltBinaryFactory
+	testCase.Description = description
+	t.Run(description, func(t *testing.T) {
+		t.Helper()
+		RunBp2BuildTestCaseSimple(t, testCase)
+	})
+}
+
+func TestPrebuiltBinary(t *testing.T) {
+	runCcPrebuiltBinaryTestCase(t,
+		Bp2buildTestCase{
+			Description: "simple",
+			Filesystem: map[string]string{
+				"bin": "",
+			},
+			Blueprint: `
+cc_prebuilt_binary {
+	name: "bintest",
+	srcs: ["bin"],
+	bazel_module: { bp2build_available: true },
+}`,
+			ExpectedBazelTargets: []string{
+				MakeBazelTarget("cc_prebuilt_binary", "bintest", AttrNameToString{
+					"src": `"bin"`,
+				})},
+		})
+}
+
+func TestPrebuiltBinaryWithStrip(t *testing.T) {
+	runCcPrebuiltBinaryTestCase(t,
+		Bp2buildTestCase{
+			Description: "with strip",
+			Filesystem: map[string]string{
+				"bin": "",
+			},
+			Blueprint: `
+cc_prebuilt_binary {
+	name: "bintest",
+	srcs: ["bin"],
+	strip: { all: true },
+	bazel_module: { bp2build_available: true },
+}`, ExpectedBazelTargets: []string{
+				MakeBazelTarget("cc_prebuilt_binary", "bintest", AttrNameToString{
+					"src": `"bin"`,
+					"strip": `{
+        "all": True,
+    }`,
+				}),
+			},
+		})
+}
+
+func TestPrebuiltBinaryWithArchVariance(t *testing.T) {
+	runCcPrebuiltBinaryTestCase(t,
+		Bp2buildTestCase{
+			Description: "with arch variance",
+			Filesystem: map[string]string{
+				"bina": "",
+				"binb": "",
+			},
+			Blueprint: `
+cc_prebuilt_binary {
+	name: "bintest",
+	arch: {
+		arm64: { srcs: ["bina"], },
+		arm: { srcs: ["binb"], },
+	},
+	bazel_module: { bp2build_available: true },
+}`, ExpectedBazelTargets: []string{
+				MakeBazelTarget("cc_prebuilt_binary", "bintest", AttrNameToString{
+					"src": `select({
+        "//build/bazel/platforms/arch:arm": "binb",
+        "//build/bazel/platforms/arch:arm64": "bina",
+        "//conditions:default": None,
+    })`,
+				}),
+			},
+		})
+}
+
+func TestPrebuiltBinaryMultipleSrcsFails(t *testing.T) {
+	runCcPrebuiltBinaryTestCase(t,
+		Bp2buildTestCase{
+			Description: "fails because multiple sources",
+			Filesystem: map[string]string{
+				"bina": "",
+				"binb": "",
+			},
+			Blueprint: `
+cc_prebuilt_binary {
+	name: "bintest",
+	srcs: ["bina", "binb"],
+	bazel_module: { bp2build_available: true },
+}`,
+			ExpectedErr: fmt.Errorf("Expected at most one source file"),
+		})
+}
+
+// TODO: nosrcs test
diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
index dd217c3..47006ac 100644
--- a/bp2build/cc_prebuilt_library_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_conversion_test.go
@@ -36,10 +36,10 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library": `"libf.so"`,
 				}),
-				MakeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libf.so"`,
 				}),
 			},
@@ -66,14 +66,14 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
         "//conditions:default": None,
     })`,
 				}),
-				MakeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
@@ -104,13 +104,13 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library":         `"libf.so"`,
 					"export_includes":        `["testdir/1/"]`,
 					"export_system_includes": `["testdir/2/"]`,
 				}),
 				// TODO(b/229374533): When fixed, update this test
-				MakeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libf.so"`,
 				}),
 			},
@@ -185,10 +185,10 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library": `"libf.so"`,
 				}),
-				MakeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libg.so"`,
 				}),
 			},
@@ -215,7 +215,7 @@
 //	bazel_module: { bp2build_available: true },
 //}`,
 //			expectedBazelTargets: []string{
-//				makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+//				makeBazelTarget("cc_prebuilt_library_shared", "libtest", attrNameToString{
 //					"shared_library": `"libf.so"`,
 //				}),
 //			},
@@ -242,7 +242,7 @@
 //	bazel_module: { bp2build_available: true },
 //}`,
 //			expectedBazelTargets: []string{
-//				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+//				makeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
 //					"static_library": `"libf.so"`,
 //				}),
 //			},
diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go
index 541ce5e..58c0a70 100644
--- a/bp2build/cc_prebuilt_library_shared_test.go
+++ b/bp2build/cc_prebuilt_library_shared_test.go
@@ -23,7 +23,7 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libf.so"`,
 				}),
 			},
@@ -50,7 +50,7 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
diff --git a/bp2build/cc_prebuilt_library_static_test.go b/bp2build/cc_prebuilt_library_static_test.go
index 69a1b5e..6116b00 100644
--- a/bp2build/cc_prebuilt_library_static_test.go
+++ b/bp2build/cc_prebuilt_library_static_test.go
@@ -36,7 +36,7 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_static", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
 					"static_library": `"libf.so"`,
 				}),
 			},
@@ -63,7 +63,7 @@
 	bazel_module: { bp2build_available: true },
 }`,
 			ExpectedBazelTargets: []string{
-				MakeBazelTarget("prebuilt_library_static", "libtest", AttrNameToString{
+				MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
 					"static_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 4d8b8a4..8ca13b8 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -32,7 +32,7 @@
 	files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
 	files = append(files, newFile("apex_toolchain", "constants.bzl", apex.BazelApexToolchainVars()))
 
-	files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
+	files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.Serialize().ConvertedModules, "\n")))
 
 	convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t")
 	if err != nil {
@@ -55,10 +55,6 @@
 	return files
 }
 
-func convertedModules(convertedModules []string) string {
-	return strings.Join(convertedModules, "\n")
-}
-
 func CreateBazelFiles(
 	cfg android.Config,
 	ruleShims map[string]RuleShim,
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index b696a98..cfd6128 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -84,7 +84,7 @@
 
 func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
 	testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
-	files := CreateSoongInjectionFiles(testConfig, CodegenMetrics{})
+	files := CreateSoongInjectionFiles(testConfig, CreateCodegenMetrics())
 
 	expectedFilePaths := []bazelFilepath{
 		{
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 160395b..3490881 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -15,12 +15,13 @@
 package bp2build
 
 import (
+	"fmt"
+	"testing"
+
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/genrule"
 	"android/soong/java"
-	"fmt"
-	"testing"
 )
 
 func registerGenruleModuleTypes(ctx android.RegistrationContext) {
@@ -643,3 +644,50 @@
 		})
 	}
 }
+
+func TestCcGenruleArchAndExcludeSrcs(t *testing.T) {
+	name := "cc_genrule with arch"
+	bp := `
+	cc_genrule {
+		name: "foo",
+		srcs: [
+			"foo1.in",
+			"foo2.in",
+		],
+		exclude_srcs: ["foo2.in"],
+		arch: {
+			arm: {
+				srcs: [
+					"foo1_arch.in",
+					"foo2_arch.in",
+				],
+				exclude_srcs: ["foo2_arch.in"],
+			},
+		},
+		cmd: "cat $(in) > $(out)",
+		bazel_module: { bp2build_available: true },
+	}`
+
+	expectedBazelAttrs := AttrNameToString{
+		"srcs": `["foo1.in"] + select({
+        "//build/bazel/platforms/arch:arm": ["foo1_arch.in"],
+        "//conditions:default": [],
+    })`,
+		"cmd":                    `"cat $(SRCS) > $(OUTS)"`,
+		"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+	}
+
+	expectedBazelTargets := []string{
+		MakeBazelTargetNoRestrictions("genrule", "foo", expectedBazelAttrs),
+	}
+
+	t.Run(name, func(t *testing.T) {
+		RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+			Bp2buildTestCase{
+				ModuleTypeUnderTest:        "cc_genrule",
+				ModuleTypeUnderTestFactory: cc.GenRuleFactory,
+				Blueprint:                  bp,
+				ExpectedBazelTargets:       expectedBazelTargets,
+			})
+	})
+}
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 86f3d42..e8551e5 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -29,10 +29,11 @@
 	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory)
 		ctx.RegisterModuleType("java_library", java.LibraryFactory)
+		ctx.RegisterModuleType("java_import_host", java.ImportFactory)
 	}, tc)
 }
 
-var fs = map[string]string{
+var testFs = map[string]string{
 	"test.mf": "Main-Class: com.android.test.MainClass",
 	"other/Android.bp": `cc_library_host_shared {
     name: "jni-lib-1",
@@ -43,7 +44,7 @@
 func TestJavaBinaryHost(t *testing.T) {
 	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
 		Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
-		Filesystem:  fs,
+		Filesystem:  testFs,
 		Blueprint: `java_binary_host {
     name: "java-binary-host-1",
     srcs: ["a.java", "b.java"],
@@ -76,7 +77,7 @@
 func TestJavaBinaryHostRuntimeDeps(t *testing.T) {
 	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
 		Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
-		Filesystem:  fs,
+		Filesystem:  testFs,
 		Blueprint: `java_binary_host {
     name: "java-binary-host-1",
     static_libs: ["java-dep-1"],
@@ -102,3 +103,34 @@
 		},
 	})
 }
+
+func TestJavaBinaryHostLibs(t *testing.T) {
+	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_binary_host with srcs, libs.",
+		Filesystem:  testFs,
+		Blueprint: `java_binary_host {
+    name: "java-binary-host-libs",
+    libs: ["java-lib-dep-1"],
+    manifest: "test.mf",
+    srcs: ["a.java"],
+}
+
+java_import_host{
+    name: "java-lib-dep-1",
+    jars: ["foo.jar"],
+    bazel_module: { bp2build_available: false },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_binary", "java-binary-host-libs", AttrNameToString{
+				"main_class": `"com.android.test.MainClass"`,
+				"srcs":       `["a.java"]`,
+				"deps":       `[":java-lib-dep-1-neverlink"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go
index 05d7142..ac7dfff 100644
--- a/bp2build/java_import_conversion_test.go
+++ b/bp2build/java_import_conversion_test.go
@@ -48,6 +48,10 @@
 			MakeBazelTarget("java_import", "example_import", AttrNameToString{
 				"jars": `["import.jar"]`,
 			}),
+			MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
+				"exports":   `[":example_import"]`,
+				"neverlink": `True`,
+			}),
 		}})
 }
 
@@ -81,5 +85,35 @@
         "//conditions:default": [],
     })`,
 			}),
+			MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
+				"exports":   `[":example_import"]`,
+				"neverlink": `True`,
+			}),
+		}})
+}
+
+func TestJavaImportHost(t *testing.T) {
+	runJavaImportTestCase(t, Bp2buildTestCase{
+		Description:                "Java import host- simple example",
+		ModuleTypeUnderTest:        "java_import_host",
+		ModuleTypeUnderTestFactory: java.ImportFactory,
+		Filesystem: map[string]string{
+			"import.jar": "",
+		},
+		Blueprint: `
+java_import_host {
+        name: "example_import",
+        jars: ["import.jar"],
+        bazel_module: { bp2build_available: true },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_import", "example_import", AttrNameToString{
+				"jars": `["import.jar"]`,
+			}),
+			MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
+				"exports":   `[":example_import"]`,
+				"neverlink": `True`,
+			}),
 		}})
 }
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 0b45996..bd21629 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -9,25 +9,16 @@
 	"android/soong/android"
 	"android/soong/shared"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+	"google.golang.org/protobuf/proto"
 
 	"github.com/google/blueprint"
 )
 
-// Simple metrics struct to collect information about a Blueprint to BUILD
+// CodegenMetrics represents information about the Blueprint-to-BUILD
 // conversion process.
+// Use CreateCodegenMetrics() to get a properly initialized instance
 type CodegenMetrics struct {
-	// Total number of Soong modules converted to generated targets
-	generatedModuleCount uint64
-
-	// Total number of Soong modules converted to handcrafted targets
-	handCraftedModuleCount uint64
-
-	// Total number of unconverted Soong modules
-	unconvertedModuleCount uint64
-
-	// Counts of generated Bazel targets per Bazel rule class
-	ruleClassCount map[string]uint64
-
+	serialized *bp2build_metrics_proto.Bp2BuildMetrics
 	// List of modules with unconverted deps
 	// NOTE: NOT in the .proto
 	moduleWithUnconvertedDepsMsgs []string
@@ -36,40 +27,32 @@
 	// NOTE: NOT in the .proto
 	moduleWithMissingDepsMsgs []string
 
-	// List of converted modules
-	convertedModules []string
-
 	// Map of converted modules and paths to call
+	// NOTE: NOT in the .proto
 	convertedModulePathMap map[string]string
+}
 
-	// Counts of converted modules by module type.
-	convertedModuleTypeCount map[string]uint64
-
-	// Counts of total modules by module type.
-	totalModuleTypeCount map[string]uint64
-
-	Events []*bp2build_metrics_proto.Event
+func CreateCodegenMetrics() CodegenMetrics {
+	return CodegenMetrics{
+		serialized: &bp2build_metrics_proto.Bp2BuildMetrics{
+			RuleClassCount:           make(map[string]uint64),
+			ConvertedModuleTypeCount: make(map[string]uint64),
+			TotalModuleTypeCount:     make(map[string]uint64),
+		},
+		convertedModulePathMap: make(map[string]string),
+	}
 }
 
 // Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
-func (metrics *CodegenMetrics) Serialize() bp2build_metrics_proto.Bp2BuildMetrics {
-	return bp2build_metrics_proto.Bp2BuildMetrics{
-		GeneratedModuleCount:     metrics.generatedModuleCount,
-		HandCraftedModuleCount:   metrics.handCraftedModuleCount,
-		UnconvertedModuleCount:   metrics.unconvertedModuleCount,
-		RuleClassCount:           metrics.ruleClassCount,
-		ConvertedModules:         metrics.convertedModules,
-		ConvertedModuleTypeCount: metrics.convertedModuleTypeCount,
-		TotalModuleTypeCount:     metrics.totalModuleTypeCount,
-		Events:                   metrics.Events,
-	}
+func (metrics *CodegenMetrics) Serialize() *bp2build_metrics_proto.Bp2BuildMetrics {
+	return metrics.serialized
 }
 
 // Print the codegen metrics to stdout.
 func (metrics *CodegenMetrics) Print() {
 	generatedTargetCount := uint64(0)
-	for _, ruleClass := range android.SortedStringKeys(metrics.ruleClassCount) {
-		count := metrics.ruleClassCount[ruleClass]
+	for _, ruleClass := range android.SortedStringKeys(metrics.serialized.RuleClassCount) {
+		count := metrics.serialized.RuleClassCount[ruleClass]
 		fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
 		generatedTargetCount += count
 	}
@@ -80,9 +63,9 @@
 %d converted modules have missing deps:
 	%s
 `,
-		metrics.generatedModuleCount,
+		metrics.serialized.GeneratedModuleCount,
 		generatedTargetCount,
-		metrics.handCraftedModuleCount,
+		metrics.serialized.HandCraftedModuleCount,
 		metrics.TotalModuleCount(),
 		len(metrics.moduleWithUnconvertedDepsMsgs),
 		strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"),
@@ -119,29 +102,67 @@
 		fail(err, "Error outputting %s", metricsFile)
 	}
 	if _, err := os.Stat(metricsFile); err != nil {
-		fail(err, "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s", metricsFile)
+		if os.IsNotExist(err) {
+			fail(err, "MISSING BP2BUILD METRICS OUTPUT: %s", metricsFile)
+		} else {
+			fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
+		}
+	}
+}
+
+// ReadCodegenMetrics loads CodegenMetrics from `dir`
+// returns a nil pointer if the file doesn't exist
+func ReadCodegenMetrics(dir string) *CodegenMetrics {
+	metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
+	if _, err := os.Stat(metricsFile); err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		} else {
+			fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
+			panic("unreachable after fail")
+		}
+	}
+	if buf, err := os.ReadFile(metricsFile); err != nil {
+		fail(err, "FAILED TO READ BP2BUILD METRICS OUTPUT: %s", metricsFile)
+		panic("unreachable after fail")
+	} else {
+		bp2BuildMetrics := bp2build_metrics_proto.Bp2BuildMetrics{
+			RuleClassCount:           make(map[string]uint64),
+			ConvertedModuleTypeCount: make(map[string]uint64),
+			TotalModuleTypeCount:     make(map[string]uint64),
+		}
+		if err := proto.Unmarshal(buf, &bp2BuildMetrics); err != nil {
+			fail(err, "FAILED TO PARSE BP2BUILD METRICS OUTPUT: %s", metricsFile)
+		}
+		return &CodegenMetrics{
+			serialized:             &bp2BuildMetrics,
+			convertedModulePathMap: make(map[string]string),
+		}
 	}
 }
 
 func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
-	metrics.ruleClassCount[ruleClass] += 1
+	metrics.serialized.RuleClassCount[ruleClass] += 1
 }
 
+func (metrics *CodegenMetrics) AddEvent(event *bp2build_metrics_proto.Event) {
+	metrics.serialized.Events = append(metrics.serialized.Events, event)
+}
 func (metrics *CodegenMetrics) AddUnconvertedModule(moduleType string) {
-	metrics.unconvertedModuleCount += 1
-	metrics.totalModuleTypeCount[moduleType] += 1
+	metrics.serialized.UnconvertedModuleCount += 1
+	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
 }
 
 func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
-	return metrics.handCraftedModuleCount +
-		metrics.generatedModuleCount +
-		metrics.unconvertedModuleCount
+	return metrics.serialized.HandCraftedModuleCount +
+		metrics.serialized.GeneratedModuleCount +
+		metrics.serialized.UnconvertedModuleCount
 }
 
 // Dump serializes the metrics to the given filename
 func (metrics *CodegenMetrics) dump(filename string) (err error) {
 	ser := metrics.Serialize()
-	return shared.Save(&ser, filename)
+	return shared.Save(ser, filename)
 }
 
 type ConversionType int
@@ -154,14 +175,14 @@
 func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string, conversionType ConversionType) {
 	// Undo prebuilt_ module name prefix modifications
 	moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
-	metrics.convertedModules = append(metrics.convertedModules, moduleName)
+	metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName)
 	metrics.convertedModulePathMap[moduleName] = "//" + dir
-	metrics.convertedModuleTypeCount[moduleType] += 1
-	metrics.totalModuleTypeCount[moduleType] += 1
+	metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
+	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
 
 	if conversionType == Handcrafted {
-		metrics.handCraftedModuleCount += 1
+		metrics.serialized.HandCraftedModuleCount += 1
 	} else if conversionType == Generated {
-		metrics.generatedModuleCount += 1
+		metrics.serialized.GeneratedModuleCount += 1
 	}
 }
diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go
index c4bbae2..272ebf5 100644
--- a/bp2build/performance_test.go
+++ b/bp2build/performance_test.go
@@ -22,11 +22,12 @@
 // run for longer, set -benchtime to a larger value.
 
 import (
-	"android/soong/android"
 	"fmt"
 	"math"
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 const (
@@ -105,7 +106,7 @@
 	ctx := android.NewTestContext(config)
 
 	registerCustomModuleForBp2buildConversion(ctx)
-	codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 	return testConfig{
 		config,
 		ctx,
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index e8b9bc4..1b538d0 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -4,6 +4,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/genrule"
 	"android/soong/python"
 )
 
@@ -12,6 +13,8 @@
 	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
 		ctx.RegisterModuleType("python_library_host", python.PythonLibraryHostFactory)
+		ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
+		ctx.RegisterModuleType("python_defaults", python.DefaultsFactory)
 	}, tc)
 }
 
@@ -165,3 +168,152 @@
 		},
 	})
 }
+
+func TestPythonBinaryMainIsNotSpecified(t *testing.T) {
+	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+		Description:                "python_binary_host main label in same package",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Blueprint: `python_binary_host {
+    name: "foo",
+    bazel_module: { bp2build_available: true },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("py_binary", "foo", AttrNameToString{
+				"imports": `["."]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestPythonBinaryMainIsLabel(t *testing.T) {
+	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+		Description:                "python_binary_host main label in same package",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Blueprint: `python_binary_host {
+    name: "foo",
+    main: ":a",
+    bazel_module: { bp2build_available: true },
+}
+
+genrule {
+		name: "a",
+		bazel_module: { bp2build_available: false },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("py_binary", "foo", AttrNameToString{
+				"main":    `":a"`,
+				"imports": `["."]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestPythonBinaryMainIsSubpackageFile(t *testing.T) {
+	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+		Description:                "python_binary_host main is subpackage file",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Filesystem: map[string]string{
+			"a/Android.bp": "",
+			"a/b.py":       "",
+		},
+		Blueprint: `python_binary_host {
+    name: "foo",
+    main: "a/b.py",
+    bazel_module: { bp2build_available: true },
+}
+
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("py_binary", "foo", AttrNameToString{
+				"main":    `"//a:b.py"`,
+				"imports": `["."]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestPythonBinaryMainIsSubDirFile(t *testing.T) {
+	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+		Description:                "python_binary_host main is file in sub directory that is not Bazel package",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Filesystem: map[string]string{
+			"a/b.py": "",
+		},
+		Blueprint: `python_binary_host {
+    name: "foo",
+    main: "a/b.py",
+    bazel_module: { bp2build_available: true },
+}
+
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("py_binary", "foo", AttrNameToString{
+				"main":    `"a/b.py"`,
+				"imports": `["."]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestPythonBinaryDuplicatesInRequired(t *testing.T) {
+	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+		Description:                "python_binary_host duplicates in required attribute of the module and its defaults",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Blueprint: `python_binary_host {
+    name: "foo",
+    main: "a.py",
+		defaults: ["d"],
+    required: [
+        "r1",
+    ],
+    bazel_module: { bp2build_available: true },
+}
+
+python_defaults {
+    name: "d",
+    required: [
+        "r1",
+        "r2",
+    ],
+}` + simpleModuleDoNotConvertBp2build("genrule", "r1") +
+			simpleModuleDoNotConvertBp2build("genrule", "r2"),
+
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("py_binary", "foo", AttrNameToString{
+				"main":    `"a.py"`,
+				"imports": `["."]`,
+				"data": `[
+        ":r1",
+        ":r2",
+    ]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index 7c39a11..81ec7ee 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -15,13 +15,16 @@
 package bp2build
 
 import (
+	"errors"
 	"fmt"
+	"io/fs"
 	"io/ioutil"
 	"os"
 	"path/filepath"
 	"regexp"
+	"sync"
+	"sync/atomic"
 
-	"android/soong/android"
 	"android/soong/shared"
 )
 
@@ -31,14 +34,78 @@
 // or a directory. If excluded is true, then that file/directory should be
 // excluded from symlinking. Otherwise, the node is not excluded, but one of its
 // descendants is (otherwise the node in question would not exist)
-type node struct {
+
+type instructionsNode struct {
 	name     string
 	excluded bool // If false, this is just an intermediate node
-	children map[string]*node
+	children map[string]*instructionsNode
+}
+
+type symlinkForestContext struct {
+	verbose bool
+	topdir  string // $TOPDIR
+
+	// State
+	wg    sync.WaitGroup
+	depCh chan string
+	okay  atomic.Bool // Whether the forest was successfully constructed
+}
+
+// A simple thread pool to limit concurrency on system calls.
+// Necessary because Go spawns a new OS-level thread for each blocking system
+// call. This means that if syscalls are too slow and there are too many of
+// them, the hard limit on OS-level threads can be exhausted.
+type syscallPool struct {
+	shutdownCh []chan<- struct{}
+	workCh     chan syscall
+}
+
+type syscall struct {
+	work func()
+	done chan<- struct{}
+}
+
+func createSyscallPool(count int) *syscallPool {
+	result := &syscallPool{
+		shutdownCh: make([]chan<- struct{}, count),
+		workCh:     make(chan syscall),
+	}
+
+	for i := 0; i < count; i++ {
+		shutdownCh := make(chan struct{})
+		result.shutdownCh[i] = shutdownCh
+		go result.worker(shutdownCh)
+	}
+
+	return result
+}
+
+func (p *syscallPool) do(work func()) {
+	doneCh := make(chan struct{})
+	p.workCh <- syscall{work, doneCh}
+	<-doneCh
+}
+
+func (p *syscallPool) shutdown() {
+	for _, ch := range p.shutdownCh {
+		ch <- struct{}{} // Blocks until the value is received
+	}
+}
+
+func (p *syscallPool) worker(shutdownCh <-chan struct{}) {
+	for {
+		select {
+		case <-shutdownCh:
+			return
+		case work := <-p.workCh:
+			work.work()
+			work.done <- struct{}{}
+		}
+	}
 }
 
 // Ensures that the node for the given path exists in the tree and returns it.
-func ensureNodeExists(root *node, path string) *node {
+func ensureNodeExists(root *instructionsNode, path string) *instructionsNode {
 	if path == "" {
 		return root
 	}
@@ -56,15 +123,14 @@
 	if child, ok := dn.children[base]; ok {
 		return child
 	} else {
-		dn.children[base] = &node{base, false, make(map[string]*node)}
+		dn.children[base] = &instructionsNode{base, false, make(map[string]*instructionsNode)}
 		return dn.children[base]
 	}
 }
 
-// Turns a list of paths to be excluded into a tree made of "node" objects where
-// the specified paths are marked as excluded.
-func treeFromExcludePathList(paths []string) *node {
-	result := &node{"", false, make(map[string]*node)}
+// Turns a list of paths to be excluded into a tree
+func instructionsFromExcludePathList(paths []string) *instructionsNode {
+	result := &instructionsNode{"", false, make(map[string]*instructionsNode)}
 
 	for _, p := range paths {
 		ensureNodeExists(result, p).excluded = true
@@ -179,17 +245,23 @@
 
 // Recursively plants a symlink forest at forestDir. The symlink tree will
 // contain every file in buildFilesDir and srcDir excluding the files in
-// exclude. Collects every directory encountered during the traversal of srcDir
-// into acc.
-func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir string, buildFilesDir string, srcDir string, exclude *node, acc *[]string, okay *bool) {
-	if exclude != nil && exclude.excluded {
+// instructions. Collects every directory encountered during the traversal of
+// srcDir .
+func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *instructionsNode, forestDir string, buildFilesDir string, srcDir string) {
+	defer context.wg.Done()
+
+	if instructions != nil && instructions.excluded {
 		// This directory is not needed, bail out
 		return
 	}
 
-	*acc = append(*acc, srcDir)
-	srcDirMap := readdirToMap(shared.JoinPath(topdir, srcDir))
-	buildFilesMap := readdirToMap(shared.JoinPath(topdir, buildFilesDir))
+	// We don't add buildFilesDir here because the bp2build files marker files is
+	// already a dependency which covers it. If we ever wanted to turn this into
+	// a generic symlink forest creation tool, we'd need to add it, too.
+	context.depCh <- srcDir
+
+	srcDirMap := readdirToMap(shared.JoinPath(context.topdir, srcDir))
+	buildFilesMap := readdirToMap(shared.JoinPath(context.topdir, buildFilesDir))
 
 	renamingBuildFile := false
 	if _, ok := srcDirMap["BUILD"]; ok {
@@ -202,16 +274,16 @@
 		}
 	}
 
-	allEntries := make(map[string]bool)
+	allEntries := make(map[string]struct{})
 	for n := range srcDirMap {
-		allEntries[n] = true
+		allEntries[n] = struct{}{}
 	}
 
 	for n := range buildFilesMap {
-		allEntries[n] = true
+		allEntries[n] = struct{}{}
 	}
 
-	err := os.MkdirAll(shared.JoinPath(topdir, forestDir), 0777)
+	err := os.MkdirAll(shared.JoinPath(context.topdir, forestDir), 0777)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Cannot mkdir '%s': %s\n", forestDir, err)
 		os.Exit(1)
@@ -230,100 +302,152 @@
 		}
 		buildFilesChild := shared.JoinPath(buildFilesDir, f)
 
-		// Descend in the exclusion tree, if there are any excludes left
-		var excludeChild *node = nil
-		if exclude != nil {
+		// Descend in the instruction tree if it exists
+		var instructionsChild *instructionsNode = nil
+		if instructions != nil {
 			if f == "BUILD.bazel" && renamingBuildFile {
-				excludeChild = exclude.children["BUILD"]
+				instructionsChild = instructions.children["BUILD"]
 			} else {
-				excludeChild = exclude.children[f]
+				instructionsChild = instructions.children[f]
 			}
 		}
 
 		srcChildEntry, sExists := srcDirMap[f]
 		buildFilesChildEntry, bExists := buildFilesMap[f]
 
-		if excludeChild != nil && excludeChild.excluded {
+		if instructionsChild != nil && instructionsChild.excluded {
 			if bExists {
-				symlinkIntoForest(topdir, forestChild, buildFilesChild)
+				symlinkIntoForest(context.topdir, forestChild, buildFilesChild)
 			}
 			continue
 		}
 
-		sDir := false
-		bDir := false
-		if sExists {
-			sDir = isDir(shared.JoinPath(topdir, srcChild), srcChildEntry)
-		}
-
-		if bExists {
-			bDir = isDir(shared.JoinPath(topdir, buildFilesChild), buildFilesChildEntry)
-		}
+		sDir := sExists && isDir(shared.JoinPath(context.topdir, srcChild), srcChildEntry)
+		bDir := bExists && isDir(shared.JoinPath(context.topdir, buildFilesChild), buildFilesChildEntry)
 
 		if !sExists {
-			if bDir && excludeChild != nil {
+			if bDir && instructionsChild != nil {
 				// Not in the source tree, but we have to exclude something from under
 				// this subtree, so descend
-				plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+				context.wg.Add(1)
+				go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
 			} else {
 				// Not in the source tree, symlink BUILD file
-				symlinkIntoForest(topdir, forestChild, buildFilesChild)
+				symlinkIntoForest(context.topdir, forestChild, buildFilesChild)
 			}
 		} else if !bExists {
-			if sDir && excludeChild != nil {
+			if sDir && instructionsChild != nil {
 				// Not in the build file tree, but we have to exclude something from
 				// under this subtree, so descend
-				plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+				context.wg.Add(1)
+				go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
 			} else {
 				// Not in the build file tree, symlink source tree, carry on
-				symlinkIntoForest(topdir, forestChild, srcChild)
+				symlinkIntoForest(context.topdir, forestChild, srcChild)
 			}
 		} else if sDir && bDir {
 			// Both are directories. Descend.
-			plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+			context.wg.Add(1)
+			go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
 		} else if !sDir && !bDir {
 			// Neither is a directory. Merge them.
-			srcBuildFile := shared.JoinPath(topdir, srcChild)
-			generatedBuildFile := shared.JoinPath(topdir, buildFilesChild)
-			// Add the src and generated build files as dependencies so that bp2build
-			// is rerun when they change. Currently, this is only really necessary
-			// for srcBuildFile, because if we regenerate the generated build files
-			// we will always rerun the symlink forest generation as well. If that
-			// is later split up into separate, fully dependency-tracing steps, then
-			// we'll need srcBuildFile as well. Adding srcBuildFile here today
-			// technically makes it a dependency of bp2build_workspace_marker, which
-			// also implicitly outputs that file, but since bp2build_workspace_marker
-			// will always have a newer timestamp than the generatedBuildFile it
-			// shouldn't be a problem.
-			*acc = append(*acc, srcBuildFile, generatedBuildFile)
-			err = mergeBuildFiles(shared.JoinPath(topdir, forestChild), srcBuildFile, generatedBuildFile, cfg.IsEnvTrue("BP2BUILD_VERBOSE"))
+			srcBuildFile := shared.JoinPath(context.topdir, srcChild)
+			generatedBuildFile := shared.JoinPath(context.topdir, buildFilesChild)
+			// The Android.bp file that codegen used to produce `buildFilesChild` is
+			// already a dependency, we can ignore `buildFilesChild`.
+			context.depCh <- srcChild
+			err = mergeBuildFiles(shared.JoinPath(context.topdir, forestChild), srcBuildFile, generatedBuildFile, context.verbose)
 			if err != nil {
 				fmt.Fprintf(os.Stderr, "Error merging %s and %s: %s",
 					srcBuildFile, generatedBuildFile, err)
-				*okay = false
+				context.okay.Store(false)
 			}
 		} else {
 			// Both exist and one is a file. This is an error.
 			fmt.Fprintf(os.Stderr,
 				"Conflict in workspace symlink tree creation: both '%s' and '%s' exist and exactly one is a directory\n",
 				srcChild, buildFilesChild)
-			*okay = false
+			context.okay.Store(false)
 		}
 	}
 }
 
+func removeParallelRecursive(pool *syscallPool, path string, fi os.FileInfo, wg *sync.WaitGroup) {
+	defer wg.Done()
+
+	if fi.IsDir() {
+		children := readdirToMap(path)
+		childrenWg := &sync.WaitGroup{}
+		childrenWg.Add(len(children))
+
+		for child, childFi := range children {
+			go removeParallelRecursive(pool, shared.JoinPath(path, child), childFi, childrenWg)
+		}
+
+		childrenWg.Wait()
+	}
+
+	pool.do(func() {
+		if err := os.Remove(path); err != nil {
+			fmt.Fprintf(os.Stderr, "Cannot unlink '%s': %s\n", path, err)
+			os.Exit(1)
+		}
+	})
+}
+
+func removeParallel(path string) {
+	fi, err := os.Lstat(path)
+	if err != nil {
+		if errors.Is(err, fs.ErrNotExist) {
+			return
+		}
+
+		fmt.Fprintf(os.Stderr, "Cannot lstat '%s': %s\n", path, err)
+		os.Exit(1)
+	}
+
+	wg := &sync.WaitGroup{}
+	wg.Add(1)
+
+	// Random guess as to the best number of syscalls to run in parallel
+	pool := createSyscallPool(100)
+	removeParallelRecursive(pool, path, fi, wg)
+	pool.shutdown()
+
+	wg.Wait()
+}
+
 // Creates a symlink forest by merging the directory tree at "buildFiles" and
 // "srcDir" while excluding paths listed in "exclude". Returns the set of paths
 // under srcDir on which readdir() had to be called to produce the symlink
 // forest.
-func PlantSymlinkForest(cfg android.Config, topdir string, forest string, buildFiles string, srcDir string, exclude []string) []string {
+func PlantSymlinkForest(verbose bool, topdir string, forest string, buildFiles string, exclude []string) []string {
+	context := &symlinkForestContext{
+		verbose: verbose,
+		topdir:  topdir,
+		depCh:   make(chan string),
+	}
+
+	context.okay.Store(true)
+
+	removeParallel(shared.JoinPath(topdir, forest))
+
+	instructions := instructionsFromExcludePathList(exclude)
+	go func() {
+		context.wg.Add(1)
+		plantSymlinkForestRecursive(context, instructions, forest, buildFiles, ".")
+		context.wg.Wait()
+		close(context.depCh)
+	}()
+
 	deps := make([]string, 0)
-	os.RemoveAll(shared.JoinPath(topdir, forest))
-	excludeTree := treeFromExcludePathList(exclude)
-	okay := true
-	plantSymlinkForestRecursive(cfg, topdir, forest, buildFiles, srcDir, excludeTree, &deps, &okay)
-	if !okay {
+	for dep := range context.depCh {
+		deps = append(deps, dep)
+	}
+
+	if !context.okay.Load() {
 		os.Exit(1)
 	}
+
 	return deps
 }
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 31aa830..3750804 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -155,7 +155,7 @@
 	if tc.Dir != "" {
 		checkDir = tc.Dir
 	}
-	codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 	codegenCtx.unconvertedDepMode = tc.UnconvertedDepsMode
 	bazelTargets, errs := generateBazelTargetsForDir(codegenCtx, checkDir)
 	if tc.ExpectedErr != nil {
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 60a410d..a840fa3 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -18,11 +18,13 @@
 	"fmt"
 	"io"
 	"path/filepath"
+	"runtime"
 	"strings"
 
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
+	"android/soong/cc"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -31,6 +33,7 @@
 func init() {
 	registerBpfBuildComponents(android.InitRegistrationContext)
 	pctx.Import("android/soong/cc/config")
+	pctx.StaticVariable("relPwd", cc.PwdPrefix())
 }
 
 var (
@@ -40,7 +43,7 @@
 		blueprint.RuleParams{
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
-			Command:     "$ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
+			Command:     "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
 			CommandDeps: []string{"$ccCmd"},
 		},
 		"ccCmd", "cFlags")
@@ -164,6 +167,9 @@
 
 	if proptools.Bool(bpf.properties.Btf) {
 		cflags = append(cflags, "-g")
+		if runtime.GOOS != "darwin" {
+			cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
+		}
 	}
 
 	srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs)
diff --git a/build_test.bash b/build_test.bash
index 92819a1..eda4beb 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -48,8 +48,10 @@
 
 case $(uname) in
   Linux)
-    export LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
-    export SEGFAULT_USE_ALTSTACK=1
+    if [[ -f /lib/x86_64-linux-gnu/libSegFault.so ]]; then
+      export LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
+      export SEGFAULT_USE_ALTSTACK=1
+    fi
     ulimit -a
     ;;
 esac
@@ -62,7 +64,7 @@
 
 echo
 echo "Running Bazel smoke test..."
-STANDALONE_BAZEL=true "${TOP}/tools/bazel" --batch --max_idle_secs=1 help
+STANDALONE_BAZEL=true "${TOP}/build/bazel/bin/bazel" --batch --max_idle_secs=1 help
 
 echo
 echo "Running Soong test..."
diff --git a/cc/afdo.go b/cc/afdo.go
index fb66bbe..d36f4af 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -36,7 +36,7 @@
 
 func getAfdoProfileProjects(config android.DeviceConfig) []string {
 	return config.OnceStringSlice(afdoProfileProjectsConfigKey, func() []string {
-		return append(globalAfdoProfileProjects, config.AfdoAdditionalProfileDirs()...)
+		return globalAfdoProfileProjects
 	})
 }
 
diff --git a/cc/api_level.go b/cc/api_level.go
index 8f9e1f6..fdff5cb 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -20,7 +20,7 @@
 	"android/soong/android"
 )
 
-func MinApiForArch(ctx android.EarlyModuleContext,
+func minApiForArch(ctx android.EarlyModuleContext,
 	arch android.ArchType) android.ApiLevel {
 
 	switch arch {
@@ -38,7 +38,7 @@
 func nativeApiLevelFromUser(ctx android.BaseModuleContext,
 	raw string) (android.ApiLevel, error) {
 
-	min := MinApiForArch(ctx, ctx.Arch().ArchType)
+	min := minApiForArch(ctx, ctx.Arch().ArchType)
 	if raw == "minimum" {
 		return min, nil
 	}
diff --git a/cc/binary.go b/cc/binary.go
index 69cf4ac..c2868e7 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -577,25 +577,20 @@
 
 func (handler *ccBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
+	bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
 }
 
 func (handler *ccBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
 	bazelCtx := ctx.Config().BazelContext
-	filePaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
+	info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKey(ctx))
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
 		return
 	}
 
-	if len(filePaths) != 1 {
-		ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, filePaths)
-		return
-	}
-	outputFilePath := android.PathForBazelOut(ctx, filePaths[0])
+	outputFilePath := android.PathForBazelOut(ctx, info.OutputFile)
 	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
-	// TODO(b/220164721): We need to decide if we should return the stripped as the unstripped.
-	handler.module.linker.(*binaryDecorator).unstrippedOutputFile = outputFilePath
+	handler.module.linker.(*binaryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput)
 }
 
 func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAttributes {
@@ -651,6 +646,8 @@
 		sdkAttributes: bp2BuildParseSdkAttributes(m),
 	}
 
+	m.convertTidyAttributes(ctx, &attrs.tidyAttributes)
+
 	return attrs
 }
 
@@ -703,4 +700,6 @@
 	Features bazel.StringListAttribute
 
 	sdkAttributes
+
+	tidyAttributes
 }
diff --git a/cc/binary_test.go b/cc/binary_test.go
index cba5974..db6fb3a 100644
--- a/cc/binary_test.go
+++ b/cc/binary_test.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"android/soong/bazel/cquery"
 	"testing"
 
 	"android/soong/android"
@@ -30,8 +31,11 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.BazelContext = android.MockBazelContext{
 		OutputBaseDir: "outputbase",
-		LabelToOutputFiles: map[string][]string{
-			"//foo/bar:bar": []string{"foo"},
+		LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{
+			"//foo/bar:bar": cquery.CcUnstrippedInfo{
+				OutputFile:       "foo",
+				UnstrippedOutput: "foo.unstripped",
+			},
 		},
 	}
 	ctx := testCcWithConfig(t, config)
@@ -46,7 +50,7 @@
 	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
 
 	unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile()
-	expectedUnStrippedFile := "outputbase/execroot/__main__/foo"
+	expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped"
 	android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
 }
 
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 868ff0d..6caa854 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -66,6 +66,40 @@
 	Native_coverage bazel.BoolAttribute
 
 	sdkAttributes
+
+	tidyAttributes
+}
+
+type tidyAttributes struct {
+	Tidy                  *bool
+	Tidy_flags            []string
+	Tidy_checks           []string
+	Tidy_checks_as_errors []string
+	Tidy_disabled_srcs    bazel.LabelListAttribute
+	Tidy_timeout_srcs     bazel.LabelListAttribute
+}
+
+func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) {
+	for _, f := range m.features {
+		if tidy, ok := f.(*tidyFeature); ok {
+			moduleAttrs.Tidy = tidy.Properties.Tidy
+			moduleAttrs.Tidy_flags = tidy.Properties.Tidy_flags
+			moduleAttrs.Tidy_checks = tidy.Properties.Tidy_checks
+			moduleAttrs.Tidy_checks_as_errors = tidy.Properties.Tidy_checks_as_errors
+		}
+
+	}
+	archVariantProps := m.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
+	for axis, configToProps := range archVariantProps {
+		for config, _props := range configToProps {
+			if archProps, ok := _props.(*BaseCompilerProperties); ok {
+				archDisabledSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_disabled_srcs)
+				moduleAttrs.Tidy_disabled_srcs.SetSelectValue(axis, config, archDisabledSrcs)
+				archTimeoutSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_timeout_srcs)
+				moduleAttrs.Tidy_timeout_srcs.SetSelectValue(axis, config, archTimeoutSrcs)
+			}
+		}
+	}
 }
 
 // groupSrcsByExtension partitions `srcs` into groups based on file extension.
@@ -169,6 +203,14 @@
 	}
 }
 
+func bp2BuildPropParseHelper(ctx android.ArchVariantContext, module *Module, propsType interface{}, parseFunc func(axis bazel.ConfigurationAxis, config string, props interface{})) {
+	for axis, configToProps := range module.GetArchVariantProperties(ctx, propsType) {
+		for config, props := range configToProps {
+			parseFunc(axis, config, props)
+		}
+	}
+}
+
 // Parses properties common to static and shared libraries. Also used for prebuilt libraries.
 func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
 	attrs := staticOrSharedAttributes{}
@@ -227,32 +269,30 @@
 	Enabled bazel.BoolAttribute
 }
 
+func parseSrc(ctx android.BazelConversionPathContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) {
+	srcFileError := func() {
+		ctx.ModuleErrorf("parseSrc: Expected at most one source file for %s %s\n", axis, config)
+	}
+	if len(srcs) > 1 {
+		srcFileError()
+		return
+	} else if len(srcs) == 0 {
+		return
+	}
+	if srcLabelAttribute.SelectValue(axis, config) != nil {
+		srcFileError()
+		return
+	}
+	srcLabelAttribute.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, srcs[0]))
+}
+
 // NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package
 func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes {
-	manySourceFileError := func(axis bazel.ConfigurationAxis, config string) {
-		ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most one source file for %s %s\n", axis, config)
-	}
+
 	var srcLabelAttribute bazel.LabelAttribute
-
-	parseSrcs := func(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, srcs []string) {
-		if len(srcs) > 1 {
-			manySourceFileError(axis, config)
-			return
-		} else if len(srcs) == 0 {
-			return
-		}
-		if srcLabelAttribute.SelectValue(axis, config) != nil {
-			manySourceFileError(axis, config)
-			return
-		}
-
-		src := android.BazelLabelForModuleSrcSingle(ctx, srcs[0])
-		srcLabelAttribute.SetSelectValue(axis, config, src)
-	}
-
 	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok {
-			parseSrcs(ctx, axis, config, prebuiltLinkerProperties.Srcs)
+			parseSrc(ctx, &srcLabelAttribute, axis, config, prebuiltLinkerProperties.Srcs)
 		}
 	})
 
@@ -261,7 +301,7 @@
 		if props.Enabled != nil {
 			enabledLabelAttribute.SetSelectValue(axis, config, props.Enabled)
 		}
-		parseSrcs(ctx, axis, config, props.Srcs)
+		parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs)
 	}
 
 	if isStatic {
@@ -284,11 +324,16 @@
 	}
 }
 
-func bp2BuildPropParseHelper(ctx android.ArchVariantContext, module *Module, propsType interface{}, parseFunc func(axis bazel.ConfigurationAxis, config string, props interface{})) {
-	for axis, configToProps := range module.GetArchVariantProperties(ctx, propsType) {
-		for config, props := range configToProps {
-			parseFunc(axis, config, props)
+func bp2BuildParsePrebuiltBinaryProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
+	var srcLabelAttribute bazel.LabelAttribute
+	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
+		if props, ok := props.(*prebuiltLinkerProperties); ok {
+			parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs)
 		}
+	})
+
+	return prebuiltAttributes{
+		Src: srcLabelAttribute,
 	}
 }
 
diff --git a/cc/builder.go b/cc/builder.go
index 39f7dc3..46cea0b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -924,9 +924,9 @@
 }
 
 // sourceAbiDiff registers a build statement to compare linked sAbi dump files (.lsdump).
-func sourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
-	baseName, exportedHeaderFlags string, diffFlags []string, prevVersion int,
-	checkAllApis, isLlndk, isNdk, isVndkExt, previousVersionDiff bool) android.OptionalPath {
+func sourceAbiDiff(ctx android.ModuleContext, inputDump, referenceDump android.Path,
+	baseName string, diffFlags []string, prevVersion int,
+	checkAllApis, isLlndkOrNdk, isVndkExt, previousVersionDiff bool) android.OptionalPath {
 
 	var outputFile android.ModuleOutPath
 	if previousVersionDiff {
@@ -946,12 +946,8 @@
 	}
 
 	var errorMessage string
-	// When error occurs in previous version ABI diff, Developers can't just update ABI
-	// reference but need to follow instructions to ensure ABI backward compatibility.
 	if previousVersionDiff {
-		// TODO(b/241496591): Remove -advice-only after b/239792343 and b/239790286 are reolved.
-		extraFlags = append(extraFlags, "-advice-only")
-		errorMessage = "error: Please follow development/vndk/tools/header-checker/README.md to ensure the ABI compatibility between your source code and version " + strconv.Itoa(prevVersion) + "."
+		errorMessage = "error: Please follow https://android.googlesource.com/platform/development/+/master/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the ABI difference between your source code and version " + strconv.Itoa(prevVersion) + "."
 		sourceVersion := prevVersion + 1
 		extraFlags = append(extraFlags, "-target-version", strconv.Itoa(sourceVersion))
 	} else {
@@ -959,7 +955,7 @@
 		extraFlags = append(extraFlags, "-target-version", "current")
 	}
 
-	if isLlndk || isNdk {
+	if isLlndkOrNdk {
 		extraFlags = append(extraFlags, "-consider-opaque-types-different")
 	}
 	if isVndkExt || previousVersionDiff {
diff --git a/cc/cc.go b/cc/cc.go
index d4eaa53..306e483 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1853,6 +1853,11 @@
 func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
 	bazelModuleLabel := c.getBazelModuleLabel(ctx)
 
+	bazelCtx := ctx.Config().BazelContext
+	if ccInfo, err := bazelCtx.GetCcInfo(bazelModuleLabel, android.GetConfigKey(ctx)); err == nil {
+		c.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+	}
+
 	c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel)
 
 	c.Properties.SubName = GetSubnameProperty(ctx, c)
@@ -2335,9 +2340,11 @@
 	ctx.ctx = ctx
 
 	deps := c.deps(ctx)
-
 	apiImportInfo := GetApiImports(c, actx)
-	deps = updateDepsWithApiImports(deps, apiImportInfo)
+
+	if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+		deps = updateDepsWithApiImports(deps, apiImportInfo)
+	}
 
 	c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
 
@@ -2362,7 +2369,9 @@
 		}
 
 		// Check header lib replacement from API surface first, and then check again with VSDK
-		lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
+		if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+			lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
+		}
 		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
 
 		if c.isNDKStubLibrary() {
@@ -2536,6 +2545,8 @@
 			}, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
 		}
 	}
+
+	updateImportedLibraryDependency(ctx)
 }
 
 func BeginMutator(ctx android.BottomUpMutatorContext) {
@@ -3626,6 +3637,16 @@
 		return err
 	}
 
+	// A dependency only needs to support a min_sdk_version at least
+	// as high as  the api level that the architecture was introduced in.
+	// This allows introducing new architectures in the platform that
+	// need to be included in apexes that normally require an older
+	// min_sdk_version.
+	minApiForArch := minApiForArch(ctx, c.Target().Arch.ArchType)
+	if sdkVersion.LessThan(minApiForArch) {
+		sdkVersion = minApiForArch
+	}
+
 	if ver.GreaterThan(sdkVersion) {
 		return fmt.Errorf("newer SDK(%v)", ver)
 	}
@@ -3714,7 +3735,9 @@
 	prebuilt := c.IsPrebuilt()
 	switch c.typ() {
 	case binary:
-		if !prebuilt {
+		if prebuilt {
+			prebuiltBinaryBp2Build(ctx, c)
+		} else {
 			binaryBp2build(ctx, c)
 		}
 	case testBin:
@@ -3751,7 +3774,18 @@
 var _ android.ApiProvider = (*Module)(nil)
 
 func (c *Module) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
+	if c.IsPrebuilt() {
+		return
+	}
 	switch c.typ() {
+	case fullLibrary:
+		apiContributionBp2Build(ctx, c)
+	case sharedLibrary:
+		apiContributionBp2Build(ctx, c)
+	case headerLibrary:
+		// Aggressively generate api targets for all header modules
+		// This is necessary since the header module does not know if it is a dep of API surface stub library
+		apiLibraryHeadersBp2Build(ctx, c)
 	case ndkLibrary:
 		ndkLibraryBp2build(ctx, c)
 	}
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 2d316e6..9f5124b 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -58,8 +58,8 @@
 )
 
 func init() {
-	pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " "))
-	pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " "))
+	exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Cflags", linuxCrossCflags)
+	exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Ldflags", linuxCrossLdflags)
 }
 
 // toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index b53a097..981d1ea 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -222,6 +222,7 @@
 		"":               "${config.ArmGenericCflags}",
 		"cortex-a7":      "${config.ArmCortexA7Cflags}",
 		"cortex-a8":      "${config.ArmCortexA8Cflags}",
+		"cortex-a9":      "${config.ArmGenericCflags}",
 		"cortex-a15":     "${config.ArmCortexA15Cflags}",
 		"cortex-a53":     "${config.ArmCortexA53Cflags}",
 		"cortex-a53.a57": "${config.ArmCortexA53Cflags}",
diff --git a/cc/config/global.go b/cc/config/global.go
index bf80907..9f18784 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -76,9 +76,6 @@
 		// Help catch common 32/64-bit errors.
 		"-Werror=int-conversion",
 
-		// Enable the new pass manager.
-		"-fexperimental-new-pass-manager",
-
 		// Disable overly aggressive warning for macros defined with a leading underscore
 		// This happens in AndroidConfig.h, which is included nearly everywhere.
 		// TODO: can we remove this now?
@@ -91,9 +88,6 @@
 		// Warnings from clang-7.0
 		"-Wno-sign-compare",
 
-		// Warnings from clang-8.0
-		"-Wno-defaulted-function-deleted",
-
 		// Disable -Winconsistent-missing-override until we can clean up the existing
 		// codebase for it.
 		"-Wno-inconsistent-missing-override",
@@ -150,6 +144,11 @@
 		"-fdebug-info-for-profiling",
 	}
 
+	commonGlobalLldflags = []string{
+		"-fuse-ld=lld",
+		"-Wl,--icf=safe",
+	}
+
 	deviceGlobalCppflags = []string{
 		"-fvisibility-inlines-hidden",
 	}
@@ -167,13 +166,9 @@
 		"-Wl,--exclude-libs,libgcc_stripped.a",
 		"-Wl,--exclude-libs,libunwind_llvm.a",
 		"-Wl,--exclude-libs,libunwind.a",
-		"-Wl,--icf=safe",
 	}
 
-	deviceGlobalLldflags = append(deviceGlobalLdflags,
-		[]string{
-			"-fuse-ld=lld",
-		}...)
+	deviceGlobalLldflags = append(deviceGlobalLdflags, commonGlobalLldflags...)
 
 	hostGlobalCflags = []string{}
 
@@ -181,7 +176,7 @@
 
 	hostGlobalLdflags = []string{}
 
-	hostGlobalLldflags = []string{"-fuse-ld=lld"}
+	hostGlobalLldflags = commonGlobalLldflags
 
 	commonGlobalCppflags = []string{
 		"-Wsign-promo",
@@ -295,10 +290,8 @@
 	}
 
 	llvmNextExtraCommonGlobalCflags = []string{
-		// New warnings to be fixed after clang-r468909
-		"-Wno-error=array-parameter",     // http://b/241941550
-		"-Wno-error=deprecated-builtins", // http://b/241601211
-		"-Wno-error=deprecated",          // in external/googletest/googletest
+		// New warnings to be fixed after clang-r475365
+		"-Wno-error=single-bit-bitfield-constant-conversion", // http://b/243965903
 	}
 
 	IllegalFlags = []string{
@@ -312,8 +305,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r468909"
-	ClangDefaultShortVersion = "15.0.2"
+	ClangDefaultVersion      = "clang-r468909b"
+	ClangDefaultShortVersion = "15.0.3"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index d8918f1..825be7f 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -25,6 +25,7 @@
 	riscv64Cflags = []string{
 		// Help catch common 32/64-bit errors.
 		"-Werror=implicit-function-declaration",
+		"-fno-emulated-tls",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index af49e88..f32ebf2 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -58,17 +58,14 @@
 )
 
 func init() {
-	// Many clang-tidy checks like altera-*, llvm-*, modernize-*
-	// are not designed for Android source code or creating too
-	// many (false-positive) warnings. The global default tidy checks
-	// should include only tested groups and exclude known noisy checks.
+	// The global default tidy checks should include clang-tidy
+	// default checks and tested groups, but exclude known noisy checks.
 	// See https://clang.llvm.org/extra/clang-tidy/checks/list.html
-	pctx.VariableFunc("TidyDefaultGlobalChecks", func(ctx android.PackageVarContext) string {
-		if override := ctx.Config().Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
+	exportedVars.ExportVariableConfigMethod("TidyDefaultGlobalChecks", func(config android.Config) string {
+		if override := config.Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
 			return override
 		}
 		checks := strings.Join([]string{
-			"-*",
 			"android-*",
 			"bugprone-*",
 			"cert-*",
@@ -95,7 +92,7 @@
 			"-misc-non-private-member-variables-in-classes",
 			"-misc-unused-parameters",
 			"-performance-no-int-to-ptr",
-			// the following groups are excluded by -*
+			// the following groups are not in clang-tidy default checks.
 			// -altera-*
 			// -cppcoreguidelines-*
 			// -darwin-*
@@ -109,49 +106,55 @@
 			// -readability-*
 			// -zircon-*
 		}, ",")
-		// clang-analyzer-* checks are too slow to be in the default for WITH_TIDY=1.
-		// nightly builds add CLANG_ANALYZER_CHECKS=1 to run those checks.
+		// clang-analyzer-* checks are slow for large files, but we have TIDY_TIMEOUT to
+		// limit clang-tidy runtime. We allow clang-tidy default clang-analyzer-* checks,
+		// and add it explicitly when CLANG_ANALYZER_CHECKS is set.
 		// The insecureAPI.DeprecatedOrUnsafeBufferHandling warning does not apply to Android.
-		if ctx.Config().IsEnvTrue("CLANG_ANALYZER_CHECKS") {
+		if config.IsEnvTrue("CLANG_ANALYZER_CHECKS") {
 			checks += ",clang-analyzer-*,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
+		} else {
+			checks += ",-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
 		}
 		return checks
 	})
 
-	// There are too many clang-tidy warnings in external and vendor projects.
-	// Enable only some google checks for these projects.
-	pctx.VariableFunc("TidyExternalVendorChecks", func(ctx android.PackageVarContext) string {
-		if override := ctx.Config().Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
+	// The external and vendor projects do not run clang-tidy unless TIDY_EXTERNAL_VENDOR is set.
+	// We do not add "-*" to the check list to avoid suppressing the check list in .clang-tidy config files.
+	// There are too many clang-tidy warnings in external and vendor projects, so we only
+	// enable some google checks for these projects. Users can add more checks locally with the
+	// "tidy_checks" list in .bp files, or the "Checks" list in .clang-tidy config files.
+	exportedVars.ExportVariableConfigMethod("TidyExternalVendorChecks", func(config android.Config) string {
+		if override := config.Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
 			return override
 		}
 		return strings.Join([]string{
-			"-*",
 			"clang-diagnostic-unused-command-line-argument",
 			"google-build-explicit-make-pair",
 			"google-build-namespaces",
 			"google-runtime-operator",
 			"google-upgrade-*",
+			"-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling",
 		}, ",")
 	})
 
-	pctx.VariableFunc("TidyGlobalNoChecks", func(ctx android.PackageVarContext) string {
+	exportedVars.ExportVariableFuncVariable("TidyGlobalNoChecks", func() string {
 		return strings.Join(globalNoCheckList, ",")
 	})
 
-	pctx.VariableFunc("TidyGlobalNoErrorChecks", func(ctx android.PackageVarContext) string {
+	exportedVars.ExportVariableFuncVariable("TidyGlobalNoErrorChecks", func() string {
 		return strings.Join(globalNoErrorCheckList, ",")
 	})
 
 	// To reduce duplicate warnings from the same header files,
 	// header-filter will contain only the module directory and
 	// those specified by DEFAULT_TIDY_HEADER_DIRS.
-	pctx.VariableFunc("TidyDefaultHeaderDirs", func(ctx android.PackageVarContext) string {
-		return ctx.Config().Getenv("DEFAULT_TIDY_HEADER_DIRS")
+	exportedVars.ExportVariableConfigMethod("TidyDefaultHeaderDirs", func(config android.Config) string {
+		return config.Getenv("DEFAULT_TIDY_HEADER_DIRS")
 	})
 
 	// Use WTIH_TIDY_FLAGS to pass extra global default clang-tidy flags.
-	pctx.VariableFunc("TidyWithTidyFlags", func(ctx android.PackageVarContext) string {
-		return ctx.Config().Getenv("WITH_TIDY_FLAGS")
+	exportedVars.ExportVariableConfigMethod("TidyWithTidyFlags", func(config android.Config) string {
+		return config.Getenv("WITH_TIDY_FLAGS")
 	})
 }
 
@@ -202,11 +205,18 @@
 	return tidyDefault
 }
 
-func NoClangTidyForDir(dir string) bool {
+func neverTidyForDir(dir string) bool {
+	// This function can be extended if tidy needs to be disabled for more directories.
+	return strings.HasPrefix(dir, "external/grpc-grpc")
+}
+
+func NoClangTidyForDir(allowExternalVendor bool, dir string) bool {
+	// Tidy can be disable for a module in dir, if the dir is "neverTidyForDir",
+	// or if it belongs to external|vendor and !allowExternalVendor.
 	// This function depends on TidyChecksForDir, which selects tidyExternalVendor
-	// checks for external/vendor projects. For those projects we disable clang-tidy
-	// by default, unless some modules enable clang-tidy with tidy:true.
-	return TidyChecksForDir(dir) == tidyExternalVendor
+	// checks for external/vendor projects.
+	return neverTidyForDir(dir) ||
+		(!allowExternalVendor && TidyChecksForDir(dir) == tidyExternalVendor)
 }
 
 // Returns a globally disabled tidy checks, overriding locally selected checks.
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index eb71aa1..052832d 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -244,4 +244,8 @@
 	return LibclangRuntimeLibrary(t, "fuzzer")
 }
 
+func LibFuzzerRuntimeInterceptors(t Toolchain) string {
+	return LibclangRuntimeLibrary(t, "fuzzer_interceptors")
+}
+
 var inList = android.InList
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index 96a53bf..e006471 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -15,8 +15,6 @@
 package config
 
 import (
-	"strings"
-
 	"android/soong/android"
 )
 
@@ -71,14 +69,13 @@
 )
 
 func init() {
-
-	pctx.StaticVariable("LinuxBionicCflags", strings.Join(linuxBionicCflags, " "))
-	pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " "))
-	pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLdflags, " "))
+	exportedVars.ExportStringListStaticVariable("LinuxBionicCflags", linuxBionicCflags)
+	exportedVars.ExportStringListStaticVariable("LinuxBionicLdflags", linuxBionicLdflags)
+	exportedVars.ExportStringListStaticVariable("LinuxBionicLldflags", linuxBionicLdflags)
 
 	// Use the device gcc toolchain for now
-	pctx.StaticVariable("LinuxBionicGccVersion", x86_64GccVersion)
-	pctx.SourcePathVariable("LinuxBionicGccRoot",
+	exportedVars.ExportStringStaticVariable("LinuxBionicGccVersion", x86_64GccVersion)
+	exportedVars.ExportSourcePathVariable("LinuxBionicGccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${LinuxBionicGccVersion}")
 }
 
diff --git a/cc/coverage.go b/cc/coverage.go
index d0902ea..a7356f8 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -108,6 +108,12 @@
 			if EnableContinuousCoverage(ctx) {
 				flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-runtime-counter-relocation")
 			}
+
+			// http://b/248022906, http://b/247941801  enabling coverage and hwasan-globals
+			// instrumentation together causes duplicate-symbol errors for __llvm_profile_filename.
+			if c, ok := ctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(Hwasan) {
+				flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-hwasan-globals=0")
+			}
 		}
 	}
 
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 13c94ad..64bb7dd 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -126,6 +126,14 @@
 		deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers")
 	} else {
 		deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
+		// Fuzzers built with HWASAN should use the interceptors for better
+		// mutation based on signals in strcmp, memcpy, etc. This is only needed for
+		// fuzz targets, not generic HWASAN-ified binaries or libraries.
+		if module, ok := ctx.Module().(*Module); ok {
+			if module.IsSanitizerEnabled(Hwasan) {
+				deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeInterceptors(ctx.toolchain()))
+			}
+		}
 	}
 
 	deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
@@ -137,9 +145,18 @@
 	// RunPaths on devices isn't instantiated by the base linker. `../lib` for
 	// installed fuzz targets (both host and device), and `./lib` for fuzz
 	// target packages.
-	flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
 	flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
 
+	// When running on device, fuzz targets with vendor: true set will be in
+	// fuzzer_name/vendor/fuzzer_name (note the extra 'vendor' and thus need to
+	// link with libraries in ../../lib/. Non-vendor binaries only need to look
+	// one level up, in ../lib/.
+	if ctx.inVendor() {
+		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../lib`)
+	} else {
+		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
+	}
+
 	return flags
 }
 
@@ -264,7 +281,7 @@
 	}
 
 	// Grab the list of required shared libraries.
-	fuzzBin.sharedLibraries = CollectAllSharedDependencies(ctx)
+	fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx)
 
 	for _, lib := range fuzzBin.sharedLibraries {
 		fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
@@ -478,9 +495,10 @@
 // VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer
 // runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies
 // have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
-func CollectAllSharedDependencies(ctx android.ModuleContext) android.Paths {
+func CollectAllSharedDependencies(ctx android.ModuleContext) (android.Paths, []android.Module) {
 	seen := make(map[string]bool)
 	recursed := make(map[string]bool)
+	deps := []android.Module{}
 
 	var sharedLibraries android.Paths
 
@@ -494,6 +512,7 @@
 			return
 		}
 		seen[ctx.OtherModuleName(dep)] = true
+		deps = append(deps, dep)
 		sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, dep, "unstripped"))
 	})
 
@@ -503,6 +522,7 @@
 		}
 		if !seen[ctx.OtherModuleName(child)] {
 			seen[ctx.OtherModuleName(child)] = true
+			deps = append(deps, child)
 			sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, child, "unstripped"))
 		}
 
@@ -513,5 +533,5 @@
 		return true
 	})
 
-	return sharedLibraries
+	return sharedLibraries, deps
 }
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index f25f704..0d16e62 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -40,14 +40,13 @@
 					name: "gen",
 					tool_files: ["tool"],
 					cmd: "$(location tool) $(in) $(out)",
+					out: ["out_arm"],
 					arch: {
 						arm: {
 							srcs: ["foo"],
-							out: ["out_arm"],
 						},
 						arm64: {
 							srcs: ["bar"],
-							out: ["out_arm64"],
 						},
 					},
 				}
@@ -70,7 +69,7 @@
 		t.Errorf(`want arm inputs %v, got %v`, expected, gen.Implicits.Strings())
 	}
 
-	gen = ctx.ModuleForTests("gen", "android_arm64_armv8-a").Output("out_arm64")
+	gen = ctx.ModuleForTests("gen", "android_arm64_armv8-a").Output("out_arm")
 	expected = []string{"bar"}
 	if !reflect.DeepEqual(expected, gen.Implicits.Strings()[:len(expected)]) {
 		t.Errorf(`want arm64 inputs %v, got %v`, expected, gen.Implicits.Strings())
diff --git a/cc/library.go b/cc/library.go
index 13a7a3e..897f3c7 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -30,6 +30,7 @@
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
+	"github.com/google/blueprint/proptools"
 )
 
 // LibraryProperties is a collection of properties shared by cc library rules/cc.
@@ -288,6 +289,16 @@
 	None                         bazel.BoolAttribute
 }
 
+func stripAttrsFromLinkerAttrs(la *linkerAttributes) stripAttributes {
+	return stripAttributes{
+		Keep_symbols:                 la.stripKeepSymbols,
+		Keep_symbols_and_debug_frame: la.stripKeepSymbolsAndDebugFrame,
+		Keep_symbols_list:            la.stripKeepSymbolsList,
+		All:                          la.stripAll,
+		None:                         la.stripNone,
+	}
+}
+
 func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
 	// For some cc_library modules, their static variants are ready to be
 	// converted, but not their shared variants. For these modules, delegate to
@@ -394,13 +405,7 @@
 
 		Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
 
-		Strip: stripAttributes{
-			Keep_symbols:                 linkerAttrs.stripKeepSymbols,
-			Keep_symbols_and_debug_frame: linkerAttrs.stripKeepSymbolsAndDebugFrame,
-			Keep_symbols_list:            linkerAttrs.stripKeepSymbolsList,
-			All:                          linkerAttrs.stripAll,
-			None:                         linkerAttrs.stripNone,
-		},
+		Strip:    stripAttrsFromLinkerAttrs(&linkerAttrs),
 		Features: baseAttributes.features,
 	}
 
@@ -466,6 +471,147 @@
 	}
 }
 
+func apiContributionBp2Build(ctx android.TopDownMutatorContext, module *Module) {
+	apiSurfaces := make([]string, 0)
+	apiHeaders := make([]string, 0)
+	// systemapi (non-null `stubs` property)
+	if module.HasStubsVariants() {
+		apiSurfaces = append(apiSurfaces, android.SystemApi.String())
+		apiIncludes := getSystemApiIncludes(ctx, module)
+		if !apiIncludes.isEmpty() {
+			createApiHeaderTarget(ctx, apiIncludes)
+			apiHeaders = append(apiHeaders, apiIncludes.name)
+		}
+	}
+	// vendorapi (non-null `llndk` property)
+	if module.HasLlndkStubs() {
+		apiSurfaces = append(apiSurfaces, android.VendorApi.String())
+		apiIncludes := getVendorApiIncludes(ctx, module)
+		if !apiIncludes.isEmpty() {
+			createApiHeaderTarget(ctx, apiIncludes)
+			apiHeaders = append(apiHeaders, apiIncludes.name)
+		}
+	}
+	// create a target only if this module contributes to an api surface
+	// TODO: Currently this does not distinguish systemapi-only headers and vendrorapi-only headers
+	// TODO: Update so that systemapi-only headers do not get exported to vendorapi (and vice-versa)
+	if len(apiSurfaces) > 0 {
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class:        "cc_api_contribution",
+			Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
+		}
+		attrs := &bazelCcApiContributionAttributes{
+			Library_name: module.Name(),
+			Api_surfaces: bazel.MakeStringListAttribute(apiSurfaces),
+			Api:          apiLabelAttribute(ctx, module),
+			Hdrs: bazel.MakeLabelListAttribute(
+				bazel.MakeLabelListFromTargetNames(apiHeaders),
+			),
+		}
+		ctx.CreateBazelTargetModule(
+			props,
+			android.CommonAttributes{
+				Name:     android.ApiContributionTargetName(module.Name()),
+				SkipData: proptools.BoolPtr(true),
+			},
+			attrs,
+		)
+	}
+}
+
+// Native apis are versioned in a single .map.txt for all api surfaces
+// Pick any one of the .map.txt files
+func apiLabelAttribute(ctx android.TopDownMutatorContext, module *Module) bazel.LabelAttribute {
+	var apiFile *string
+	linker := module.linker.(*libraryDecorator)
+	if llndkApi := linker.Properties.Llndk.Symbol_file; llndkApi != nil {
+		apiFile = llndkApi
+	} else if systemApi := linker.Properties.Stubs.Symbol_file; systemApi != nil {
+		apiFile = systemApi
+	} else {
+		ctx.ModuleErrorf("API surface library does not have any API file")
+	}
+	apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label
+	return *bazel.MakeLabelAttribute(apiLabel)
+}
+
+// wrapper struct to flatten the arch and os specific export_include_dirs
+// flattening is necessary since we want to export apis of all arches even when we build for x86 (e.g.)
+type bazelCcApiLibraryHeadersAttributes struct {
+	bazelCcLibraryHeadersAttributes
+
+	Arch *string
+}
+
+func (a *bazelCcApiLibraryHeadersAttributes) isEmpty() bool {
+	return a.Export_includes.IsEmpty() &&
+		a.Export_system_includes.IsEmpty() &&
+		a.Deps.IsEmpty()
+}
+
+type apiIncludes struct {
+	name  string // name of the Bazel target in the generated bp2build workspace
+	attrs bazelCcApiLibraryHeadersAttributes
+}
+
+func (includes *apiIncludes) isEmpty() bool {
+	return includes.attrs.isEmpty()
+}
+
+func (includes *apiIncludes) addDep(name string) {
+	l := bazel.Label{Label: ":" + name}
+	ll := bazel.MakeLabelList([]bazel.Label{l})
+	lla := bazel.MakeLabelListAttribute(ll)
+	includes.attrs.Deps.Append(lla)
+}
+
+func getSystemApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
+	flagProps := c.library.(*libraryDecorator).flagExporter.Properties
+	linkProps := c.library.(*libraryDecorator).baseLinker.Properties
+	includes := android.FirstUniqueStrings(flagProps.Export_include_dirs)
+	systemIncludes := android.FirstUniqueStrings(flagProps.Export_system_include_dirs)
+	headerLibs := android.FirstUniqueStrings(linkProps.Export_header_lib_headers)
+	attrs := bazelCcLibraryHeadersAttributes{
+		Export_includes:        bazel.MakeStringListAttribute(includes),
+		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
+		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, headerLibs)),
+	}
+
+	return apiIncludes{
+		name: c.Name() + ".systemapi.headers",
+		attrs: bazelCcApiLibraryHeadersAttributes{
+			bazelCcLibraryHeadersAttributes: attrs,
+		},
+	}
+}
+
+func getVendorApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
+	baseProps := c.library.(*libraryDecorator).flagExporter.Properties
+	llndkProps := c.library.(*libraryDecorator).Properties.Llndk
+	includes := baseProps.Export_include_dirs
+	systemIncludes := baseProps.Export_system_include_dirs
+	// LLNDK can override the base includes
+	if llndkIncludes := llndkProps.Override_export_include_dirs; llndkIncludes != nil {
+		includes = llndkIncludes
+	}
+	if proptools.Bool(llndkProps.Export_headers_as_system) {
+		systemIncludes = append(systemIncludes, includes...)
+		includes = nil
+	}
+
+	attrs := bazelCcLibraryHeadersAttributes{
+		Export_includes:        bazel.MakeStringListAttribute(includes),
+		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
+		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, llndkProps.Export_llndk_headers)),
+	}
+	return apiIncludes{
+		name: c.Name() + ".vendorapi.headers",
+		attrs: bazelCcApiLibraryHeadersAttributes{
+			bazelCcLibraryHeadersAttributes: attrs,
+		},
+	}
+}
+
 // cc_library creates both static and/or shared libraries for a device and/or
 // host. By default, a cc_library has a single variant that targets the device.
 // Specifying `host_supported: true` also creates a library that targets the
@@ -739,7 +885,7 @@
 	outputFilePath := android.PathForBazelOut(ctx, rootDynamicLibraries[0])
 	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
 
-	handler.module.linker.(*libraryDecorator).unstrippedOutputFile = outputFilePath
+	handler.module.linker.(*libraryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, ccInfo.UnstrippedOutput)
 
 	var tocFile android.OptionalPath
 	if len(ccInfo.TocFile) > 0 {
@@ -810,7 +956,7 @@
 	for _, path := range paths {
 		dir := path.String()
 		// Skip if dir is for generated headers
-		if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
+		if strings.HasPrefix(dir, ctx.Config().OutDir()) {
 			continue
 		}
 
@@ -1764,26 +1910,28 @@
 
 		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
 
+		isNdk := ctx.isNdk(ctx.Config())
+		isLlndk := ctx.isImplementationForLLNDKPublic()
 		// If NDK or PLATFORM library, check against previous version ABI.
 		if !ctx.useVndk() {
 			prevRefAbiDumpFile := getRefAbiDumpFile(ctx, strconv.Itoa(prevVersion), fileName)
 			if prevRefAbiDumpFile != nil {
 				library.prevSAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
-					prevRefAbiDumpFile, fileName, exportedHeaderFlags,
+					prevRefAbiDumpFile, fileName,
 					library.Properties.Header_abi_checker.Diff_flags, prevVersion,
 					Bool(library.Properties.Header_abi_checker.Check_all_apis),
-					ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt(), true)
+					isLlndk || isNdk, ctx.IsVndkExt(), true)
 			}
 		}
 
 		refAbiDumpFile := getRefAbiDumpFile(ctx, version, fileName)
 		if refAbiDumpFile != nil {
 			library.sAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
-				refAbiDumpFile, fileName, exportedHeaderFlags,
+				refAbiDumpFile, fileName,
 				library.Properties.Header_abi_checker.Diff_flags,
 				/* unused if not previousVersionDiff */ 0,
 				Bool(library.Properties.Header_abi_checker.Check_all_apis),
-				ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt(), false)
+				isLlndk || isNdk, ctx.IsVndkExt(), false)
 		}
 	}
 }
@@ -2451,11 +2599,12 @@
 	m := mctx.Module().(*Module)
 	isLLNDK := m.IsLlndk()
 	isVendorPublicLibrary := m.IsVendorPublicLibrary()
+	isImportedApiLibrary := m.isImportedApiLibrary()
 
 	modules := mctx.CreateLocalVariations(variants...)
 	for i, m := range modules {
 
-		if variants[i] != "" || isLLNDK || isVendorPublicLibrary {
+		if variants[i] != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary {
 			// A stubs or LLNDK stubs variant.
 			c := m.(*Module)
 			c.sanitize = nil
@@ -2645,6 +2794,8 @@
 		Runtime_deps:                      linkerAttrs.runtimeDeps,
 	}
 
+	module.convertTidyAttributes(ctx, &commonAttrs.tidyAttributes)
+
 	var attrs interface{}
 	if isStatic {
 		commonAttrs.Deps.Add(baseAttributes.protoDependency)
@@ -2697,13 +2848,7 @@
 			Absolute_includes:        compilerAttrs.absoluteIncludes,
 			Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
 
-			Strip: stripAttributes{
-				Keep_symbols:                 linkerAttrs.stripKeepSymbols,
-				Keep_symbols_and_debug_frame: linkerAttrs.stripKeepSymbolsAndDebugFrame,
-				Keep_symbols_list:            linkerAttrs.stripKeepSymbolsList,
-				All:                          linkerAttrs.stripAll,
-				None:                         linkerAttrs.stripNone,
-			},
+			Strip: stripAttrsFromLinkerAttrs(&linkerAttrs),
 
 			Features: baseAttributes.features,
 
diff --git a/cc/library_headers.go b/cc/library_headers.go
index a683f58..1c4f354 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -15,6 +15,8 @@
 package cc
 
 import (
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
@@ -145,3 +147,118 @@
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
 }
+
+// Append .contribution suffix to input labels
+func apiBazelTargets(ll bazel.LabelList) bazel.LabelList {
+	labels := make([]bazel.Label, 0)
+	for _, l := range ll.Includes {
+		labels = append(labels, bazel.Label{
+			Label: android.ApiContributionTargetName(l.Label),
+		})
+	}
+	return bazel.MakeLabelList(labels)
+}
+
+func apiLibraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) {
+	// cc_api_library_headers have a 1:1 mapping to arch/no-arch
+	// For API export, create a top-level arch-agnostic target and list the arch-specific targets as its deps
+
+	// arch-agnostic includes
+	apiIncludes := getSystemApiIncludes(ctx, module)
+	// arch and os specific includes
+	archApiIncludes, androidOsIncludes := archOsSpecificApiIncludes(ctx, module)
+	for _, arch := range allArches { // sorted iteration
+		archApiInclude := archApiIncludes[arch]
+		if !archApiInclude.isEmpty() {
+			createApiHeaderTarget(ctx, archApiInclude)
+			apiIncludes.addDep(archApiInclude.name)
+		}
+	}
+	// os==android includes
+	if !androidOsIncludes.isEmpty() {
+		createApiHeaderTarget(ctx, androidOsIncludes)
+		apiIncludes.addDep(androidOsIncludes.name)
+	}
+
+	if !apiIncludes.isEmpty() {
+		// override the name from <mod>.systemapi.headers --> <mod>.contribution
+		apiIncludes.name = android.ApiContributionTargetName(module.Name())
+		createApiHeaderTarget(ctx, apiIncludes)
+	}
+}
+
+func createApiHeaderTarget(ctx android.TopDownMutatorContext, includes apiIncludes) {
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_api_library_headers",
+		Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
+	}
+	ctx.CreateBazelTargetModule(
+		props,
+		android.CommonAttributes{
+			Name:     includes.name,
+			SkipData: proptools.BoolPtr(true),
+		},
+		&includes.attrs,
+	)
+}
+
+var (
+	allArches = []string{"arm", "arm64", "x86", "x86_64"}
+)
+
+type archApiIncludes map[string]apiIncludes
+
+func archOsSpecificApiIncludes(ctx android.TopDownMutatorContext, module *Module) (archApiIncludes, apiIncludes) {
+	baseProps := bp2BuildParseBaseProps(ctx, module)
+	i := bp2BuildParseExportedIncludes(ctx, module, &baseProps.includes)
+	archRet := archApiIncludes{}
+	for _, arch := range allArches {
+		includes := i.Includes.SelectValue(
+			bazel.ArchConfigurationAxis,
+			arch)
+		systemIncludes := i.SystemIncludes.SelectValue(
+			bazel.ArchConfigurationAxis,
+			arch)
+		deps := baseProps.deps.SelectValue(
+			bazel.ArchConfigurationAxis,
+			arch)
+		attrs := bazelCcLibraryHeadersAttributes{
+			Export_includes:        bazel.MakeStringListAttribute(includes),
+			Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
+		}
+		apiDeps := apiBazelTargets(deps)
+		if !apiDeps.IsEmpty() {
+			attrs.Deps = bazel.MakeLabelListAttribute(apiDeps)
+		}
+		apiIncludes := apiIncludes{
+			name: android.ApiContributionTargetName(module.Name()) + "." + arch,
+			attrs: bazelCcApiLibraryHeadersAttributes{
+				bazelCcLibraryHeadersAttributes: attrs,
+				Arch:                            proptools.StringPtr(arch),
+			},
+		}
+		archRet[arch] = apiIncludes
+	}
+
+	// apiIncludes for os == Android
+	androidOsDeps := baseProps.deps.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid)
+	androidOsAttrs := bazelCcLibraryHeadersAttributes{
+		Export_includes: bazel.MakeStringListAttribute(
+			i.Includes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
+		),
+		Export_system_includes: bazel.MakeStringListAttribute(
+			i.SystemIncludes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
+		),
+	}
+	androidOsApiDeps := apiBazelTargets(androidOsDeps)
+	if !androidOsApiDeps.IsEmpty() {
+		androidOsAttrs.Deps = bazel.MakeLabelListAttribute(androidOsApiDeps)
+	}
+	osRet := apiIncludes{
+		name: android.ApiContributionTargetName(module.Name()) + ".androidos",
+		attrs: bazelCcApiLibraryHeadersAttributes{
+			bazelCcLibraryHeadersAttributes: androidOsAttrs,
+		},
+	}
+	return archRet, osRet
+}
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 2ebb6ef..2fb21a3 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -15,6 +15,10 @@
 package cc
 
 import (
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/multitree"
 )
@@ -26,10 +30,30 @@
 func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
 	ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory)
+	ctx.RegisterModuleType("cc_api_variant", CcApiVariantFactory)
+}
 
-	// cc_api_stub_library shares a lot of ndk_library, and this will be refactored later
-	ctx.RegisterModuleType("cc_api_stub_library", CcApiStubLibraryFactory)
-	ctx.RegisterModuleType("cc_api_contribution", CcApiContributionFactory)
+func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) {
+	m, ok := ctx.Module().(*Module)
+	if !ok {
+		return
+	}
+
+	apiLibrary, ok := m.linker.(*apiLibraryDecorator)
+	if !ok {
+		return
+	}
+
+	if m.UseVndk() && apiLibrary.hasLLNDKStubs() {
+		// Add LLNDK dependencies
+		for _, variant := range apiLibrary.properties.Variants {
+			if variant == "llndk" {
+				variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+				ctx.AddDependency(m, nil, variantName)
+				break
+			}
+		}
+	}
 }
 
 // 'cc_api_library' is a module type which is from the exported API surface
@@ -37,7 +61,8 @@
 // offer a link to the module that generates shared library object from the
 // map file.
 type apiLibraryProperties struct {
-	Src *string `android:"arch_variant"`
+	Src      *string `android:"arch_variant"`
+	Variants []string
 }
 
 type apiLibraryDecorator struct {
@@ -59,11 +84,9 @@
 	module.compiler = nil
 	module.linker = apiLibraryDecorator
 	module.installer = nil
+	module.library = apiLibraryDecorator
 	module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
 
-	// Mark module as stub, so APEX would not include this stub in the package.
-	module.library.setBuildStubs(true)
-
 	// Prevent default system libs (libc, libm, and libdl) from being linked
 	if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
 		apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
@@ -81,25 +104,79 @@
 	return basename + multitree.GetApiImportSuffix()
 }
 
+// Export include dirs without checking for existence.
+// The directories are not guaranteed to exist during Soong analysis.
+func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) {
+	exporterProps := d.flagExporter.Properties
+	for _, dir := range exporterProps.Export_include_dirs {
+		d.dirs = append(d.dirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir))
+	}
+	// system headers
+	for _, dir := range exporterProps.Export_system_include_dirs {
+		d.systemDirs = append(d.systemDirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir))
+	}
+}
+
 func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
-	// Export headers as system include dirs if specified. Mostly for libc
-	if Bool(d.libraryDecorator.Properties.Llndk.Export_headers_as_system) {
-		d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
-			d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
-			d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
-		d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
+	m, _ := ctx.Module().(*Module)
+
+	var in android.Path
+
+	if src := proptools.String(d.properties.Src); src != "" {
+		in = android.PathForModuleSrc(ctx, src)
+	}
+
+	// LLNDK variant
+	if m.UseVndk() && d.hasLLNDKStubs() {
+		apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+
+		var mod android.Module
+
+		ctx.VisitDirectDeps(func(depMod android.Module) {
+			if depMod.Name() == apiVariantModule {
+				mod = depMod
+			}
+		})
+
+		if mod != nil {
+			variantMod, ok := mod.(*CcApiVariant)
+			if ok {
+				in = variantMod.Src()
+
+				// Copy LLDNK properties to cc_api_library module
+				d.libraryDecorator.flagExporter.Properties.Export_include_dirs = append(
+					d.libraryDecorator.flagExporter.Properties.Export_include_dirs,
+					variantMod.exportProperties.Export_headers...)
+
+				// Export headers as system include dirs if specified. Mostly for libc
+				if proptools.Bool(variantMod.exportProperties.Export_headers_as_system) {
+					d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
+						d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
+						d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
+					d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
+				}
+			}
+		}
 	}
 
 	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
-	d.libraryDecorator.flagExporter.exportIncludes(ctx)
+	d.exportIncludes(ctx)
 	d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
 	d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
 	d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
 	d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
 	d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
-	d.libraryDecorator.flagExporter.setProvider(ctx)
 
-	in := android.PathForModuleSrc(ctx, *d.properties.Src)
+	if in == nil {
+		ctx.PropertyErrorf("src", "Unable to locate source property")
+		return nil
+	}
+
+	// Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file)
+	// The .so file itself has an order-only dependency on the headers contributed by this library.
+	// Creating this dependency ensures that the headers are assembled before compilation of rdeps begins.
+	d.libraryDecorator.reexportDeps(in)
+	d.libraryDecorator.flagExporter.setProvider(ctx)
 
 	d.unstrippedOutputFile = in
 	libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
@@ -123,6 +200,43 @@
 	return true
 }
 
+func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+	m, ok := ctx.Module().(*Module)
+
+	if !ok {
+		return nil
+	}
+
+	if d.hasLLNDKStubs() && m.UseVndk() {
+		// LLNDK libraries only need a single stubs variant.
+		return []string{android.FutureApiLevel.String()}
+	}
+
+	// TODO(b/244244438) Create more version information for NDK and APEX variations
+	// NDK variants
+	if m.MinSdkVersion() == "" {
+		return nil
+	}
+
+	firstVersion, err := nativeApiLevelFromUser(ctx,
+		m.MinSdkVersion())
+
+	if err != nil {
+		return nil
+	}
+
+	return ndkLibraryVersions(ctx, firstVersion)
+}
+
+func (d *apiLibraryDecorator) hasLLNDKStubs() bool {
+	for _, variant := range d.properties.Variants {
+		if strings.Contains(variant, "llndk") {
+			return true
+		}
+	}
+	return false
+}
+
 // 'cc_api_headers' is similar with 'cc_api_library', but which replaces
 // header libraries. The module will replace any dependencies to existing
 // original header libraries.
@@ -145,9 +259,6 @@
 	module.linker = apiHeadersDecorator
 	module.installer = nil
 
-	// Mark module as stub, so APEX would not include this stub in the package.
-	module.library.setBuildStubs(true)
-
 	// Prevent default system libs (libc, libm, and libdl) from being linked
 	if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil {
 		apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{}
@@ -170,135 +281,90 @@
 	return true
 }
 
-func CcApiStubLibraryFactory() android.Module {
-	module, decorator := NewLibrary(android.DeviceSupported)
-	apiStubDecorator := &apiStubDecorator{
-		libraryDecorator: decorator,
-	}
-	apiStubDecorator.BuildOnlyShared()
+type ccApiexportProperties struct {
+	Src     *string `android:"arch_variant"`
+	Variant *string
+	Version *string
+}
 
-	module.compiler = apiStubDecorator
-	module.linker = apiStubDecorator
-	module.installer = nil
-	module.library = apiStubDecorator
-	module.Properties.HideFromMake = true // TODO: remove
+type variantExporterProperties struct {
+	// Header directory or library to export
+	Export_headers []string
+
+	// Export all headers as system include
+	Export_headers_as_system *bool
+}
+
+type CcApiVariant struct {
+	android.ModuleBase
+
+	properties       ccApiexportProperties
+	exportProperties variantExporterProperties
+
+	src android.Path
+}
+
+var _ android.Module = (*CcApiVariant)(nil)
+var _ android.ImageInterface = (*CcApiVariant)(nil)
+
+func CcApiVariantFactory() android.Module {
+	module := &CcApiVariant{}
+
+	module.AddProperties(&module.properties)
+	module.AddProperties(&module.exportProperties)
 
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
-	module.AddProperties(&module.Properties,
-		&apiStubDecorator.properties,
-		&apiStubDecorator.MutatedProperties,
-		&apiStubDecorator.apiStubLibraryProperties)
 	return module
 }
 
-type apiStubLiraryProperties struct {
-	Imported_includes []string `android:"path"`
-}
+func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// No need to build
 
-type apiStubDecorator struct {
-	*libraryDecorator
-	properties               libraryProperties
-	apiStubLibraryProperties apiStubLiraryProperties
-}
-
-func (compiler *apiStubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
-	firstVersion := String(compiler.properties.First_version)
-	return ndkLibraryVersions(ctx, android.ApiLevelOrPanic(ctx, firstVersion))
-}
-
-func (decorator *apiStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
-	if decorator.stubsVersion() == "" {
-		decorator.setStubsVersion("current")
-	} // TODO: fix
-	symbolFile := String(decorator.properties.Symbol_file)
-	nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
-		android.ApiLevelOrPanic(ctx, decorator.stubsVersion()),
-		"")
-	return compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
-}
-
-func (decorator *apiStubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
-	decorator.reexportDirs(android.PathsForModuleSrc(ctx, decorator.apiStubLibraryProperties.Imported_includes)...)
-	return decorator.libraryDecorator.link(ctx, flags, deps, objects)
-}
-
-func init() {
-	pctx.HostBinToolVariable("gen_api_surface_build_files", "gen_api_surface_build_files")
-}
-
-type CcApiContribution struct {
-	android.ModuleBase
-	properties ccApiContributionProperties
-}
-
-type ccApiContributionProperties struct {
-	Symbol_file        *string `android:"path"`
-	First_version      *string
-	Export_include_dir *string
-}
-
-func CcApiContributionFactory() android.Module {
-	module := &CcApiContribution{}
-	module.AddProperties(&module.properties)
-	android.InitAndroidModule(module)
-	return module
-}
-
-// Do some simple validations
-// Majority of the build rules will be created in the ctx of the api surface this module contributes to
-func (contrib *CcApiContribution) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if contrib.properties.Symbol_file == nil {
-		ctx.PropertyErrorf("symbol_file", "%v does not have symbol file", ctx.ModuleName())
+	if proptools.String(v.properties.Src) == "" {
+		ctx.PropertyErrorf("src", "src is a required property")
 	}
-	if contrib.properties.First_version == nil {
-		ctx.PropertyErrorf("first_version", "%v does not have first_version for stub variants", ctx.ModuleName())
+
+	// Skip the existence check of the stub prebuilt file.
+	// The file is not guaranteed to exist during Soong analysis.
+	// Build orchestrator will be responsible for creating a connected ninja graph.
+	v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), proptools.String(v.properties.Src))
+}
+
+func (v *CcApiVariant) Name() string {
+	version := proptools.String(v.properties.Version)
+	return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version)
+}
+
+func (v *CcApiVariant) Src() android.Path {
+	return v.src
+}
+
+func BuildApiVariantName(baseName string, variant string, version string) string {
+	names := []string{baseName, variant}
+	if version != "" {
+		names = append(names, version)
 	}
+
+	return strings.Join(names[:], ".") + multitree.GetApiImportSuffix()
 }
 
-// Path is out/soong/.export/ but will be different in final multi-tree layout
-func outPathApiSurface(ctx android.ModuleContext, myModuleName string, pathComponent string) android.OutputPath {
-	return android.PathForOutput(ctx, ".export", ctx.ModuleName(), myModuleName, pathComponent)
-}
+// Implement ImageInterface to generate image variants
+func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext)               {}
+func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool          { return false }
+func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool       { return false }
+func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
+func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool  { return false }
+func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool      { return false }
+func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+	var variations []string
+	platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
 
-func (contrib *CcApiContribution) CopyFilesWithTag(apiSurfaceContext android.ModuleContext) map[string]android.Paths {
-	// copy map.txt for now
-	// hardlinks cannot be created since nsjail creates a different mountpoint for out/
-	myDir := apiSurfaceContext.OtherModuleDir(contrib)
-	genMapTxt := outPathApiSurface(apiSurfaceContext, contrib.Name(), String(contrib.properties.Symbol_file))
-	apiSurfaceContext.Build(pctx, android.BuildParams{
-		Rule:        android.Cp,
-		Description: "import map.txt file",
-		Input:       android.PathForSource(apiSurfaceContext, myDir, String(contrib.properties.Symbol_file)),
-		Output:      genMapTxt,
-	})
-
-	outputs := make(map[string]android.Paths)
-	outputs["map"] = []android.Path{genMapTxt}
-
-	if contrib.properties.Export_include_dir != nil {
-		includeDir := android.PathForSource(apiSurfaceContext, myDir, String(contrib.properties.Export_include_dir))
-		outputs["export_include_dir"] = []android.Path{includeDir}
+	if proptools.String(v.properties.Variant) == "llndk" {
+		variations = append(variations, VendorVariationPrefix+platformVndkVersion)
+		variations = append(variations, ProductVariationPrefix+platformVndkVersion)
 	}
-	return outputs
+
+	return variations
 }
-
-var _ multitree.ApiContribution = (*CcApiContribution)(nil)
-
-/*
-func (contrib *CcApiContribution) GenerateBuildFiles(apiSurfaceContext android.ModuleContext) android.Paths {
-	genAndroidBp := outPathApiSurface(apiSurfaceContext, contrib.Name(), "Android.bp")
-
-	// generate Android.bp
-	apiSurfaceContext.Build(pctx, android.BuildParams{
-		Rule:        genApiSurfaceBuildFiles,
-		Description: "generate API surface build files",
-		Outputs:     []android.WritablePath{genAndroidBp},
-		Args: map[string]string{
-			"name":          contrib.Name() + "." + apiSurfaceContext.ModuleName(), //e.g. liblog.ndk
-			"symbol_file":   String(contrib.properties.Symbol_file),
-			"first_version": String(contrib.properties.First_version),
-		},
-	})
-	return []android.Path{genAndroidBp}
+func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
 }
-*/
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index cd06172..8ce74c4 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -21,94 +21,10 @@
 	"testing"
 
 	"android/soong/android"
-	"android/soong/multitree"
 
 	"github.com/google/blueprint"
 )
 
-func TestCcApiStubLibraryOutputFiles(t *testing.T) {
-	bp := `
-		cc_api_stub_library {
-			name: "foo",
-			symbol_file: "foo.map.txt",
-			first_version: "29",
-		}
-	`
-	result := prepareForCcTest.RunTestWithBp(t, bp)
-	outputs := result.ModuleForTests("foo", "android_arm64_armv8-a_shared").AllOutputs()
-	expected_file_suffixes := []string{".c", "stub.map", ".o", ".so"}
-	for _, expected_file_suffix := range expected_file_suffixes {
-		android.AssertBoolEquals(t, expected_file_suffix+" file not found in output", true, android.SuffixInList(outputs, expected_file_suffix))
-	}
-}
-
-func TestCcApiStubLibraryVariants(t *testing.T) {
-	bp := `
-		cc_api_stub_library {
-			name: "foo",
-			symbol_file: "foo.map.txt",
-			first_version: "29",
-		}
-	`
-	result := prepareForCcTest.RunTestWithBp(t, bp)
-	variants := result.ModuleVariantsForTests("foo")
-	expected_variants := []string{"29", "30", "S", "Tiramisu"} //TODO: make this test deterministic by using fixtures
-	for _, expected_variant := range expected_variants {
-		android.AssertBoolEquals(t, expected_variant+" variant not found in foo", true, android.SubstringInList(variants, expected_variant))
-	}
-}
-
-func TestCcLibraryUsesCcApiStubLibrary(t *testing.T) {
-	bp := `
-		cc_api_stub_library {
-			name: "foo",
-			symbol_file: "foo.map.txt",
-			first_version: "29",
-		}
-		cc_library {
-			name: "foo_user",
-			shared_libs: [
-				"foo#29",
-			],
-		}
-
-	`
-	prepareForCcTest.RunTestWithBp(t, bp)
-}
-
-func TestApiSurfaceOutputs(t *testing.T) {
-	bp := `
-		api_surface {
-			name: "mysdk",
-			contributions: [
-				"foo",
-			],
-		}
-
-		cc_api_contribution {
-			name: "foo",
-			symbol_file: "foo.map.txt",
-			first_version: "29",
-		}
-	`
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-		multitree.PrepareForTestWithApiSurface,
-	).RunTestWithBp(t, bp)
-	mysdk := result.ModuleForTests("mysdk", "")
-
-	actual_surface_inputs := mysdk.Rule("phony").BuildParams.Inputs.Strings()
-	expected_file_suffixes := []string{"mysdk/foo/foo.map.txt"}
-	for _, expected_file_suffix := range expected_file_suffixes {
-		android.AssertBoolEquals(t, expected_file_suffix+" file not found in input", true, android.SuffixInList(actual_surface_inputs, expected_file_suffix))
-	}
-
-	// check args/inputs to rule
-	/*api_surface_gen_rule_args := result.ModuleForTests("mysdk", "").Rule("genApiSurfaceBuildFiles").Args
-	android.AssertStringEquals(t, "name", "foo.mysdk", api_surface_gen_rule_args["name"])
-	android.AssertStringEquals(t, "symbol_file", "foo.map.txt", api_surface_gen_rule_args["symbol_file"])*/
-}
-
 func hasDirectDependency(t *testing.T, ctx *android.TestResult, from android.Module, to android.Module) bool {
 	t.Helper()
 	var found bool
@@ -325,3 +241,97 @@
 	android.AssertBoolEquals(t, "original header should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeader))
 	android.AssertBoolEquals(t, "Header from API surface should not be used for original library", false, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport))
 }
+
+func TestExportDirFromStubLibrary(t *testing.T) {
+	bp := `
+		cc_library {
+			name: "libfoo",
+			export_include_dirs: ["source_include_dir"],
+			export_system_include_dirs: ["source_system_include_dir"],
+			vendor_available: true,
+		}
+		cc_api_library {
+			name: "libfoo",
+			export_include_dirs: ["stub_include_dir"],
+			export_system_include_dirs: ["stub_system_include_dir"],
+			vendor_available: true,
+			src: "libfoo.so",
+		}
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libfoo",
+			],
+			header_libs: [],
+		}
+		// vendor binary
+		cc_binary {
+			name: "vendorbin",
+			vendor: true,
+			srcs: ["vendor.cc"],
+			shared_libs: ["libfoo"],
+		}
+	`
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+	vendorCFlags := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
+	android.AssertStringDoesContain(t, "Vendor binary should compile using headers provided by stub", vendorCFlags, "-Istub_include_dir")
+	android.AssertStringDoesNotContain(t, "Vendor binary should not compile using headers of source", vendorCFlags, "-Isource_include_dir")
+	android.AssertStringDoesContain(t, "Vendor binary should compile using system headers provided by stub", vendorCFlags, "-isystem stub_system_include_dir")
+	android.AssertStringDoesNotContain(t, "Vendor binary should not compile using system headers of source", vendorCFlags, "-isystem source_system_include_dir")
+
+	vendorImplicits := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").OrderOnly.Strings()
+	// Building the stub.so file first assembles its .h files in multi-tree out.
+	// These header files are required for compiling the other API domain (vendor in this case)
+	android.AssertStringListContains(t, "Vendor binary compilation should have an implicit dep on the stub .so file", vendorImplicits, "libfoo.so")
+}
+
+func TestApiLibraryWithLlndkVariant(t *testing.T) {
+	bp := `
+		cc_binary {
+			name: "binfoo",
+			vendor: true,
+			srcs: ["binfoo.cc"],
+			shared_libs: ["libbar"],
+		}
+
+		cc_api_library {
+			name: "libbar",
+			// TODO(b/244244438) Remove src property once all variants are implemented.
+			src: "libbar.so",
+			vendor_available: true,
+			variants: [
+				"llndk",
+			],
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "llndk",
+			src: "libbar_llndk.so",
+			export_headers: ["libbar_llndk_include"]
+		}
+
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libbar",
+			],
+			header_libs: [],
+		}
+	`
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	libfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module()
+	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
+	libbarApiVariant := ctx.ModuleForTests("libbar.llndk.apiimport", "android_vendor.29_arm64_armv8-a").Module()
+
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+	android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant))
+
+	libFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"]
+	android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", libFooLibFlags, "libbar_llndk.so")
+
+	libFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
+	android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", libFooCFlags, "-Ilibbar_llndk_include")
+}
diff --git a/cc/library_test.go b/cc/library_test.go
index 6d5eda2..2bc9967 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -259,6 +259,7 @@
 				SystemIncludes:       []string{"system_include"},
 				Headers:              []string{"foo.h"},
 				RootDynamicLibraries: []string{"foo.so"},
+				UnstrippedOutput:     "foo_unstripped.so",
 			},
 			"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
 				CcObjectFiles:      []string{"foo.o"},
@@ -294,6 +295,7 @@
 	expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
 	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
 
+	android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String())
 	flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
 	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
 	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
diff --git a/cc/lto.go b/cc/lto.go
index 581856b..1afa1dd 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -91,6 +91,11 @@
 		return flags
 	}
 
+	// TODO(b/254713216): LTO doesn't work on riscv64 yet.
+	if ctx.Arch().ArchType == android.Riscv64 {
+		return flags
+	}
+
 	if lto.LTO(ctx) {
 		var ltoCFlag string
 		var ltoLdFlag string
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 06ded3f..d704e32 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -307,6 +307,7 @@
 	impl, ok := dep.(*Module)
 	if !ok {
 		ctx.ModuleErrorf("Implementation for stub is not correct module type")
+		return nil
 	}
 	output := impl.UnstrippedOutputFile()
 	if output == nil {
@@ -581,12 +582,12 @@
 }
 
 // Names of the cc_api_header targets in the bp2build workspace
-func (s *stubDecorator) apiHeaderLabels(ctx android.TopDownMutatorContext) bazel.LabelList {
+func apiHeaderLabels(ctx android.TopDownMutatorContext, hdrLibs []string) bazel.LabelList {
 	addSuffix := func(ctx android.BazelConversionPathContext, module blueprint.Module) string {
 		label := android.BazelModuleLabel(ctx, module)
 		return android.ApiContributionTargetName(label)
 	}
-	return android.BazelLabelForModuleDepsWithFn(ctx, s.properties.Export_header_libs, addSuffix)
+	return android.BazelLabelForModuleDepsWithFn(ctx, hdrLibs, addSuffix)
 }
 
 func ndkLibraryBp2build(ctx android.TopDownMutatorContext, m *Module) {
@@ -604,7 +605,7 @@
 		apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(symbolFile)).Label
 		attrs.Api = *bazel.MakeLabelAttribute(apiLabel)
 	}
-	apiHeaders := stubLibrary.apiHeaderLabels(ctx)
+	apiHeaders := apiHeaderLabels(ctx, stubLibrary.properties.Export_header_libs)
 	attrs.Hdrs = bazel.MakeLabelListAttribute(apiHeaders)
 	apiContributionTargetName := android.ApiContributionTargetName(ctx.ModuleName())
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: apiContributionTargetName}, attrs)
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 867c36c..1842e5a 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -33,7 +33,7 @@
 	ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
 	ctx.RegisterModuleType("cc_prebuilt_test_library_shared", PrebuiltSharedTestLibraryFactory)
 	ctx.RegisterModuleType("cc_prebuilt_object", prebuiltObjectFactory)
-	ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
+	ctx.RegisterModuleType("cc_prebuilt_binary", PrebuiltBinaryFactory)
 }
 
 type prebuiltLinkerInterface interface {
@@ -358,12 +358,12 @@
 
 // TODO(b/228623543): The below is not entirely true until the bug is fixed. For now, both targets are always generated
 // Implements bp2build for cc_prebuilt_library modules. This will generate:
-//   - Only a prebuilt_library_static if the shared.enabled property is set to false across all variants.
-//   - Only a prebuilt_library_shared if the static.enabled property is set to false across all variants
-//   - Both a prebuilt_library_static and prebuilt_library_shared if the aforementioned properties are not false across
+//   - Only a cc_prebuilt_library_static if the shared.enabled property is set to false across all variants.
+//   - Only a cc_prebuilt_library_shared if the static.enabled property is set to false across all variants
+//   - Both a cc_prebuilt_library_static and cc_prebuilt_library_shared if the aforementioned properties are not false across
 //     all variants
 //
-// In all cases, prebuilt_library_static target names will be appended with "_bp2build_cc_library_static".
+// In all cases, cc_prebuilt_library_static target names will be appended with "_bp2build_cc_library_static".
 func prebuiltLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module) {
 	prebuiltLibraryStaticBp2Build(ctx, module, true)
 	prebuiltLibrarySharedBp2Build(ctx, module)
@@ -380,8 +380,8 @@
 	}
 
 	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "prebuilt_library_static",
-		Bzl_load_location: "//build/bazel/rules/cc:prebuilt_library_static.bzl",
+		Rule_class:        "cc_prebuilt_library_static",
+		Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_static.bzl",
 	}
 
 	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
@@ -403,8 +403,8 @@
 	}
 
 	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "prebuilt_library_shared",
-		Bzl_load_location: "//build/bazel/rules/cc:prebuilt_library_shared.bzl",
+		Rule_class:        "cc_prebuilt_library_shared",
+		Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_shared.bzl",
 	}
 
 	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
@@ -668,15 +668,21 @@
 }
 
 // cc_prebuilt_binary installs a precompiled executable in srcs property in the
-// device's directory.
-func prebuiltBinaryFactory() android.Module {
+// device's directory, for both the host and device
+func PrebuiltBinaryFactory() android.Module {
 	module, _ := NewPrebuiltBinary(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
+type prebuiltBinaryBazelHandler struct {
+	module    *Module
+	decorator *binaryDecorator
+}
+
 func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
-	module, binary := newBinary(hod, false)
+	module, binary := newBinary(hod, true)
 	module.compiler = nil
+	module.bazelHandler = &prebuiltBinaryBazelHandler{module, binary}
 
 	prebuilt := &prebuiltBinaryLinker{
 		binaryDecorator: binary,
@@ -690,6 +696,53 @@
 	return module, binary
 }
 
+var _ BazelHandler = (*prebuiltBinaryBazelHandler)(nil)
+
+func (h *prebuiltBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
+	bazelCtx := ctx.Config().BazelContext
+	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
+}
+
+func (h *prebuiltBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
+	bazelCtx := ctx.Config().BazelContext
+	outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
+	if err != nil {
+		ctx.ModuleErrorf(err.Error())
+		return
+	}
+	if len(outputs) != 1 {
+		ctx.ModuleErrorf("Expected a single output for `%s`, but got:\n%v", label, outputs)
+		return
+	}
+	out := android.PathForBazelOut(ctx, outputs[0])
+	h.module.outputFile = android.OptionalPathForPath(out)
+	h.module.maybeUnhideFromMake()
+}
+
+type bazelPrebuiltBinaryAttributes struct {
+	Src   bazel.LabelAttribute
+	Strip stripAttributes
+}
+
+func prebuiltBinaryBp2Build(ctx android.TopDownMutatorContext, module *Module) {
+	prebuiltAttrs := bp2BuildParsePrebuiltBinaryProps(ctx, module)
+
+	var la linkerAttributes
+	la.convertStripProps(ctx, module)
+	attrs := &bazelPrebuiltBinaryAttributes{
+		Src:   prebuiltAttrs.Src,
+		Strip: stripAttrsFromLinkerAttrs(&la),
+	}
+
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_prebuilt_binary",
+		Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_binary.bzl",
+	}
+
+	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
+}
+
 type Sanitized struct {
 	None struct {
 		Srcs []string `android:"path,arch_variant"`
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 53cf781..95fa99e 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -683,3 +683,27 @@
 }`
 	testCcError(t, `Android.bp:4:6: module "bintest" variant "android_arm64_armv8-a": srcs: multiple prebuilt source files`, bp)
 }
+
+func TestPrebuiltBinaryWithBazel(t *testing.T) {
+	const bp = `
+cc_prebuilt_binary {
+	name: "bintest",
+	srcs: ["bin"],
+	bazel_module: { label: "//bin/foo:foo" },
+}`
+	const outBaseDir = "outputbase"
+	const expectedOut = outBaseDir + "/execroot/__main__/bin"
+	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+	config.BazelContext = android.MockBazelContext{
+		OutputBaseDir:      outBaseDir,
+		LabelToOutputFiles: map[string][]string{"//bin/foo:foo": []string{"bin"}},
+	}
+	ctx := testCcWithConfig(t, config)
+	bin := ctx.ModuleForTests("bintest", "android_arm64_armv8-a").Module().(*Module)
+	out := bin.OutputFile()
+	if !out.Valid() {
+		t.Error("Invalid output file")
+		return
+	}
+	android.AssertStringEquals(t, "output file", expectedOut, out.String())
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 0b47f0e..d3fc221 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -511,6 +511,12 @@
 		s.Integer_overflow = nil
 	}
 
+	// TODO(b/254713216): CFI doesn't work for riscv64 yet because LTO doesn't work.
+	if ctx.Arch().ArchType == android.Riscv64 {
+		s.Cfi = nil
+		s.Diag.Cfi = nil
+	}
+
 	// Disable CFI for musl
 	if ctx.toolchain().Musl() {
 		s.Cfi = nil
@@ -613,6 +619,14 @@
 		return flags
 	}
 
+	// Currently unwinding through tagged frames for exceptions is broken, so disable memtag stack
+	// in that case, so we don't end up tagging those.
+	// TODO(b/174878242): Remove once https://r.android.com/2251926 is included in toolchain.
+	if android.InList("-fexceptions", flags.Local.CFlags) || android.InList("-fexceptions", flags.Global.CFlags) {
+		sanitize.Properties.Sanitize.Memtag_stack = nil
+		_, sanitize.Properties.Sanitizers = android.RemoveFromList("memtag-stack", sanitize.Properties.Sanitizers)
+	}
+
 	if Bool(sanitize.Properties.Sanitize.Address) {
 		if ctx.Arch().ArchType == android.Arm {
 			// Frame pointer based unwinder in ASan requires ARM frame setup.
@@ -1384,6 +1398,7 @@
 
 		// Determine the runtime library required
 		runtimeLibrary := ""
+		alwaysStaticRuntime := false
 		var extraStaticDeps []string
 		toolchain := c.toolchain(mctx)
 		if Bool(c.sanitize.Properties.Sanitize.Address) {
@@ -1408,8 +1423,15 @@
 			Bool(c.sanitize.Properties.Sanitize.Undefined) ||
 			Bool(c.sanitize.Properties.Sanitize.All_undefined) {
 			runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)
-			if c.staticBinary() {
+			if c.staticBinary() || toolchain.Musl() {
+				// Use a static runtime for static binaries.
+				// Also use a static runtime for musl to match
+				// what clang does for glibc.  Otherwise dlopening
+				// libraries that depend on libclang_rt.ubsan_standalone.so
+				// fails with:
+				// Error relocating ...: initial-exec TLS resolves to dynamic definition
 				runtimeLibrary += ".static"
+				alwaysStaticRuntime = true
 			}
 		}
 
@@ -1453,7 +1475,7 @@
 			//
 			// Note that by adding dependency with {static|shared}DepTag, the lib is
 			// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
-			if c.staticBinary() {
+			if c.staticBinary() || alwaysStaticRuntime {
 				addStaticDeps(runtimeLibrary)
 				addStaticDeps(extraStaticDeps...)
 			} else if !c.static() && !c.Header() {
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 48ac650..2393f3e 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -41,6 +41,7 @@
 			static_libs: [
 				"libstatic",
 				"libnoasan",
+				"libstatic_asan",
 			],
 			sanitize: {
 				address: true,
@@ -57,6 +58,7 @@
 			static_libs: [
 				"libstatic",
 				"libnoasan",
+				"libstatic_asan",
 			],
 		}
 
@@ -92,6 +94,15 @@
 				address: false,
 			}
 		}
+
+		cc_library_static {
+			name: "libstatic_asan",
+			host_supported: true,
+			sanitize: {
+				address: true,
+			}
+		}
+
 	`
 
 	result := android.GroupFixturePreparers(
@@ -125,6 +136,10 @@
 		// Static library that never uses asan.
 		libNoAsan := result.ModuleForTests("libnoasan", staticVariant)
 
+		// Static library that specifies asan
+		libStaticAsan := result.ModuleForTests("libstatic_asan", staticAsanVariant)
+		libStaticAsanNoAsanVariant := result.ModuleForTests("libstatic_asan", staticVariant)
+
 		// expectSharedLinkDep verifies that the from module links against the to module as a
 		// shared library.
 		expectSharedLinkDep := func(from, to android.TestingModule) {
@@ -176,6 +191,7 @@
 
 		expectStaticLinkDep(binWithAsan, libStaticAsanVariant)
 		expectStaticLinkDep(binWithAsan, libNoAsan)
+		expectStaticLinkDep(binWithAsan, libStaticAsan)
 
 		expectInstallDep(binWithAsan, libShared)
 		expectInstallDep(binWithAsan, libAsan)
@@ -190,6 +206,7 @@
 
 		expectStaticLinkDep(binNoAsan, libStaticNoAsanVariant)
 		expectStaticLinkDep(binNoAsan, libNoAsan)
+		expectStaticLinkDep(binNoAsan, libStaticAsanNoAsanVariant)
 
 		expectInstallDep(binNoAsan, libShared)
 		expectInstallDep(binNoAsan, libAsan)
diff --git a/cc/sdk.go b/cc/sdk.go
index a83e5ad..a0d196b 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -78,5 +78,7 @@
 		}
 	case *snapshotModule:
 		ctx.CreateVariations("")
+	case *CcApiVariant:
+		ctx.CreateVariations("")
 	}
 }
diff --git a/cc/stl.go b/cc/stl.go
index 85a06da..6353a4a 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -139,6 +139,8 @@
 	return "libunwind"
 }
 
+// Should be kept up to date with
+// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/stl.bzl;l=46;drc=21771b671ae08565033768a6d3d151c54f887fa2
 func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
 	switch stl.Properties.SelectedStl {
 	case "libstdc++":
@@ -194,6 +196,8 @@
 	return deps
 }
 
+// Should be kept up to date with
+// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/stl.bzl;l=94;drc=5bc8e39d2637927dc57dd0850210d43d348a1341
 func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags {
 	switch stl.Properties.SelectedStl {
 	case "libc++", "libc++_static":
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index 9bf07f2..94c8567 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -41,6 +41,7 @@
 ALL_ARCHITECTURES = (
     Arch('arm'),
     Arch('arm64'),
+    Arch('riscv64'),
     Arch('x86'),
     Arch('x86_64'),
 )
diff --git a/cc/test.go b/cc/test.go
index 715c537..536210b 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -643,6 +643,8 @@
 
 	Gtest    bool
 	Isolated bool
+
+	tidyAttributes
 }
 
 // testBinaryBp2build is the bp2build converter for cc_test modules. A cc_test's
@@ -676,6 +678,8 @@
 		}
 	}
 
+	m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes)
+
 	for _, propIntf := range m.GetProperties() {
 		if testLinkerProps, ok := propIntf.(*TestLinkerProperties); ok {
 			testBinaryAttrs.Gtest = proptools.BoolDefault(testLinkerProps.Gtest, true)
diff --git a/cc/tidy.go b/cc/tidy.go
index 2ba13ca..a3d548b 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -68,6 +68,7 @@
 // Then, that old style usage will be obsolete and an error.
 const NoWarningsAsErrorsInTidyFlags = true
 
+// keep this up to date with https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/clang_tidy.bzl
 func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
 	CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
 	CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
@@ -79,9 +80,10 @@
 	// Some projects like external/* and vendor/* have clang-tidy disabled by default,
 	// unless they are enabled explicitly with the "tidy:true" property or
 	// when TIDY_EXTERNAL_VENDOR is set to true.
-	if !ctx.Config().IsEnvTrue("TIDY_EXTERNAL_VENDOR") &&
-		!proptools.Bool(tidy.Properties.Tidy) &&
-		config.NoClangTidyForDir(ctx.ModuleDir()) {
+	if !proptools.Bool(tidy.Properties.Tidy) &&
+		config.NoClangTidyForDir(
+			ctx.Config().IsEnvTrue("TIDY_EXTERNAL_VENDOR"),
+			ctx.ModuleDir()) {
 		return flags
 	}
 	// If not explicitly disabled, set flags.Tidy to generate .tidy rules.
diff --git a/cmd/extract_apks/bundle_proto/Android.bp b/cmd/extract_apks/bundle_proto/Android.bp
new file mode 100644
index 0000000..e56c0fb
--- /dev/null
+++ b/cmd/extract_apks/bundle_proto/Android.bp
@@ -0,0 +1,13 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_library_host {
+    name: "config_proto",
+    srcs: [
+        "config.proto",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+}
diff --git a/cmd/extract_apks/bundle_proto/config.proto b/cmd/extract_apks/bundle_proto/config.proto
index d6fac03..946bd9a 100644
--- a/cmd/extract_apks/bundle_proto/config.proto
+++ b/cmd/extract_apks/bundle_proto/config.proto
@@ -26,6 +26,9 @@
     ASSET_ONLY = 2;
   }
   BundleType type = 8;
+
+  // Configuration for locales.
+  Locales locales = 9;
 }
 
 message Bundletool {
@@ -40,6 +43,48 @@
   // the name of the modules, and using forward slash ("/") as a name separator.
   // Examples: "res/raw/**", "assets/**/*.uncompressed", etc.
   repeated string uncompressed_glob = 1;
+
+  enum AssetModuleCompression {
+    UNSPECIFIED = 0;
+    // Assets are left uncompressed in the generated asset module.
+    UNCOMPRESSED = 1;
+    // Assets are compressed in the generated asset module.
+    // This option can be overridden at a finer granularity by specifying
+    // files or folders to keep uncompressed in `uncompressed_glob`.
+    // This option should only be used if the app is able to handle compressed
+    // asset module content at runtime (some runtime APIs may misbehave).
+    COMPRESSED = 2;
+  }
+
+  // Default compression strategy for install-time asset modules.
+  // If the compression strategy indicates to compress a file and the same file
+  // matches one of the `uncompressed_glob` values, the `uncompressed_glob`
+  // takes precedence (the file is left uncompressed in the generated APK).
+  //
+  // If unspecified, asset module content is left uncompressed in the
+  // generated asset modules.
+  //
+  // Note: this flag only configures the compression strategy for install-time
+  // asset modules; the content of on-demand and fast-follow asset modules is
+  // always kept uncompressed.
+  AssetModuleCompression install_time_asset_module_default_compression = 2;
+
+  enum ApkCompressionAlgorithm {
+    // Default in the current version of bundletool is zlib deflate algorithm
+    // with compression level 9 for the application's resources and compression
+    // level 6 for other entries.
+    //
+    // This is a good trade-off between size of final APK and size of patches
+    // which are used to update the application from previous to next version.
+    DEFAULT_APK_COMPRESSION_ALGORITHM = 0;
+
+    // 7zip implementation of deflate algorithm which gives smaller APK size
+    // but size of patches required to update the application are larger.
+    P7ZIP = 1;
+  }
+
+  // Compression algorithm which is used to compress entries in final APKs.
+  ApkCompressionAlgorithm apk_compression_algorithm = 3;
 }
 
 // Resources to keep in the master split.
@@ -55,12 +100,40 @@
   // This is for uncompressing native libraries on M+ devices (L+ devices on
   // instant apps).
   UncompressNativeLibraries uncompress_native_libraries = 2;
-  // This is for uncompressing dex files on P+ devices.
+  // This is for uncompressing dex files.
   UncompressDexFiles uncompress_dex_files = 3;
   // Configuration for the generation of standalone APKs.
   // If no StandaloneConfig is set, the configuration is inherited from
   // splits_config.
   StandaloneConfig standalone_config = 4;
+
+  // Optimizations that are applied to resources.
+  ResourceOptimizations resource_optimizations = 5;
+
+  // Configuration for archiving the app.
+  StoreArchive store_archive = 6;
+}
+
+message ResourceOptimizations {
+  // Whether to use sparse encoding for resource tables.
+  // Resources in sparse resource table are accessed using a binary search tree.
+  // This decreases APK size at the cost of resource retrieval performance.
+  SparseEncoding sparse_encoding = 1;
+
+  enum SparseEncoding {
+    // Previously 'ENFORCED'. This option is deprecated because of issues found
+    // in Android O up to Android Sv2 and causes segfaults in
+    // Resources#getIdentifier.
+    reserved 1;
+    reserved "ENFORCED";
+
+    // Disables sparse encoding.
+    UNSPECIFIED = 0;
+    // Generates special APKs for Android SDK +32 with sparse resource tables.
+    // Devices with Android SDK below 32 will still receive APKs with regular
+    // resource tables.
+    VARIANT_FOR_SDK_32 = 2;
+  }
 }
 
 message UncompressNativeLibraries {
@@ -68,7 +141,39 @@
 }
 
 message UncompressDexFiles {
+  //  A new variant with uncompressed dex will be generated. The sdk targeting
+  //  of the variant is determined by 'uncompressed_dex_target_sdk'.
   bool enabled = 1;
+
+  //  If 'enabled' field is set, this will determine the sdk targeting of the
+  //  generated variant.
+  UncompressedDexTargetSdk uncompressed_dex_target_sdk = 2;
+
+  enum UncompressedDexTargetSdk {
+    // Q+ variant will be generated.
+    UNSPECIFIED = 0;
+    // S+ variant will be generated.
+    SDK_31 = 1;
+  }
+}
+
+message StoreArchive {
+  // Archive is an app state that allows an official app store to reclaim device
+  // storage and disable app functionality temporarily until the user interacts
+  // with the app again. Upon interaction the latest available version of the
+  // app will be restored while leaving user data unaffected.
+  // Enabled by default.
+  bool enabled = 1;
+}
+
+message Locales {
+  // Instructs bundletool to generate locale config and inject it into
+  // AndroidManifest.xml. A locale is marked as supported by the application if
+  // there is at least one resource value in this locale. Be very careful with
+  // this setting because if some of your libraries expose resources in some
+  // locales which are not actually supported by your application it will mark
+  // this locale as supported. Disabled by default.
+  bool inject_locale_config = 1;
 }
 
 // Optimization configuration used to generate Split APKs.
@@ -82,8 +187,28 @@
   repeated SplitDimension split_dimension = 1;
   // Whether 64 bit libraries should be stripped from Standalone APKs.
   bool strip_64_bit_libraries = 2;
+  // Dex merging strategy that should be applied to produce Standalone APKs.
+  DexMergingStrategy dex_merging_strategy = 3;
+
+  enum DexMergingStrategy {
+    // Strategy that does dex merging for applications that have minimum SDK
+    // below 21 to ensure dex files from all modules are merged into one or
+    // mainDexList is applied when merging into one dex is not possible. For
+    // applications with minSdk >= 21 dex files from all modules are copied into
+    // standalone APK as is because Android supports multiple dex files natively
+    // starting from Android 5.0.
+    MERGE_IF_NEEDED = 0;
+    // Requires to copy dex files from all modules into standalone APK as is.
+    // If an application supports SDKs below 21 this strategy puts
+    // responsibility of providing dex files compatible with legacy multidex on
+    // application developers.
+    NEVER_MERGE = 1;
+  }
 }
 
+// BEGIN-INTERNAL
+// LINT.IfChange
+// END-INTERNAL
 message SplitDimension {
   enum Value {
     UNSPECIFIED_VALUE = 0;
@@ -92,8 +217,9 @@
     LANGUAGE = 3;
     TEXTURE_COMPRESSION_FORMAT = 4;
     // BEGIN-INTERNAL
-    GRAPHICS_API = 5;
+    GRAPHICS_API = 5 [deprecated = true];
     // END-INTERNAL
+    DEVICE_TIER = 6;
   }
   Value value = 1;
 
@@ -105,11 +231,14 @@
   // the targeting is encoded in the directory name (e.g: assets/foo#tcf_etc1)
   SuffixStripping suffix_stripping = 3;
 }
+// BEGIN-INTERNAL
+// LINT.ThenChange(//depot/google3/wireless/android/vending/developer/proto/storage/app/apk_bundle.proto)
+// END-INTERNAL
 
 message SuffixStripping {
   // If set to 'true', indicates that the targeting suffix should be removed
-  // from assets paths for this dimension when splits (or asset slices) are
-  // generated.
+  // from assets paths for this dimension when splits (e.g: "asset packs") or
+  // standalone/universal APKs are generated.
   // This only applies to assets.
   // For example a folder with path "assets/level1_textures#tcf_etc1"
   // would be outputted to "assets/level1_textures". File contents are
@@ -117,9 +246,9 @@
   bool enabled = 1;
 
   // The default suffix to be used for the cases where separate slices can't
-  // be generated for this dimension. In the case of standalone/universal APKs
-  // generation, stripping the suffix can lead to file name collisions. This
-  // default suffix defines the directories to retain. The others are
+  // be generated for this dimension - typically for standalone or universal
+  // APKs.
+  // This default suffix defines the directories to retain. The others are
   // discarded: standalone/universal APKs will contain only directories
   // targeted at this value for the dimension.
   //
@@ -135,6 +264,15 @@
 message ApexConfig {
   // Configuration for processing of APKs embedded in an APEX image.
   repeated ApexEmbeddedApkConfig apex_embedded_apk_config = 1;
+
+  // Explicit list of supported ABIs.
+  // Default: See ApexBundleValidator.REQUIRED_ONE_OF_ABI_SETS
+  repeated SupportedAbiSet supported_abi_set = 2;
+}
+
+// Represents a set of ABIs which must be supported by a single APEX image.
+message SupportedAbiSet {
+  repeated string abi = 1;
 }
 
 message ApexEmbeddedApkConfig {
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 7cb8ab7..d8d5e5d 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -48,6 +48,10 @@
 var outDir = flag.String("out", "", "path to store output directories (defaults to tmpdir under $OUT when empty)")
 var alternateResultDir = flag.Bool("dist", false, "write select results to $DIST_DIR (or <out>/dist when empty)")
 
+var bazelMode = flag.Bool("bazel-mode", false, "use bazel for analysis of certain modules")
+var bazelModeStaging = flag.Bool("bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
+var bazelModeDev = flag.Bool("bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
+
 var onlyConfig = flag.Bool("only-config", false, "Only run product config (not Soong or Kati)")
 var onlySoong = flag.Bool("only-soong", false, "Only run product config and Soong (not Kati)")
 
@@ -214,6 +218,31 @@
 	return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true"
 }
 
+func getBazelArg() string {
+	count := 0
+	str := ""
+	if *bazelMode {
+		count++
+		str = "--bazel-mode"
+	}
+	if *bazelModeStaging {
+		count++
+		str = "--bazel-mode-staging"
+	}
+	if *bazelModeDev {
+		count++
+		str = "--bazel-mode-dev"
+	}
+
+	if count > 1 {
+		// Can't set more than one
+		fmt.Errorf("Only one bazel mode is permitted to be set.")
+		os.Exit(1)
+	}
+
+	return str
+}
+
 func main() {
 	stdio := terminal.StdioImpl{}
 
@@ -472,6 +501,11 @@
 		args = append(args, "--soong-only")
 	}
 
+	bazelStr := getBazelArg()
+	if bazelStr != "" {
+		args = append(args, bazelStr)
+	}
+
 	cmd := exec.Command(mpctx.SoongUi, args...)
 	cmd.Stdout = consoleLogWriter
 	cmd.Stderr = consoleLogWriter
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index 0e8ad05..ba0648d 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -207,6 +207,10 @@
 	return p.Packaging == "jar"
 }
 
+func (p Pom) IsApk() bool {
+	return p.Packaging == "apk"
+}
+
 func (p Pom) IsHostModule() bool {
 	return hostModuleNames.IsHostModule(p.GroupId, p.ArtifactId)
 }
@@ -244,6 +248,8 @@
 func (p Pom) ImportModuleType() string {
 	if p.IsAar() {
 		return "android_library_import"
+	} else if p.IsApk() {
+		return "android_app_import"
 	} else if p.IsHostOnly() {
 		return "java_import_host"
 	} else {
@@ -254,6 +260,8 @@
 func (p Pom) BazelImportTargetType() string {
 	if p.IsAar() {
 		return "aar_import"
+	} else if p.IsApk() {
+		return "apk_import"
 	} else {
 		return "java_import"
 	}
@@ -262,6 +270,8 @@
 func (p Pom) ImportProperty() string {
 	if p.IsAar() {
 		return "aars"
+	} else if p.IsApk() {
+		return "apk"
 	} else {
 		return "jars"
 	}
@@ -270,6 +280,8 @@
 func (p Pom) BazelImportProperty() string {
 	if p.IsAar() {
 		return "aar"
+	} else if p.IsApk() {
+		return "apk"
 	} else {
 		return "jars"
 	}
@@ -493,8 +505,12 @@
 var bpTemplate = template.Must(template.New("bp").Parse(`
 {{.ImportModuleType}} {
     name: "{{.BpName}}",
+    {{- if .IsApk}}
+    {{.ImportProperty}}: "{{.ArtifactFile}}",
+    {{- else}}
     {{.ImportProperty}}: ["{{.ArtifactFile}}"],
     sdk_version: "{{.SdkVersion}}",
+    {{- end}}
     {{- if .Jetifier}}
     jetifier: true,
     {{- end}}
@@ -535,8 +551,14 @@
     ],
     {{- end}}
     {{- else if not .IsHostOnly}}
+    {{- if not .IsApk}}
     min_sdk_version: "{{.DefaultMinSdkVersion}}",
     {{- end}}
+    {{- end}}
+    {{- if .IsApk}}
+    presigned: true
+    {{- end}}
+
 }
 `))
 
@@ -995,7 +1017,7 @@
 
 	for _, pom := range poms {
 		var err error
-		if staticDeps {
+		if staticDeps && !pom.IsApk() {
 			err = depsTemplate.Execute(buf, pom)
 		} else {
 			err = template.Execute(buf, pom)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 9f00fc3..3fed1a1 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -15,6 +15,7 @@
 package main
 
 import (
+	"bytes"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -55,6 +56,7 @@
 	bazelQueryViewDir   string
 	bazelApiBp2buildDir string
 	bp2buildMarker      string
+	symlinkForestMarker string
 
 	cmdlineArgs bootstrap.Args
 )
@@ -85,9 +87,11 @@
 	flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
 	flag.StringVar(&bazelApiBp2buildDir, "bazel_api_bp2build_dir", "", "path to the bazel api_bp2build directory relative to --top")
 	flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
+	flag.StringVar(&symlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
 	flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
 	flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
 	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
+	flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
 	flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
 
 	// Flags that probably shouldn't be flags of soong_build but we haven't found
@@ -128,7 +132,9 @@
 func newConfig(availableEnv map[string]string) android.Config {
 	var buildMode android.SoongBuildMode
 
-	if bp2buildMarker != "" {
+	if symlinkForestMarker != "" {
+		buildMode = android.SymlinkForest
+	} else if bp2buildMarker != "" {
 		buildMode = android.Bp2build
 	} else if bazelQueryViewDir != "" {
 		buildMode = android.GenerateQueryView
@@ -142,6 +148,8 @@
 		buildMode = android.BazelDevMode
 	} else if cmdlineArgs.BazelMode {
 		buildMode = android.BazelProdMode
+	} else if cmdlineArgs.BazelModeStaging {
+		buildMode = android.BazelStagingMode
 	} else {
 		buildMode = android.AnalysisNoBazel
 	}
@@ -167,21 +175,26 @@
 		return configuration.BazelContext.InvokeBazel(configuration)
 	}
 	ctx.SetBeforePrepareBuildActionsHook(bazelHook)
-
 	ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs, bootstrap.DoEverything, ctx.Context, configuration)
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
+	bazelPaths, err := readBazelPaths(configuration)
+	if err != nil {
+		panic("Bazel deps file not found: " + err.Error())
+	}
+	ninjaDeps = append(ninjaDeps, bazelPaths...)
+
 	globListFiles := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
 	ninjaDeps = append(ninjaDeps, globListFiles...)
 
-	writeDepFile(cmdlineArgs.OutFile, *ctx.EventHandler, ninjaDeps)
+	writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
 }
 
 // Run the code-generation phase to convert BazelTargetModules to BUILD files.
 func runQueryView(queryviewDir, queryviewMarker string, configuration android.Config, ctx *android.Context) {
 	ctx.EventHandler.Begin("queryview")
 	defer ctx.EventHandler.End("queryview")
-	codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
+	codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.QueryView)
 	absoluteQueryViewDir := shared.JoinPath(topDir, queryviewDir)
 	if err := createBazelWorkspace(codegenContext, absoluteQueryViewDir); err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
@@ -222,7 +235,7 @@
 	ninjaDeps = append(ninjaDeps, globs...)
 
 	// Run codegen to generate BUILD files
-	codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.ApiBp2build)
+	codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.ApiBp2build)
 	absoluteApiBp2buildDir := shared.JoinPath(topDir, bazelApiBp2buildDir)
 	if err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir); err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
@@ -231,7 +244,7 @@
 	ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
 
 	// Create soong_injection repository
-	soongInjectionFiles := bp2build.CreateSoongInjectionFiles(configuration, bp2build.CodegenMetrics{})
+	soongInjectionFiles := bp2build.CreateSoongInjectionFiles(configuration, bp2build.CreateCodegenMetrics())
 	absoluteSoongInjectionDir := shared.JoinPath(topDir, configuration.SoongOutDir(), bazel.SoongInjectionDirName)
 	for _, file := range soongInjectionFiles {
 		writeReadOnlyFile(absoluteSoongInjectionDir, file)
@@ -245,16 +258,15 @@
 
 	// Create the symlink forest
 	symlinkDeps := bp2build.PlantSymlinkForest(
-		configuration,
+		configuration.IsEnvTrue("BP2BUILD_VERBOSE"),
 		topDir,
 		workspace,
 		bazelApiBp2buildDir,
-		".",
 		excludes)
 	ninjaDeps = append(ninjaDeps, symlinkDeps...)
 
 	workspaceMarkerFile := workspace + ".marker"
-	writeDepFile(workspaceMarkerFile, *ctx.EventHandler, ninjaDeps)
+	writeDepFile(workspaceMarkerFile, ctx.EventHandler, ninjaDeps)
 	touch(shared.JoinPath(topDir, workspaceMarkerFile))
 	return workspaceMarkerFile
 }
@@ -281,7 +293,7 @@
 	return ret
 }
 
-func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
+func writeMetrics(configuration android.Config, eventHandler *metrics.EventHandler, metricsDir string) {
 	if len(metricsDir) < 1 {
 		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
 		os.Exit(1)
@@ -321,7 +333,7 @@
 	return bootstrap.GlobFileListFiles(globDir)
 }
 
-func writeDepFile(outputFile string, eventHandler metrics.EventHandler, ninjaDeps []string) {
+func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
 	eventHandler.Begin("ninja_deps")
 	defer eventHandler.End("ninja_deps")
 	depFile := shared.JoinPath(topDir, outputFile+".d")
@@ -335,11 +347,14 @@
 // doChosenActivity runs Soong for a specific activity, like bp2build, queryview
 // or the actual Soong build for the build.ninja file. Returns the top level
 // output file of the specific activity.
-func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string) string {
-	if configuration.BuildMode == android.Bp2build {
+func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string, metricsDir string) string {
+	if configuration.BuildMode == android.SymlinkForest {
+		runSymlinkForestCreation(configuration, extraNinjaDeps, metricsDir)
+		return symlinkForestMarker
+	} else if configuration.BuildMode == android.Bp2build {
 		// Run the alternate pipeline of bp2build mutators and singleton to convert
 		// Blueprint to BUILD files before everything else.
-		runBp2Build(configuration, extraNinjaDeps)
+		runBp2Build(configuration, extraNinjaDeps, metricsDir)
 		return bp2buildMarker
 	} else if configuration.IsMixedBuildsEnabled() {
 		runMixedModeBuild(configuration, ctx, extraNinjaDeps)
@@ -365,11 +380,11 @@
 		if configuration.BuildMode == android.GenerateQueryView {
 			queryviewMarkerFile := bazelQueryViewDir + ".marker"
 			runQueryView(bazelQueryViewDir, queryviewMarkerFile, configuration, ctx)
-			writeDepFile(queryviewMarkerFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(queryviewMarkerFile, ctx.EventHandler, ninjaDeps)
 			return queryviewMarkerFile
 		} else if configuration.BuildMode == android.GenerateModuleGraph {
 			writeJsonModuleGraphAndActions(ctx, moduleGraphFile, moduleActionsFile)
-			writeDepFile(moduleGraphFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(moduleGraphFile, ctx.EventHandler, ninjaDeps)
 			return moduleGraphFile
 		} else if configuration.BuildMode == android.GenerateDocFile {
 			// TODO: we could make writeDocs() return the list of documentation files
@@ -379,12 +394,12 @@
 				fmt.Fprintf(os.Stderr, "error building Soong documentation: %s\n", err)
 				os.Exit(1)
 			}
-			writeDepFile(docFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(docFile, ctx.EventHandler, ninjaDeps)
 			return docFile
 		} else {
 			// The actual output (build.ninja) was written in the RunBlueprint() call
 			// above
-			writeDepFile(cmdlineArgs.OutFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
 		}
 	}
 
@@ -450,10 +465,10 @@
 	ctx := newContext(configuration)
 	ctx.EventHandler.Begin("soong_build")
 
-	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps)
+	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps, logDir)
 
 	ctx.EventHandler.End("soong_build")
-	writeMetrics(configuration, *ctx.EventHandler, logDir)
+	writeMetrics(configuration, ctx.EventHandler, logDir)
 
 	writeUsedEnvironmentFile(configuration, finalOutputFile)
 }
@@ -470,12 +485,19 @@
 		os.Exit(1)
 	}
 
-	err = ioutil.WriteFile(path, data, 0666)
-	if err != nil {
+	if preexistingData, err := os.ReadFile(path); err != nil {
+		if !os.IsNotExist(err) {
+			fmt.Fprintf(os.Stderr, "error reading used environment file '%s': %s\n", usedEnvFile, err)
+			os.Exit(1)
+		}
+	} else if bytes.Equal(preexistingData, data) {
+		// used environment file is unchanged
+		return
+	}
+	if err = os.WriteFile(path, data, 0666); err != nil {
 		fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err)
 		os.Exit(1)
 	}
-
 	// Touch the output file so that it's not older than the file we just
 	// wrote. We can't write the environment file earlier because one an access
 	// new environment variables while writing it.
@@ -583,12 +605,69 @@
 	}
 }
 
+// This could in theory easily be separated into a binary that generically
+// merges two directories into a symlink tree. The main obstacle is that this
+// function currently depends on both Bazel-specific knowledge (the existence
+// of bazel-* symlinks) and configuration (the set of BUILD.bazel files that
+// should and should not be kept)
+//
+// Ideally, bp2build would write a file that contains instructions to the
+// symlink tree creation binary. Then the latter would not need to depend on
+// the very heavy-weight machinery of soong_build .
+func runSymlinkForestCreation(configuration android.Config, extraNinjaDeps []string, metricsDir string) {
+	eventHandler := &metrics.EventHandler{}
+
+	var ninjaDeps []string
+	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
+
+	generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
+	workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
+
+	excludes := bazelArtifacts()
+
+	if outDir[0] != '/' {
+		excludes = append(excludes, outDir)
+	}
+
+	existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
+		os.Exit(1)
+	}
+
+	pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(configuration.Bp2buildPackageConfig, topDir, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
+	excludes = append(excludes, pathsToIgnoredBuildFiles...)
+	excludes = append(excludes, getTemporaryExcludes()...)
+
+	// PlantSymlinkForest() returns all the directories that were readdir()'ed.
+	// Such a directory SHOULD be added to `ninjaDeps` so that a child directory
+	// or file created/deleted under it would trigger an update of the symlink
+	// forest.
+	eventHandler.Do("symlink_forest", func() {
+		symlinkForestDeps := bp2build.PlantSymlinkForest(
+			configuration.IsEnvTrue("BP2BUILD_VERBOSE"), topDir, workspaceRoot, generatedRoot, excludes)
+		ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
+	})
+
+	writeDepFile(symlinkForestMarker, eventHandler, ninjaDeps)
+	touch(shared.JoinPath(topDir, symlinkForestMarker))
+	codegenMetrics := bp2build.ReadCodegenMetrics(metricsDir)
+	if codegenMetrics == nil {
+		m := bp2build.CreateCodegenMetrics()
+		codegenMetrics = &m
+	} else {
+		//TODO (usta) we cannot determine if we loaded a stale file, i.e. from an unrelated prior
+		//invocation of codegen. We should simply use a separate .pb file
+	}
+	writeBp2BuildMetrics(codegenMetrics, eventHandler, metricsDir)
+}
+
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
-func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
-	var codegenMetrics bp2build.CodegenMetrics
-	eventHandler := metrics.EventHandler{}
+func runBp2Build(configuration android.Config, extraNinjaDeps []string, metricsDir string) {
+	var codegenMetrics *bp2build.CodegenMetrics
+	eventHandler := &metrics.EventHandler{}
 	eventHandler.Do("bp2build", func() {
 
 		// Register an alternate set of singletons and mutators for bazel
@@ -600,21 +679,11 @@
 		bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
 		bp2buildCtx.SetNameInterface(newNameResolver(configuration))
 		bp2buildCtx.RegisterForBazelConversion()
+		bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile)
 
 		var ninjaDeps []string
 		ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
-		// The bp2build process is a purely functional process that only depends on
-		// Android.bp files. It must not depend on the values of per-build product
-		// configurations or variables, since those will generate different BUILD
-		// files based on how the user has configured their tree.
-		bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile)
-		if modulePaths, err := bp2buildCtx.ListModulePaths("."); err != nil {
-			panic(err)
-		} else {
-			ninjaDeps = append(ninjaDeps, modulePaths...)
-		}
-
 		// Run the loading and analysis pipeline to prepare the graph of regular
 		// Modules parsed from Android.bp files, and the BazelTargetModules mapped
 		// from the regular Modules.
@@ -629,46 +698,14 @@
 
 		// Run the code-generation phase to convert BazelTargetModules to BUILD files
 		// and print conversion codegenMetrics to the user.
-		codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
+		codegenContext := bp2build.NewCodegenContext(configuration, bp2buildCtx, bp2build.Bp2Build)
 		eventHandler.Do("codegen", func() {
 			codegenMetrics = bp2build.Codegen(codegenContext)
 		})
 
-		generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
-		workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
-
-		excludes := bazelArtifacts()
-
-		if outDir[0] != '/' {
-			excludes = append(excludes, outDir)
-		}
-
-		existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
-			os.Exit(1)
-		}
-
-		pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(configuration.Bp2buildPackageConfig, topDir, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
-		excludes = append(excludes, pathsToIgnoredBuildFiles...)
-
-		excludes = append(excludes, getTemporaryExcludes()...)
-
-		// PlantSymlinkForest() returns all the directories that were readdir()'ed.
-		// Such a directory SHOULD be added to `ninjaDeps` so that a child directory
-		// or file created/deleted under it would trigger an update of the symlink
-		// forest.
-		eventHandler.Do("symlink_forest", func() {
-			symlinkForestDeps := bp2build.PlantSymlinkForest(
-				configuration, topDir, workspaceRoot, generatedRoot, ".", excludes)
-			ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
-		})
-
 		ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
 
 		writeDepFile(bp2buildMarker, eventHandler, ninjaDeps)
-
-		// Create an empty bp2build marker file.
 		touch(shared.JoinPath(topDir, bp2buildMarker))
 	})
 
@@ -678,24 +715,32 @@
 	if configuration.IsEnvTrue("BP2BUILD_VERBOSE") {
 		codegenMetrics.Print()
 	}
-	writeBp2BuildMetrics(&codegenMetrics, configuration, eventHandler)
+	writeBp2BuildMetrics(codegenMetrics, eventHandler, metricsDir)
 }
 
 // Write Bp2Build metrics into $LOG_DIR
-func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics,
-	configuration android.Config, eventHandler metrics.EventHandler) {
+func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics, eventHandler *metrics.EventHandler, metricsDir string) {
 	for _, event := range eventHandler.CompletedEvents() {
-		codegenMetrics.Events = append(codegenMetrics.Events,
-			&bp2build_metrics_proto.Event{
-				Name:      event.Id,
-				StartTime: uint64(event.Start.UnixNano()),
-				RealTime:  event.RuntimeNanoseconds(),
-			})
+		codegenMetrics.AddEvent(&bp2build_metrics_proto.Event{
+			Name:      event.Id,
+			StartTime: uint64(event.Start.UnixNano()),
+			RealTime:  event.RuntimeNanoseconds(),
+		})
 	}
-	metricsDir := configuration.Getenv("LOG_DIR")
 	if len(metricsDir) < 1 {
 		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating bp2build metrics: LOG_DIR\n")
 		os.Exit(1)
 	}
 	codegenMetrics.Write(metricsDir)
 }
+
+func readBazelPaths(configuration android.Config) ([]string, error) {
+	depsPath := configuration.Getenv("BAZEL_DEPS_FILE")
+
+	data, err := os.ReadFile(depsPath)
+	if err != nil {
+		return nil, err
+	}
+	paths := strings.Split(strings.TrimSpace(string(data)), "\n")
+	return paths, nil
+}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index b06e4fe..19166d2 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -132,8 +132,13 @@
 		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"),
 		build.OsEnvironment().IsEnvTrue("SOONG_UI_ANSI_OUTPUT"))
 
+	// Create and start a new metric record.
+	met := metrics.New()
+	met.SetBuildDateTime(buildStarted)
+	met.SetBuildCommand(os.Args)
+
 	// Attach a new logger instance to the terminal output.
-	log := logger.New(output)
+	log := logger.NewWithMetrics(output, met)
 	defer log.Cleanup()
 
 	// Create a context to simplify the program termination process.
@@ -144,11 +149,6 @@
 	trace := tracer.New(log)
 	defer trace.Close()
 
-	// Create and start a new metric record.
-	met := metrics.New()
-	met.SetBuildDateTime(buildStarted)
-	met.SetBuildCommand(os.Args)
-
 	// Create a new Status instance, which manages action counts and event output channels.
 	stat := &status.Status{}
 	defer stat.Finish()
@@ -281,7 +281,7 @@
 
 	if flags.NArg() != 1 {
 		flags.Usage()
-		os.Exit(1)
+		ctx.Fatalf("Invalid usage")
 	}
 
 	varName := flags.Arg(0)
@@ -341,7 +341,7 @@
 
 	if flags.NArg() != 0 {
 		flags.Usage()
-		os.Exit(1)
+		ctx.Fatalf("Invalid usage")
 	}
 
 	vars := strings.Fields(*varsStr)
@@ -502,7 +502,7 @@
 		fmt.Fprintln(writer, "!")
 		fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
 		fmt.Fprintln(writer, "")
-		ctx.Fatal("done")
+		ctx.Fatal("Invalid argument")
 	}
 
 	if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
@@ -513,7 +513,7 @@
 		fmt.Fprintln(writer, "!")
 		fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
 		fmt.Fprintln(writer, "")
-		ctx.Fatal("done")
+		ctx.Fatal("Invalid environment")
 	}
 
 	build.Build(ctx, config)
diff --git a/compliance/build_license_metadata/build_license_metadata.go b/compliance/build_license_metadata/build_license_metadata.go
index 53d2407..fb4b784 100644
--- a/compliance/build_license_metadata/build_license_metadata.go
+++ b/compliance/build_license_metadata/build_license_metadata.go
@@ -66,6 +66,7 @@
 
 	packageName := flags.String("p", "", "license package name")
 	moduleType := newMultiString(flags, "mt", "module type")
+	moduleName := flags.String("mn", "", "module name")
 	kinds := newMultiString(flags, "k", "license kinds")
 	moduleClass := newMultiString(flags, "mc", "module class")
 	conditions := newMultiString(flags, "c", "license conditions")
@@ -83,6 +84,7 @@
 
 	metadata := license_metadata_proto.LicenseMetadata{}
 	metadata.PackageName = proto.String(*packageName)
+	metadata.ModuleName = proto.String(*moduleName)
 	metadata.ModuleTypes = *moduleType
 	metadata.ModuleClasses = *moduleClass
 	metadata.IsContainer = proto.Bool(*isContainer)
diff --git a/compliance/license_metadata_proto/license_metadata.pb.go b/compliance/license_metadata_proto/license_metadata.pb.go
index 44dbc78..69aa377 100644
--- a/compliance/license_metadata_proto/license_metadata.pb.go
+++ b/compliance/license_metadata_proto/license_metadata.pb.go
@@ -14,8 +14,8 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.27.1
-// 	protoc        v3.19.0
+// 	protoc-gen-go v1.28.0
+// 	protoc        v3.12.4
 // source: license_metadata.proto
 
 package license_metadata_proto
@@ -40,7 +40,9 @@
 	unknownFields protoimpl.UnknownFields
 
 	// package_name identifies the source package. License texts are named relative to the package name.
-	PackageName   *string  `protobuf:"bytes,1,opt,name=package_name,json=packageName" json:"package_name,omitempty"`
+	PackageName *string `protobuf:"bytes,1,opt,name=package_name,json=packageName" json:"package_name,omitempty"`
+	// module_name identifies the target
+	ModuleName    *string  `protobuf:"bytes,14,opt,name=module_name,json=moduleName" json:"module_name,omitempty"`
 	ModuleTypes   []string `protobuf:"bytes,2,rep,name=module_types,json=moduleTypes" json:"module_types,omitempty"`
 	ModuleClasses []string `protobuf:"bytes,3,rep,name=module_classes,json=moduleClasses" json:"module_classes,omitempty"`
 	// projects identifies the git project(s) containing the associated source code.
@@ -104,6 +106,13 @@
 	return ""
 }
 
+func (x *LicenseMetadata) GetModuleName() string {
+	if x != nil && x.ModuleName != nil {
+		return *x.ModuleName
+	}
+	return ""
+}
+
 func (x *LicenseMetadata) GetModuleTypes() []string {
 	if x != nil {
 		return x.ModuleTypes
@@ -311,52 +320,54 @@
 	0x0a, 0x16, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
 	0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
 	0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
-	0x22, 0x8a, 0x04, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61,
+	0x22, 0xab, 0x04, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61,
 	0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f,
 	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b,
-	0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d,
-	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03,
-	0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65,
-	0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a,
-	0x0d, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x05,
-	0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4b, 0x69, 0x6e,
-	0x64, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f,
-	0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11,
-	0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
-	0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x65, 0x78,
-	0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73,
-	0x65, 0x54, 0x65, 0x78, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6e,
-	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73,
-	0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x69,
-	0x6c, 0x74, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x12,
-	0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x03,
-	0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x43, 0x0a,
-	0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x0b, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x63, 0x65, 0x6e,
-	0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x49, 0x6e, 0x73, 0x74,
-	0x61, 0x6c, 0x6c, 0x4d, 0x61, 0x70, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4d,
-	0x61, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x0c, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x04,
-	0x64, 0x65, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x62, 0x75, 0x69,
-	0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64,
-	0x61, 0x74, 0x61, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65, 0x70,
-	0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73, 0x22, 0x50, 0x0a,
-	0x0a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4d, 0x61, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x66,
-	0x72, 0x6f, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
-	0x66, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74,
-	0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x61, 0x74, 0x68, 0x22,
-	0x4b, 0x0a, 0x13, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65, 0x70, 0x65,
-	0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6e,
-	0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
-	0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x31, 0x5a, 0x2f,
-	0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6f,
-	0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65,
-	0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
+	0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f,
+	0x64, 0x75, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b,
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73,
+	0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23,
+	0x0a, 0x0d, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18,
+	0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4b, 0x69,
+	0x6e, 0x64, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x63,
+	0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52,
+	0x11, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x65,
+	0x78, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e,
+	0x73, 0x65, 0x54, 0x65, 0x78, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x63, 0x6f,
+	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69,
+	0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75,
+	0x69, 0x6c, 0x74, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x62, 0x75, 0x69, 0x6c, 0x74,
+	0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x0a, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x43,
+	0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x0b, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x63, 0x65,
+	0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x49, 0x6e, 0x73,
+	0x74, 0x61, 0x6c, 0x6c, 0x4d, 0x61, 0x70, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c,
+	0x4d, 0x61, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x0c,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3f, 0x0a,
+	0x04, 0x64, 0x65, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x62, 0x75,
+	0x69, 0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61,
+	0x64, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65,
+	0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73, 0x22, 0x50,
+	0x0a, 0x0a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4d, 0x61, 0x70, 0x12, 0x1b, 0x0a, 0x09,
+	0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x66, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e,
+	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x61, 0x74, 0x68,
+	0x22, 0x4b, 0x0a, 0x13, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65, 0x70,
+	0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61,
+	0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x31, 0x5a,
+	0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63,
+	0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73,
+	0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 }
 
 var (
diff --git a/compliance/license_metadata_proto/license_metadata.proto b/compliance/license_metadata_proto/license_metadata.proto
index 1b4f34f..61f8126 100644
--- a/compliance/license_metadata_proto/license_metadata.proto
+++ b/compliance/license_metadata_proto/license_metadata.proto
@@ -21,6 +21,9 @@
   // package_name identifies the source package. License texts are named relative to the package name.
   optional string package_name = 1;
 
+  // module_name identifies the target
+  optional string module_name = 14;
+
   repeated string module_types = 2;
 
   repeated string module_classes = 3;
@@ -54,6 +57,9 @@
 
   // deps lists the license metadata files depended on.
   repeated AnnotatedDependency deps = 13;
+
+  // next id: 15
+
 }
 
 // InstallMap messages describe the mapping from an input filesystem file to the path to the file
diff --git a/compliance/project_metadata_proto/Android.bp b/compliance/project_metadata_proto/Android.bp
new file mode 100644
index 0000000..56e76e7
--- /dev/null
+++ b/compliance/project_metadata_proto/Android.bp
@@ -0,0 +1,27 @@
+// 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: "project_metadata_proto",
+    pkgPath: "android/soong/compliance/project_metadata_proto",
+    srcs: ["project_metadata.pb.go"],
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+}
diff --git a/compliance/project_metadata_proto/project_metadata.pb.go b/compliance/project_metadata_proto/project_metadata.pb.go
new file mode 100644
index 0000000..529159c
--- /dev/null
+++ b/compliance/project_metadata_proto/project_metadata.pb.go
@@ -0,0 +1,765 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A proto definition used to parse METADATA file in third party projects.
+
+// This proto will only contain fields and values used by android compliance.
+// It is not intended to be the formal definition of METADATA file.
+
+// See google3/third_party/metadata.proto if you need to add more stuff to
+// match upstream. Do not add new fields and values here. Add them upstream
+// when necessary, and copy them here.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.0
+// 	protoc        v3.12.4
+// source: project_metadata.proto
+
+package project_metadata_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// License type that identifies how the packages may be used. See
+// go/thirdpartylicenses for full explanation of each license type.
+type LicenseType int32
+
+const (
+	LicenseType_BY_EXCEPTION_ONLY               LicenseType = 1
+	LicenseType_NOTICE                          LicenseType = 2
+	LicenseType_PERMISSIVE                      LicenseType = 3
+	LicenseType_RECIPROCAL                      LicenseType = 4
+	LicenseType_RESTRICTED_IF_STATICALLY_LINKED LicenseType = 5
+	LicenseType_RESTRICTED                      LicenseType = 6
+	LicenseType_UNENCUMBERED                    LicenseType = 7
+)
+
+// Enum value maps for LicenseType.
+var (
+	LicenseType_name = map[int32]string{
+		1: "BY_EXCEPTION_ONLY",
+		2: "NOTICE",
+		3: "PERMISSIVE",
+		4: "RECIPROCAL",
+		5: "RESTRICTED_IF_STATICALLY_LINKED",
+		6: "RESTRICTED",
+		7: "UNENCUMBERED",
+	}
+	LicenseType_value = map[string]int32{
+		"BY_EXCEPTION_ONLY":               1,
+		"NOTICE":                          2,
+		"PERMISSIVE":                      3,
+		"RECIPROCAL":                      4,
+		"RESTRICTED_IF_STATICALLY_LINKED": 5,
+		"RESTRICTED":                      6,
+		"UNENCUMBERED":                    7,
+	}
+)
+
+func (x LicenseType) Enum() *LicenseType {
+	p := new(LicenseType)
+	*p = x
+	return p
+}
+
+func (x LicenseType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (LicenseType) Descriptor() protoreflect.EnumDescriptor {
+	return file_project_metadata_proto_enumTypes[0].Descriptor()
+}
+
+func (LicenseType) Type() protoreflect.EnumType {
+	return &file_project_metadata_proto_enumTypes[0]
+}
+
+func (x LicenseType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *LicenseType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = LicenseType(num)
+	return nil
+}
+
+// Deprecated: Use LicenseType.Descriptor instead.
+func (LicenseType) EnumDescriptor() ([]byte, []int) {
+	return file_project_metadata_proto_rawDescGZIP(), []int{0}
+}
+
+type URL_Type int32
+
+const (
+	// The homepage for the package. For example, "https://bazel.io/". This URL
+	// is optional, but encouraged to help disambiguate similarly named packages
+	// or to get more information about the package. This is especially helpful
+	// when no other URLs provide human readable resources (such as git:// or
+	// sso:// URLs).
+	URL_HOMEPAGE URL_Type = 1
+	// The URL of the archive containing the source code for the package, for
+	// example a zip or tgz file.
+	URL_ARCHIVE URL_Type = 2
+	// The URL of the upstream git repository this package is retrieved from.
+	// For example:
+	//   - https://github.com/git/git.git
+	//   - git://git.kernel.org/pub/scm/git/git.git
+	//
+	// Use of a git URL requires that the package "version" value must specify a
+	// specific git tag or revision.
+	URL_GIT URL_Type = 3
+	// The URL of the upstream SVN repository this package is retrieved from.
+	// For example:
+	//   - http://llvm.org/svn/llvm-project/llvm/
+	//
+	// Use of an SVN URL requires that the package "version" value must specify
+	// a specific SVN tag or revision.
+	URL_SVN URL_Type = 7
+	// The URL of the upstream mercurial repository this package is retrieved
+	// from. For example:
+	//   - https://mercurial-scm.org/repo/evolve
+	//
+	// Use of a mercurial URL requires that the package "version" value must
+	// specify a specific tag or revision.
+	URL_HG URL_Type = 8
+	// The URL of the upstream darcs repository this package is retrieved
+	// from. For example:
+	//   - https://hub.darcs.net/hu.dwim/hu.dwim.util
+	//
+	// Use of a DARCS URL requires that the package "version" value must
+	// specify a specific tag or revision.
+	URL_DARCS URL_Type = 9
+	// The URL of the upstream piper location.  This is primarily used when a
+	// package is being migrated into third_party from elsewhere in piper, or
+	// when a package is being newly developed in third_party.  For newly
+	// developed packages, the PIPER URL should reference the package itself
+	// (e.g. "http://google3/third_party/my/package")
+	URL_PIPER URL_Type = 4
+	// A URL that does not fit any other type. This may also indicate that the
+	// source code was received via email or some other out-of-band way. This is
+	// most commonly used with commercial software received directly from the
+	// vendor. In the case of email, the URL value can be used to provide
+	// additional information about how it was received.
+	URL_OTHER URL_Type = 11
+	// The URL identifying where the local copy of the package source code can
+	// be found.
+	//
+	// Typically, the metadata files describing a package reside in the same
+	// directory as the source code for the package. In a few rare cases where
+	// they are separate, the LOCAL_SOURCE URL identifies where to find the
+	// source code. This only describes where to find the local copy of the
+	// source; there should always be an additional URL describing where the
+	// package was retrieved from.
+	//
+	// Examples:
+	//   - http://google3/third_party/java_src/gerritcodereview/gerrit/
+	//   - https://android.googlesource.com/platform/external/apache-http/
+	URL_LOCAL_SOURCE URL_Type = 6
+)
+
+// Enum value maps for URL_Type.
+var (
+	URL_Type_name = map[int32]string{
+		1:  "HOMEPAGE",
+		2:  "ARCHIVE",
+		3:  "GIT",
+		7:  "SVN",
+		8:  "HG",
+		9:  "DARCS",
+		4:  "PIPER",
+		11: "OTHER",
+		6:  "LOCAL_SOURCE",
+	}
+	URL_Type_value = map[string]int32{
+		"HOMEPAGE":     1,
+		"ARCHIVE":      2,
+		"GIT":          3,
+		"SVN":          7,
+		"HG":           8,
+		"DARCS":        9,
+		"PIPER":        4,
+		"OTHER":        11,
+		"LOCAL_SOURCE": 6,
+	}
+)
+
+func (x URL_Type) Enum() *URL_Type {
+	p := new(URL_Type)
+	*p = x
+	return p
+}
+
+func (x URL_Type) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (URL_Type) Descriptor() protoreflect.EnumDescriptor {
+	return file_project_metadata_proto_enumTypes[1].Descriptor()
+}
+
+func (URL_Type) Type() protoreflect.EnumType {
+	return &file_project_metadata_proto_enumTypes[1]
+}
+
+func (x URL_Type) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *URL_Type) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = URL_Type(num)
+	return nil
+}
+
+// Deprecated: Use URL_Type.Descriptor instead.
+func (URL_Type) EnumDescriptor() ([]byte, []int) {
+	return file_project_metadata_proto_rawDescGZIP(), []int{2, 0}
+}
+
+type Metadata struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Name of this API/package.
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// A short description (a few lines) of the package. It will be
+	// included on the summary page.
+	// Example: "Handles location lookups, throttling, batching, etc."
+	Description *string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
+	// Specifies additional data about third-party packages.
+	ThirdParty *ThirdParty `protobuf:"bytes,13,opt,name=third_party,json=thirdParty" json:"third_party,omitempty"`
+}
+
+func (x *Metadata) Reset() {
+	*x = Metadata{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_project_metadata_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Metadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Metadata) ProtoMessage() {}
+
+func (x *Metadata) ProtoReflect() protoreflect.Message {
+	mi := &file_project_metadata_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Metadata.ProtoReflect.Descriptor instead.
+func (*Metadata) Descriptor() ([]byte, []int) {
+	return file_project_metadata_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Metadata) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *Metadata) GetDescription() string {
+	if x != nil && x.Description != nil {
+		return *x.Description
+	}
+	return ""
+}
+
+func (x *Metadata) GetThirdParty() *ThirdParty {
+	if x != nil {
+		return x.ThirdParty
+	}
+	return nil
+}
+
+type ThirdParty struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// URL(s) associated with the package.
+	//
+	// At a minimum, all packages must specify a URL which identifies where it
+	// came from, containing a type of: ARCHIVE, GIT, PIPER, or OTHER. Typically,
+	// a package should contain only a single URL from these types.  Occasionally,
+	// a package may be broken across multiple archive files for whatever reason,
+	// in which case having multiple ARCHIVE URLs is okay.  However, this should
+	// not be used to combine different logical packages that are versioned and
+	// possibly licensed differently.
+	Url []*URL `protobuf:"bytes,1,rep,name=url" json:"url,omitempty"`
+	// The package version.  In order of preference, this should contain:
+	//   - If the package comes from Git or another source control system,
+	//     a specific tag or revision in source control, such as "r123" or
+	//     "58e27d2".  This MUST NOT be a mutable ref such as a branch name.
+	//   - a released package version such as "1.0", "2.3-beta", etc.
+	//   - the date the package was retrieved, formatted as "As of YYYY-MM-DD".
+	Version *string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"`
+	// The date of the change in which the package was last upgraded from
+	// upstream.
+	// This should only identify package upgrades from upstream, not local
+	// modifications. This may identify the date of either the original or
+	// merged change.
+	//
+	// Note: this is NOT the date that this version of the package was released
+	// externally.
+	LastUpgradeDate *Date `protobuf:"bytes,10,opt,name=last_upgrade_date,json=lastUpgradeDate" json:"last_upgrade_date,omitempty"`
+	// License type that identifies how the package may be used. See
+	// go/thirdpartylicenses for instructions on selecting the appropriate type.
+	LicenseType *LicenseType `protobuf:"varint,4,opt,name=license_type,json=licenseType,enum=project_metadata.LicenseType" json:"license_type,omitempty"`
+	// Description of local changes that have been made to the package.  This does
+	// not need to (and in most cases should not) attempt to include an exhaustive
+	// list of all changes, but may instead direct readers to review the local
+	// commit history, a collection of patch files, a separate README.md (or
+	// similar) document, etc.
+	// Note: Use of this field to store IDs of advisories fixed with a backported
+	// patch is deprecated, use "security.mitigated_security_patch" instead.
+	LocalModifications *string `protobuf:"bytes,6,opt,name=local_modifications,json=localModifications" json:"local_modifications,omitempty"`
+	// The URL for any public mirror created for compliance purposes.
+	// See go/thirdpartylicenses#reciprocal policy for more details.
+	ComplianceMirrorUrl *string `protobuf:"bytes,12,opt,name=compliance_mirror_url,json=complianceMirrorUrl" json:"compliance_mirror_url,omitempty"`
+	// The homepage for the package. This will eventually replace
+	// `url { type: HOMEPAGE }`
+	Homepage *string `protobuf:"bytes,14,opt,name=homepage" json:"homepage,omitempty"`
+}
+
+func (x *ThirdParty) Reset() {
+	*x = ThirdParty{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_project_metadata_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ThirdParty) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ThirdParty) ProtoMessage() {}
+
+func (x *ThirdParty) ProtoReflect() protoreflect.Message {
+	mi := &file_project_metadata_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ThirdParty.ProtoReflect.Descriptor instead.
+func (*ThirdParty) Descriptor() ([]byte, []int) {
+	return file_project_metadata_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ThirdParty) GetUrl() []*URL {
+	if x != nil {
+		return x.Url
+	}
+	return nil
+}
+
+func (x *ThirdParty) GetVersion() string {
+	if x != nil && x.Version != nil {
+		return *x.Version
+	}
+	return ""
+}
+
+func (x *ThirdParty) GetLastUpgradeDate() *Date {
+	if x != nil {
+		return x.LastUpgradeDate
+	}
+	return nil
+}
+
+func (x *ThirdParty) GetLicenseType() LicenseType {
+	if x != nil && x.LicenseType != nil {
+		return *x.LicenseType
+	}
+	return LicenseType_BY_EXCEPTION_ONLY
+}
+
+func (x *ThirdParty) GetLocalModifications() string {
+	if x != nil && x.LocalModifications != nil {
+		return *x.LocalModifications
+	}
+	return ""
+}
+
+func (x *ThirdParty) GetComplianceMirrorUrl() string {
+	if x != nil && x.ComplianceMirrorUrl != nil {
+		return *x.ComplianceMirrorUrl
+	}
+	return ""
+}
+
+func (x *ThirdParty) GetHomepage() string {
+	if x != nil && x.Homepage != nil {
+		return *x.Homepage
+	}
+	return ""
+}
+
+// URL associated with a third-party package.
+type URL struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The type of resource this URL identifies.
+	Type *URL_Type `protobuf:"varint,1,opt,name=type,enum=project_metadata.URL_Type" json:"type,omitempty"`
+	// The actual URL value.  URLs should be absolute and start with 'http://' or
+	// 'https://' (or occasionally 'git://' or 'ftp://' where appropriate).
+	Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
+}
+
+func (x *URL) Reset() {
+	*x = URL{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_project_metadata_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *URL) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*URL) ProtoMessage() {}
+
+func (x *URL) ProtoReflect() protoreflect.Message {
+	mi := &file_project_metadata_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use URL.ProtoReflect.Descriptor instead.
+func (*URL) Descriptor() ([]byte, []int) {
+	return file_project_metadata_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *URL) GetType() URL_Type {
+	if x != nil && x.Type != nil {
+		return *x.Type
+	}
+	return URL_HOMEPAGE
+}
+
+func (x *URL) GetValue() string {
+	if x != nil && x.Value != nil {
+		return *x.Value
+	}
+	return ""
+}
+
+// Represents a whole or partial calendar date, such as a birthday. The time of
+// day and time zone are either specified elsewhere or are insignificant. The
+// date is relative to the Gregorian Calendar. This can represent one of the
+// following:
+//
+//   - A full date, with non-zero year, month, and day values.
+//   - A month and day, with a zero year (for example, an anniversary).
+//   - A year on its own, with a zero month and a zero day.
+//   - A year and month, with a zero day (for example, a credit card expiration
+//     date).
+type Date struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Year of the date. Must be from 1 to 9999, or 0 to specify a date without
+	// a year.
+	Year *int32 `protobuf:"varint,1,opt,name=year" json:"year,omitempty"`
+	// Month of a year. Must be from 1 to 12, or 0 to specify a year without a
+	// month and day.
+	Month *int32 `protobuf:"varint,2,opt,name=month" json:"month,omitempty"`
+	// Day of a month. Must be from 1 to 31 and valid for the year and month, or 0
+	// to specify a year by itself or a year and month where the day isn't
+	// significant.
+	Day *int32 `protobuf:"varint,3,opt,name=day" json:"day,omitempty"`
+}
+
+func (x *Date) Reset() {
+	*x = Date{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_project_metadata_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Date) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Date) ProtoMessage() {}
+
+func (x *Date) ProtoReflect() protoreflect.Message {
+	mi := &file_project_metadata_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Date.ProtoReflect.Descriptor instead.
+func (*Date) Descriptor() ([]byte, []int) {
+	return file_project_metadata_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Date) GetYear() int32 {
+	if x != nil && x.Year != nil {
+		return *x.Year
+	}
+	return 0
+}
+
+func (x *Date) GetMonth() int32 {
+	if x != nil && x.Month != nil {
+		return *x.Month
+	}
+	return 0
+}
+
+func (x *Date) GetDay() int32 {
+	if x != nil && x.Day != nil {
+		return *x.Day
+	}
+	return 0
+}
+
+var File_project_metadata_proto protoreflect.FileDescriptor
+
+var file_project_metadata_proto_rawDesc = []byte{
+	0x0a, 0x16, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+	0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+	0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7f, 0x0a, 0x08, 0x4d, 0x65,
+	0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x0b,
+	0x74, 0x68, 0x69, 0x72, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61,
+	0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x52,
+	0x0a, 0x74, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x22, 0xd6, 0x02, 0x0a, 0x0a,
+	0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x12, 0x27, 0x0a, 0x03, 0x75, 0x72,
+	0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+	0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x55, 0x52, 0x4c, 0x52, 0x03,
+	0x75, 0x72, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a,
+	0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x5f, 0x64, 0x61,
+	0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+	0x63, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x65,
+	0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x44, 0x61, 0x74,
+	0x65, 0x12, 0x40, 0x0a, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70,
+	0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+	0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e,
+	0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54,
+	0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x6f, 0x64,
+	0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e,
+	0x63, 0x65, 0x5f, 0x6d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0c, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x4d,
+	0x69, 0x72, 0x72, 0x6f, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x6d, 0x65,
+	0x70, 0x61, 0x67, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x6d, 0x65,
+	0x70, 0x61, 0x67, 0x65, 0x22, 0xbb, 0x01, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x2e, 0x0a, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f,
+	0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x55, 0x52,
+	0x4c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x22, 0x6e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x48, 0x4f,
+	0x4d, 0x45, 0x50, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x52, 0x43, 0x48,
+	0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x54, 0x10, 0x03, 0x12, 0x07,
+	0x0a, 0x03, 0x53, 0x56, 0x4e, 0x10, 0x07, 0x12, 0x06, 0x0a, 0x02, 0x48, 0x47, 0x10, 0x08, 0x12,
+	0x09, 0x0a, 0x05, 0x44, 0x41, 0x52, 0x43, 0x53, 0x10, 0x09, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x49,
+	0x50, 0x45, 0x52, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x0b,
+	0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45,
+	0x10, 0x06, 0x22, 0x42, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65,
+	0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x14,
+	0x0a, 0x05, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6d,
+	0x6f, 0x6e, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x05, 0x52, 0x03, 0x64, 0x61, 0x79, 0x2a, 0x97, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e,
+	0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x42, 0x59, 0x5f, 0x45, 0x58, 0x43,
+	0x45, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x12, 0x0a, 0x0a,
+	0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52,
+	0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43,
+	0x49, 0x50, 0x52, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x53,
+	0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x49,
+	0x43, 0x41, 0x4c, 0x4c, 0x59, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x10, 0x05, 0x12, 0x0e,
+	0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x06, 0x12, 0x10,
+	0x0a, 0x0c, 0x55, 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x45, 0x44, 0x10, 0x07,
+	0x42, 0x31, 0x5a, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e,
+	0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f,
+	0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_project_metadata_proto_rawDescOnce sync.Once
+	file_project_metadata_proto_rawDescData = file_project_metadata_proto_rawDesc
+)
+
+func file_project_metadata_proto_rawDescGZIP() []byte {
+	file_project_metadata_proto_rawDescOnce.Do(func() {
+		file_project_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_project_metadata_proto_rawDescData)
+	})
+	return file_project_metadata_proto_rawDescData
+}
+
+var file_project_metadata_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_project_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_project_metadata_proto_goTypes = []interface{}{
+	(LicenseType)(0),   // 0: project_metadata.LicenseType
+	(URL_Type)(0),      // 1: project_metadata.URL.Type
+	(*Metadata)(nil),   // 2: project_metadata.Metadata
+	(*ThirdParty)(nil), // 3: project_metadata.ThirdParty
+	(*URL)(nil),        // 4: project_metadata.URL
+	(*Date)(nil),       // 5: project_metadata.Date
+}
+var file_project_metadata_proto_depIdxs = []int32{
+	3, // 0: project_metadata.Metadata.third_party:type_name -> project_metadata.ThirdParty
+	4, // 1: project_metadata.ThirdParty.url:type_name -> project_metadata.URL
+	5, // 2: project_metadata.ThirdParty.last_upgrade_date:type_name -> project_metadata.Date
+	0, // 3: project_metadata.ThirdParty.license_type:type_name -> project_metadata.LicenseType
+	1, // 4: project_metadata.URL.type:type_name -> project_metadata.URL.Type
+	5, // [5:5] is the sub-list for method output_type
+	5, // [5:5] is the sub-list for method input_type
+	5, // [5:5] is the sub-list for extension type_name
+	5, // [5:5] is the sub-list for extension extendee
+	0, // [0:5] is the sub-list for field type_name
+}
+
+func init() { file_project_metadata_proto_init() }
+func file_project_metadata_proto_init() {
+	if File_project_metadata_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_project_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Metadata); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_project_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ThirdParty); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_project_metadata_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*URL); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_project_metadata_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Date); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_project_metadata_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_project_metadata_proto_goTypes,
+		DependencyIndexes: file_project_metadata_proto_depIdxs,
+		EnumInfos:         file_project_metadata_proto_enumTypes,
+		MessageInfos:      file_project_metadata_proto_msgTypes,
+	}.Build()
+	File_project_metadata_proto = out.File
+	file_project_metadata_proto_rawDesc = nil
+	file_project_metadata_proto_goTypes = nil
+	file_project_metadata_proto_depIdxs = nil
+}
diff --git a/compliance/project_metadata_proto/project_metadata.proto b/compliance/project_metadata_proto/project_metadata.proto
new file mode 100644
index 0000000..94cc516
--- /dev/null
+++ b/compliance/project_metadata_proto/project_metadata.proto
@@ -0,0 +1,225 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A proto definition used to parse METADATA file in third party projects.
+
+// This proto will only contain fields and values used by android compliance.
+// It is not intended to be the formal definition of METADATA file.
+
+// See google3/third_party/metadata.proto if you need to add more stuff to
+// match upstream. Do not add new fields and values here. Add them upstream
+// when necessary, and copy them here.
+
+syntax = "proto2"; // As long as upstream is proto2...
+
+package project_metadata;
+option go_package = "android/soong/compliance/project_metadata_proto";
+
+// Definitions for project metadata. (go/thirdparty/metadata)
+
+// Special naming conventions:
+// Repeated fields should have singular names (instead of plural).
+
+message Metadata {
+  // Name of this API/package.
+  optional string name = 1;
+
+  // A short description (a few lines) of the package. It will be
+  // included on the summary page.
+  // Example: "Handles location lookups, throttling, batching, etc."
+  optional string description = 3;
+
+  // Specifies additional data about third-party packages.
+  optional ThirdParty third_party = 13;
+}
+
+message ThirdParty {
+  // The name and description for the package should be specified using the top
+  // level fields in MetaData above
+  //
+  // Description should only specify a short description (a few lines) of the
+  // packages. Instructions for maintainers or similar information should be
+  // specified in BUILD comments, a separate README.md file, etc.
+
+  // URL(s) associated with the package.
+  //
+  // At a minimum, all packages must specify a URL which identifies where it
+  // came from, containing a type of: ARCHIVE, GIT, PIPER, or OTHER. Typically,
+  // a package should contain only a single URL from these types.  Occasionally,
+  // a package may be broken across multiple archive files for whatever reason,
+  // in which case having multiple ARCHIVE URLs is okay.  However, this should
+  // not be used to combine different logical packages that are versioned and
+  // possibly licensed differently.
+  repeated URL url = 1;
+
+  // The package version.  In order of preference, this should contain:
+  //  - If the package comes from Git or another source control system,
+  //    a specific tag or revision in source control, such as "r123" or
+  //    "58e27d2".  This MUST NOT be a mutable ref such as a branch name.
+  //  - a released package version such as "1.0", "2.3-beta", etc.
+  //  - the date the package was retrieved, formatted as "As of YYYY-MM-DD".
+  optional string version = 2;
+
+  // The date of the change in which the package was last upgraded from
+  // upstream.
+  // This should only identify package upgrades from upstream, not local
+  // modifications. This may identify the date of either the original or
+  // merged change.
+  //
+  // Note: this is NOT the date that this version of the package was released
+  // externally.
+  optional Date last_upgrade_date = 10;
+
+  // License type that identifies how the package may be used. See
+  // go/thirdpartylicenses for instructions on selecting the appropriate type.
+  optional LicenseType license_type = 4;
+
+  // Description of local changes that have been made to the package.  This does
+  // not need to (and in most cases should not) attempt to include an exhaustive
+  // list of all changes, but may instead direct readers to review the local
+  // commit history, a collection of patch files, a separate README.md (or
+  // similar) document, etc.
+  // Note: Use of this field to store IDs of advisories fixed with a backported
+  // patch is deprecated, use "security.mitigated_security_patch" instead.
+  optional string local_modifications = 6;
+
+  // The URL for any public mirror created for compliance purposes.
+  // See go/thirdpartylicenses#reciprocal policy for more details.
+  optional string compliance_mirror_url = 12;
+
+  // The homepage for the package. This will eventually replace
+  // `url { type: HOMEPAGE }`
+  optional string homepage = 14;
+}
+
+// URL associated with a third-party package.
+message URL {
+  enum Type {
+    // The homepage for the package. For example, "https://bazel.io/". This URL
+    // is optional, but encouraged to help disambiguate similarly named packages
+    // or to get more information about the package. This is especially helpful
+    // when no other URLs provide human readable resources (such as git:// or
+    // sso:// URLs).
+    HOMEPAGE = 1;
+
+    // The URL of the archive containing the source code for the package, for
+    // example a zip or tgz file.
+    ARCHIVE = 2;
+
+    // The URL of the upstream git repository this package is retrieved from.
+    // For example:
+    //  - https://github.com/git/git.git
+    //  - git://git.kernel.org/pub/scm/git/git.git
+    //
+    // Use of a git URL requires that the package "version" value must specify a
+    // specific git tag or revision.
+    GIT = 3;
+
+    // The URL of the upstream SVN repository this package is retrieved from.
+    // For example:
+    //  - http://llvm.org/svn/llvm-project/llvm/
+    //
+    // Use of an SVN URL requires that the package "version" value must specify
+    // a specific SVN tag or revision.
+    SVN = 7;
+
+    // The URL of the upstream mercurial repository this package is retrieved
+    // from. For example:
+    //   - https://mercurial-scm.org/repo/evolve
+    //
+    // Use of a mercurial URL requires that the package "version" value must
+    // specify a specific tag or revision.
+    HG = 8;
+
+    // The URL of the upstream darcs repository this package is retrieved
+    // from. For example:
+    //   - https://hub.darcs.net/hu.dwim/hu.dwim.util
+    //
+    // Use of a DARCS URL requires that the package "version" value must
+    // specify a specific tag or revision.
+    DARCS = 9;
+
+    // The URL of the upstream piper location.  This is primarily used when a
+    // package is being migrated into third_party from elsewhere in piper, or
+    // when a package is being newly developed in third_party.  For newly
+    // developed packages, the PIPER URL should reference the package itself
+    // (e.g. "http://google3/third_party/my/package")
+    PIPER = 4;
+
+    // A URL that does not fit any other type. This may also indicate that the
+    // source code was received via email or some other out-of-band way. This is
+    // most commonly used with commercial software received directly from the
+    // vendor. In the case of email, the URL value can be used to provide
+    // additional information about how it was received.
+    OTHER = 11;
+
+    // The URL identifying where the local copy of the package source code can
+    // be found.
+    //
+    // Typically, the metadata files describing a package reside in the same
+    // directory as the source code for the package. In a few rare cases where
+    // they are separate, the LOCAL_SOURCE URL identifies where to find the
+    // source code. This only describes where to find the local copy of the
+    // source; there should always be an additional URL describing where the
+    // package was retrieved from.
+    //
+    // Examples:
+    //  - http://google3/third_party/java_src/gerritcodereview/gerrit/
+    //  - https://android.googlesource.com/platform/external/apache-http/
+    LOCAL_SOURCE = 6;
+  }
+
+  // The type of resource this URL identifies.
+  optional Type type = 1;
+
+  // The actual URL value.  URLs should be absolute and start with 'http://' or
+  // 'https://' (or occasionally 'git://' or 'ftp://' where appropriate).
+  optional string value = 2;
+}
+
+// License type that identifies how the packages may be used. See
+// go/thirdpartylicenses for full explanation of each license type.
+enum LicenseType {
+  BY_EXCEPTION_ONLY = 1;
+  NOTICE = 2;
+  PERMISSIVE = 3;
+  RECIPROCAL = 4;
+  RESTRICTED_IF_STATICALLY_LINKED = 5;
+  RESTRICTED = 6;
+  UNENCUMBERED = 7;
+}
+
+
+// Represents a whole or partial calendar date, such as a birthday. The time of
+// day and time zone are either specified elsewhere or are insignificant. The
+// date is relative to the Gregorian Calendar. This can represent one of the
+// following:
+//
+// * A full date, with non-zero year, month, and day values.
+// * A month and day, with a zero year (for example, an anniversary).
+// * A year on its own, with a zero month and a zero day.
+// * A year and month, with a zero day (for example, a credit card expiration
+//   date).
+message Date {
+  // Year of the date. Must be from 1 to 9999, or 0 to specify a date without
+  // a year.
+  optional int32 year = 1;
+  // Month of a year. Must be from 1 to 12, or 0 to specify a year without a
+  // month and day.
+  optional int32 month = 2;
+  // Day of a month. Must be from 1 to 31 and valid for the year and month, or 0
+  // to specify a year by itself or a year and month where the day isn't
+  // significant.
+  optional int32 day = 3;
+}
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index eb248bb..5e5769b 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -151,6 +151,8 @@
 	// If there's a Java fuzzer with JNI, a different version of Jazzer would
 	// need to be added to the fuzzer package than one without JNI
 	IsJni *bool `json:"is_jni,omitempty"`
+	// List of modules for monitoring coverage drops in directories (e.g. "libicu")
+	Target_modules []string `json:"target_modules,omitempty"`
 }
 
 type FuzzFrameworks struct {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index d4ed363..14895c9 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -875,7 +875,7 @@
 
 type genRuleProperties struct {
 	// names of the output files that will be generated
-	Out []string `android:"arch_variant"`
+	Out []string
 }
 
 type bazelGenruleAttributes struct {
@@ -893,11 +893,27 @@
 	tools_prop.Append(tool_files_prop)
 
 	tools := bazel.MakeLabelListAttribute(tools_prop)
-	srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs))
+	srcs := bazel.LabelListAttribute{}
+	srcs_labels := bazel.LabelList{}
+	// Only cc_genrule is arch specific
+	if ctx.ModuleType() == "cc_genrule" {
+		for axis, configToProps := range m.GetArchVariantProperties(ctx, &generatorProperties{}) {
+			for config, props := range configToProps {
+				if props, ok := props.(*generatorProperties); ok {
+					labels := android.BazelLabelForModuleSrcExcludes(ctx, props.Srcs, props.Exclude_srcs)
+					srcs_labels.Append(labels)
+					srcs.SetSelectValue(axis, config, labels)
+				}
+			}
+		}
+	} else {
+		srcs_labels = android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
+		srcs = bazel.MakeLabelListAttribute(srcs_labels)
+	}
 
 	var allReplacements bazel.LabelList
 	allReplacements.Append(tools.Value)
-	allReplacements.Append(srcs.Value)
+	allReplacements.Append(bazel.FirstUniqueBazelLabelList(srcs_labels))
 
 	// Replace in and out variables with $< and $@
 	var cmd string
diff --git a/go.mod b/go.mod
index 8c1a9f0..5f0b91a 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,12 @@
 
 replace github.com/google/go-cmp v0.5.5 => ../../external/go-cmp
 
-// Indirect dep from go-cmp
-exclude golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
+require prebuilts/bazel/common/proto/analysis_v2 v0.0.0
+
+replace prebuilts/bazel/common/proto/analysis_v2 => ../../prebuilts/bazel/common/proto/analysis_v2
+
+require prebuilts/bazel/common/proto/build v0.0.0 // indirect
+
+replace prebuilts/bazel/common/proto/build => ../../prebuilts/bazel/common/proto/build
 
 go 1.18
diff --git a/java/androidmk.go b/java/androidmk.go
index cd86880..42b4ef1 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -139,6 +139,7 @@
 	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 		entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", "null-suite")
 		androidMkWriteTestData(j.jniFilePaths, entries)
+		androidMkWriteTestData(android.Paths{j.implementationJarFile}, entries)
 	})
 	return entriesList
 }
diff --git a/java/app.go b/java/app.go
index bbd9d2d..2a51e10 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1486,22 +1486,8 @@
 	*bazelAapt
 	Deps             bazel.LabelListAttribute
 	Custom_package   *string
-	Certificate      *bazel.Label
-	Certificate_name *string
-}
-
-// ParseCertificateToAttribute splits the certificate prop into a certificate
-// label attribute or a certificate_name string attribute.
-func ParseCertificateToAttribute(ctx android.TopDownMutatorContext, certificate *string) (*string, *bazel.Label) {
-	var certificateLabel *bazel.Label
-	certificateName := proptools.StringDefault(certificate, "")
-	certModule := android.SrcIsModule(certificateName)
-	if certModule != "" {
-		c := android.BazelLabelForModuleDepSingle(ctx, certificateName)
-		certificateLabel = &c
-		certificate = nil
-	}
-	return certificate, certificateLabel
+	Certificate      bazel.LabelAttribute
+	Certificate_name bazel.StringAttribute
 }
 
 // ConvertWithBp2build is used to convert android_app to Bazel.
@@ -1513,7 +1499,8 @@
 
 	aapt := a.convertAaptAttrsWithBp2Build(ctx)
 
-	certificateName, certificate := ParseCertificateToAttribute(ctx, a.overridableAppProperties.Certificate)
+	certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate)
+
 	attrs := &bazelAndroidAppAttributes{
 		commonAttrs,
 		aapt,
diff --git a/java/app_import.go b/java/app_import.go
index 6e603c9..8c1e19c 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -500,7 +500,18 @@
 type AndroidTestImport struct {
 	AndroidAppImport
 
-	testProperties testProperties
+	testProperties struct {
+		// list of compatibility suites (for example "cts", "vts") that the module should be
+		// installed into.
+		Test_suites []string `android:"arch_variant"`
+
+		// list of files or filegroup modules that provide data that should be installed alongside
+		// the test
+		Data []string `android:"path"`
+
+		// Install the test into a folder named for the module in all test suites.
+		Per_testcase_directory *bool
+	}
 
 	testImportProperties androidTestImportProperties
 
diff --git a/java/app_set.go b/java/app_set.go
index d99fadb..d8c2a8d 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -90,9 +90,10 @@
 }
 
 var TargetCpuAbi = map[string]string{
-	"arm":     "ARMEABI_V7A",
-	"arm64":   "ARM64_V8A",
-	"riscv64": "RISCV64",
+	"arm":   "ARMEABI_V7A",
+	"arm64": "ARM64_V8A",
+	// TODO: use "RISCV64" when that is supported in bundles
+	"riscv64": "ARM64_V8A",
 	"x86":     "X86",
 	"x86_64":  "X86_64",
 }
diff --git a/java/base.go b/java/base.go
index bcb7226..602e8d8 100644
--- a/java/base.go
+++ b/java/base.go
@@ -190,7 +190,7 @@
 // constructing a new module.
 type DeviceProperties struct {
 	// If not blank, set to the version of the sdk to compile against.
-	// Defaults to private.
+	// Defaults to an empty string, which compiles the module against the private platform APIs.
 	// Values are of one of the following forms:
 	// 1) numerical API level, "current", "none", or "core_platform"
 	// 2) An SDK kind with an API level: "<sdk kind>_<API level>"
@@ -447,9 +447,11 @@
 	// installed file for hostdex copy
 	hostdexInstallFile android.InstallPath
 
-	// list of .java files and srcjars that was passed to javac
-	compiledJavaSrcs android.Paths
-	compiledSrcJars  android.Paths
+	// list of unique .java and .kt source files
+	uniqueSrcFiles android.Paths
+
+	// list of srcjars that was passed to javac
+	compiledSrcJars android.Paths
 
 	// manifest file to use instead of properties.Manifest
 	overrideManifest android.OptionalPath
@@ -591,6 +593,8 @@
 		return android.Paths{j.outputFile}, nil
 	case ".jar":
 		return android.Paths{j.implementationAndResourcesJar}, nil
+	case ".hjar":
+		return android.Paths{j.headerJarFile}, nil
 	case ".proguard_map":
 		if j.dexer.proguardDictionary.Valid() {
 			return android.Paths{j.dexer.proguardDictionary.Path()}, nil
@@ -1078,15 +1082,26 @@
 
 	jarName := ctx.ModuleName() + ".jar"
 
-	javaSrcFiles := srcFiles.FilterByExt(".java")
-	var uniqueSrcFiles android.Paths
+	var uniqueJavaFiles android.Paths
 	set := make(map[string]bool)
-	for _, v := range javaSrcFiles {
+	for _, v := range srcFiles.FilterByExt(".java") {
 		if _, found := set[v.String()]; !found {
 			set[v.String()] = true
-			uniqueSrcFiles = append(uniqueSrcFiles, v)
+			uniqueJavaFiles = append(uniqueJavaFiles, v)
 		}
 	}
+	var uniqueKtFiles android.Paths
+	for _, v := range srcFiles.FilterByExt(".kt") {
+		if _, found := set[v.String()]; !found {
+			set[v.String()] = true
+			uniqueKtFiles = append(uniqueKtFiles, v)
+		}
+	}
+
+	var uniqueSrcFiles android.Paths
+	uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...)
+	uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...)
+	j.uniqueSrcFiles = uniqueSrcFiles
 
 	// We don't currently run annotation processors in turbine, which means we can't use turbine
 	// generated header jars when an annotation processor that generates API is enabled.  One
@@ -1094,7 +1109,7 @@
 	//  is used to run all of the annotation processors.
 	disableTurbine := deps.disableTurbine
 
-	// Collect .java files for AIDEGen
+	// Collect .java and .kt files for AIDEGen
 	j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...)
 
 	var kotlinJars android.Paths
@@ -1132,12 +1147,7 @@
 			flags.kotlincFlags += "$kotlincFlags"
 		}
 
-		var kotlinSrcFiles android.Paths
-		kotlinSrcFiles = append(kotlinSrcFiles, uniqueSrcFiles...)
-		kotlinSrcFiles = append(kotlinSrcFiles, srcFiles.FilterByExt(".kt")...)
-
-		// Collect .kt files for AIDEGen
-		j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, srcFiles.FilterByExt(".kt").Strings()...)
+		// Collect common .kt files for AIDEGen
 		j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...)
 
 		flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
@@ -1150,7 +1160,7 @@
 			// Use kapt for annotation processing
 			kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar")
 			kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar")
-			kotlinKapt(ctx, kaptSrcJar, kaptResJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
+			kotlinKapt(ctx, kaptSrcJar, kaptResJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
 			srcJars = append(srcJars, kaptSrcJar)
 			kotlinJars = append(kotlinJars, kaptResJar)
 			// Disable annotation processing in javac, it's already been handled by kapt
@@ -1160,7 +1170,7 @@
 
 		kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
 		kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName)
-		kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
+		kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
 		if ctx.Failed() {
 			return
 		}
@@ -1185,8 +1195,6 @@
 
 	jars := append(android.Paths(nil), kotlinJars...)
 
-	// Store the list of .java files that was passed to javac
-	j.compiledJavaSrcs = uniqueSrcFiles
 	j.compiledSrcJars = srcJars
 
 	enableSharding := false
@@ -1201,12 +1209,12 @@
 			// with sharding enabled. See: b/77284273.
 		}
 		headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
-			j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
+			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
 		if ctx.Failed() {
 			return
 		}
 	}
-	if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
+	if len(uniqueJavaFiles) > 0 || len(srcJars) > 0 {
 		hasErrorproneableFiles := false
 		for _, ext := range j.sourceExtensions {
 			if ext != ".proto" && ext != ".aidl" {
@@ -1231,7 +1239,7 @@
 			errorproneFlags := enableErrorproneFlags(flags)
 			errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
 
-			transformJavaToClasses(ctx, errorprone, -1, uniqueSrcFiles, srcJars, errorproneFlags, nil,
+			transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneFlags, nil,
 				"errorprone", "errorprone")
 
 			extraJarDeps = append(extraJarDeps, errorprone)
@@ -1243,8 +1251,8 @@
 			}
 			shardSize := int(*(j.properties.Javac_shard_size))
 			var shardSrcs []android.Paths
-			if len(uniqueSrcFiles) > 0 {
-				shardSrcs = android.ShardPaths(uniqueSrcFiles, shardSize)
+			if len(uniqueJavaFiles) > 0 {
+				shardSrcs = android.ShardPaths(uniqueJavaFiles, shardSize)
 				for idx, shardSrc := range shardSrcs {
 					classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
 						nil, flags, extraJarDeps)
@@ -1257,7 +1265,7 @@
 				jars = append(jars, classes)
 			}
 		} else {
-			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueSrcFiles, srcJars, flags, extraJarDeps)
+			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
 			jars = append(jars, classes)
 		}
 		if ctx.Failed() {
diff --git a/java/builder.go b/java/builder.go
index c0fadd4..b1b9a4a 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -83,9 +83,9 @@
 	_ = pctx.VariableFunc("kytheCuJavaSourceMax",
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuJavaSourceMax() })
 	_ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
-	// Run it with -add-opens=java.base/java.nio=ALL-UNNAMED to avoid JDK9's warning about
-	// "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ...
-	// to field java.nio.Buffer.address"
+	// Run it with several --add-exports to allow the classes in the
+	// com.google.devtools.kythe.extractors.java.standalone package access the packages in the
+	// jdk.compiler compiler module. Long live Java modules.
 	kytheExtract = pctx.AndroidStaticRule("kythe",
 		blueprint.RuleParams{
 			Command: `${config.ZipSyncCmd} -d $srcJarDir ` +
@@ -97,7 +97,17 @@
 				`KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
 				`KYTHE_JAVA_SOURCE_BATCH_SIZE=${kytheCuJavaSourceMax} ` +
 				`${config.SoongJavacWrapper} ${config.JavaCmd} ` +
+				// Avoid JDK9's warning about "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ...
+				// to field java.nio.Buffer.address"
 				`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
+				// Allow the classes in the com.google.devtools.kythe.extractors.java.standalone package
+				// access the packages in the jdk.compiler compiler module
+				`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
+				`--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED ` +
+				`--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED ` +
+				`--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED ` +
+				`--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED ` +
+				`--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED ` +
 				`-jar ${config.JavaKytheExtractorJar} ` +
 				`${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
 				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
diff --git a/java/config/config.go b/java/config/config.go
index a84c315..49d88c4 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -43,6 +43,7 @@
 	InstrumentFrameworkModules = []string{
 		"framework",
 		"framework-minus-apex",
+		"ims-common",
 		"telephony-common",
 		"services",
 		"android.car",
@@ -83,7 +84,7 @@
 
 	// ErrorProne can use significantly more memory than javac alone, give it a higher heap
 	// size (b/221480398).
-	exportedVars.ExportStringStaticVariable("ErrorProneHeapSize", "4096M")
+	exportedVars.ExportStringStaticVariable("ErrorProneHeapSize", "8192M")
 	exportedVars.ExportStringStaticVariable("ErrorProneHeapFlags", "-J-Xmx${ErrorProneHeapSize}")
 
 	// D8 invocations are shorter lived, so we restrict their JIT tiering relative to R8.
@@ -124,10 +125,6 @@
 		// This is set up and guaranteed by soong_ui
 		return ctx.Config().Getenv("ANDROID_JAVA_HOME")
 	})
-	pctx.VariableFunc("Java11Home", func(ctx android.PackageVarContext) string {
-		// This is set up and guaranteed by soong_ui
-		return ctx.Config().Getenv("ANDROID_JAVA11_HOME")
-	})
 	pctx.VariableFunc("JlinkVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" {
 			return override
@@ -136,12 +133,11 @@
 	})
 
 	pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
-	pctx.SourcePathVariable("Java11Toolchain", "${Java11Home}/bin")
 	pctx.SourcePathVariableWithEnvOverride("JavacCmd",
 		"${JavaToolchain}/javac", "ALTERNATE_JAVAC")
 	pctx.SourcePathVariable("JavaCmd", "${JavaToolchain}/java")
 	pctx.SourcePathVariable("JarCmd", "${JavaToolchain}/jar")
-	pctx.SourcePathVariable("JavadocCmd", "${Java11Toolchain}/javadoc")
+	pctx.SourcePathVariable("JavadocCmd", "${JavaToolchain}/javadoc")
 	pctx.SourcePathVariable("JlinkCmd", "${JavaToolchain}/jlink")
 	pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
 	pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar")
@@ -268,7 +264,7 @@
 
 // JavadocCmd returns a SourcePath object with the path to the java command.
 func JavadocCmd(ctx android.PathContext) android.SourcePath {
-	return java11Tool(ctx, "javadoc")
+	return javaTool(ctx, "javadoc")
 }
 
 func javaTool(ctx android.PathContext, tool string) android.SourcePath {
@@ -282,17 +278,6 @@
 
 }
 
-func java11Tool(ctx android.PathContext, tool string) android.SourcePath {
-	type javaToolKey string
-
-	key := android.NewCustomOnceKey(javaToolKey(tool))
-
-	return ctx.Config().OnceSourcePath(key, func() android.SourcePath {
-		return java11Toolchain(ctx).Join(ctx, tool)
-	})
-
-}
-
 var javaToolchainKey = android.NewOnceKey("javaToolchain")
 
 func javaToolchain(ctx android.PathContext) android.SourcePath {
@@ -301,14 +286,6 @@
 	})
 }
 
-var java11ToolchainKey = android.NewOnceKey("java11Toolchain")
-
-func java11Toolchain(ctx android.PathContext) android.SourcePath {
-	return ctx.Config().OnceSourcePath(java11ToolchainKey, func() android.SourcePath {
-		return java11Home(ctx).Join(ctx, "bin")
-	})
-}
-
 var javaHomeKey = android.NewOnceKey("javaHome")
 
 func javaHome(ctx android.PathContext) android.SourcePath {
@@ -317,12 +294,3 @@
 		return android.PathForSource(ctx, ctx.Config().Getenv("ANDROID_JAVA_HOME"))
 	})
 }
-
-var java11HomeKey = android.NewOnceKey("java11Home")
-
-func java11Home(ctx android.PathContext) android.SourcePath {
-	return ctx.Config().OnceSourcePath(java11HomeKey, func() android.SourcePath {
-		// This is set up and guaranteed by soong_ui
-		return android.PathForSource(ctx, ctx.Config().Getenv("ANDROID_JAVA11_HOME"))
-	})
-}
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 1c1070a..3d2c5c3 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -63,6 +63,7 @@
 				java_binary {
 					name: "foo",
 					srcs: ["a.java"],
+					main_class: "foo.bar.jb",
 				}`,
 			enabled: true,
 		},
diff --git a/java/droidstubs.go b/java/droidstubs.go
index d9efb40..5777b18 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -28,7 +28,7 @@
 )
 
 // The values allowed for Droidstubs' Api_levels_sdk_type
-var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib"}
+var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}
 
 func init() {
 	RegisterStubsBuildComponents(android.InitRegistrationContext)
@@ -134,7 +134,7 @@
 	// the dirs which Metalava extracts API levels annotations from.
 	Api_levels_annotations_dirs []string
 
-	// the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system' and 'module-lib' for now; defaults to public.
+	// the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public.
 	Api_levels_sdk_type *string
 
 	// the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
@@ -445,6 +445,8 @@
 	// for older releases. Similarly, module-lib falls back to system API.
 	var sdkDirs []string
 	switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
+	case "system-server":
+		sdkDirs = []string{"system-server", "module-lib", "system", "public"}
 	case "module-lib":
 		sdkDirs = []string{"module-lib", "system", "public"}
 	case "system":
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 2443692..25f8c86 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -122,7 +122,7 @@
 				"some-other-exported-dir",
 			],
 			api_levels_annotations_enabled: true,
-      api_levels_sdk_type: "%s",
+			api_levels_sdk_type: "%s",
 		}
 		`, sdkType),
 		map[string][]byte{
@@ -169,6 +169,21 @@
 	}, patterns)
 }
 
+func TestSystemServerDroidstubs(t *testing.T) {
+	patterns := getAndroidJarPatternsForDroidstubs(t, "system-server")
+
+	android.AssertArrayString(t, "order of patterns", []string{
+		"--android-jar-pattern somedir/%/system-server/android.jar",
+		"--android-jar-pattern someotherdir/%/system-server/android.jar",
+		"--android-jar-pattern somedir/%/module-lib/android.jar",
+		"--android-jar-pattern someotherdir/%/module-lib/android.jar",
+		"--android-jar-pattern somedir/%/system/android.jar",
+		"--android-jar-pattern someotherdir/%/system/android.jar",
+		"--android-jar-pattern somedir/%/public/android.jar",
+		"--android-jar-pattern someotherdir/%/public/android.jar",
+	}, patterns)
+}
+
 func TestDroidstubsSandbox(t *testing.T) {
 	ctx, _ := testJavaWithFS(t, `
 		genrule {
diff --git a/java/fuzz.go b/java/fuzz.go
index d0f369f..1d6b913 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"path/filepath"
 	"sort"
 	"strings"
 
@@ -26,6 +27,11 @@
 	"android/soong/fuzz"
 )
 
+const (
+	hostString   = "host"
+	targetString = "target"
+)
+
 type jniProperties struct {
 	// list of jni libs
 	Jni_libs []string
@@ -39,8 +45,10 @@
 }
 
 func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("java_fuzz_host", FuzzFactory)
-	ctx.RegisterSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory)
+	ctx.RegisterModuleType("java_fuzz", JavaFuzzFactory)
+	ctx.RegisterModuleType("java_fuzz_host", JavaFuzzHostFactory)
+	ctx.RegisterSingletonType("java_fuzz_host_packaging", javaFuzzHostPackagingFactory)
+	ctx.RegisterSingletonType("java_fuzz_device_packaging", javaFuzzDevicePackagingFactory)
 }
 
 type JavaFuzzLibrary struct {
@@ -55,11 +63,11 @@
 // sanitized for the given sanitizer or not.
 func (j *JavaFuzzLibrary) IsSanitizerEnabledForJni(ctx android.BaseModuleContext, sanitizerName string) bool {
 	// TODO: once b/231370928 is resolved, please uncomment the loop
-	// 	for _, s := range j.jniProperties.Sanitizers {
-	// 		if sanitizerName == s {
-	// 			return true
-	// 		}
-	// 	}
+	//     for _, s := range j.jniProperties.Sanitizers {
+	//         if sanitizerName == s {
+	//             return true
+	//         }
+	//     }
 	return false
 }
 
@@ -72,7 +80,6 @@
 		// this will be used by the ingestion pipeline to determine the version
 		// of jazzer to add to the fuzzer package
 		j.fuzzPackagedModule.FuzzProperties.Fuzz_config.IsJni = proptools.BoolPtr(true)
-
 		for _, target := range mctx.MultiTargets() {
 			sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
 			mctx.AddFarVariationDependencies(sharedLibVariations, cc.JniFuzzLibTag, j.jniProperties.Jni_libs...)
@@ -91,17 +98,28 @@
 	if j.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
 		j.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *j.fuzzPackagedModule.FuzzProperties.Dictionary)
 	}
-
 	if j.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
 		configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
 		android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
 		j.fuzzPackagedModule.Config = configPath
 	}
 
-	ctx.VisitDirectDepsWithTag(cc.JniFuzzLibTag, func(dep android.Module) {
+	_, sharedDeps := cc.CollectAllSharedDependencies(ctx)
+
+	for _, dep := range sharedDeps {
 		sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
 		if sharedLibInfo.SharedLibrary != nil {
-			libPath := android.PathForModuleOut(ctx, sharedLibInfo.SharedLibrary.Base())
+			// The .class jars are output in slightly different locations
+			// relative to the jni libs. Therefore, for consistency across
+			// host and device fuzzers of jni lib location, we save it in a
+			// native_libs directory.
+			var relPath string
+			if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" {
+				relPath = filepath.Join("lib64", sharedLibInfo.SharedLibrary.Base())
+			} else {
+				relPath = filepath.Join("lib", sharedLibInfo.SharedLibrary.Base())
+			}
+			libPath := android.PathForModuleOut(ctx, relPath)
 			ctx.Build(pctx, android.BuildParams{
 				Rule:   android.Cp,
 				Input:  sharedLibInfo.SharedLibrary,
@@ -111,18 +129,17 @@
 		} else {
 			ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
 		}
-	})
+	}
 
 	j.Library.GenerateAndroidBuildActions(ctx)
 }
 
-// java_fuzz builds and links sources into a `.jar` file for the host.
+// java_fuzz_host builds and links sources into a `.jar` file for the host.
 //
 // By default, a java_fuzz produces a `.jar` file containing `.class` files.
 // This jar is not suitable for installing on a device.
-func FuzzFactory() android.Module {
+func JavaFuzzHostFactory() android.Module {
 	module := &JavaFuzzLibrary{}
-
 	module.addHostProperties()
 	module.AddProperties(&module.jniProperties)
 	module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -141,23 +158,54 @@
 		ctx.AppendProperties(&disableLinuxBionic)
 	})
 
-	module.initModuleAndImport(module)
-	android.InitSdkAwareModule(module)
-	InitJavaModuleMultiTargets(module, android.HostSupported)
+	InitJavaModuleMultiTargets(module, android.HostSupportedNoCross)
 	return module
 }
 
-// Responsible for generating rules that package fuzz targets into
-// their architecture & target/host specific zip file.
-type javaFuzzPackager struct {
+// java_fuzz builds and links sources into a `.jar` file for the device.
+// This generates .class files in a jar which can then be instrumented before
+// fuzzing in Android Runtime (ART: Android OS on emulator or device)
+func JavaFuzzFactory() android.Module {
+	module := &JavaFuzzLibrary{}
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.jniProperties)
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+	module.AddProperties(&module.fuzzPackagedModule.FuzzProperties)
+	module.Module.dexpreopter.isTest = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+	InitJavaModuleMultiTargets(module, android.DeviceSupported)
+	return module
+}
+
+// Responsible for generating rules that package host fuzz targets into
+// a zip file.
+type javaFuzzHostPackager struct {
 	fuzz.FuzzPackager
 }
 
-func javaFuzzPackagingFactory() android.Singleton {
-	return &javaFuzzPackager{}
+// Responsible for generating rules that package device fuzz targets into
+// a zip file.
+type javaFuzzDevicePackager struct {
+	fuzz.FuzzPackager
 }
 
-func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
+func javaFuzzHostPackagingFactory() android.Singleton {
+	return &javaFuzzHostPackager{}
+}
+
+func javaFuzzDevicePackagingFactory() android.Singleton {
+	return &javaFuzzDevicePackager{}
+}
+
+func (s *javaFuzzHostPackager) GenerateBuildActions(ctx android.SingletonContext) {
+	generateBuildActions(&s.FuzzPackager, hostString, ctx)
+}
+
+func (s *javaFuzzDevicePackager) GenerateBuildActions(ctx android.SingletonContext) {
+	generateBuildActions(&s.FuzzPackager, targetString, ctx)
+}
+
+func generateBuildActions(s *fuzz.FuzzPackager, hostOrTargetString string, ctx android.SingletonContext) {
 	// Map between each architecture + host/device combination.
 	archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
 
@@ -171,8 +219,14 @@
 			return
 		}
 
-		if javaFuzzModule.Target().HostCross {
-			return
+		if hostOrTargetString == hostString {
+			if !javaFuzzModule.Host() {
+				return
+			}
+		} else if hostOrTargetString == targetString {
+			if javaFuzzModule.Host() || javaFuzzModule.Target().HostCross {
+				return
+			}
 		}
 
 		fuzzModuleValidator := fuzz.FuzzModule{
@@ -185,12 +239,7 @@
 			return
 		}
 
-		hostOrTargetString := "target"
-		if javaFuzzModule.Host() {
-			hostOrTargetString = "host"
-		}
 		archString := javaFuzzModule.Arch().ArchType.String()
-
 		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
 		archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
 
@@ -201,7 +250,7 @@
 		files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
 
 		// Add .jar
-		files = append(files, fuzz.FileToZip{javaFuzzModule.outputFile, ""})
+		files = append(files, fuzz.FileToZip{javaFuzzModule.implementationJarFile, ""})
 
 		// Add jni .so files
 		for _, fPath := range javaFuzzModule.jniFilePaths {
@@ -217,12 +266,22 @@
 	s.CreateFuzzPackage(ctx, archDirs, fuzz.Java, pctx)
 }
 
-func (s *javaFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
+func (s *javaFuzzHostPackager) MakeVars(ctx android.MakeVarsContext) {
 	packages := s.Packages.Strings()
 	sort.Strings(packages)
 
-	ctx.Strict("SOONG_JAVA_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
+	ctx.Strict("SOONG_JAVA_FUZZ_HOST_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
 
 	// Preallocate the slice of fuzz targets to minimize memory allocations.
-	s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_TARGETS")
+	s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_HOST_TARGETS")
+}
+
+func (s *javaFuzzDevicePackager) MakeVars(ctx android.MakeVarsContext) {
+	packages := s.Packages.Strings()
+	sort.Strings(packages)
+
+	ctx.Strict("SOONG_JAVA_FUZZ_DEVICE_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
+
+	// Preallocate the slice of fuzz targets to minimize memory allocations.
+	s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_DEVICE_TARGETS")
 }
diff --git a/java/java.go b/java/java.go
index 5091d26..b6fc6b8 100644
--- a/java/java.go
+++ b/java/java.go
@@ -211,6 +211,14 @@
 			PropertyName: "java_tests",
 		},
 	}
+
+	// Rule for generating device binary default wrapper
+	deviceBinaryWrapper = pctx.StaticRule("deviceBinaryWrapper", blueprint.RuleParams{
+		Command: `echo -e '#!/system/bin/sh\n` +
+			`export CLASSPATH=/system/framework/$jar_name\n` +
+			`exec app_process /$partition/bin $main_class "$$@"'> ${out}`,
+		Description: "Generating device binary wrapper ${jar_name}",
+	}, "jar_name", "partition", "main_class")
 )
 
 // JavaInfo contains information about a java module for use by modules that depend on it.
@@ -1398,7 +1406,31 @@
 				ctx.PropertyErrorf("wrapper", "wrapper is required for Windows")
 			}
 
-			j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+			if ctx.Device() {
+				// device binary should have a main_class property if it does not
+				// have a specific wrapper, so that a default wrapper can
+				// be generated for it.
+				if j.binaryProperties.Main_class == nil {
+					ctx.PropertyErrorf("main_class", "main_class property "+
+						"is required for device binary if no default wrapper is assigned")
+				} else {
+					wrapper := android.PathForModuleOut(ctx, ctx.ModuleName()+".sh")
+					jarName := j.Stem() + ".jar"
+					partition := j.PartitionTag(ctx.DeviceConfig())
+					ctx.Build(pctx, android.BuildParams{
+						Rule:   deviceBinaryWrapper,
+						Output: wrapper,
+						Args: map[string]string{
+							"jar_name":   jarName,
+							"partition":  partition,
+							"main_class": String(j.binaryProperties.Main_class),
+						},
+					})
+					j.wrapperFile = wrapper
+				}
+			} else {
+				j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+			}
 		}
 
 		ext := ""
@@ -2312,7 +2344,7 @@
 		ctx.CreateBazelTargetModule(
 			bazel.BazelTargetModuleProperties{
 				Rule_class:        "event_log_tags",
-				Bzl_load_location: "//build/make/tools:event_log_tags.bzl",
+				Bzl_load_location: "//build/bazel/rules/java:event_log_tags.bzl",
 			},
 			android.CommonAttributes{Name: logtagsLibName},
 			&eventLogTagsAttributes{
@@ -2384,7 +2416,18 @@
 	}
 
 	if m.properties.Libs != nil {
-		deps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Libs))))
+
+		// TODO 244210934 ALIX Check if this else statement breaks presubmits get rid of it if it doesn't
+		if strings.HasPrefix(ctx.ModuleType(), "java_binary") {
+			for _, d := range m.properties.Libs {
+				neverlinkLabel := android.BazelLabelForModuleDepSingle(ctx, d)
+				neverlinkLabel.Label = neverlinkLabel.Label + "-neverlink"
+				deps.Add(&neverlinkLabel)
+			}
+
+		} else {
+			deps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Libs))))
+		}
 	}
 
 	if m.properties.Static_libs != nil {
@@ -2409,8 +2452,9 @@
 
 type javaLibraryAttributes struct {
 	*javaCommonAttributes
-	Deps    bazel.LabelListAttribute
-	Exports bazel.LabelListAttribute
+	Deps      bazel.LabelListAttribute
+	Exports   bazel.LabelListAttribute
+	Neverlink bazel.BoolAttribute
 }
 
 func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
@@ -2440,7 +2484,8 @@
 		Bzl_load_location: "//build/bazel/rules/java:library.bzl",
 	}
 
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+	name := m.Name()
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
 }
 
 type javaBinaryHostAttributes struct {
@@ -2522,7 +2567,8 @@
 }
 
 type bazelJavaImportAttributes struct {
-	Jars bazel.LabelListAttribute
+	Jars    bazel.LabelListAttribute
+	Exports bazel.LabelListAttribute
 }
 
 // java_import bp2Build converter.
@@ -2543,7 +2589,17 @@
 	}
 	props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"}
 
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: android.RemoveOptionalPrebuiltPrefix(i.Name())}, attrs)
+	name := android.RemoveOptionalPrebuiltPrefix(i.Name())
+
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
+
+	neverlink := true
+	neverlinkAttrs := &javaLibraryAttributes{
+		Neverlink: bazel.BoolAttribute{Value: &neverlink},
+		Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
+	}
+	ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{Rule_class: "java_library"}, android.CommonAttributes{Name: name + "-neverlink"}, neverlinkAttrs)
+
 }
 
 var _ android.MixedBuildBuildable = (*Import)(nil)
diff --git a/java/java_test.go b/java/java_test.go
index 7f0cea7..f06b520 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -588,8 +588,8 @@
 	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
 
 	fooLibrary := fooModule.Module().(*Library)
-	assertDeepEquals(t, "foo java sources incorrect",
-		[]string{"a.java"}, fooLibrary.compiledJavaSrcs.Strings())
+	assertDeepEquals(t, "foo unique sources incorrect",
+		[]string{"a.java"}, fooLibrary.uniqueSrcFiles.Strings())
 
 	assertDeepEquals(t, "foo java source jars incorrect",
 		[]string{".intermediates/stubs-source/android_common/stubs-source-stubs.srcjar"},
@@ -1288,6 +1288,8 @@
 }
 
 func TestAidlIncludeDirFromConvertedFileGroupWithPathPropInMixedBuilds(t *testing.T) {
+	// TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups
+	t.Skip("Re-enable once filegroups are corrected for mixed builds")
 	bp := `
 	filegroup {
 		name: "foo_aidl",
@@ -1781,3 +1783,26 @@
 		t.Errorf("expected flags to be %q; was %q", expectedFlags, flags)
 	}
 }
+
+func TestDeviceBinaryWrapperGeneration(t *testing.T) {
+	// Scenario 1: java_binary has main_class property in its bp
+	ctx, _ := testJava(t, `
+		java_binary {
+			name: "foo",
+			srcs: ["foo.java"],
+			main_class: "foo.bar.jb",
+		}
+	`)
+	wrapperPath := fmt.Sprint(ctx.ModuleForTests("foo", "android_arm64_armv8-a").AllOutputs())
+	if !strings.Contains(wrapperPath, "foo.sh") {
+		t.Errorf("wrapper file foo.sh is not generated")
+	}
+
+	// Scenario 2: java_binary has neither wrapper nor main_class, its build
+	// is expected to be failed.
+	testJavaError(t, "main_class property is required for device binary if no default wrapper is assigned", `
+		java_binary {
+			name: "foo",
+			srcs: ["foo.java"],
+		}`)
+}
diff --git a/java/lint.go b/java/lint.go
index 931820d..9827159 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -333,7 +333,7 @@
 		l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
 		// Skip lint warning checks for NewApi warnings for libcore where they come from source
 		// files that reference the API they are adding (b/208656169).
-		if ctx.ModuleDir() != "libcore" {
+		if !strings.HasPrefix(ctx.ModuleDir(), "libcore") {
 			_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
 
 			if len(filtered) != 0 {
@@ -473,20 +473,23 @@
 
 	cmd.FlagWithOutput("--write-reference-baseline ", baseline)
 
-	cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
+	cmd.Text("; EXITCODE=$?; ")
+
+	// The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
+	// export them out of the sandbox.  Do this before exiting so that the suggestions exit even after
+	// a fatal error.
+	cmd.BuiltTool("soong_zip").
+		FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
+		FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
+		FlagWithInput("-r ", srcsList)
+
+	cmd.Text("; if [ $EXITCODE != 0 ]; then if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit $EXITCODE; fi")
 
 	rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
 
 	// The HTML output contains a date, remove it to make the output deterministic.
 	rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
 
-	// The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
-	// export them out of the sandbox.
-	rule.Command().BuiltTool("soong_zip").
-		FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
-		FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
-		FlagWithInput("-r ", srcsList)
-
 	rule.Build("lint", "lint")
 
 	l.outputs = lintOutputs{
diff --git a/java/robolectric.go b/java/robolectric.go
index 7f2981f..2cb0798 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -65,6 +65,10 @@
 	// The version number of a robolectric prebuilt to use from prebuilts/misc/common/robolectric
 	// instead of the one built from source in external/robolectric-shadows.
 	Robolectric_prebuilt_version *string
+
+	// Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectri
+	// to use.  /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows
+	Upstream *bool
 }
 
 type robolectricTest struct {
@@ -108,7 +112,11 @@
 	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
 		ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
 	} else {
-		ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
+		if proptools.Bool(r.robolectricProperties.Upstream) {
+			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream")
+		} else {
+			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
+		}
 	}
 
 	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
@@ -188,9 +196,9 @@
 
 	// TODO: this could all be removed if tradefed was used as the test runner, it will find everything
 	// annotated as a test and run it.
-	for _, src := range r.compiledJavaSrcs {
+	for _, src := range r.uniqueSrcFiles {
 		s := src.Rel()
-		if !strings.HasSuffix(s, "Test.java") {
+		if !strings.HasSuffix(s, "Test.java") && !strings.HasSuffix(s, "Test.kt") {
 			continue
 		} else if strings.HasSuffix(s, "/BaseRobolectricTest.java") {
 			continue
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 61b17bf..54981e1 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -839,84 +839,84 @@
 
 license_kind {
     name: "SPDX-license-identifier-LGPL",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.0",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.0.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.0+",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.0+.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.0-only",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.0-only.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.0-or-later",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.0-or-later.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.1",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.1.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.1+",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.1+.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.1-only",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.1-only.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-2.1-or-later",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-2.1-or-later.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-3.0",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-3.0.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-3.0+",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-3.0+.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-3.0-only",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-3.0-only.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPL-3.0-or-later",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPL-3.0-or-later.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-LGPLLR",
-    conditions: ["restricted"],
+    conditions: ["restricted_allows_dynamic_linking"],
     url: "https://spdx.org/licenses/LGPLLR.html",
 }
 
@@ -1152,7 +1152,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-WTFPL",
-    conditions: ["notice"],
+    conditions: ["permissive"],
     url: "https://spdx.org/licenses/WTFPL.html",
 }
 
diff --git a/python/Android.bp b/python/Android.bp
index 99c02bd..e49fa6a 100644
--- a/python/Android.bp
+++ b/python/Android.bp
@@ -27,15 +27,3 @@
     ],
     pluginFor: ["soong_build"],
 }
-
-// We're transitioning all of these flags to be true by default.
-// This is a defaults flag that can be used to easily add all of them to
-// certain modules.
-python_defaults {
-    name: "modern_python_path_defaults",
-    dont_add_top_level_directories_to_path: true,
-    dont_add_entrypoint_folder_to_path: true,
-    proto: {
-        respect_pkg_path: true,
-    },
-}
diff --git a/python/binary.go b/python/binary.go
index e6324a3..670e0d3 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -34,7 +34,7 @@
 }
 
 type bazelPythonBinaryAttributes struct {
-	Main           *string
+	Main           *bazel.Label
 	Srcs           bazel.LabelListAttribute
 	Deps           bazel.LabelListAttribute
 	Python_version *string
@@ -42,17 +42,6 @@
 }
 
 func pythonBinaryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
-	var main *string
-	for _, propIntf := range m.GetProperties() {
-		if props, ok := propIntf.(*BinaryProperties); ok {
-			// main is optional.
-			if props.Main != nil {
-				main = props.Main
-				break
-			}
-		}
-	}
-
 	// TODO(b/182306917): this doesn't fully handle all nested props versioned
 	// by the python version, which would have been handled by the version split
 	// mutator. This is sufficient for very simple python_binary_host modules
@@ -72,13 +61,24 @@
 
 	baseAttrs := m.makeArchVariantBaseAttributes(ctx)
 	attrs := &bazelPythonBinaryAttributes{
-		Main:           main,
+		Main:           nil,
 		Srcs:           baseAttrs.Srcs,
 		Deps:           baseAttrs.Deps,
 		Python_version: python_version,
 		Imports:        baseAttrs.Imports,
 	}
 
+	for _, propIntf := range m.GetProperties() {
+		if props, ok := propIntf.(*BinaryProperties); ok {
+			// main is optional.
+			if props.Main != nil {
+				main := android.BazelLabelForModuleSrcSingle(ctx, *props.Main)
+				attrs.Main = &main
+				break
+			}
+		}
+	}
+
 	props := bazel.BazelTargetModuleProperties{
 		// Use the native py_binary rule.
 		Rule_class: "py_binary",
@@ -116,22 +116,6 @@
 	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
 	// explicitly.
 	Auto_gen_config *bool
-
-	// Currently, both the root of the zipfile and all the directories 1 level
-	// below that are added to the python path. When this flag is set to true,
-	// only the root of the zipfile will be added to the python path. This flag
-	// will be removed after all the python modules in the tree have been updated
-	// to support it. When using embedded_launcher: true, this is already the
-	// behavior. The default is currently false.
-	Dont_add_top_level_directories_to_path *bool
-
-	// Setting this to true will mimic Python 3.11+'s PYTHON_SAFE_PATH environment
-	// variable or -P flag, even on older python versions. This is a temporary
-	// flag while modules are changed to support it, eventually true will be the
-	// default and the flag will be removed. The default is currently false. It
-	// is only applicable when embedded_launcher is false, when embedded_launcher
-	// is true this is already implied.
-	Dont_add_entrypoint_folder_to_path *bool
 }
 
 type binaryDecorator struct {
@@ -191,14 +175,9 @@
 			}
 		})
 	}
-
-	addTopDirectoriesToPath := !proptools.BoolDefault(binary.binaryProperties.Dont_add_top_level_directories_to_path, false)
-	dontAddEntrypointFolderToPath := proptools.BoolDefault(binary.binaryProperties.Dont_add_entrypoint_folder_to_path, false)
-
 	binFile := registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
 		binary.getHostInterpreterName(ctx, actualVersion),
-		main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...),
-		addTopDirectoriesToPath, dontAddEntrypointFolderToPath)
+		main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...))
 
 	return android.OptionalPathForPath(binFile)
 }
diff --git a/python/builder.go b/python/builder.go
index f7f9a99..b4ab206 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -43,17 +43,7 @@
 
 	hostPar = pctx.AndroidStaticRule("hostPar",
 		blueprint.RuleParams{
-			Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' -e 's/ADD_TOP_DIRECTORIES_TO_PATH/$addTopDirectoriesToPath/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` +
-				`echo "#!/usr/bin/env $interp" >${out}.prefix &&` +
-				`$mergeParCmd -p --prefix ${out}.prefix -pm $out.main $out $srcsZips && ` +
-				`chmod +x $out && (rm -f $out.main; rm -f ${out}.prefix)`,
-			CommandDeps: []string{"$mergeParCmd", "build/soong/python/scripts/stub_template_host.txt"},
-		},
-		"interp", "main", "srcsZips", "addTopDirectoriesToPath")
-
-	hostParWithoutAddingEntrypointFolderToPath = pctx.AndroidStaticRule("hostParWithoutAddingEntrypointFolderToPath",
-		blueprint.RuleParams{
-			Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/__soong_entrypoint_redirector__.py/g' -e 's/ADD_TOP_DIRECTORIES_TO_PATH/$addTopDirectoriesToPath/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` +
+			Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/__soong_entrypoint_redirector__.py/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` +
 				"sed -e 's/ENTRY_POINT/$main/g' build/soong/python/scripts/main_non_embedded.py >`dirname $out`/__soong_entrypoint_redirector__.py && " +
 				"$parCmd -o $out.entrypoint_zip -C `dirname $out` -f `dirname $out`/__soong_entrypoint_redirector__.py && " +
 				`echo "#!/usr/bin/env $interp" >${out}.prefix &&` +
@@ -61,7 +51,7 @@
 				"chmod +x $out && (rm -f $out.main; rm -f ${out}.prefix; rm -f $out.entrypoint_zip; rm -f `dirname $out`/__soong_entrypoint_redirector__.py)",
 			CommandDeps: []string{"$mergeParCmd", "$parCmd", "build/soong/python/scripts/stub_template_host.txt", "build/soong/python/scripts/main_non_embedded.py"},
 		},
-		"interp", "main", "srcsZips", "addTopDirectoriesToPath")
+		"interp", "main", "srcsZips")
 
 	embeddedPar = pctx.AndroidStaticRule("embeddedPar",
 		blueprint.RuleParams{
@@ -92,7 +82,7 @@
 
 func registerBuildActionForParFile(ctx android.ModuleContext, embeddedLauncher bool,
 	launcherPath android.OptionalPath, interpreter, main, binName string,
-	srcsZips android.Paths, addTopDirectoriesToPath bool, dontAddEntrypointFolderToPath bool) android.Path {
+	srcsZips android.Paths) android.Path {
 
 	// .intermediate output path for bin executable.
 	binFile := android.PathForModuleOut(ctx, binName)
@@ -101,37 +91,17 @@
 	implicits := srcsZips
 
 	if !embeddedLauncher {
-		addDirsString := "False"
-		if addTopDirectoriesToPath {
-			addDirsString = "True"
-		}
-		if dontAddEntrypointFolderToPath {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        hostParWithoutAddingEntrypointFolderToPath,
-				Description: "host python archive",
-				Output:      binFile,
-				Implicits:   implicits,
-				Args: map[string]string{
-					"interp":                  strings.Replace(interpreter, "/", `\/`, -1),
-					"main":                    strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1),
-					"srcsZips":                strings.Join(srcsZips.Strings(), " "),
-					"addTopDirectoriesToPath": addDirsString,
-				},
-			})
-		} else {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        hostPar,
-				Description: "host python archive",
-				Output:      binFile,
-				Implicits:   implicits,
-				Args: map[string]string{
-					"interp":                  strings.Replace(interpreter, "/", `\/`, -1),
-					"main":                    strings.Replace(main, "/", `\/`, -1),
-					"srcsZips":                strings.Join(srcsZips.Strings(), " "),
-					"addTopDirectoriesToPath": addDirsString,
-				},
-			})
-		}
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        hostPar,
+			Description: "host python archive",
+			Output:      binFile,
+			Implicits:   implicits,
+			Args: map[string]string{
+				"interp":   strings.Replace(interpreter, "/", `\/`, -1),
+				"main":     strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1),
+				"srcsZips": strings.Join(srcsZips.Strings(), " "),
+			},
+		})
 	} else if launcherPath.Valid() {
 		// added launcherPath to the implicits Ninja dependencies.
 		implicits = append(implicits, launcherPath.Path())
diff --git a/python/defaults.go b/python/defaults.go
index c54e7d0..3dc5bc4 100644
--- a/python/defaults.go
+++ b/python/defaults.go
@@ -19,7 +19,7 @@
 )
 
 func init() {
-	android.RegisterModuleType("python_defaults", defaultsFactory)
+	android.RegisterModuleType("python_defaults", DefaultsFactory)
 }
 
 type Defaults struct {
@@ -30,7 +30,7 @@
 func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 }
 
-func defaultsFactory() android.Module {
+func DefaultsFactory() android.Module {
 	module := &Defaults{}
 
 	module.AddProperties(
diff --git a/python/proto.go b/python/proto.go
index 53ebb58..400e72c 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -18,7 +18,7 @@
 	"android/soong/android"
 )
 
-func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags, pkgPath string) android.Path {
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path {
 	srcsZipFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip")
 
 	outDir := srcsZipFile.ReplaceExtension(ctx, "tmp")
@@ -36,9 +36,6 @@
 	zipCmd := rule.Command().
 		BuiltTool("soong_zip").
 		FlagWithOutput("-o ", srcsZipFile)
-	if pkgPath != "" {
-		zipCmd.FlagWithArg("-P ", pkgPath)
-	}
 	zipCmd.FlagWithArg("-C ", outDir.String()).
 		FlagWithArg("-D ", outDir.String())
 
diff --git a/python/python.go b/python/python.go
index f6029c2..24e1bb2 100644
--- a/python/python.go
+++ b/python/python.go
@@ -120,15 +120,6 @@
 	// whether the binary is required to be built with embedded launcher for this actual_version.
 	// this is set by the python version mutator based on version-specific properties
 	Embedded_launcher *bool `blueprint:"mutated"`
-
-	Proto struct {
-		// Whether generated python protos should include the pkg_path in
-		// their import statements. This is a temporary flag to help transition to
-		// the new behavior where this is always true. It will be removed after all
-		// usages of protos with pkg_path have been updated. The default is currently
-		// false.
-		Respect_pkg_path *bool
-	}
 }
 
 type baseAttributes struct {
@@ -677,10 +668,7 @@
 		protoFlags := android.GetProtoFlags(ctx, &p.protoProperties)
 		protoFlags.OutTypeFlag = "--python_out"
 
-		// TODO(b/247578564): Change the default to true, and then eventually remove respect_pkg_path
-		protosRespectPkgPath := proptools.BoolDefault(p.properties.Proto.Respect_pkg_path, false)
-		pkgPathForProtos := pkgPath
-		if pkgPathForProtos != "" && protosRespectPkgPath {
+		if pkgPath != "" {
 			pkgPathStagingDir := android.PathForModuleGen(ctx, "protos_staged_for_pkg_path")
 			rule := android.NewRuleBuilder(pctx, ctx)
 			var stagedProtoSrcs android.Paths
@@ -692,11 +680,10 @@
 			}
 			rule.Build("stage_protos_for_pkg_path", "Stage protos for pkg_path")
 			protoSrcs = stagedProtoSrcs
-			pkgPathForProtos = ""
 		}
 
 		for _, srcFile := range protoSrcs {
-			zip := genProto(ctx, srcFile, protoFlags, pkgPathForProtos)
+			zip := genProto(ctx, srcFile, protoFlags)
 			zips = append(zips, zip)
 		}
 	}
diff --git a/python/scripts/stub_template_host.txt b/python/scripts/stub_template_host.txt
index a0ddffe..5eedc18 100644
--- a/python/scripts/stub_template_host.txt
+++ b/python/scripts/stub_template_host.txt
@@ -23,16 +23,7 @@
     zf.extractall(runfiles_path)
     zf.close()
 
-    # Add runfiles path to PYTHONPATH.
-    python_path_entries = [runfiles_path]
-
-    if ADD_TOP_DIRECTORIES_TO_PATH:
-      # Add top dirs within runfiles path to PYTHONPATH.
-      top_entries = [os.path.join(runfiles_path, i) for i in os.listdir(runfiles_path)]
-      top_pkg_dirs = [i for i in top_entries if os.path.isdir(i)]
-      python_path_entries += top_pkg_dirs
-
-    new_python_path = ":".join(python_path_entries)
+    new_python_path = runfiles_path
     old_python_path = os.environ.get(PYTHON_PATH)
 
     if old_python_path:
diff --git a/python/tests/dont_import_folder_of_entrypoint/Android.bp b/python/tests/dont_import_folder_of_entrypoint/Android.bp
index ea5076e..e54e9b2 100644
--- a/python/tests/dont_import_folder_of_entrypoint/Android.bp
+++ b/python/tests/dont_import_folder_of_entrypoint/Android.bp
@@ -9,7 +9,6 @@
         "mypkg/main.py",
         "mypkg/mymodule.py",
     ],
-    defaults: ["modern_python_path_defaults"],
 }
 
 python_test_host {
diff --git a/python/tests/proto_pkg_path/Android.bp b/python/tests/proto_pkg_path/Android.bp
index ef79850..a6bfd3f 100644
--- a/python/tests/proto_pkg_path/Android.bp
+++ b/python/tests/proto_pkg_path/Android.bp
@@ -12,6 +12,5 @@
     pkg_path: "mylib/subpackage",
     proto: {
         canonical_path_from_root: false,
-        respect_pkg_path: true,
     },
 }
diff --git a/python/tests/top_level_dirs/Android.bp b/python/tests/top_level_dirs/Android.bp
index fe13d4f..574350a 100644
--- a/python/tests/top_level_dirs/Android.bp
+++ b/python/tests/top_level_dirs/Android.bp
@@ -9,5 +9,4 @@
         "main.py",
         "mypkg/mymodule.py",
     ],
-    dont_add_top_level_directories_to_path: true,
 }
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 0199d3a..17d80dd 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -30,7 +30,7 @@
 	defaultBindgenFlags = []string{""}
 
 	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
-	bindgenClangVersion = "clang-r450784d"
+	bindgenClangVersion = "clang-r468909b"
 
 	_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
@@ -51,7 +51,7 @@
 	})
 	_ = pctx.VariableFunc("bindgenClangLibdir", func(ctx android.PackageVarContext) string {
 		if ctx.Config().UseHostMusl() {
-			return "musl/lib64/"
+			return "musl/lib/"
 		} else {
 			return "lib64/"
 		}
@@ -239,6 +239,10 @@
 		cflags = append(cflags, "-x c")
 	}
 
+	// clang-r468909b complains about the -x c in the flags in clang-sys parse_search_paths:
+	// clang: error: '-x c' after last input file has no effect [-Werror,-Wunused-command-line-argument]
+	cflags = append(cflags, "-Wno-unused-command-line-argument")
+
 	// LLVM_NEXT may contain flags that bindgen doesn't recognise. Turn off unknown flags warning.
 	if ctx.Config().IsEnvTrue("LLVM_NEXT") {
 		cflags = append(cflags, "-Wno-unknown-warning-option")
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 76cf21a..6faf55c 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -91,7 +91,7 @@
 	out := fuzzer.binaryDecorator.compile(ctx, flags, deps)
 
 	// Grab the list of required shared libraries.
-	fuzzer.sharedLibraries = cc.CollectAllSharedDependencies(ctx)
+	fuzzer.sharedLibraries, _ = cc.CollectAllSharedDependencies(ctx)
 
 	return out
 }
diff --git a/rust/sanitize.go b/rust/sanitize.go
index a3c5cb5..c68137e 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -189,16 +189,6 @@
 		}
 	}
 
-	// TODO:(b/178369775)
-	// For now sanitizing is only supported on devices
-	if ctx.Os() == android.Android && Bool(s.Fuzzer) {
-		sanitize.Properties.SanitizerEnabled = true
-	}
-
-	if ctx.Os() == android.Android && Bool(s.Address) {
-		sanitize.Properties.SanitizerEnabled = true
-	}
-
 	// HWASan requires AArch64 hardware feature (top-byte-ignore).
 	if ctx.Arch().ArchType != android.Arm64 || !ctx.Os().Bionic() {
 		s.Hwaddress = nil
@@ -219,7 +209,9 @@
 		s.Memtag_heap = nil
 	}
 
-	if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap)) {
+	// TODO:(b/178369775)
+	// For now sanitizing is only supported on devices
+	if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) {
 		sanitize.Properties.SanitizerEnabled = true
 	}
 }
diff --git a/scripts/gen_ndk_usedby_apex.sh b/scripts/gen_ndk_usedby_apex.sh
index 0d3ed5a..93d1370 100755
--- a/scripts/gen_ndk_usedby_apex.sh
+++ b/scripts/gen_ndk_usedby_apex.sh
@@ -19,6 +19,7 @@
 # For example, current line llvm-readelf output is:
 # 1: 00000000     0     FUNC      GLOBAL  DEFAULT   UND   dlopen@LIBC
 # After the parse function below "dlopen" would be write to the output file.
+
 printHelp() {
     echo "**************************** Usage Instructions ****************************"
     echo "This script is used to generate the Mainline modules used-by NDK symbols."
@@ -29,30 +30,33 @@
 }
 
 parseReadelfOutput() {
+  local readelfOutput=$1; shift
+  local ndkApisOutput=$1; shift
   while IFS= read -r line
   do
       if [[ $line = *FUNC*GLOBAL*UND*@* ]] ;
       then
-          echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "$2"
+          echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "${ndkApisOutput}"
       fi
-  done < "$1"
-  echo "" >> "$2"
+  done < "${readelfOutput}"
+  echo "" >> "${ndkApisOutput}"
 }
 
 unzipJarAndApk() {
-  tmpUnzippedDir="$1"/tmpUnzipped
-  [[ -e "$tmpUnzippedDir" ]] && rm -rf "$tmpUnzippedDir"
-  mkdir -p "$tmpUnzippedDir"
-  find "$1" -name "*.jar" -exec unzip -o {} -d "$tmpUnzippedDir" \;
-  find "$1" -name "*.apk" -exec unzip -o {} -d "$tmpUnzippedDir" \;
-  find "$tmpUnzippedDir" -name "*.MF" -exec rm {} \;
+  local dir="$1"; shift
+  local tmpUnzippedDir="$1"; shift
+  mkdir -p "${tmpUnzippedDir}"
+  find "$dir" -name "*.jar" -exec unzip -o {} -d "${tmpUnzippedDir}" \;
+  find "$dir" -name "*.apk" -exec unzip -o {} -d "${tmpUnzippedDir}" \;
+  find "${tmpUnzippedDir}" -name "*.MF" -exec rm {} \;
 }
 
 lookForExecFile() {
-  dir="$1"
-  readelf="$2"
-  find "$dir" -type f -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
-  find "$dir" -type f -perm /111 ! -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
+  local dir="$1"; shift
+  local readelf="$1"; shift
+  local tmpOutput="$1"; shift
+  find -L "$dir" -type f -name "*.so"  -exec "${readelf}" --dyn-symbols {} >> "${tmpOutput}" \;
+  find -L "$dir" -type f -perm /111 ! -name "*.so" -exec "${readelf}" --dyn-symbols {} >> "${tmpOutput}" \;
 }
 
 if [[ "$1" == "help" ]]
@@ -62,11 +66,22 @@
 then
   echo "Wrong argument length. Expecting 3 argument representing image file directory, llvm-readelf tool path, output path."
 else
-  unzipJarAndApk "$1"
-  lookForExecFile "$1" "$2"
-  tmpReadelfOutput="$1/../tmpReadelf.txt"
-  [[ -e "$3" ]] && rm "$3"
-  parseReadelfOutput "$tmpReadelfOutput" "$3"
-  [[ -e "$tmpReadelfOutput" ]] && rm "$tmpReadelfOutput"
-  rm -rf "$1/tmpUnzipped"
-fi
\ No newline at end of file
+  imageDir="$1"; shift
+  readelf="$1"; shift
+  outputFile="$1"; shift
+
+  tmpReadelfOutput=$(mktemp /tmp/temporary-file.XXXXXXXX)
+  tmpUnzippedDir=$(mktemp -d /tmp/temporary-dir.XXXXXXXX)
+  trap 'rm -rf -- "${tmpReadelfOutput}" "${tmpUnzippedDir}"' EXIT
+
+  # If there are any jars or apks, unzip them to surface native files.
+  unzipJarAndApk "${imageDir}" "${tmpUnzippedDir}"
+  # Analyze the unzipped files.
+  lookForExecFile "${tmpUnzippedDir}" "${readelf}" "${tmpReadelfOutput}"
+
+  # Analyze the apex image staging dir itself.
+  lookForExecFile "${imageDir}" "${readelf}" "${tmpReadelfOutput}"
+
+  [[ -e "${outputFile}" ]] && rm "${outputFile}"
+  parseReadelfOutput "${tmpReadelfOutput}" "${outputFile}"
+fi
diff --git a/scripts/microfactory.bash b/scripts/microfactory.bash
index 192b38f..ce4a0e4 100644
--- a/scripts/microfactory.bash
+++ b/scripts/microfactory.bash
@@ -59,7 +59,7 @@
     BUILDDIR=$(getoutdir) \
       SRCDIR=${TOP} \
       BLUEPRINTDIR=${TOP}/build/blueprint \
-      EXTRA_ARGS="-pkg-path android/soong=${TOP}/build/soong -pkg-path rbcrun=${TOP}/build/make/tools/rbcrun -pkg-path google.golang.org/protobuf=${TOP}/external/golang-protobuf -pkg-path go.starlark.net=${TOP}/external/starlark-go" \
+      EXTRA_ARGS="-pkg-path android/soong=${TOP}/build/soong -pkg-path prebuilts/bazel/common/proto=${TOP}/prebuilts/bazel/common/proto -pkg-path rbcrun=${TOP}/build/make/tools/rbcrun -pkg-path google.golang.org/protobuf=${TOP}/external/golang-protobuf -pkg-path go.starlark.net=${TOP}/external/starlark-go" \
       build_go $@
 }
 
diff --git a/symbol_inject/macho.go b/symbol_inject/macho.go
index 9946d34..ca3d50e 100644
--- a/symbol_inject/macho.go
+++ b/symbol_inject/macho.go
@@ -16,9 +16,12 @@
 
 import (
 	"debug/macho"
+	"encoding/binary"
 	"fmt"
 	"io"
+	"os"
 	"os/exec"
+	"path/filepath"
 	"sort"
 	"strings"
 )
@@ -98,6 +101,80 @@
 }
 
 func CodeSignMachoFile(path string) error {
-	cmd := exec.Command("/usr/bin/codesign", "--force", "-s", "-", path)
-	return cmd.Run()
+	filename := filepath.Base(path)
+	cmd := exec.Command("/usr/bin/codesign", "--force", "-s", "-", "-i", filename, path)
+	if err := cmd.Run(); err != nil {
+		return err
+	}
+	return modifyCodeSignFlags(path)
+}
+
+const LC_CODE_SIGNATURE = 0x1d
+const CSSLOT_CODEDIRECTORY = 0
+
+// To make codesign not invalidated by stripping, modify codesign flags to 0x20002
+// (adhoc | linkerSigned).
+func modifyCodeSignFlags(path string) error {
+	f, err := os.OpenFile(path, os.O_RDWR, 0)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	// Step 1: find code signature section.
+	machoFile, err := macho.NewFile(f)
+	if err != nil {
+		return err
+	}
+	var codeSignSectionOffset uint32 = 0
+	var codeSignSectionSize uint32 = 0
+	for _, l := range machoFile.Loads {
+		data := l.Raw()
+		cmd := machoFile.ByteOrder.Uint32(data)
+		if cmd == LC_CODE_SIGNATURE {
+			codeSignSectionOffset = machoFile.ByteOrder.Uint32(data[8:])
+			codeSignSectionSize = machoFile.ByteOrder.Uint32(data[12:])
+		}
+	}
+	if codeSignSectionOffset == 0 {
+		return fmt.Errorf("code signature section not found")
+	}
+
+	data := make([]byte, codeSignSectionSize)
+	_, err = f.ReadAt(data, int64(codeSignSectionOffset))
+	if err != nil {
+		return err
+	}
+
+	// Step 2: get flags offset.
+	blobCount := binary.BigEndian.Uint32(data[8:])
+	off := 12
+	var codeDirectoryOff uint32 = 0
+	for blobCount > 0 {
+		blobType := binary.BigEndian.Uint32(data[off:])
+		if blobType == CSSLOT_CODEDIRECTORY {
+			codeDirectoryOff = binary.BigEndian.Uint32(data[off+4:])
+			break
+		}
+		blobCount--
+		off += 8
+	}
+	if codeDirectoryOff == 0 {
+		return fmt.Errorf("no code directory in code signature section")
+	}
+	flagsOff := codeSignSectionOffset + codeDirectoryOff + 12
+
+	// Step 3: modify flags.
+	flagsData := make([]byte, 4)
+	_, err = f.ReadAt(flagsData, int64(flagsOff))
+	if err != nil {
+		return err
+	}
+	oldFlags := binary.BigEndian.Uint32(flagsData)
+	if oldFlags != 0x2 {
+		return fmt.Errorf("unexpected flags in code signature section: 0x%x", oldFlags)
+	}
+	binary.BigEndian.PutUint32(flagsData, 0x20002)
+	_, err = f.WriteAt(flagsData, int64(flagsOff))
+	return err
 }
diff --git a/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
index 61d131b..5fbbd0f 100755
--- a/tests/apex_comparison_tests.sh
+++ b/tests/apex_comparison_tests.sh
@@ -34,7 +34,7 @@
 BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel"
 
 function call_bazel() {
-  tools/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
+  build/bazel/bin/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
 }
 
 function cleanup {
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index e92a561..d89e6b7 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -285,6 +285,35 @@
 
 }
 
+function test_create_global_include_directory() {
+  setup
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  # Soong needs to know if top level directories like hardware/ exist for use
+  # as global include directories.  Make sure that doesn't cause regens for
+  # unrelated changes to the top level directory.
+  mkdir -p system/core
+
+  run_soong
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime1" != "$mtime2" ]]; then
+    fail "Output Ninja file changed when top level directory changed"
+  fi
+
+  # Make sure it does regen if a missing directory in the path of a global
+  # include directory is added.
+  mkdir -p system/core/include
+
+  run_soong
+  local mtime3=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime2" = "$mtime3" ]]; then
+    fail "Output Ninja file did not change when global include directory created"
+  fi
+
+}
+
+
 function test_add_file_to_soong_build() {
   setup
   run_soong
@@ -547,12 +576,48 @@
 
 function test_bp2build_generates_marker_file {
   setup
-  create_mock_bazel
 
   run_soong bp2build
 
+  if [[ ! -f "./out/soong/bp2build_files_marker" ]]; then
+    fail "bp2build marker file was not generated"
+  fi
+
   if [[ ! -f "./out/soong/bp2build_workspace_marker" ]]; then
-    fail "Marker file was not generated"
+    fail "symlink forest marker file was not generated"
+  fi
+}
+
+function test_bp2build_add_irrelevant_file {
+  setup
+
+  mkdir -p a/b
+  touch a/b/c.txt
+  cat > a/b/Android.bp <<'EOF'
+filegroup {
+  name: "c",
+  srcs: ["c.txt"],
+  bazel_module: { bp2build_available: true },
+}
+EOF
+
+  run_soong bp2build
+  if [[ ! -e out/soong/bp2build/a/b/BUILD.bazel ]]; then
+    fail "BUILD file in symlink forest was not created";
+  fi
+
+  local mtime1=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel)
+
+  touch a/irrelevant.txt
+  run_soong bp2build
+  local mtime2=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel)
+
+  if [[ "$mtime1" != "$mtime2" ]]; then
+    fail "BUILD.bazel file was regenerated"
+  fi
+
+  if [[ ! -e "out/soong/workspace/a/irrelevant.txt" ]]; then
+    fail "New file was not symlinked into symlink forest"
   fi
 }
 
@@ -838,6 +903,7 @@
 test_add_file_to_soong_build
 test_glob_during_bootstrapping
 test_soong_build_rerun_iff_environment_changes
+test_create_global_include_directory
 test_multiple_soong_build_modes
 test_dump_json_module_graph
 test_json_module_graph_back_and_forth_null_build
@@ -849,6 +915,7 @@
 test_bp2build_null_build
 test_bp2build_back_and_forth_null_build
 test_bp2build_add_android_bp
+test_bp2build_add_irrelevant_file
 test_bp2build_add_to_glob
 test_bp2build_bazel_workspace_structure
 test_bp2build_bazel_workspace_add_file
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 3cb6c8c..679ac55 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -48,9 +48,52 @@
 
 test_bp2build_null_build_with_globs
 
+function test_different_relative_outdir {
+  setup
+
+  mkdir -p a
+  touch a/g.txt
+  cat > a/Android.bp <<'EOF'
+filegroup {
+    name: "g",
+    srcs: ["g.txt"],
+    bazel_module: {bp2build_available: true},
+  }
+EOF
+
+  # A directory under $MOCK_TOP
+  outdir=out2
+  trap "rm -rf $outdir" EXIT
+  # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
+  (export OUT_DIR=$outdir; run_soong bp2build && run_bazel build --config=bp2build //a:g)
+}
+
+test_different_relative_outdir
+
+function test_different_absolute_outdir {
+  setup
+
+  mkdir -p a
+  touch a/g.txt
+  cat > a/Android.bp <<'EOF'
+filegroup {
+    name: "g",
+    srcs: ["g.txt"],
+    bazel_module: {bp2build_available: true},
+  }
+EOF
+
+  # A directory under /tmp/...
+  outdir=$(mktemp -t -d st.XXXXX)
+  trap 'rm -rf $outdir' EXIT
+  # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
+  (export OUT_DIR=$outdir; run_soong bp2build && run_bazel build --config=bp2build //a:g)
+}
+
+test_different_absolute_outdir
+
 function test_bp2build_generates_all_buildfiles {
   setup
-  create_mock_bazel
 
   mkdir -p foo/convertible_soong_module
   cat > foo/convertible_soong_module/Android.bp <<'EOF'
@@ -121,7 +164,6 @@
 
 function test_cc_correctness {
   setup
-  create_mock_bazel
 
   mkdir -p a
   cat > a/Android.bp <<EOF
diff --git a/tests/lib.sh b/tests/lib.sh
index 4b4d908..e40f0ad 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -82,6 +82,7 @@
 }
 
 function create_mock_soong {
+  create_mock_bazel
   copy_directory build/blueprint
   copy_directory build/soong
   copy_directory build/make/tools/rbcrun
@@ -128,7 +129,6 @@
 
   symlink_file WORKSPACE
   symlink_file BUILD
-  symlink_file tools/bazel
 }
 
 function run_bazel {
@@ -136,7 +136,7 @@
   # output should not be parsed as such.
   rm -rf out/ninja_build
 
-  tools/bazel "$@"
+  build/bazel/bin/bazel "$@"
 }
 
 function run_ninja {
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index f6fffad..8949b42 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -12,11 +12,56 @@
 
 function test_bazel_smoke {
   setup
-  create_mock_bazel
 
   run_soong bp2build
 
   run_bazel info --config=bp2build
 }
 
+function test_add_irrelevant_file {
+  setup
+
+  mkdir -p soong_tests/a/b
+  touch soong_tests/a/b/c.txt
+  cat > soong_tests/a/b/Android.bp <<'EOF'
+filegroup {
+  name: "c",
+  srcs: ["c.txt"],
+  bazel_module: { bp2build_available: true },
+}
+EOF
+
+  run_soong --bazel-mode-staging nothing
+
+  if [[ ! -e out/soong/bp2build/soong_tests/a/b/BUILD.bazel ]]; then
+    fail "BUILD.bazel not created"
+  fi
+
+  if [[ ! -e out/soong/build.ninja ]]; then
+    fail "build.ninja not created"
+  fi
+
+  local mtime_build1=$(stat -c "%y" out/soong/bp2build/soong_tests/a/b/BUILD.bazel)
+  local mtime_ninja1=$(stat -c "%y" out/soong/build.ninja)
+
+  touch soong_tests/a/irrelevant.txt
+
+  run_soong --bazel-mode-staging nothing
+  local mtime_build2=$(stat -c "%y" out/soong/bp2build/soong_tests/a/b/BUILD.bazel)
+  local mtime_ninja2=$(stat -c "%y" out/soong/build.ninja)
+
+  if [[ "$mtime_build1" != "$mtime_build2" ]]; then
+    fail "BUILD.bazel was generated"
+  fi
+
+  if [[ "$mtime_ninja1" != "$mtime_ninja2" ]]; then
+    fail "build.ninja was regenerated"
+  fi
+
+  if [[ ! -e out/soong/workspace/soong_tests/a/irrelevant.txt ]]; then
+    fail "new file was not symlinked"
+  fi
+}
+
+test_add_irrelevant_file
 test_bazel_smoke
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index 0ebfcd8..bd469a4 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -85,9 +85,9 @@
 
 	bazelEnv["SHELL"] = "/bin/bash"
 
-	// `tools/bazel` is the default entry point for executing Bazel in the AOSP
+	// `build/bazel/bin/bazel` is the default entry point for executing Bazel in the AOSP
 	// source tree.
-	bazelExecutable := filepath.Join("tools", "bazel")
+	bazelExecutable := filepath.Join("build", "bazel", "bin", "bazel")
 	cmd := Command(ctx, config, "bazel", bazelExecutable)
 
 	// Append custom startup flags to the Bazel command. Startup flags affect
diff --git a/ui/build/build.go b/ui/build/build.go
index 2022e50..b9bd898 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -112,9 +112,19 @@
 // checkBazelMode fails the build if there are conflicting arguments for which bazel
 // build mode to use.
 func checkBazelMode(ctx Context, config Config) {
-	if config.bazelProdMode && config.bazelDevMode {
+	count := 0
+	if config.bazelProdMode {
+		count++
+	}
+	if config.bazelDevMode {
+		count++
+	}
+	if config.bazelStagingMode {
+		count++
+	}
+	if count > 1 {
 		ctx.Fatalln("Conflicting bazel mode.\n" +
-			"Do not specify both --bazel-mode and --bazel-mode-dev")
+			"Do not specify more than one of --bazel-mode and --bazel-mode-dev and --bazel-mode-staging ")
 	}
 }
 
diff --git a/ui/build/config.go b/ui/build/config.go
index f6f5b46..de10112 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -100,8 +100,9 @@
 
 	pathReplaced bool
 
-	bazelProdMode bool
-	bazelDevMode  bool
+	bazelProdMode    bool
+	bazelDevMode     bool
+	bazelStagingMode bool
 
 	// Set by multiproduct_kati
 	emptyNinjaFile bool
@@ -235,6 +236,19 @@
 	return nil
 }
 
+func defaultBazelProdMode(cfg *configImpl) bool {
+	// Envirnoment flag to disable Bazel for users which experience
+	// broken bazel-handled builds, or significant performance regressions.
+	if cfg.IsBazelMixedBuildForceDisabled() {
+		return false
+	}
+	// Darwin-host builds are currently untested with Bazel.
+	if runtime.GOOS == "darwin" {
+		return false
+	}
+	return true
+}
+
 func NewConfig(ctx Context, args ...string) Config {
 	ret := &configImpl{
 		environ:       OsEnvironment(),
@@ -463,10 +477,11 @@
 
 func buildConfig(config Config) *smpb.BuildConfig {
 	c := &smpb.BuildConfig{
-		ForceUseGoma:    proto.Bool(config.ForceUseGoma()),
-		UseGoma:         proto.Bool(config.UseGoma()),
-		UseRbe:          proto.Bool(config.UseRBE()),
-		BazelMixedBuild: proto.Bool(config.BazelBuildEnabled()),
+		ForceUseGoma:                proto.Bool(config.ForceUseGoma()),
+		UseGoma:                     proto.Bool(config.UseGoma()),
+		UseRbe:                      proto.Bool(config.UseRBE()),
+		BazelMixedBuild:             proto.Bool(config.BazelBuildEnabled()),
+		ForceDisableBazelMixedBuild: proto.Bool(config.IsBazelMixedBuildForceDisabled()),
 	}
 	c.Targets = append(c.Targets, config.arguments...)
 
@@ -721,6 +736,8 @@
 			c.bazelProdMode = true
 		} else if arg == "--bazel-mode-dev" {
 			c.bazelDevMode = true
+		} else if arg == "--bazel-mode-staging" {
+			c.bazelStagingMode = true
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -770,6 +787,9 @@
 			c.arguments = append(c.arguments, arg)
 		}
 	}
+	if (!c.bazelProdMode) && (!c.bazelDevMode) && (!c.bazelStagingMode) {
+		c.bazelProdMode = defaultBazelProdMode(c)
+	}
 }
 
 func (c *configImpl) configureLocale(ctx Context) {
@@ -907,7 +927,11 @@
 	return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag)
 }
 
-func (c *configImpl) Bp2BuildMarkerFile() string {
+func (c *configImpl) Bp2BuildFilesMarkerFile() string {
+	return shared.JoinPath(c.SoongOutDir(), "bp2build_files_marker")
+}
+
+func (c *configImpl) Bp2BuildWorkspaceMarkerFile() string {
 	return shared.JoinPath(c.SoongOutDir(), "bp2build_workspace_marker")
 }
 
@@ -1115,7 +1139,7 @@
 }
 
 func (c *configImpl) BazelBuildEnabled() bool {
-	return c.bazelProdMode || c.bazelDevMode
+	return c.bazelProdMode || c.bazelDevMode || c.bazelStagingMode
 }
 
 func (c *configImpl) StartRBE() bool {
@@ -1449,6 +1473,10 @@
 	return c.emptyNinjaFile
 }
 
+func (c *configImpl) IsBazelMixedBuildForceDisabled() bool {
+	return c.Environment().IsEnvTrue("BUILD_BROKEN_DISABLE_BAZEL")
+}
+
 func GetMetricsUploader(topDir string, env *Environment) string {
 	if p, ok := env.Get("METRICS_UPLOADER"); ok {
 		metricsUploader := filepath.Join(topDir, p)
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 150ec35..940d85c 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -28,6 +28,7 @@
 	"android/soong/ui/logger"
 	smpb "android/soong/ui/metrics/metrics_proto"
 	"android/soong/ui/status"
+
 	"google.golang.org/protobuf/encoding/prototext"
 
 	"google.golang.org/protobuf/proto"
@@ -89,7 +90,9 @@
 				t.Fatal(err)
 			})
 
+			env := Environment([]string{})
 			c := &configImpl{
+				environ:   &env,
 				parallel:  -1,
 				keepGoing: -1,
 			}
@@ -1008,46 +1011,62 @@
 		useBazel            bool
 		bazelDevMode        bool
 		bazelProdMode       bool
+		bazelStagingMode    bool
 		expectedBuildConfig *smpb.BuildConfig
 	}{
 		{
 			name:    "none set",
 			environ: Environment{},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(false),
-				UseGoma:         proto.Bool(false),
-				UseRbe:          proto.Bool(false),
-				BazelMixedBuild: proto.Bool(false),
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(false),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
 			},
 		},
 		{
 			name:    "force use goma",
 			environ: Environment{"FORCE_USE_GOMA=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(true),
-				UseGoma:         proto.Bool(false),
-				UseRbe:          proto.Bool(false),
-				BazelMixedBuild: proto.Bool(false),
+				ForceUseGoma:                proto.Bool(true),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(false),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
 			},
 		},
 		{
 			name:    "use goma",
 			environ: Environment{"USE_GOMA=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(false),
-				UseGoma:         proto.Bool(true),
-				UseRbe:          proto.Bool(false),
-				BazelMixedBuild: proto.Bool(false),
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(true),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(false),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
 			},
 		},
 		{
 			name:    "use rbe",
 			environ: Environment{"USE_RBE=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(false),
-				UseGoma:         proto.Bool(false),
-				UseRbe:          proto.Bool(true),
-				BazelMixedBuild: proto.Bool(false),
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(true),
+				BazelMixedBuild:             proto.Bool(false),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
+			},
+		},
+		{
+			name:    "disable mixed builds",
+			environ: Environment{"BUILD_BROKEN_DISABLE_BAZEL=1"},
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(false),
+				ForceDisableBazelMixedBuild: proto.Bool(true),
 			},
 		},
 		{
@@ -1055,10 +1074,11 @@
 			environ:  Environment{},
 			useBazel: true,
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(false),
-				UseGoma:         proto.Bool(false),
-				UseRbe:          proto.Bool(false),
-				BazelMixedBuild: proto.Bool(false),
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(false),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
 			},
 		},
 		{
@@ -1066,10 +1086,11 @@
 			environ:      Environment{},
 			bazelDevMode: true,
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(false),
-				UseGoma:         proto.Bool(false),
-				UseRbe:          proto.Bool(false),
-				BazelMixedBuild: proto.Bool(true),
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(true),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
 			},
 		},
 		{
@@ -1077,10 +1098,23 @@
 			environ:       Environment{},
 			bazelProdMode: true,
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(false),
-				UseGoma:         proto.Bool(false),
-				UseRbe:          proto.Bool(false),
-				BazelMixedBuild: proto.Bool(true),
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(true),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
+			},
+		},
+		{
+			name:             "bazel mixed build from staging mode",
+			environ:          Environment{},
+			bazelStagingMode: true,
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(true),
+				ForceDisableBazelMixedBuild: proto.Bool(false),
 			},
 		},
 		{
@@ -1089,11 +1123,12 @@
 			useBazel:  true,
 			arguments: []string{"droid", "dist"},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(false),
-				UseGoma:         proto.Bool(false),
-				UseRbe:          proto.Bool(false),
-				BazelMixedBuild: proto.Bool(false),
-				Targets:         []string{"droid", "dist"},
+				ForceUseGoma:                proto.Bool(false),
+				UseGoma:                     proto.Bool(false),
+				UseRbe:                      proto.Bool(false),
+				BazelMixedBuild:             proto.Bool(false),
+				Targets:                     []string{"droid", "dist"},
+				ForceDisableBazelMixedBuild: proto.Bool(false),
 			},
 		},
 		{
@@ -1102,14 +1137,16 @@
 				"FORCE_USE_GOMA=1",
 				"USE_GOMA=1",
 				"USE_RBE=1",
+				"BUILD_BROKEN_DISABLE_BAZEL=1",
 			},
 			useBazel:     true,
 			bazelDevMode: true,
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:    proto.Bool(true),
-				UseGoma:         proto.Bool(true),
-				UseRbe:          proto.Bool(true),
-				BazelMixedBuild: proto.Bool(true),
+				ForceUseGoma:                proto.Bool(true),
+				UseGoma:                     proto.Bool(true),
+				UseRbe:                      proto.Bool(true),
+				BazelMixedBuild:             proto.Bool(true),
+				ForceDisableBazelMixedBuild: proto.Bool(true),
 			},
 		},
 	}
@@ -1118,10 +1155,11 @@
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			c := &configImpl{
-				environ:       &tc.environ,
-				bazelDevMode:  tc.bazelDevMode,
-				bazelProdMode: tc.bazelProdMode,
-				arguments:     tc.arguments,
+				environ:          &tc.environ,
+				bazelDevMode:     tc.bazelDevMode,
+				bazelProdMode:    tc.bazelProdMode,
+				bazelStagingMode: tc.bazelStagingMode,
+				arguments:        tc.arguments,
 			}
 			config := Config{c}
 			checkBazelMode(ctx, config)
diff --git a/ui/build/context.go b/ui/build/context.go
index 4a4352c..2fef0d0 100644
--- a/ui/build/context.go
+++ b/ui/build/context.go
@@ -48,7 +48,7 @@
 		c.Tracer.Begin(desc, c.Thread)
 	}
 	if c.Metrics != nil {
-		c.Metrics.EventTracer.Begin(name, desc, c.Thread)
+		c.Metrics.EventTracer.Begin(name, desc)
 	}
 }
 
@@ -58,7 +58,7 @@
 		c.Tracer.End(c.Thread)
 	}
 	if c.Metrics != nil {
-		c.Metrics.SetTimeMetrics(c.Metrics.EventTracer.End(c.Thread))
+		c.Metrics.SetTimeMetrics(c.Metrics.EventTracer.End())
 	}
 }
 
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 6231e52..c3e52c6 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -94,6 +94,9 @@
 }
 
 func startRBE(ctx Context, config Config) {
+	if !config.GoogleProdCredsExist() && prodCredsAuthType(config) {
+		ctx.Fatalf("Unable to start RBE reproxy\nFAILED: Missing LOAS credentials.")
+	}
 	ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
 	defer ctx.EndTrace()
 
diff --git a/ui/build/soong.go b/ui/build/soong.go
index e0d67cc..4aded17 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -41,12 +41,13 @@
 	availableEnvFile = "soong.environment.available"
 	usedEnvFile      = "soong.environment.used"
 
-	soongBuildTag      = "build"
-	bp2buildTag        = "bp2build"
-	jsonModuleGraphTag = "modulegraph"
-	queryviewTag       = "queryview"
-	apiBp2buildTag     = "api_bp2build"
-	soongDocsTag       = "soong_docs"
+	soongBuildTag        = "build"
+	bp2buildFilesTag     = "bp2build_files"
+	bp2buildWorkspaceTag = "bp2build_workspace"
+	jsonModuleGraphTag   = "modulegraph"
+	queryviewTag         = "queryview"
+	apiBp2buildTag       = "api_bp2build"
+	soongDocsTag         = "soong_docs"
 
 	// bootstrapEpoch is used to determine if an incremental build is incompatible with the current
 	// version of bootstrap and needs cleaning before continuing the build.  Increment this for
@@ -235,7 +236,7 @@
 func bootstrapGlobFileList(config Config) []string {
 	return []string{
 		config.NamedGlobFile(soongBuildTag),
-		config.NamedGlobFile(bp2buildTag),
+		config.NamedGlobFile(bp2buildFilesTag),
 		config.NamedGlobFile(jsonModuleGraphTag),
 		config.NamedGlobFile(queryviewTag),
 		config.NamedGlobFile(apiBp2buildTag),
@@ -260,6 +261,9 @@
 	if config.bazelDevMode {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-dev")
 	}
+	if config.bazelStagingMode {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-staging")
+	}
 
 	mainSoongBuildInvocation := primaryBuilderInvocation(
 		config,
@@ -273,20 +277,33 @@
 		// Mixed builds call Bazel from soong_build and they therefore need the
 		// Bazel workspace to be available. Make that so by adding a dependency on
 		// the bp2build marker file to the action that invokes soong_build .
-		mainSoongBuildInvocation.Inputs = append(mainSoongBuildInvocation.Inputs,
-			config.Bp2BuildMarkerFile())
+		mainSoongBuildInvocation.OrderOnlyInputs = append(mainSoongBuildInvocation.OrderOnlyInputs,
+			config.Bp2BuildWorkspaceMarkerFile())
 	}
 
 	bp2buildInvocation := primaryBuilderInvocation(
 		config,
-		bp2buildTag,
-		config.Bp2BuildMarkerFile(),
+		bp2buildFilesTag,
+		config.Bp2BuildFilesMarkerFile(),
 		[]string{
-			"--bp2build_marker", config.Bp2BuildMarkerFile(),
+			"--bp2build_marker", config.Bp2BuildFilesMarkerFile(),
 		},
 		fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()),
 	)
 
+	bp2buildWorkspaceInvocation := primaryBuilderInvocation(
+		config,
+		bp2buildWorkspaceTag,
+		config.Bp2BuildWorkspaceMarkerFile(),
+		[]string{
+			"--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile(),
+		},
+		fmt.Sprintf("Creating Bazel symlink forest"),
+	)
+
+	bp2buildWorkspaceInvocation.Inputs = append(bp2buildWorkspaceInvocation.Inputs,
+		config.Bp2BuildFilesMarkerFile())
+
 	jsonModuleGraphInvocation := primaryBuilderInvocation(
 		config,
 		jsonModuleGraphTag,
@@ -358,6 +375,7 @@
 		primaryBuilderInvocations: []bootstrap.PrimaryBuilderInvocation{
 			mainSoongBuildInvocation,
 			bp2buildInvocation,
+			bp2buildWorkspaceInvocation,
 			jsonModuleGraphInvocation,
 			queryviewInvocation,
 			apiBp2buildInvocation,
@@ -396,7 +414,7 @@
 	soongBuildEnv := config.Environment().Copy()
 	soongBuildEnv.Set("TOP", os.Getenv("TOP"))
 	// For Bazel mixed builds.
-	soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel")
+	soongBuildEnv.Set("BAZEL_PATH", "./build/bazel/bin/bazel")
 	// Bazel's HOME var is set to an output subdirectory which doesn't exist. This
 	// prevents Bazel from file I/O in the actual user HOME directory.
 	soongBuildEnv.Set("BAZEL_HOME", absPath(ctx, filepath.Join(config.BazelOutDir(), "bazelhome")))
@@ -404,6 +422,7 @@
 	soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
 	soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
 	soongBuildEnv.Set("LOG_DIR", config.LogsDir())
+	soongBuildEnv.Set("BAZEL_DEPS_FILE", absPath(ctx, filepath.Join(config.BazelOutDir(), "bazel.list")))
 
 	// For Soong bootstrapping tests
 	if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
@@ -422,7 +441,7 @@
 		checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongBuildTag))
 
 		if config.BazelBuildEnabled() || config.Bp2Build() {
-			checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(bp2buildTag))
+			checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(bp2buildFilesTag))
 		}
 
 		if config.JsonModuleGraph() {
@@ -493,7 +512,7 @@
 	}
 
 	if config.Bp2Build() {
-		targets = append(targets, config.Bp2BuildMarkerFile())
+		targets = append(targets, config.Bp2BuildWorkspaceMarkerFile())
 	}
 
 	if config.Queryview() {
@@ -513,17 +532,22 @@
 		targets = append(targets, config.SoongNinjaFile())
 	}
 
-	ninja("bootstrap", "bootstrap.ninja", targets...)
-
 	if shouldCollectBuildSoongMetrics(config) {
-		soongBuildMetrics := loadSoongBuildMetrics(ctx, config)
-		if soongBuildMetrics != nil {
-			logSoongBuildMetrics(ctx, soongBuildMetrics)
-			if ctx.Metrics != nil {
-				ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
-			}
+		soongBuildMetricsFile := filepath.Join(config.LogsDir(), "soong_build_metrics.pb")
+		if err := os.Remove(soongBuildMetricsFile); err != nil && !os.IsNotExist(err) {
+			ctx.Verbosef("Failed to remove %s", soongBuildMetricsFile)
 		}
+		defer func() {
+			soongBuildMetrics := loadSoongBuildMetrics(ctx, soongBuildMetricsFile)
+			if soongBuildMetrics != nil {
+				logSoongBuildMetrics(ctx, soongBuildMetrics)
+				if ctx.Metrics != nil {
+					ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
+				}
+			}
+		}()
 	}
+	ninja("bootstrap", "bootstrap.ninja", targets...)
 
 	distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
 	distFile(ctx, config, config.SoongVarsFile(), "soong")
@@ -562,8 +586,7 @@
 	return config.SoongBuildInvocationNeeded()
 }
 
-func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics {
-	soongBuildMetricsFile := filepath.Join(config.LogsDir(), "soong_build_metrics.pb")
+func loadSoongBuildMetrics(ctx Context, soongBuildMetricsFile string) *soong_metrics_proto.SoongBuildMetrics {
 	buf, err := os.ReadFile(soongBuildMetricsFile)
 	if errors.Is(err, fs.ErrNotExist) {
 		// Soong may not have run during this invocation
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 687f519..9f14bdd 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -18,6 +18,7 @@
 // another.
 
 import (
+	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -56,7 +57,9 @@
 		}
 
 		if fi.IsDir() {
-			if l, err := ioutil.ReadDir(p); err == nil {
+			if l, err := ioutil.ReadDir(p); err != nil {
+				_, _ = fmt.Fprintf(os.Stderr, "Failed to find files under %s\n", p)
+			} else {
 				files := make([]string, 0, len(l))
 				for _, fi := range l {
 					files = append(files, filepath.Join(p, fi.Name()))
diff --git a/ui/logger/Android.bp b/ui/logger/Android.bp
index 269a5a0..7883ea6 100644
--- a/ui/logger/Android.bp
+++ b/ui/logger/Android.bp
@@ -25,4 +25,7 @@
     testSrcs: [
         "logger_test.go",
     ],
+    deps: [
+        "soong-ui-metrics",
+    ],
 }
diff --git a/ui/logger/logger.go b/ui/logger/logger.go
index 9b26ae8..1185298 100644
--- a/ui/logger/logger.go
+++ b/ui/logger/logger.go
@@ -29,6 +29,7 @@
 package logger
 
 import (
+	"android/soong/ui/metrics"
 	"errors"
 	"fmt"
 	"io"
@@ -72,8 +73,8 @@
 	Output(calldepth int, str string) error
 }
 
-// fatalLog is the type used when Fatal[f|ln]
-type fatalLog struct {
+// fatalError is the type used when Fatal[f|ln]
+type fatalError struct {
 	error
 }
 
@@ -127,7 +128,7 @@
 
 	if p == nil {
 		return
-	} else if log, ok := p.(fatalLog); ok {
+	} else if log, ok := p.(fatalError); ok {
 		fn(error(log))
 	} else {
 		panic(p)
@@ -141,6 +142,7 @@
 	fileLogger *log.Logger
 	mutex      sync.Mutex
 	file       *os.File
+	metrics    *metrics.Metrics
 }
 
 var _ Logger = &stdLogger{}
@@ -149,9 +151,14 @@
 // os.Stderr, but it may be a buffer for tests, or a separate log file if
 // the user doesn't need to see the output.
 func New(out io.Writer) *stdLogger {
+	return NewWithMetrics(out, nil)
+}
+
+func NewWithMetrics(out io.Writer, m *metrics.Metrics) *stdLogger {
 	return &stdLogger{
 		stderr:     log.New(out, "", log.Ltime),
 		fileLogger: log.New(ioutil.Discard, "", log.Ldate|log.Lmicroseconds|log.Llongfile),
+		metrics:    m,
 	}
 }
 
@@ -201,7 +208,7 @@
 	fatal := false
 	p := recover()
 
-	if _, ok := p.(fatalLog); ok {
+	if _, ok := p.(fatalError); ok {
 		fatal = true
 		p = nil
 	} else if p != nil {
@@ -217,40 +224,56 @@
 	}
 }
 
+type verbosityLevel int
+
+const (
+	verboseLog verbosityLevel = iota
+	infoLog
+	fatalLog
+	panicLog
+)
+
 // Output writes string to both stderr and the file log.
 func (s *stdLogger) Output(calldepth int, str string) error {
-	s.stderr.Output(calldepth+1, str)
+	return s.output(calldepth, str, infoLog)
+}
+
+// output writes string to stderr, the file log, and if fatal or panic, to metrics.
+func (s *stdLogger) output(calldepth int, str string, level verbosityLevel) error {
+	if level != verboseLog || s.verbose {
+		s.stderr.Output(calldepth+1, str)
+	}
+	if level >= fatalLog {
+		s.metrics.SetFatalOrPanicMessage(str)
+	}
 	return s.fileLogger.Output(calldepth+1, str)
 }
 
 // VerboseOutput is equivalent to Output, but only goes to the file log
 // unless SetVerbose(true) has been called.
 func (s *stdLogger) VerboseOutput(calldepth int, str string) error {
-	if s.verbose {
-		s.stderr.Output(calldepth+1, str)
-	}
-	return s.fileLogger.Output(calldepth+1, str)
+	return s.output(calldepth, str, verboseLog)
 }
 
 // Print prints to both stderr and the file log.
 // Arguments are handled in the manner of fmt.Print.
 func (s *stdLogger) Print(v ...interface{}) {
 	output := fmt.Sprint(v...)
-	s.Output(2, output)
+	s.output(2, output, infoLog)
 }
 
 // Printf prints to both stderr and the file log.
 // Arguments are handled in the manner of fmt.Printf.
 func (s *stdLogger) Printf(format string, v ...interface{}) {
 	output := fmt.Sprintf(format, v...)
-	s.Output(2, output)
+	s.output(2, output, infoLog)
 }
 
 // Println prints to both stderr and the file log.
 // Arguments are handled in the manner of fmt.Println.
 func (s *stdLogger) Println(v ...interface{}) {
 	output := fmt.Sprintln(v...)
-	s.Output(2, output)
+	s.output(2, output, infoLog)
 }
 
 // Verbose is equivalent to Print, but only goes to the file log unless
@@ -278,43 +301,43 @@
 // Cleanup will convert to a os.Exit(1).
 func (s *stdLogger) Fatal(v ...interface{}) {
 	output := fmt.Sprint(v...)
-	s.Output(2, output)
-	panic(fatalLog{errors.New(output)})
+	s.output(2, output, fatalLog)
+	panic(fatalError{errors.New(output)})
 }
 
 // Fatalf is equivalent to Printf() followed by a call to panic() that
 // Cleanup will convert to a os.Exit(1).
 func (s *stdLogger) Fatalf(format string, v ...interface{}) {
 	output := fmt.Sprintf(format, v...)
-	s.Output(2, output)
-	panic(fatalLog{errors.New(output)})
+	s.output(2, output, fatalLog)
+	panic(fatalError{errors.New(output)})
 }
 
 // Fatalln is equivalent to Println() followed by a call to panic() that
 // Cleanup will convert to a os.Exit(1).
 func (s *stdLogger) Fatalln(v ...interface{}) {
 	output := fmt.Sprintln(v...)
-	s.Output(2, output)
-	panic(fatalLog{errors.New(output)})
+	s.output(2, output, fatalLog)
+	panic(fatalError{errors.New(output)})
 }
 
 // Panic is equivalent to Print() followed by a call to panic().
 func (s *stdLogger) Panic(v ...interface{}) {
 	output := fmt.Sprint(v...)
-	s.Output(2, output)
+	s.output(2, output, panicLog)
 	panic(output)
 }
 
 // Panicf is equivalent to Printf() followed by a call to panic().
 func (s *stdLogger) Panicf(format string, v ...interface{}) {
 	output := fmt.Sprintf(format, v...)
-	s.Output(2, output)
+	s.output(2, output, panicLog)
 	panic(output)
 }
 
 // Panicln is equivalent to Println() followed by a call to panic().
 func (s *stdLogger) Panicln(v ...interface{}) {
 	output := fmt.Sprintln(v...)
-	s.Output(2, output)
+	s.output(2, output, panicLog)
 	panic(output)
 }
diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp
index 05db1d7..2301c56 100644
--- a/ui/metrics/Android.bp
+++ b/ui/metrics/Android.bp
@@ -25,7 +25,6 @@
         "soong-ui-metrics_upload_proto",
         "soong-ui-metrics_proto",
         "soong-ui-mk_metrics_proto",
-        "soong-ui-tracer",
         "soong-shared",
     ],
     srcs: [
diff --git a/ui/metrics/event.go b/ui/metrics/event.go
index ebe664f..b3a027e 100644
--- a/ui/metrics/event.go
+++ b/ui/metrics/event.go
@@ -31,7 +31,6 @@
 	"time"
 
 	soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
-	"android/soong/ui/tracer"
 
 	"google.golang.org/protobuf/proto"
 )
@@ -50,6 +49,10 @@
 	// for metrics analysis).
 	desc string
 
+	nonZeroExitCode bool
+
+	errorMsg *string
+
 	// The time that the event started to occur.
 	start time.Time
 
@@ -68,13 +71,18 @@
 
 func (e event) perfInfo() soong_metrics_proto.PerfInfo {
 	realTime := uint64(_now().Sub(e.start).Nanoseconds())
-	return soong_metrics_proto.PerfInfo{
+	perfInfo := soong_metrics_proto.PerfInfo{
 		Description:           proto.String(e.desc),
 		Name:                  proto.String(e.name),
 		StartTime:             proto.Uint64(uint64(e.start.UnixNano())),
 		RealTime:              proto.Uint64(realTime),
 		ProcessesResourceInfo: e.procResInfo,
+		NonZeroExit:           proto.Bool(e.nonZeroExitCode),
 	}
+	if m := e.errorMsg; m != nil {
+		perfInfo.ErrorMessage = proto.String(*m)
+	}
+	return perfInfo
 }
 
 // EventTracer is an array of events that provides functionality to trace a
@@ -94,6 +102,9 @@
 
 // peek returns the active build event.
 func (t *EventTracer) peek() *event {
+	if t.empty() {
+		return nil
+	}
 	return (*t)[t.lastIndex()]
 }
 
@@ -137,12 +148,12 @@
 }
 
 // Begin starts tracing the event.
-func (t *EventTracer) Begin(name, desc string, _ tracer.Thread) {
+func (t *EventTracer) Begin(name, desc string) {
 	t.push(newEvent(name, desc))
 }
 
 // End performs post calculations such as duration of the event, aggregates
 // the collected performance information into PerfInfo protobuf message.
-func (t *EventTracer) End(tracer.Thread) soong_metrics_proto.PerfInfo {
+func (t *EventTracer) End() soong_metrics_proto.PerfInfo {
 	return t.pop().perfInfo()
 }
diff --git a/ui/metrics/event_test.go b/ui/metrics/event_test.go
index 043450b..a80e7cf 100644
--- a/ui/metrics/event_test.go
+++ b/ui/metrics/event_test.go
@@ -17,8 +17,6 @@
 import (
 	"testing"
 	"time"
-
-	"android/soong/ui/tracer"
 )
 
 func TestEnd(t *testing.T) {
@@ -35,8 +33,31 @@
 		start: startTime,
 	})
 
-	perf := et.End(tracer.Thread(0))
+	perf := et.End()
 	if perf.GetRealTime() != uint64(dur.Nanoseconds()) {
 		t.Errorf("got %d, want %d nanoseconds for event duration", perf.GetRealTime(), dur.Nanoseconds())
 	}
 }
+
+func TestEndWithError(t *testing.T) {
+	startTime := time.Date(2020, time.July, 13, 13, 0, 0, 0, time.UTC)
+	dur := time.Nanosecond * 10
+	initialNow := _now
+	_now = func() time.Time { return startTime.Add(dur) }
+	defer func() { _now = initialNow }()
+
+	err := "foobar"
+	et := &EventTracer{}
+	et.push(&event{
+		desc:            "test",
+		name:            "test",
+		start:           startTime,
+		nonZeroExitCode: true,
+		errorMsg:        &err,
+	})
+
+	perf := et.End()
+	if msg := perf.GetErrorMessage(); msg != err {
+		t.Errorf("got %q, want %q for even error message", msg, err)
+	}
+}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 0c62865..ce2d946 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -125,6 +125,21 @@
 	}
 }
 
+// SetFatalOrPanicMessage stores a non-zero exit and the relevant message in the latest event if
+// available or the metrics base.
+func (m *Metrics) SetFatalOrPanicMessage(errMsg string) {
+	if m == nil {
+		return
+	}
+	if event := m.EventTracer.peek(); event != nil {
+		event.nonZeroExitCode = true
+		event.errorMsg = &errMsg
+	} else {
+		m.metrics.ErrorMessage = proto.String(errMsg)
+	}
+	m.metrics.NonZeroExit = proto.Bool(true)
+}
+
 // BuildConfig stores information about the build configuration.
 func (m *Metrics) BuildConfig(b *soong_metrics_proto.BuildConfig) {
 	m.metrics.BuildConfig = b
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 2dd8299..90d124b 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -338,6 +338,12 @@
 	BazelRuns []*PerfInfo `protobuf:"bytes,27,rep,name=bazel_runs,json=bazelRuns" json:"bazel_runs,omitempty"`
 	// The metrics of the experiment config fetcher
 	ExpConfigFetcher *ExpConfigFetcher `protobuf:"bytes,28,opt,name=exp_config_fetcher,json=expConfigFetcher" json:"exp_config_fetcher,omitempty"`
+	// Whether the build exited with a panic or non-zero exit code, includes both
+	// non-zero exits of recorded phases and non-recorded phases of the build.
+	NonZeroExit *bool `protobuf:"varint,29,opt,name=non_zero_exit,json=nonZeroExit" json:"non_zero_exit,omitempty"`
+	// The error message due to a non-zero exit _only_ if it did not occur in a
+	// recorded phase of the build.
+	ErrorMessage *string `protobuf:"bytes,30,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"`
 }
 
 // Default values for MetricsBase fields.
@@ -576,6 +582,20 @@
 	return nil
 }
 
+func (x *MetricsBase) GetNonZeroExit() bool {
+	if x != nil && x.NonZeroExit != nil {
+		return *x.NonZeroExit
+	}
+	return false
+}
+
+func (x *MetricsBase) GetErrorMessage() string {
+	if x != nil && x.ErrorMessage != nil {
+		return *x.ErrorMessage
+	}
+	return ""
+}
+
 type BuildConfig struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -592,6 +612,8 @@
 	// These are the targets soong passes to ninja, these targets include special
 	// targets such as droid as well as the regular build targets.
 	Targets []string `protobuf:"bytes,6,rep,name=targets" json:"targets,omitempty"`
+	// Whether the user explicitly disabled bazel mixed builds for this build.
+	ForceDisableBazelMixedBuild *bool `protobuf:"varint,7,opt,name=force_disable_bazel_mixed_build,json=forceDisableBazelMixedBuild" json:"force_disable_bazel_mixed_build,omitempty"`
 }
 
 func (x *BuildConfig) Reset() {
@@ -668,6 +690,13 @@
 	return nil
 }
 
+func (x *BuildConfig) GetForceDisableBazelMixedBuild() bool {
+	if x != nil && x.ForceDisableBazelMixedBuild != nil {
+		return *x.ForceDisableBazelMixedBuild
+	}
+	return false
+}
+
 type SystemResourceInfo struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -746,6 +775,11 @@
 	MemoryUse *uint64 `protobuf:"varint,5,opt,name=memory_use,json=memoryUse" json:"memory_use,omitempty"`
 	// The resource information of each executed process.
 	ProcessesResourceInfo []*ProcessResourceInfo `protobuf:"bytes,6,rep,name=processes_resource_info,json=processesResourceInfo" json:"processes_resource_info,omitempty"`
+	// Whether the phase of tool running exited with a panic or non-zero exit
+	// code.
+	NonZeroExit *bool `protobuf:"varint,7,opt,name=non_zero_exit,json=nonZeroExit" json:"non_zero_exit,omitempty"`
+	// The error message, if any, due to a non-zero exit.
+	ErrorMessage *string `protobuf:"bytes,8,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"`
 }
 
 func (x *PerfInfo) Reset() {
@@ -823,6 +857,20 @@
 	return nil
 }
 
+func (x *PerfInfo) GetNonZeroExit() bool {
+	if x != nil && x.NonZeroExit != nil {
+		return *x.NonZeroExit
+	}
+	return false
+}
+
+func (x *PerfInfo) GetErrorMessage() string {
+	if x != nil && x.ErrorMessage != nil {
+		return *x.ErrorMessage
+	}
+	return ""
+}
+
 type ProcessResourceInfo struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1361,7 +1409,7 @@
 var file_metrics_proto_rawDesc = []byte{
 	0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
 	0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x22, 0xad, 0x0d, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+	0x72, 0x69, 0x63, 0x73, 0x22, 0xf6, 0x0d, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
 	0x42, 0x61, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61,
 	0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
 	0x28, 0x03, 0x52, 0x12, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d,
@@ -1461,152 +1509,166 @@
 	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
 	0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68,
 	0x65, 0x72, 0x52, 0x10, 0x65, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74,
-	0x63, 0x68, 0x65, 0x72, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72,
-	0x69, 0x61, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d,
-	0x0a, 0x09, 0x55, 0x53, 0x45, 0x52, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a,
-	0x03, 0x45, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b,
-	0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41,
-	0x52, 0x4d, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12,
-	0x07, 0x0a, 0x03, 0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f,
-	0x36, 0x34, 0x10, 0x04, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f,
-	0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12,
-	0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
-	0x52, 0x06, 0x75, 0x73, 0x65, 0x52, 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63,
-	0x65, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
-	0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24,
-	0x0a, 0x0e, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e,
-	0x69, 0x6e, 0x6a, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69,
-	0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
-	0x0f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
-	0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28,
-	0x09, 0x52, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79,
-	0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f,
-	0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63,
-	0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65,
-	0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c,
-	0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76,
-	0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0x81, 0x02, 0x0a, 0x08,
-	0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63,
-	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64,
-	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d,
-	0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a,
-	0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65,
-	0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02,
-	0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a,
-	0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75,
-	0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28,
-	0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f,
-	0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73,
-	0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22,
-	0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75,
-	0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75,
-	0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d,
-	0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f,
-	0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63,
-	0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b,
-	0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b,
-	0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f,
-	0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69,
-	0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a,
-	0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c,
-	0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50,
-	0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f,
-	0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09,
-	0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f,
-	0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76,
-	0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
-	0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78,
-	0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76,
-	0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
-	0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74,
-	0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e,
-	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b,
-	0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
-	0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53,
-	0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b,
-	0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d,
-	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e,
-	0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65,
-	0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09,
-	0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b,
-	0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55,
-	0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
-	0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
-	0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65,
-	0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f,
-	0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65,
-	0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52,
-	0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42,
-	0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d,
-	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74,
-	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74,
-	0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63,
-	0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f,
-	0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a,
-	0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a,
-	0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c,
-	0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68,
-	0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
-	0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65,
-	0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f,
-	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
-	0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e,
-	0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e,
+	0x63, 0x68, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f,
+	0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e,
+	0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f,
+	0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x30, 0x0a,
+	0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x12, 0x08, 0x0a,
+	0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x53, 0x45, 0x52, 0x44,
+	0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e, 0x47, 0x10, 0x02, 0x22,
+	0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
+	0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10, 0x01, 0x12, 0x09, 0x0a,
+	0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x38, 0x36, 0x10,
+	0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10, 0x04, 0x22, 0x99, 0x02,
+	0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a,
+	0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f,
+	0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x52, 0x62,
+	0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x67,
+	0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65,
+	0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x61, 0x7a, 0x65, 0x6c,
+	0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x12, 0x2a, 0x0a,
+	0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x4d,
+	0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x72,
+	0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x72, 0x67,
+	0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x69, 0x73,
+	0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64,
+	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x66, 0x6f,
+	0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d,
+	0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79, 0x73,
+	0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61,
+	0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13,
+	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d,
+	0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65,
+	0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61,
+	0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50,
+	0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a,
+	0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09,
+	0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d,
+	0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18,
+	0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17,
+	0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e,
 	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49,
-	0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73,
-	0x49, 0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61,
-	0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
-	0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
-	0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72,
-	0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73,
-	0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d,
-	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d,
-	0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e,
-	0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f,
-	0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46,
-	0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12,
-	0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54,
-	0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c,
-	0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f,
-	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78,
-	0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78,
-	0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d,
-	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-	0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
+	0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22,
+	0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78,
+	0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63,
+	0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+	0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75,
+	0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a,
+	0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63,
+	0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65,
+	0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d,
+	0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e,
+	0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46,
+	0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70,
+	0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74,
+	0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62,
+	0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b,
+	0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b,
+	0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75,
+	0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79,
+	0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65,
+	0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61,
+	0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65,
+	0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79,
+	0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65,
+	0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e,
+	0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63,
+	0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79,
+	0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
+	0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66,
+	0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55,
+	0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73,
+	0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79,
+	0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
+	0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75,
+	0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75,
+	0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b,
+	0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10,
+	0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43,
+	0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e,
+	0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a,
+	0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20,
+	0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65,
+	0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69,
+	0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79,
+	0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73,
+	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
+	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69,
+	0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79,
+	0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02,
+	0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a,
+	0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74,
+	0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63,
+	0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61,
+	0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12,
+	0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53,
+	0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
+	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e,
+	0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69,
+	0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65,
+	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78,
+	0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a,
+	0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65,
+	0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
+	0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a,
+	0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63,
+	0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f,
+	0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00,
+	0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05,
+	0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49,
+	0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d,
+	0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d,
+	0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e,
+	0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45,
+	0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a,
+	0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73,
+	0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44,
+	0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x28,
+	0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f,
+	0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 }
 
 var (
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 4f8fe7f..07a7df1 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -111,6 +111,14 @@
 
   // The metrics of the experiment config fetcher
   optional ExpConfigFetcher exp_config_fetcher = 28;
+
+  // Whether the build exited with a panic or non-zero exit code, includes both
+  // non-zero exits of recorded phases and non-recorded phases of the build.
+  optional bool non_zero_exit = 29;
+
+  // The error message due to a non-zero exit _only_ if it did not occur in a
+  // recorded phase of the build.
+  optional string error_message = 30;
 }
 
 message BuildConfig {
@@ -130,6 +138,9 @@
   // These are the targets soong passes to ninja, these targets include special
   // targets such as droid as well as the regular build targets.
   repeated string targets = 6;
+
+  // Whether the user explicitly disabled bazel mixed builds for this build.
+  optional bool force_disable_bazel_mixed_build = 7;
 }
 
 message SystemResourceInfo {
@@ -160,6 +171,13 @@
 
   // The resource information of each executed process.
   repeated ProcessResourceInfo processes_resource_info = 6;
+
+  // Whether the phase of tool running exited with a panic or non-zero exit
+  // code.
+  optional bool non_zero_exit = 7;
+
+  // The error message, if any, due to a non-zero exit.
+  optional string error_message = 8;
 }
 
 message ProcessResourceInfo {