Merge "Remove clang indirection, affects command line ordering"
diff --git a/OWNERS b/OWNERS
index bbfd011..f15bd32 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,17 +1,22 @@
 # This file is included by several other projects as the list of people
 # approving build related projects.
 
+# AMER
 ahumesky@google.com
 asmundak@google.com
 ccross@android.com
 cparsons@google.com
 dwillemsen@google.com
 eakammer@google.com
-jingwen@google.com
 joeo@google.com
-lberki@google.com
+spandandas@google.com
+yuntaoxu@google.com
+
+# APAC
+jingwen@google.com
 ruperts@google.com
 
-# To expedite LON reviews
+# EMEA
 hansson@google.com
+lberki@google.com
 paulduffin@google.com
diff --git a/android/arch.go b/android/arch.go
index 340f136..cc70eee 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1987,6 +1987,10 @@
 	axisToProps[bazel.OsConfigurationAxis] = osToProp
 	axisToProps[bazel.OsArchConfigurationAxis] = archOsToProp
 
+	axisToProps[bazel.BionicConfigurationAxis] = map[string]interface{}{
+		"bionic": getTargetStruct(ctx, propertySet, archProperties, "Bionic"),
+	}
+
 	return axisToProps
 }
 
diff --git a/android/bazel.go b/android/bazel.go
index 992d8aa..46212dc 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -129,7 +129,7 @@
 	// Keep any existing BUILD files (and do not generate new BUILD files) for these directories
 	bp2buildKeepExistingBuildFile = map[string]bool{
 		// This is actually build/bazel/build.BAZEL symlinked to ./BUILD
-		".":/*recrusive = */ false,
+		".":/*recursive = */ false,
 
 		"build/bazel":/* recursive = */ true,
 		"build/pesto":/* recursive = */ true,
@@ -144,9 +144,10 @@
 
 	// Configure modules in these directories to enable bp2build_available: true or false by default.
 	bp2buildDefaultConfig = Bp2BuildConfig{
-		"bionic":                Bp2BuildDefaultTrueRecursively,
-		"external/gwp_asan":     Bp2BuildDefaultTrueRecursively,
-		"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
+		"bionic":                            Bp2BuildDefaultTrueRecursively,
+		"build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively,
+		"external/gwp_asan":                 Bp2BuildDefaultTrueRecursively,
+		"system/core/libcutils":             Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
 		"system/libbase":                  Bp2BuildDefaultTrueRecursively,
 		"system/logging/liblog":           Bp2BuildDefaultTrueRecursively,
@@ -180,7 +181,6 @@
 		//                                                       also depends on //system/logging/liblog:liblog (http://b/186822772)
 		"libc_ndk",          // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661)
 		"libc_malloc_hooks", // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
-		"libm",              // http://b/183064661, cc_library, math.h:25:16: error: unexpected token in argument list
 
 		// http://b/186823769: Needs C++ STL support, includes from unconverted standard libraries in //external/libcxx
 		// c++_static
@@ -189,7 +189,7 @@
 		"libBionicBenchmarksUtils", // cc_library_static, fatal error: 'map' file not found, from libcxx
 		"fmtlib",                   // cc_library_static, fatal error: 'cassert' file not found, from libcxx
 		"fmtlib_ndk",               // cc_library_static, fatal error: 'cassert' file not found
-		"libbase",                  // http://b/186826479, cc_library, fatal error: 'memory' file not found, from libcxx
+		"libbase",                  // Requires liblog. http://b/186826479, cc_library, fatal error: 'memory' file not found, from libcxx.
 
 		// http://b/186024507: Includes errors because of the system_shared_libs default value.
 		// Missing -isystem bionic/libc/include through the libc/libm/libdl
diff --git a/android/config.go b/android/config.go
index ed90c31..396b1a6 100644
--- a/android/config.go
+++ b/android/config.go
@@ -821,6 +821,12 @@
 	return Bool(c.productVariables.Unbundled_build_apps)
 }
 
+// Returns true if building image that aren't bundled with the platform.
+// UnbundledBuild() is always true when this is true.
+func (c *config) UnbundledBuildImage() bool {
+	return Bool(c.productVariables.Unbundled_build_image)
+}
+
 // Returns true if building modules against prebuilt SDKs.
 func (c *config) AlwaysUsePrebuiltSdks() bool {
 	return Bool(c.productVariables.Always_use_prebuilt_sdks)
diff --git a/android/module.go b/android/module.go
index 196b095..11f63bd 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2812,44 +2812,85 @@
 	return m.bp
 }
 
-// SrcIsModule decodes module references in the format ":name" into the module name, or empty string if the input
-// was not a module reference.
+// SrcIsModule decodes module references in the format ":unqualified-name" or "//namespace:name"
+// into the module name, or empty string if the input was not a module reference.
 func SrcIsModule(s string) (module string) {
-	if len(s) > 1 && s[0] == ':' {
-		return s[1:]
+	if len(s) > 1 {
+		if s[0] == ':' {
+			module = s[1:]
+			if !isUnqualifiedModuleName(module) {
+				// The module name should be unqualified but is not so do not treat it as a module.
+				module = ""
+			}
+		} else if s[0] == '/' && s[1] == '/' {
+			module = s
+		}
 	}
-	return ""
+	return module
 }
 
-// SrcIsModule decodes module references in the format ":name{.tag}" into the module name and tag, ":name" into the
-// module name and an empty string for the tag, or empty strings if the input was not a module reference.
+// SrcIsModuleWithTag decodes module references in the format ":unqualified-name{.tag}" or
+// "//namespace:name{.tag}" into the module name and tag, ":unqualified-name" or "//namespace:name"
+// into the module name and an empty string for the tag, or empty strings if the input was not a
+// module reference.
 func SrcIsModuleWithTag(s string) (module, tag string) {
-	if len(s) > 1 && s[0] == ':' {
-		module = s[1:]
-		if tagStart := strings.IndexByte(module, '{'); tagStart > 0 {
-			if module[len(module)-1] == '}' {
-				tag = module[tagStart+1 : len(module)-1]
-				module = module[:tagStart]
-				return module, tag
+	if len(s) > 1 {
+		if s[0] == ':' {
+			module = s[1:]
+		} else if s[0] == '/' && s[1] == '/' {
+			module = s
+		}
+
+		if module != "" {
+			if tagStart := strings.IndexByte(module, '{'); tagStart > 0 {
+				if module[len(module)-1] == '}' {
+					tag = module[tagStart+1 : len(module)-1]
+					module = module[:tagStart]
+				}
+			}
+
+			if s[0] == ':' && !isUnqualifiedModuleName(module) {
+				// The module name should be unqualified but is not so do not treat it as a module.
+				module = ""
+				tag = ""
 			}
 		}
-		return module, ""
 	}
-	return "", ""
+
+	return module, tag
 }
 
+// isUnqualifiedModuleName makes sure that the supplied module is an unqualified module name, i.e.
+// does not contain any /.
+func isUnqualifiedModuleName(module string) bool {
+	return strings.IndexByte(module, '/') == -1
+}
+
+// sourceOrOutputDependencyTag is the dependency tag added automatically by pathDepsMutator for any
+// module reference in a property annotated with `android:"path"` or passed to ExtractSourceDeps
+// or ExtractSourcesDeps.
+//
+// If uniquely identifies the dependency that was added as it contains both the module name used to
+// add the dependency as well as the tag. That makes it very simple to find the matching dependency
+// in GetModuleFromPathDep as all it needs to do is find the dependency whose tag matches the tag
+// used to add it. It does not need to check that the module name as returned by one of
+// Module.Name(), BaseModuleContext.OtherModuleName() or ModuleBase.BaseModuleName() matches the
+// name supplied in the tag. That means it does not need to handle differences in module names
+// caused by prebuilt_ prefix, or fully qualified module names.
 type sourceOrOutputDependencyTag struct {
 	blueprint.BaseDependencyTag
+
+	// The name of the module.
+	moduleName string
+
+	// The tag that will be passed to the module's OutputFileProducer.OutputFiles(tag) method.
 	tag string
 }
 
-func sourceOrOutputDepTag(tag string) blueprint.DependencyTag {
-	return sourceOrOutputDependencyTag{tag: tag}
+func sourceOrOutputDepTag(moduleName, tag string) blueprint.DependencyTag {
+	return sourceOrOutputDependencyTag{moduleName: moduleName, tag: tag}
 }
 
-// Deprecated, use IsSourceDepTagWithOutputTag(tag, "") instead.
-var SourceDepTag = sourceOrOutputDepTag("")
-
 // IsSourceDepTag returns true if the supplied blueprint.DependencyTag is one that was used to add
 // dependencies by either ExtractSourceDeps, ExtractSourcesDeps or automatically for properties
 // tagged with `android:"path"`.
@@ -2880,7 +2921,7 @@
 				ctx.ModuleErrorf("found source dependency duplicate: %q!", s)
 			} else {
 				set[s] = true
-				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
+				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m)
 			}
 		}
 	}
@@ -2893,7 +2934,7 @@
 func ExtractSourceDeps(ctx BottomUpMutatorContext, s *string) {
 	if s != nil {
 		if m, t := SrcIsModuleWithTag(*s); m != "" {
-			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
+			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m)
 		}
 	}
 }
diff --git a/android/module_test.go b/android/module_test.go
index 9ac9291..9e2b0ca 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -55,6 +55,27 @@
 			},
 			wantModule: "foo:bar",
 		},
+		{
+			name: "fully qualified",
+			args: args{
+				s: "//foo:bar",
+			},
+			wantModule: "//foo:bar",
+		},
+		{
+			name: "fully qualified with tag",
+			args: args{
+				s: "//foo:bar{.tag}",
+			},
+			wantModule: "//foo:bar{.tag}",
+		},
+		{
+			name: "invalid unqualified name",
+			args: args{
+				s: ":foo/bar",
+			},
+			wantModule: "",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -128,6 +149,35 @@
 			},
 			wantModule: "foo.bar}",
 		},
+		{
+			name: "fully qualified",
+			args: args{
+				s: "//foo:bar",
+			},
+			wantModule: "//foo:bar",
+		},
+		{
+			name: "fully qualified with tag",
+			args: args{
+				s: "//foo:bar{.tag}",
+			},
+			wantModule: "//foo:bar",
+			wantTag:    ".tag",
+		},
+		{
+			name: "invalid unqualified name",
+			args: args{
+				s: ":foo/bar",
+			},
+			wantModule: "",
+		},
+		{
+			name: "invalid unqualified name with tag",
+			args: args{
+				s: ":foo/bar{.tag}",
+			},
+			wantModule: "",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/android/path_properties.go b/android/path_properties.go
index 4446773..3976880 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -51,7 +51,7 @@
 	// Add dependencies to anything that is a module reference.
 	for _, s := range pathProperties {
 		if m, t := SrcIsModuleWithTag(s); m != "" {
-			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
+			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m)
 		}
 	}
 }
diff --git a/android/paths.go b/android/paths.go
index c5e4806..bec8a51 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -88,7 +88,8 @@
 // the Path methods that rely on module dependencies having been resolved.
 type ModuleWithDepsPathContext interface {
 	EarlyModulePathContext
-	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
+	VisitDirectDepsBlueprint(visit func(blueprint.Module))
+	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
 }
 
 // ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
@@ -484,10 +485,27 @@
 //
 // If tag is "" then the returned module will be the dependency that was added for ":moduleName".
 // Otherwise, it is the dependency that was added for ":moduleName{tag}".
-//
-// TODO(b/193228441) Make this handle fully qualified names, e.g. //namespace:moduleName.
 func GetModuleFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) blueprint.Module {
-	return ctx.GetDirectDepWithTag(moduleName, sourceOrOutputDepTag(tag))
+	var found blueprint.Module
+	// The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the
+	// module name and the tag. Dependencies added automatically for properties tagged with
+	// `android:"path"` are deduped so are guaranteed to be unique. It is possible for duplicate
+	// dependencies to be added manually using ExtractSourcesDeps or ExtractSourceDeps but even then
+	// it will always be the case that the dependencies will be identical, i.e. the same tag and same
+	// moduleName referring to the same dependency module.
+	//
+	// It does not matter whether the moduleName is a fully qualified name or if the module
+	// dependency is a prebuilt module. All that matters is the same information is supplied to
+	// create the tag here as was supplied to create the tag when the dependency was added so that
+	// this finds the matching dependency module.
+	expectedTag := sourceOrOutputDepTag(moduleName, tag)
+	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		depTag := ctx.OtherModuleDependencyTag(module)
+		if depTag == expectedTag {
+			found = module
+		}
+	})
+	return found
 }
 
 // PathsAndMissingDepsForModuleSrcExcludes returns a Paths{} containing the resolved references in
@@ -1268,10 +1286,11 @@
 // PathForModuleSrc returns a Path representing the paths... under the
 // module's local source directory.
 func PathForModuleSrc(ctx ModuleMissingDepsPathContext, pathComponents ...string) Path {
-	p, err := validatePath(pathComponents...)
-	if err != nil {
-		reportPathError(ctx, err)
-	}
+	// Just join the components textually just to make sure that it does not corrupt a fully qualified
+	// module reference, e.g. if the pathComponents is "://other:foo" then using filepath.Join() or
+	// validatePath() will corrupt it, e.g. replace "//" with "/". If the path is not a module
+	// reference then it will be validated by expandOneSrcPath anyway when it calls expandOneSrcPath.
+	p := strings.Join(pathComponents, string(filepath.Separator))
 	paths, err := expandOneSrcPath(ctx, p, nil)
 	if err != nil {
 		if depErr, ok := err.(missingDependencyError); ok {
diff --git a/android/paths_test.go b/android/paths_test.go
index 6f5d79e..f4e4ce1 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -1125,6 +1125,12 @@
 	rels []string
 	src  string
 	rel  string
+
+	// Make test specific preparations to the test fixture.
+	preparer FixturePreparer
+
+	// A test specific error handler.
+	errorHandler FixtureErrorHandler
 }
 
 func testPathForModuleSrc(t *testing.T, tests []pathForModuleSrcTestCase) {
@@ -1157,14 +1163,23 @@
 				"foo/src_special/$": nil,
 			}
 
+			errorHandler := test.errorHandler
+			if errorHandler == nil {
+				errorHandler = FixtureExpectsNoErrors
+			}
+
 			result := GroupFixturePreparers(
 				FixtureRegisterWithContext(func(ctx RegistrationContext) {
 					ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory)
 					ctx.RegisterModuleType("output_file_provider", pathForModuleSrcOutputFileProviderModuleFactory)
-					ctx.RegisterModuleType("filegroup", FileGroupFactory)
 				}),
+				PrepareForTestWithFilegroup,
+				PrepareForTestWithNamespace,
 				mockFS.AddToFixture(),
-			).RunTest(t)
+				OptionalFixturePreparer(test.preparer),
+			).
+				ExtendWithErrorHandler(errorHandler).
+				RunTest(t)
 
 			m := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
 
@@ -1333,6 +1348,73 @@
 			src: "foo/src_special/$",
 			rel: "src_special/$",
 		},
+		{
+			// This test makes sure that an unqualified module name cannot contain characters that make
+			// it appear as a qualified module name.
+			name: "output file provider, invalid fully qualified name",
+			bp: `
+			test {
+				name: "foo",
+				src: "://other:b",
+				srcs: ["://other:c"],
+			}`,
+			preparer: FixtureAddTextFile("other/Android.bp", `
+				soong_namespace {}
+
+				output_file_provider {
+					name: "b",
+					outs: ["gen/b"],
+				}
+
+				output_file_provider {
+					name: "c",
+					outs: ["gen/c"],
+				}
+			`),
+			src:  "foo/:/other:b",
+			rel:  ":/other:b",
+			srcs: []string{"foo/:/other:c"},
+			rels: []string{":/other:c"},
+		},
+		{
+			name: "output file provider, missing fully qualified name",
+			bp: `
+			test {
+				name: "foo",
+				src: "//other:b",
+				srcs: ["//other:c"],
+			}`,
+			errorHandler: FixtureExpectsAllErrorsToMatchAPattern([]string{
+				`"foo" depends on undefined module "//other:b"`,
+				`"foo" depends on undefined module "//other:c"`,
+			}),
+		},
+		{
+			name: "output file provider, fully qualified name",
+			bp: `
+			test {
+				name: "foo",
+				src: "//other:b",
+				srcs: ["//other:c"],
+			}`,
+			src:  "out/soong/.intermediates/other/b/gen/b",
+			rel:  "gen/b",
+			srcs: []string{"out/soong/.intermediates/other/c/gen/c"},
+			rels: []string{"gen/c"},
+			preparer: FixtureAddTextFile("other/Android.bp", `
+				soong_namespace {}
+
+				output_file_provider {
+					name: "b",
+					outs: ["gen/b"],
+				}
+
+				output_file_provider {
+					name: "c",
+					outs: ["gen/c"],
+				}
+			`),
+		},
 	}
 
 	testPathForModuleSrc(t, tests)
diff --git a/android/prebuilt.go b/android/prebuilt.go
index f3493bd..e611502 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -61,6 +61,16 @@
 	// a matching name.
 	Prefer *bool `android:"arch_variant"`
 
+	// When specified this names a Soong config variable that controls the prefer property.
+	//
+	// If the value of the named Soong config variable is true then prefer is set to false and vice
+	// versa. If the Soong config variable is not set then it defaults to false, so prefer defaults
+	// to true.
+	//
+	// If specified then the prefer property is ignored in favor of the value of the Soong config
+	// variable.
+	Use_source_config_var *ConfigVarProperties
+
 	SourceExists bool `blueprint:"mutated"`
 	UsePrebuilt  bool `blueprint:"mutated"`
 
@@ -68,6 +78,22 @@
 	PrebuiltRenamedToSource bool `blueprint:"mutated"`
 }
 
+// Properties that can be used to select a Soong config variable.
+type ConfigVarProperties struct {
+	// Allow instances of this struct to be used as a property value in a BpPropertySet.
+	BpPrintableBase
+
+	// The name of the configuration namespace.
+	//
+	// As passed to add_soong_config_namespace in Make.
+	Config_namespace *string
+
+	// The name of the configuration variable.
+	//
+	// As passed to add_soong_config_var_value in Make.
+	Var_name *string
+}
+
 type Prebuilt struct {
 	properties PrebuiltProperties
 
@@ -364,12 +390,18 @@
 		return false
 	}
 
-	// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
-	if Bool(p.properties.Prefer) {
+	// If source is not available or is disabled then always use the prebuilt.
+	if source == nil || !source.Enabled() {
 		return true
 	}
 
-	return source == nil || !source.Enabled()
+	// If the use_source_config_var property is set then it overrides the prefer property setting.
+	if configVar := p.properties.Use_source_config_var; configVar != nil {
+		return !ctx.Config().VendorConfig(proptools.String(configVar.Config_namespace)).Bool(proptools.String(configVar.Var_name))
+	}
+
+	// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
+	return Bool(p.properties.Prefer)
 }
 
 func (p *Prebuilt) SourceExists() bool {
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 23524a5..dcd77ea 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -26,6 +26,7 @@
 	replaceBp bool // modules is added to default bp boilerplate if false.
 	modules   string
 	prebuilt  []OsType
+	preparer  FixturePreparer
 }{
 	{
 		name: "no prebuilt",
@@ -291,6 +292,86 @@
 			}`,
 		prebuilt: []OsType{Android, BuildOs},
 	},
+	{
+		name: "prebuilt use_source_config_var={acme, use_source} - no var specified",
+		modules: `
+			source {
+				name: "bar",
+			}
+
+			prebuilt {
+				name: "bar",
+				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+				srcs: ["prebuilt_file"],
+			}`,
+		// When use_source_env is specified then it will use the prebuilt by default if the environment
+		// variable is not set.
+		prebuilt: []OsType{Android, BuildOs},
+	},
+	{
+		name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=false",
+		modules: `
+			source {
+				name: "bar",
+			}
+
+			prebuilt {
+				name: "bar",
+				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+				srcs: ["prebuilt_file"],
+			}`,
+		preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.VendorVars = map[string]map[string]string{
+				"acme": {
+					"use_source": "false",
+				},
+			}
+		}),
+		// Setting the environment variable named in use_source_env to false will cause the prebuilt to
+		// be used.
+		prebuilt: []OsType{Android, BuildOs},
+	},
+	{
+		name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true",
+		modules: `
+			source {
+				name: "bar",
+			}
+
+			prebuilt {
+				name: "bar",
+				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+				srcs: ["prebuilt_file"],
+			}`,
+		preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.VendorVars = map[string]map[string]string{
+				"acme": {
+					"use_source": "true",
+				},
+			}
+		}),
+		// Setting the environment variable named in use_source_env to true will cause the source to be
+		// used.
+		prebuilt: nil,
+	},
+	{
+		name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true, no source",
+		modules: `
+			prebuilt {
+				name: "bar",
+				use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+				srcs: ["prebuilt_file"],
+			}`,
+		preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.VendorVars = map[string]map[string]string{
+				"acme": {
+					"use_source": "true",
+				},
+			}
+		}),
+		// Although the environment variable says to use source there is no source available.
+		prebuilt: []OsType{Android, BuildOs},
+	},
 }
 
 func TestPrebuilts(t *testing.T) {
@@ -329,6 +410,7 @@
 				}),
 				fs.AddToFixture(),
 				FixtureRegisterWithContext(registerTestPrebuiltModules),
+				OptionalFixturePreparer(test.preparer),
 			).RunTestWithBp(t, bp)
 
 			for _, variant := range result.ModuleVariantsForTests("foo") {
diff --git a/android/sdk.go b/android/sdk.go
index e700031..da740f3 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -239,6 +239,12 @@
 	// to the zip
 	CopyToSnapshot(src Path, dest string)
 
+	// Return the path to an empty file.
+	//
+	// This can be used by sdk member types that need to create an empty file in the snapshot, simply
+	// pass the value returned from this to the CopyToSnapshot() method.
+	EmptyFile() Path
+
 	// Unzip the supplied zip into the snapshot relative directory destDir.
 	UnzipToSnapshot(zipPath Path, destDir string)
 
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 8f252d9..b2f8eaa 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -313,6 +313,51 @@
 	})
 }
 
+func TestNonExistentPropertyInSoongConfigModule(t *testing.T) {
+	bp := `
+		soong_config_module_type {
+			name: "acme_test",
+			module_type: "test",
+			config_namespace: "acme",
+			bool_variables: ["feature1"],
+			properties: ["made_up_property"],
+		}
+
+		acme_test {
+			name: "foo",
+			cflags: ["-DGENERIC"],
+			soong_config_variables: {
+				feature1: {
+					made_up_property: true,
+				},
+			},
+		}
+    `
+
+	fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
+		return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.VendorVars = vars
+		})
+	}
+
+	GroupFixturePreparers(
+		fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}),
+		PrepareForTestWithDefaults,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
+			ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
+			ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
+			ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+			ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
+			ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
+		}),
+		FixtureWithRootAndroidBp(bp),
+	).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
+		// TODO(b/171232169): improve the error message for non-existent properties
+		`unrecognized property "soong_config_variables`,
+	})).RunTest(t)
+}
+
 func testConfigWithVendorVars(buildDir, bp string, fs map[string][]byte, vendorVars map[string]map[string]string) Config {
 	config := TestConfig(buildDir, nil, bp, fs)
 
diff --git a/android/variable.go b/android/variable.go
index b6e168c..bbb9868 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -225,6 +225,7 @@
 	Allow_missing_dependencies   *bool `json:",omitempty"`
 	Unbundled_build              *bool `json:",omitempty"`
 	Unbundled_build_apps         *bool `json:",omitempty"`
+	Unbundled_build_image        *bool `json:",omitempty"`
 	Always_use_prebuilt_sdks     *bool `json:",omitempty"`
 	Skip_boot_jars_check         *bool `json:",omitempty"`
 	Malloc_not_svelte            *bool `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 11df288..d385ac1 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2240,6 +2240,7 @@
 	android.InitDefaultableModule(module)
 	android.InitSdkAwareModule(module)
 	android.InitOverridableModule(module, &module.overridableProperties.Overrides)
+	android.InitBazelModule(module)
 	return module
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b5b1d44..422e46c 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4687,16 +4687,26 @@
 		p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
 		dexJarBuildPath := p.DexJarBuildPath()
 		stem := android.RemoveOptionalPrebuiltPrefix(name)
-		if expected, actual := ".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", android.NormalizePathForTesting(dexJarBuildPath); actual != expected {
-			t.Errorf("Incorrect DexJarBuildPath value '%s', expected '%s'", actual, expected)
-		}
+		android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.",
+			".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar",
+			android.NormalizePathForTesting(dexJarBuildPath))
+	}
+
+	checkDexJarInstallPath := func(t *testing.T, ctx *android.TestContext, name string) {
+		// Make sure the import has been given the correct path to the dex jar.
+		p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
+		dexJarBuildPath := p.DexJarInstallPath()
+		stem := android.RemoveOptionalPrebuiltPrefix(name)
+		android.AssertStringEquals(t, "DexJarInstallPath should be apex-related path.",
+			"target/product/test_device/apex/myapex/javalib/"+stem+".jar",
+			android.NormalizePathForTesting(dexJarBuildPath))
 	}
 
 	ensureNoSourceVariant := func(t *testing.T, ctx *android.TestContext, name string) {
 		// Make sure that an apex variant is not created for the source module.
-		if expected, actual := []string{"android_common"}, ctx.ModuleVariantsForTests(name); !reflect.DeepEqual(expected, actual) {
-			t.Errorf("invalid set of variants for %q: expected %q, found %q", "libfoo", expected, actual)
-		}
+		android.AssertArrayString(t, "Check if there is no source variant",
+			[]string{"android_common"},
+			ctx.ModuleVariantsForTests(name))
 	}
 
 	t.Run("prebuilt only", func(t *testing.T) {
@@ -4745,8 +4755,10 @@
 		}
 
 		checkDexJarBuildPath(t, ctx, "libfoo")
+		checkDexJarInstallPath(t, ctx, "libfoo")
 
 		checkDexJarBuildPath(t, ctx, "libbar")
+		checkDexJarInstallPath(t, ctx, "libbar")
 	})
 
 	t.Run("prebuilt with source preferred", func(t *testing.T) {
@@ -4792,9 +4804,11 @@
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
 
 		checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
+		checkDexJarInstallPath(t, ctx, "prebuilt_libfoo")
 		ensureNoSourceVariant(t, ctx, "libfoo")
 
 		checkDexJarBuildPath(t, ctx, "prebuilt_libbar")
+		checkDexJarInstallPath(t, ctx, "prebuilt_libbar")
 		ensureNoSourceVariant(t, ctx, "libbar")
 	})
 
@@ -4842,9 +4856,11 @@
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
 
 		checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
+		checkDexJarInstallPath(t, ctx, "prebuilt_libfoo")
 		ensureNoSourceVariant(t, ctx, "libfoo")
 
 		checkDexJarBuildPath(t, ctx, "prebuilt_libbar")
+		checkDexJarInstallPath(t, ctx, "prebuilt_libbar")
 		ensureNoSourceVariant(t, ctx, "libbar")
 	})
 }
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 279cf54..7209c02 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -398,6 +398,7 @@
 			name: "foo",
 			prefer: false,
 			shared_library: false,
+			permitted_packages: ["foo"],
 			public: {
 				jars: ["sdk_library/public/foo-stubs.jar"],
 				stub_srcs: ["sdk_library/public/foo_stub_sources"],
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 282c606..35f194d 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -91,6 +91,11 @@
 		conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
 	}
 
+	platformBionicMap = map[string]string{
+		"bionic":          "//build/bazel/platforms/os:bionic",
+		conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
+	}
+
 	platformOsArchMap = map[string]string{
 		osArchAndroidArm:        "//build/bazel/platforms/os_arch:android_arm",
 		osArchAndroidArm64:      "//build/bazel/platforms/os_arch:android_arm64",
@@ -117,6 +122,7 @@
 	arch
 	os
 	osArch
+	bionic
 	productVariables
 )
 
@@ -126,6 +132,7 @@
 		arch:             "arch",
 		os:               "os",
 		osArch:           "arch_os",
+		bionic:           "bionic",
 		productVariables: "product_variables",
 	}[ct]
 }
@@ -148,6 +155,10 @@
 		if _, ok := platformOsArchMap[config]; !ok {
 			panic(fmt.Errorf("Unknown os+arch: %s", config))
 		}
+	case bionic:
+		if _, ok := platformBionicMap[config]; !ok {
+			panic(fmt.Errorf("Unknown for %s: %s", ct.String(), config))
+		}
 	case productVariables:
 		// do nothing
 	default:
@@ -167,6 +178,8 @@
 		return platformOsMap[config]
 	case osArch:
 		return platformOsArchMap[config]
+	case bionic:
+		return platformBionicMap[config]
 	case productVariables:
 		if config == conditionsDefault {
 			return ConditionsDefaultSelectKey
@@ -186,6 +199,8 @@
 	OsConfigurationAxis = ConfigurationAxis{configurationType: os}
 	// An axis for arch+os-specific configurations
 	OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
+	// An axis for bionic os-specific configurations
+	BionicConfigurationAxis = ConfigurationAxis{configurationType: bionic}
 )
 
 // ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/properties.go b/bazel/properties.go
index 0dd47da..2656bad 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -321,7 +321,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		la.Value = &value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if la.ConfigurableValues == nil {
 			la.ConfigurableValues = make(configurableLabels)
 		}
@@ -337,7 +337,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return *la.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		return *la.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -394,7 +394,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		ba.Value = value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if ba.ConfigurableValues == nil {
 			ba.ConfigurableValues = make(configurableBools)
 		}
@@ -410,7 +410,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return ba.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if v, ok := ba.ConfigurableValues[axis][config]; ok {
 			return &v
 		} else {
@@ -509,7 +509,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -525,7 +525,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		return lla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -558,6 +558,19 @@
 	return len(lla.ConfigurableValues) > 0
 }
 
+// IsEmpty returns true if the attribute has no values under any configuration.
+func (lla LabelListAttribute) IsEmpty() bool {
+	if len(lla.Value.Includes) > 0 {
+		return false
+	}
+	for axis, _ := range lla.ConfigurableValues {
+		if lla.ConfigurableValues[axis].HasConfigurableValues() {
+			return false
+		}
+	}
+	return true
+}
+
 // ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
 // the base value and included in default values as appropriate.
 func (lla *LabelListAttribute) ResolveExcludes() {
@@ -669,7 +682,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sla.Value = list
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		if sla.ConfigurableValues == nil {
 			sla.ConfigurableValues = make(configurableStringLists)
 		}
@@ -685,7 +698,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sla.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, bionic, productVariables:
 		return sla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index fbf6fa2..f4a1016 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -46,3 +46,23 @@
     manifest = "manifest.json",
 )`}})
 }
+
+func TestApexBundleHasBazelModuleProps(t *testing.T) {
+	runApexTestCase(t, bp2buildTestCase{
+		description:                        "apex - has bazel module props",
+		moduleTypeUnderTest:                "apex",
+		moduleTypeUnderTestFactory:         apex.BundleFactory,
+		moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build,
+		filesystem:                         map[string]string{},
+		blueprint: `
+apex {
+	name: "apogee",
+	manifest: "manifest.json",
+	bazel_module: { bp2build_available: true },
+}
+`,
+		expectedBazelTargets: []string{`apex(
+    name = "apogee",
+    manifest = "manifest.json",
+)`}})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 285677a..662d9d1 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -118,6 +118,7 @@
 		moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
 		filesystem: map[string]string{
 			"android.cpp": "",
+			"bionic.cpp":  "",
 			"darwin.cpp":  "",
 			// Refer to cc.headerExts for the supported header extensions in Soong.
 			"header.h":         "",
@@ -164,6 +165,9 @@
         darwin: {
             srcs: ["darwin.cpp"],
         },
+        bionic: {
+          srcs: ["bionic.cpp"]
+        },
     },
 }
 `,
@@ -190,6 +194,9 @@
         "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
         "//build/bazel/platforms/os:linux": ["linux.cpp"],
         "//conditions:default": [],
+    }) + select({
+        "//build/bazel/platforms/os:bionic": ["bionic.cpp"],
+        "//conditions:default": [],
     }),
 )`}})
 }
@@ -674,6 +681,10 @@
 		blueprint: soongCcLibraryPreamble,
 		expectedBazelTargets: []string{`cc_library(
     name = "a",
+    asflags = [
+        "-Ifoo/bar",
+        "-I$(BINDIR)/foo/bar",
+    ],
     copts = [
         "-Ifoo/bar",
         "-I$(BINDIR)/foo/bar",
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 40edec8..c33889f 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1413,7 +1413,7 @@
 
 func TestCcLibraryStaticProductVariableStringReplacement(t *testing.T) {
 	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description:                        "cc_library_static product variable selects",
+		description:                        "cc_library_static product variable string replacement",
 		moduleTypeUnderTest:                "cc_library_static",
 		moduleTypeUnderTestFactory:         cc.LibraryStaticFactory,
 		moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
@@ -1422,7 +1422,7 @@
 		blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
-    srcs: ["common.c"],
+    srcs: ["common.S"],
     product_variables: {
       platform_sdk_version: {
           asflags: ["-DPLATFORM_SDK_VERSION=%d"],
@@ -1431,7 +1431,10 @@
 } `,
 		expectedBazelTargets: []string{`cc_library_static(
     name = "foo_static",
-    asflags = select({
+    asflags = [
+        "-I.",
+        "-I$(BINDIR)/.",
+    ] + select({
         "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
         "//conditions:default": [],
     }),
@@ -1440,7 +1443,7 @@
         "-I$(BINDIR)/.",
     ],
     linkstatic = True,
-    srcs_c = ["common.c"],
+    srcs_as = ["common.S"],
 )`},
 	})
 }
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 8ede226..df4924b 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -211,6 +211,7 @@
             asflags: ["-DPLATFORM_SDK_VERSION=%d"],
         },
     },
+    srcs: ["src.S"],
 }
 `,
 		expectedBazelTargets: []string{`cc_object(
@@ -220,6 +221,7 @@
         "//conditions:default": [],
     }),
     copts = ["-fno-addrsig"],
+    srcs_as = ["src.S"],
 )`,
 		},
 	})
@@ -240,7 +242,7 @@
             cflags: ["-fPIC"], // string list
         },
         arm: {
-            srcs: ["arch/arm/file.S"], // label list
+            srcs: ["arch/arm/file.cpp"], // label list
         },
     },
 }
@@ -257,7 +259,7 @@
         "//conditions:default": [],
     }),
     srcs = ["a.cpp"] + select({
-        "//build/bazel/platforms/arch:arm": ["arch/arm/file.S"],
+        "//build/bazel/platforms/arch:arm": ["arch/arm/file.cpp"],
         "//conditions:default": [],
     }),
 )`,
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index adb0a7b..a608630 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -136,6 +136,10 @@
 		Name: "removeScudoProperty",
 		Fix:  runPatchListMod(removeObsoleteProperty("sanitize.scudo")),
 	},
+	{
+		Name: "formatFlagProperties",
+		Fix:  runPatchListMod(formatFlagProperties),
+	},
 }
 
 func NewFixRequest() FixRequest {
@@ -1343,3 +1347,69 @@
 	}
 	return false
 }
+
+func formatFlagProperty(mod *parser.Module, field string, buf []byte, patchlist *parser.PatchList) error {
+	// the comment or empty lines in the value of the field are skipped
+	listValue, ok := getLiteralListProperty(mod, field)
+	if !ok {
+		// if do not find
+		return nil
+	}
+	for i := 0; i < len(listValue.Values); i++ {
+		curValue, ok := listValue.Values[i].(*parser.String)
+		if !ok {
+			return fmt.Errorf("Expecting string for %s.%s fields", mod.Type, field)
+		}
+		if !strings.HasPrefix(curValue.Value, "-") {
+			return fmt.Errorf("Expecting the string `%s` starting with '-'", curValue.Value)
+		}
+		if i+1 < len(listValue.Values) {
+			nextValue, ok := listValue.Values[i+1].(*parser.String)
+			if !ok {
+				return fmt.Errorf("Expecting string for %s.%s fields", mod.Type, field)
+			}
+			if !strings.HasPrefix(nextValue.Value, "-") {
+				// delete the line
+				err := patchlist.Add(curValue.Pos().Offset, curValue.End().Offset+2, "")
+				if err != nil {
+					return err
+				}
+				// replace the line
+				value := "\"" + curValue.Value + " " + nextValue.Value + "\","
+				err = patchlist.Add(nextValue.Pos().Offset, nextValue.End().Offset+1, value)
+				if err != nil {
+					return err
+				}
+				// combined two lines to one
+				i++
+			}
+		}
+	}
+	return nil
+}
+
+func formatFlagProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
+	relevantFields := []string{
+		// cc flags
+		"asflags",
+		"cflags",
+		"clang_asflags",
+		"clang_cflags",
+		"conlyflags",
+		"cppflags",
+		"ldflags",
+		"tidy_flags",
+		// java flags
+		"aaptflags",
+		"dxflags",
+		"javacflags",
+		"kotlincflags",
+	}
+	for _, field := range relevantFields {
+		err := formatFlagProperty(mod, field, buf, patchlist)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index b994e25..d8772c1 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -1336,3 +1336,275 @@
 		})
 	}
 }
+
+func TestFormatFlagProperty(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "group options and values for apptflags, dxflags, javacflags, and kotlincflags",
+			in: `
+				android_test {
+					name: "foo",
+					aaptflags: [
+						// comment1_1
+						"--flag1",
+						// comment1_2
+						"1",
+						// comment2_1
+						// comment2_2
+						"--flag2",
+						// comment3_1
+						// comment3_2
+						// comment3_3
+						"--flag3",
+						// comment3_4
+						// comment3_5
+						// comment3_6
+						"3",
+						// other comment1_1
+						// other comment1_2
+					],
+					dxflags: [
+						"--flag1",
+						// comment1_1
+						"1",
+						// comment2_1
+						"--flag2",
+						// comment3_1
+						"--flag3",
+						// comment3_2
+						"3",
+					],
+					javacflags: [
+						"--flag1",
+
+						"1",
+						"--flag2",
+						"--flag3",
+						"3",
+					],
+					kotlincflags: [
+
+						"--flag1",
+						"1",
+
+						"--flag2",
+						"--flag3",
+						"3",
+
+					],
+				}
+			`,
+			out: `
+				android_test {
+					name: "foo",
+					aaptflags: [
+						// comment1_1
+						// comment1_2
+						"--flag1 1",
+						// comment2_1
+						// comment2_2
+						"--flag2",
+						// comment3_1
+						// comment3_2
+						// comment3_3
+						// comment3_4
+						// comment3_5
+						// comment3_6
+						"--flag3 3",
+						// other comment1_1
+						// other comment1_2
+					],
+					dxflags: [
+						// comment1_1
+						"--flag1 1",
+						// comment2_1
+						"--flag2",
+						// comment3_1
+						// comment3_2
+						"--flag3 3",
+					],
+					javacflags: [
+
+						"--flag1 1",
+						"--flag2",
+						"--flag3 3",
+					],
+					kotlincflags: [
+
+						"--flag1 1",
+
+						"--flag2",
+						"--flag3 3",
+
+					],
+				}
+			`,
+		},
+		{
+			name: "group options and values for asflags, cflags, clang_asflags, clang_cflags, conlyflags, cppflags, ldflags, and tidy_flags",
+			in: `
+				cc_test {
+					name: "foo",
+					asflags: [
+						// comment1_1
+						"--flag1",
+						"1",
+						// comment2_1
+						// comment2_2
+						"--flag2",
+						// comment2_3
+						"2",
+						// comment3_1
+						// comment3_2
+						"--flag3",
+						// comment3_3
+						// comment3_4
+						// comment3_4
+						"3",
+						// comment4_1
+						// comment4_2
+						// comment4_3
+						"--flag4",
+					],
+					cflags: [
+						"--flag1",
+						"1",
+						"--flag2",
+						"2",
+						"--flag3",
+						"3",
+						"--flag4",
+					],
+					clang_asflags: [
+						"--flag1",
+						"1",
+						"--flag2",
+						"2",
+						"--flag3",
+						"3",
+						"--flag4",
+					],
+					clang_cflags: [
+						"--flag1",
+						"1",
+						"--flag2",
+						"2",
+						"--flag3",
+						"3",
+						"--flag4",
+					],
+					conlyflags: [
+						"--flag1",
+						"1",
+						"--flag2",
+						"2",
+						"--flag3",
+						"3",
+						"--flag4",
+					],
+					cppflags: [
+						"--flag1",
+						"1",
+						"--flag2",
+						"2",
+						"--flag3",
+						"3",
+						"--flag4",
+					],
+					ldflags: [
+						"--flag1",
+						"1",
+						"--flag2",
+						"2",
+						"--flag3",
+						"3",
+						"--flag4",
+					],
+					tidy_flags: [
+						"--flag1",
+						"1",
+						"--flag2",
+						"2",
+						"--flag3",
+						"3",
+						"--flag4",
+					],
+				}
+			`,
+			out: `
+				cc_test {
+					name: "foo",
+					asflags: [
+						// comment1_1
+						"--flag1 1",
+						// comment2_1
+						// comment2_2
+						// comment2_3
+						"--flag2 2",
+						// comment3_1
+						// comment3_2
+						// comment3_3
+						// comment3_4
+						// comment3_4
+						"--flag3 3",
+						// comment4_1
+						// comment4_2
+						// comment4_3
+						"--flag4",
+					],
+					cflags: [
+						"--flag1 1",
+						"--flag2 2",
+						"--flag3 3",
+						"--flag4",
+					],
+					clang_asflags: [
+						"--flag1 1",
+						"--flag2 2",
+						"--flag3 3",
+						"--flag4",
+					],
+					clang_cflags: [
+						"--flag1 1",
+						"--flag2 2",
+						"--flag3 3",
+						"--flag4",
+					],
+					conlyflags: [
+						"--flag1 1",
+						"--flag2 2",
+						"--flag3 3",
+						"--flag4",
+					],
+					cppflags: [
+						"--flag1 1",
+						"--flag2 2",
+						"--flag3 3",
+						"--flag4",
+					],
+					ldflags: [
+						"--flag1 1",
+						"--flag2 2",
+						"--flag3 3",
+						"--flag4",
+					],
+					tidy_flags: [
+						"--flag1 1",
+						"--flag2 2",
+						"--flag3 3",
+						"--flag4",
+					],
+				}
+			`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, runPatchListMod(formatFlagProperties))
+		})
+	}
+}
diff --git a/cc/Android.bp b/cc/Android.bp
index 46740dc..4b750ff 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -58,6 +58,7 @@
         "binary.go",
         "binary_sdk_member.go",
         "fuzz.go",
+        "fuzz_common.go",
         "library.go",
         "library_headers.go",
         "library_sdk_member.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index e58d166..bda1006 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -401,24 +401,24 @@
 	ctx.subAndroidMk(entries, fuzz.binaryDecorator)
 
 	var fuzzFiles []string
-	for _, d := range fuzz.corpus {
+	for _, d := range fuzz.fuzzPackagedModule.Corpus {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.corpusIntermediateDir.String())+":corpus/"+d.Base())
+			filepath.Dir(fuzz.fuzzPackagedModule.CorpusIntermediateDir.String())+":corpus/"+d.Base())
 	}
 
-	for _, d := range fuzz.data {
+	for _, d := range fuzz.fuzzPackagedModule.Data {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.dataIntermediateDir.String())+":data/"+d.Rel())
+			filepath.Dir(fuzz.fuzzPackagedModule.DataIntermediateDir.String())+":data/"+d.Rel())
 	}
 
-	if fuzz.dictionary != nil {
+	if fuzz.fuzzPackagedModule.Dictionary != nil {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.dictionary.String())+":"+fuzz.dictionary.Base())
+			filepath.Dir(fuzz.fuzzPackagedModule.Dictionary.String())+":"+fuzz.fuzzPackagedModule.Dictionary.Base())
 	}
 
-	if fuzz.config != nil {
+	if fuzz.fuzzPackagedModule.Config != nil {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.config.String())+":config.json")
+			filepath.Dir(fuzz.fuzzPackagedModule.Config.String())+":config.json")
 	}
 
 	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 76c5f3b..536f112 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -90,8 +90,11 @@
 
 		// TODO(b/186024507, b/186489250): Temporarily exclude adding
 		// system_shared_libs deps until libc and libm builds.
-		// allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
-		// allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
+		if lib.static() {
+			allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
+		} else if lib.shared() {
+			allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
+		}
 
 		// Deps in the target/arch nested static: { .. } and shared: { .. } props of a cc_library.
 		// target: { <target>: shared: { ... } }
@@ -253,7 +256,7 @@
 		Copts:              bazel.StringListAttribute{Value: props.Cflags},
 		Srcs:               bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, props.Srcs)),
 		Static_deps:        bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Static_libs)),
-		Dynamic_deps:       bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Shared_libs)),
+		Dynamic_deps:       bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, append(props.Shared_libs, props.System_shared_libs...))),
 		Whole_archive_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleWholeDeps(ctx, props.Whole_static_libs)),
 	}
 
@@ -385,16 +388,6 @@
 		return result
 	}
 
-	// Parse the list of copts.
-	parseCopts := func(baseCompilerProps *BaseCompilerProperties) []string {
-		var copts []string
-		copts = append(copts, parseCommandLineFlags(baseCompilerProps.Cflags)...)
-		for _, dir := range parseLocalIncludeDirs(baseCompilerProps) {
-			copts = append(copts, includeFlags(dir)...)
-		}
-		return copts
-	}
-
 	// Parse srcs from an arch or OS's props value.
 	parseSrcs := func(baseCompilerProps *BaseCompilerProperties) bazel.LabelList {
 		// Add srcs-like dependencies such as generated files.
@@ -410,11 +403,15 @@
 	for _, props := range module.compiler.compilerProps() {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
 			srcs.SetValue(parseSrcs(baseCompilerProps))
-			copts.Value = parseCopts(baseCompilerProps)
+			copts.Value = parseCommandLineFlags(baseCompilerProps.Cflags)
 			asFlags.Value = parseCommandLineFlags(baseCompilerProps.Asflags)
 			conlyFlags.Value = parseCommandLineFlags(baseCompilerProps.Conlyflags)
 			cppFlags.Value = parseCommandLineFlags(baseCompilerProps.Cppflags)
 
+			for _, dir := range parseLocalIncludeDirs(baseCompilerProps) {
+				copts.Value = append(copts.Value, includeFlags(dir)...)
+				asFlags.Value = append(asFlags.Value, includeFlags(dir)...)
+			}
 			break
 		}
 	}
@@ -424,8 +421,10 @@
 	// "-I<module-dir>" in its copts.
 	if c, ok := module.compiler.(*baseCompiler); ok && c.includeBuildDirectory() {
 		copts.Value = append(copts.Value, includeFlags(".")...)
+		asFlags.Value = append(asFlags.Value, includeFlags(".")...)
 	} else if c, ok := module.compiler.(*libraryDecorator); ok && c.includeBuildDirectory() {
 		copts.Value = append(copts.Value, includeFlags(".")...)
+		asFlags.Value = append(asFlags.Value, includeFlags(".")...)
 	}
 
 	archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
@@ -440,8 +439,15 @@
 					srcs.SetSelectValue(axis, config, srcsList)
 				}
 
-				copts.SetSelectValue(axis, config, parseCopts(baseCompilerProps))
-				asFlags.SetSelectValue(axis, config, parseCommandLineFlags(baseCompilerProps.Asflags))
+				archVariantCopts := parseCommandLineFlags(baseCompilerProps.Cflags)
+				archVariantAsflags := parseCommandLineFlags(baseCompilerProps.Asflags)
+				for _, dir := range parseLocalIncludeDirs(baseCompilerProps) {
+					archVariantCopts = append(archVariantCopts, includeFlags(dir)...)
+					archVariantAsflags = append(archVariantAsflags, includeFlags(dir)...)
+				}
+
+				copts.SetSelectValue(axis, config, archVariantCopts)
+				asFlags.SetSelectValue(axis, config, archVariantAsflags)
 				conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(baseCompilerProps.Conlyflags))
 				cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(baseCompilerProps.Cppflags))
 			}
@@ -554,7 +560,9 @@
 			staticDeps.Value = android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs)
 			wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
 			wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
-			sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
+			// TODO(b/186024507): Handle system_shared_libs as its own attribute, so that the appropriate default
+			// may be supported.
+			sharedLibs := android.FirstUniqueStrings(append(baseLinkerProps.Shared_libs, baseLinkerProps.System_shared_libs...))
 			dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
 
 			headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs)
@@ -581,7 +589,7 @@
 				staticDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs))
 				wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
 				wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
-				sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
+				sharedLibs := android.FirstUniqueStrings(append(baseLinkerProps.Shared_libs, baseLinkerProps.System_shared_libs...))
 				dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
 
 				headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs)
diff --git a/cc/cc.go b/cc/cc.go
index 90c0237..e3ca4d7 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -756,14 +756,13 @@
 // members of the cc.Module to this decorator. Thus, a cc_binary module has custom linker and
 // installer logic.
 type Module struct {
-	android.ModuleBase
-	android.DefaultableModuleBase
-	android.ApexModuleBase
+	FuzzModule
+
 	android.SdkBase
 	android.BazelModuleBase
 
-	Properties       BaseProperties
 	VendorProperties VendorProperties
+	Properties       BaseProperties
 
 	// initialize before calling Init
 	hod      android.HostOrDeviceSupported
@@ -2014,9 +2013,9 @@
 }
 
 func GetSnapshot(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext) SnapshotInfo {
-	// Only modules with BOARD_VNDK_VERSION uses snapshot.  Others use the zero value of
+	// Only device modules with BOARD_VNDK_VERSION uses snapshot.  Others use the zero value of
 	// SnapshotInfo, which provides no mappings.
-	if *snapshotInfo == nil {
+	if *snapshotInfo == nil && c.Device() {
 		// Only retrieve the snapshot on demand in order to avoid circular dependencies
 		// between the modules in the snapshot and the snapshot itself.
 		var snapshotModule []blueprint.Module
@@ -2025,16 +2024,16 @@
 		} else if recoverySnapshotVersion := actx.DeviceConfig().RecoverySnapshotVersion(); recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && c.InRecovery() {
 			snapshotModule = actx.AddVariationDependencies(nil, nil, "recovery_snapshot")
 		}
-		if len(snapshotModule) > 0 {
+		if len(snapshotModule) > 0 && snapshotModule[0] != nil {
 			snapshot := actx.OtherModuleProvider(snapshotModule[0], SnapshotInfoProvider).(SnapshotInfo)
 			*snapshotInfo = &snapshot
 			// republish the snapshot for use in later mutators on this module
 			actx.SetProvider(SnapshotInfoProvider, snapshot)
-		} else {
-			*snapshotInfo = &SnapshotInfo{}
 		}
 	}
-
+	if *snapshotInfo == nil {
+		*snapshotInfo = &SnapshotInfo{}
+	}
 	return **snapshotInfo
 }
 
diff --git a/cc/fuzz.go b/cc/fuzz.go
index c780b6f..8b0f93e 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -94,19 +94,14 @@
 	*binaryDecorator
 	*baseCompiler
 
-	Properties            FuzzProperties
-	dictionary            android.Path
-	corpus                android.Paths
-	corpusIntermediateDir android.Path
-	config                android.Path
-	data                  android.Paths
-	dataIntermediateDir   android.Path
-	installedSharedDeps   []string
+	fuzzPackagedModule FuzzPackagedModule
+
+	installedSharedDeps []string
 }
 
 func (fuzz *fuzzBinary) linkerProps() []interface{} {
 	props := fuzz.binaryDecorator.linkerProps()
-	props = append(props, &fuzz.Properties)
+	props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties)
 	return props
 }
 
@@ -257,41 +252,41 @@
 		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
 	fuzz.binaryDecorator.baseInstaller.install(ctx, file)
 
-	fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
+	fuzz.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Corpus)
 	builder := android.NewRuleBuilder(pctx, ctx)
 	intermediateDir := android.PathForModuleOut(ctx, "corpus")
-	for _, entry := range fuzz.corpus {
+	for _, entry := range fuzz.fuzzPackagedModule.Corpus {
 		builder.Command().Text("cp").
 			Input(entry).
 			Output(intermediateDir.Join(ctx, entry.Base()))
 	}
 	builder.Build("copy_corpus", "copy corpus")
-	fuzz.corpusIntermediateDir = intermediateDir
+	fuzz.fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
 
-	fuzz.data = android.PathsForModuleSrc(ctx, fuzz.Properties.Data)
+	fuzz.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Data)
 	builder = android.NewRuleBuilder(pctx, ctx)
 	intermediateDir = android.PathForModuleOut(ctx, "data")
-	for _, entry := range fuzz.data {
+	for _, entry := range fuzz.fuzzPackagedModule.Data {
 		builder.Command().Text("cp").
 			Input(entry).
 			Output(intermediateDir.Join(ctx, entry.Rel()))
 	}
 	builder.Build("copy_data", "copy data")
-	fuzz.dataIntermediateDir = intermediateDir
+	fuzz.fuzzPackagedModule.DataIntermediateDir = intermediateDir
 
-	if fuzz.Properties.Dictionary != nil {
-		fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
-		if fuzz.dictionary.Ext() != ".dict" {
+	if fuzz.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
+		fuzz.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzz.fuzzPackagedModule.FuzzProperties.Dictionary)
+		if fuzz.fuzzPackagedModule.Dictionary.Ext() != ".dict" {
 			ctx.PropertyErrorf("dictionary",
 				"Fuzzer dictionary %q does not have '.dict' extension",
-				fuzz.dictionary.String())
+				fuzz.fuzzPackagedModule.Dictionary.String())
 		}
 	}
 
-	if fuzz.Properties.Fuzz_config != nil {
+	if fuzz.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
 		configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
-		android.WriteFileRule(ctx, configPath, fuzz.Properties.Fuzz_config.String())
-		fuzz.config = configPath
+		android.WriteFileRule(ctx, configPath, fuzz.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
+		fuzz.fuzzPackagedModule.Config = configPath
 	}
 
 	// Grab the list of required shared libraries.
@@ -359,32 +354,20 @@
 
 // Responsible for generating GNU Make rules that package fuzz targets into
 // their architecture & target/host specific zip file.
-type fuzzPackager struct {
-	packages                android.Paths
+type ccFuzzPackager struct {
+	FuzzPackager
 	sharedLibInstallStrings []string
-	fuzzTargets             map[string]bool
 }
 
 func fuzzPackagingFactory() android.Singleton {
-	return &fuzzPackager{}
+	return &ccFuzzPackager{}
 }
 
-type fileToZip struct {
-	SourceFilePath        android.Path
-	DestinationPathPrefix string
-}
-
-type archOs struct {
-	hostOrTarget string
-	arch         string
-	dir          string
-}
-
-func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
+func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
 	// Map between each architecture + host/device combination, and the files that
 	// need to be packaged (in the tuple of {source file, destination folder in
 	// archive}).
-	archDirs := make(map[archOs][]fileToZip)
+	archDirs := make(map[ArchOs][]FileToZip)
 
 	// Map tracking whether each shared library has an install rule to avoid duplicate install rules from
 	// multiple fuzzers that depend on the same shared library.
@@ -392,12 +375,16 @@
 
 	// List of individual fuzz targets, so that 'make fuzz' also installs the targets
 	// to the correct output directories as well.
-	s.fuzzTargets = make(map[string]bool)
+	s.FuzzTargets = make(map[string]bool)
 
 	ctx.VisitAllModules(func(module android.Module) {
-		// Discard non-fuzz targets.
 		ccModule, ok := module.(*Module)
-		if !ok {
+		if !ok || ccModule.Properties.PreventInstall {
+			return
+		}
+
+		// Discard non-fuzz targets.
+		if ok := IsValid(ccModule.FuzzModule); !ok {
 			return
 		}
 
@@ -406,18 +393,6 @@
 			return
 		}
 
-		// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
-		// fuzz targets we're going to package anyway.
-		if !ccModule.Enabled() || ccModule.Properties.PreventInstall ||
-			ccModule.InRamdisk() || ccModule.InVendorRamdisk() || ccModule.InRecovery() {
-			return
-		}
-
-		// Discard modules that are in an unavailable namespace.
-		if !ccModule.ExportedToMake() {
-			return
-		}
-
 		hostOrTargetString := "target"
 		if ccModule.Host() {
 			hostOrTargetString = "host"
@@ -425,42 +400,21 @@
 
 		archString := ccModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
-		archOs := archOs{hostOrTarget: hostOrTargetString, arch: archString, dir: archDir.String()}
+		archOs := ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
 
 		// Grab the list of required shared libraries.
 		sharedLibraries := collectAllSharedDependencies(ctx, module)
 
-		var files []fileToZip
+		var files []FileToZip
 		builder := android.NewRuleBuilder(pctx, ctx)
 
-		// Package the corpora into a zipfile.
-		if fuzzModule.corpus != nil {
-			corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip")
-			command := builder.Command().BuiltTool("soong_zip").
-				Flag("-j").
-				FlagWithOutput("-o ", corpusZip)
-			rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
-			command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.corpus)
-			files = append(files, fileToZip{corpusZip, ""})
-		}
-
-		// Package the data into a zipfile.
-		if fuzzModule.data != nil {
-			dataZip := archDir.Join(ctx, module.Name()+"_data.zip")
-			command := builder.Command().BuiltTool("soong_zip").
-				FlagWithOutput("-o ", dataZip)
-			for _, f := range fuzzModule.data {
-				intermediateDir := strings.TrimSuffix(f.String(), f.Rel())
-				command.FlagWithArg("-C ", intermediateDir)
-				command.FlagWithInput("-f ", f)
-			}
-			files = append(files, fileToZip{dataZip, ""})
-		}
+		// Package the corpus, data, dict and config into a zipfile.
+		files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
 
 		// Find and mark all the transiently-dependent shared libraries for
 		// packaging.
 		for _, library := range sharedLibraries {
-			files = append(files, fileToZip{library, "lib"})
+			files = append(files, FileToZip{library, "lib"})
 
 			// For each architecture-specific shared library dependency, we need to
 			// install it to the output directory. Setup the install destination here,
@@ -492,83 +446,20 @@
 		}
 
 		// The executable.
-		files = append(files, fileToZip{ccModule.UnstrippedOutputFile(), ""})
+		files = append(files, FileToZip{ccModule.UnstrippedOutputFile(), ""})
 
-		// The dictionary.
-		if fuzzModule.dictionary != nil {
-			files = append(files, fileToZip{fuzzModule.dictionary, ""})
+		archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
+		if !ok {
+			return
 		}
-
-		// Additional fuzz config.
-		if fuzzModule.config != nil {
-			files = append(files, fileToZip{fuzzModule.config, ""})
-		}
-
-		fuzzZip := archDir.Join(ctx, module.Name()+".zip")
-		command := builder.Command().BuiltTool("soong_zip").
-			Flag("-j").
-			FlagWithOutput("-o ", fuzzZip)
-		for _, file := range files {
-			if file.DestinationPathPrefix != "" {
-				command.FlagWithArg("-P ", file.DestinationPathPrefix)
-			} else {
-				command.Flag("-P ''")
-			}
-			command.FlagWithInput("-f ", file.SourceFilePath)
-		}
-
-		builder.Build("create-"+fuzzZip.String(),
-			"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
-
-		// Don't add modules to 'make haiku' that are set to not be exported to the
-		// fuzzing infrastructure.
-		if config := fuzzModule.Properties.Fuzz_config; config != nil {
-			if ccModule.Host() && !BoolDefault(config.Fuzz_on_haiku_host, true) {
-				return
-			} else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
-				return
-			}
-		}
-
-		s.fuzzTargets[module.Name()] = true
-		archDirs[archOs] = append(archDirs[archOs], fileToZip{fuzzZip, ""})
 	})
 
-	var archOsList []archOs
-	for archOs := range archDirs {
-		archOsList = append(archOsList, archOs)
-	}
-	sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].dir < archOsList[j].dir })
+	s.CreateFuzzPackage(ctx, archDirs, Cc)
 
-	for _, archOs := range archOsList {
-		filesToZip := archDirs[archOs]
-		arch := archOs.arch
-		hostOrTarget := archOs.hostOrTarget
-		builder := android.NewRuleBuilder(pctx, ctx)
-		outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
-		s.packages = append(s.packages, outputFile)
-
-		command := builder.Command().BuiltTool("soong_zip").
-			Flag("-j").
-			FlagWithOutput("-o ", outputFile).
-			Flag("-L 0") // No need to try and re-compress the zipfiles.
-
-		for _, fileToZip := range filesToZip {
-			if fileToZip.DestinationPathPrefix != "" {
-				command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
-			} else {
-				command.Flag("-P ''")
-			}
-			command.FlagWithInput("-f ", fileToZip.SourceFilePath)
-		}
-
-		builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget,
-			"Create fuzz target packages for "+arch+"-"+hostOrTarget)
-	}
 }
 
-func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) {
-	packages := s.packages.Strings()
+func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
+	packages := s.Packages.Strings()
 	sort.Strings(packages)
 	sort.Strings(s.sharedLibInstallStrings)
 	// TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
@@ -580,10 +471,5 @@
 		strings.Join(s.sharedLibInstallStrings, " "))
 
 	// Preallocate the slice of fuzz targets to minimise memory allocations.
-	fuzzTargets := make([]string, 0, len(s.fuzzTargets))
-	for target, _ := range s.fuzzTargets {
-		fuzzTargets = append(fuzzTargets, target)
-	}
-	sort.Strings(fuzzTargets)
-	ctx.Strict("ALL_FUZZ_TARGETS", strings.Join(fuzzTargets, " "))
+	s.PreallocateSlice(ctx, "ALL_FUZZ_TARGETS")
 }
diff --git a/cc/fuzz_common.go b/cc/fuzz_common.go
new file mode 100644
index 0000000..98ed7f4
--- /dev/null
+++ b/cc/fuzz_common.go
@@ -0,0 +1,201 @@
+// 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 cc
+
+// This file contains the common code for compiling C/C++ and Rust fuzzers for Android.
+
+import (
+	"sort"
+	"strings"
+
+	"android/soong/android"
+)
+
+type Lang string
+
+const (
+	Cc   Lang = ""
+	Rust Lang = "rust"
+)
+
+type FuzzModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	android.ApexModuleBase
+}
+
+type FuzzPackager struct {
+	Packages    android.Paths
+	FuzzTargets map[string]bool
+}
+
+type FileToZip struct {
+	SourceFilePath        android.Path
+	DestinationPathPrefix string
+}
+
+type ArchOs struct {
+	HostOrTarget string
+	Arch         string
+	Dir          string
+}
+
+type FuzzPackagedModule struct {
+	FuzzProperties        FuzzProperties
+	Dictionary            android.Path
+	Corpus                android.Paths
+	CorpusIntermediateDir android.Path
+	Config                android.Path
+	Data                  android.Paths
+	DataIntermediateDir   android.Path
+}
+
+func IsValid(fuzzModule FuzzModule) bool {
+	// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
+	// fuzz targets we're going to package anyway.
+	if !fuzzModule.Enabled() || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() {
+		return false
+	}
+
+	// Discard modules that are in an unavailable namespace.
+	if !fuzzModule.ExportedToMake() {
+		return false
+	}
+
+	return true
+}
+
+func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
+	// Package the corpora into a zipfile.
+	var files []FileToZip
+	if fuzzModule.Corpus != nil {
+		corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip")
+		command := builder.Command().BuiltTool("soong_zip").
+			Flag("-j").
+			FlagWithOutput("-o ", corpusZip)
+		rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
+		command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus)
+		files = append(files, FileToZip{corpusZip, ""})
+	}
+
+	// Package the data into a zipfile.
+	if fuzzModule.Data != nil {
+		dataZip := archDir.Join(ctx, module.Name()+"_data.zip")
+		command := builder.Command().BuiltTool("soong_zip").
+			FlagWithOutput("-o ", dataZip)
+		for _, f := range fuzzModule.Data {
+			intermediateDir := strings.TrimSuffix(f.String(), f.Rel())
+			command.FlagWithArg("-C ", intermediateDir)
+			command.FlagWithInput("-f ", f)
+		}
+		files = append(files, FileToZip{dataZip, ""})
+	}
+
+	// The dictionary.
+	if fuzzModule.Dictionary != nil {
+		files = append(files, FileToZip{fuzzModule.Dictionary, ""})
+	}
+
+	// Additional fuzz config.
+	if fuzzModule.Config != nil {
+		files = append(files, FileToZip{fuzzModule.Config, ""})
+	}
+
+	return files
+}
+
+func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) {
+	fuzzZip := archDir.Join(ctx, module.Name()+".zip")
+
+	command := builder.Command().BuiltTool("soong_zip").
+		Flag("-j").
+		FlagWithOutput("-o ", fuzzZip)
+
+	for _, file := range files {
+		if file.DestinationPathPrefix != "" {
+			command.FlagWithArg("-P ", file.DestinationPathPrefix)
+		} else {
+			command.Flag("-P ''")
+		}
+		command.FlagWithInput("-f ", file.SourceFilePath)
+	}
+
+	builder.Build("create-"+fuzzZip.String(),
+		"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
+
+	// Don't add modules to 'make haiku-rust' that are set to not be
+	// exported to the fuzzing infrastructure.
+	if config := fuzzModule.FuzzProperties.Fuzz_config; config != nil {
+		if strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_host, true) {
+			return archDirs[archOs], false
+		} else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
+			return archDirs[archOs], false
+		}
+	}
+
+	s.FuzzTargets[module.Name()] = true
+	archDirs[archOs] = append(archDirs[archOs], FileToZip{fuzzZip, ""})
+
+	return archDirs[archOs], true
+}
+
+func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang) {
+	var archOsList []ArchOs
+	for archOs := range archDirs {
+		archOsList = append(archOsList, archOs)
+	}
+	sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].Dir < archOsList[j].Dir })
+
+	for _, archOs := range archOsList {
+		filesToZip := archDirs[archOs]
+		arch := archOs.Arch
+		hostOrTarget := archOs.HostOrTarget
+		builder := android.NewRuleBuilder(pctx, ctx)
+		zipFileName := "fuzz-" + hostOrTarget + "-" + arch + ".zip"
+		if lang == Rust {
+			zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip"
+		}
+		outputFile := android.PathForOutput(ctx, zipFileName)
+
+		s.Packages = append(s.Packages, outputFile)
+
+		command := builder.Command().BuiltTool("soong_zip").
+			Flag("-j").
+			FlagWithOutput("-o ", outputFile).
+			Flag("-L 0") // No need to try and re-compress the zipfiles.
+
+		for _, fileToZip := range filesToZip {
+
+			if fileToZip.DestinationPathPrefix != "" {
+				command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
+			} else {
+				command.Flag("-P ''")
+			}
+			command.FlagWithInput("-f ", fileToZip.SourceFilePath)
+
+		}
+		builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget,
+			"Create fuzz target packages for "+arch+"-"+hostOrTarget)
+	}
+}
+
+func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets string) {
+	fuzzTargets := make([]string, 0, len(s.FuzzTargets))
+	for target, _ := range s.FuzzTargets {
+		fuzzTargets = append(fuzzTargets, target)
+	}
+	sort.Strings(fuzzTargets)
+	ctx.Strict(targets, strings.Join(fuzzTargets, " "))
+}
diff --git a/cc/library.go b/cc/library.go
index 4fd7c74..56c460c 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -300,6 +300,12 @@
 
 	srcs := compilerAttrs.srcs
 
+	asFlags := compilerAttrs.asFlags
+	if compilerAttrs.asSrcs.IsEmpty() && sharedAttrs.Srcs_as.IsEmpty() && staticAttrs.Srcs_as.IsEmpty() {
+		// Skip asflags for BUILD file simplicity if there are no assembly sources.
+		asFlags = bazel.MakeStringListAttribute(nil)
+	}
+
 	attrs := &bazelCcLibraryAttributes{
 		Srcs:    srcs,
 		Srcs_c:  compilerAttrs.cSrcs,
@@ -308,7 +314,7 @@
 		Copts:      compilerAttrs.copts,
 		Cppflags:   compilerAttrs.cppFlags,
 		Conlyflags: compilerAttrs.conlyFlags,
-		Asflags:    compilerAttrs.asFlags,
+		Asflags:    asFlags,
 
 		Implementation_deps: linkerAttrs.deps,
 		Deps:                linkerAttrs.exportedDeps,
@@ -2370,6 +2376,12 @@
 	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
 	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
 
+	asFlags := compilerAttrs.asFlags
+	if compilerAttrs.asSrcs.IsEmpty() {
+		// Skip asflags for BUILD file simplicity if there are no assembly sources.
+		asFlags = bazel.MakeStringListAttribute(nil)
+	}
+
 	attrs := &bazelCcLibraryStaticAttributes{
 		Copts:               compilerAttrs.copts,
 		Srcs:                compilerAttrs.srcs,
@@ -2386,7 +2398,7 @@
 		Srcs_c:     compilerAttrs.cSrcs,
 		Conlyflags: compilerAttrs.conlyFlags,
 		Srcs_as:    compilerAttrs.asSrcs,
-		Asflags:    compilerAttrs.asFlags,
+		Asflags:    asFlags,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/linkable.go b/cc/linkable.go
index 84141e2..6232efb 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -125,6 +125,7 @@
 	IsPrebuilt() bool
 	Toc() android.OptionalPath
 
+	Device() bool
 	Host() bool
 
 	InRamdisk() bool
diff --git a/cc/object.go b/cc/object.go
index ac5e41d..0f983c8 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -123,6 +123,7 @@
 // For bp2build conversion.
 type bazelObjectAttributes struct {
 	Srcs    bazel.LabelListAttribute
+	Srcs_as bazel.LabelListAttribute
 	Hdrs    bazel.LabelListAttribute
 	Deps    bazel.LabelListAttribute
 	Copts   bazel.StringListAttribute
@@ -179,13 +180,19 @@
 	// and this isn't typically done for cc_object.
 	srcs := compilerAttrs.srcs
 	srcs.Append(compilerAttrs.cSrcs)
-	srcs.Append(compilerAttrs.asSrcs)
+
+	asFlags := compilerAttrs.asFlags
+	if compilerAttrs.asSrcs.IsEmpty() {
+		// Skip asflags for BUILD file simplicity if there are no assembly sources.
+		asFlags = bazel.MakeStringListAttribute(nil)
+	}
 
 	attrs := &bazelObjectAttributes{
 		Srcs:    srcs,
+		Srcs_as: compilerAttrs.asSrcs,
 		Deps:    deps,
 		Copts:   compilerAttrs.copts,
-		Asflags: compilerAttrs.asFlags,
+		Asflags: asFlags,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index fb89224..4f031ff 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -264,6 +264,7 @@
 func init() {
 	VendorSnapshotImageSingleton.Init(android.InitRegistrationContext)
 	recoverySnapshotImageSingleton.init(android.InitRegistrationContext)
+	android.RegisterMakeVarsProvider(pctx, snapshotMakeVarsProvider)
 }
 
 const (
@@ -383,6 +384,24 @@
 
 var _ android.ImageInterface = (*snapshot)(nil)
 
+func snapshotMakeVarsProvider(ctx android.MakeVarsContext) {
+	snapshotSet := map[string]struct{}{}
+	ctx.VisitAllModules(func(m android.Module) {
+		if s, ok := m.(*snapshot); ok {
+			if _, ok := snapshotSet[s.Name()]; ok {
+				// arch variant generates duplicated modules
+				// skip this as we only need to know the path of the module.
+				return
+			}
+			snapshotSet[s.Name()] = struct{}{}
+			imageNameVersion := strings.Split(s.image.imageVariantName(ctx.DeviceConfig()), ".")
+			ctx.Strict(
+				strings.Join([]string{strings.ToUpper(imageNameVersion[0]), s.baseSnapshot.Version(), "SNAPSHOT_DIR"}, "_"),
+				ctx.ModuleDir(s))
+		}
+	})
+}
+
 func vendorSnapshotFactory() android.Module {
 	return snapshotFactory(VendorSnapshotImageSingleton)
 }
diff --git a/cmd/extract_linker/main.go b/cmd/extract_linker/main.go
index 2dcb894..f1f7bc7 100644
--- a/cmd/extract_linker/main.go
+++ b/cmd/extract_linker/main.go
@@ -85,7 +85,7 @@
 
 		fmt.Fprintf(asm, ".globl %s\n%s:\n\n", symName, symName)
 
-		fmt.Fprintf(script, "  %s %d : {\n", sectionName, baseLoadAddr+prog.Vaddr)
+		fmt.Fprintf(script, "  %s 0x%x : {\n", sectionName, baseLoadAddr+prog.Vaddr)
 		fmt.Fprintf(script, "    KEEP(*(%s));\n", sectionName)
 		fmt.Fprintln(script, "  }")
 
@@ -106,8 +106,10 @@
 		load += 1
 	}
 
+	fmt.Fprintln(asm, `.section .note.android.embedded_linker,"a",%note`)
+
 	fmt.Fprintln(script, "}")
-	fmt.Fprintln(script, "INSERT BEFORE .note.android.ident;")
+	fmt.Fprintln(script, "INSERT BEFORE .note.android.embedded_linker;")
 
 	if asmPath != "" {
 		if err := ioutil.WriteFile(asmPath, asm.Bytes(), 0777); err != nil {
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index f76a205..245af2c 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -15,6 +15,7 @@
 package dexpreopt
 
 import (
+	"encoding/json"
 	"fmt"
 	"sort"
 	"strconv"
@@ -257,6 +258,9 @@
 func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
 	hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) error {
 
+	// For prebuilts, library should have the same name as the source module.
+	lib = android.RemoveOptionalPrebuiltPrefix(lib)
+
 	devicePath := UnknownInstallLibraryPath
 	if installPath == nil {
 		if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) {
@@ -282,11 +286,19 @@
 	}
 	subcontexts := nestedClcMap[AnySdkVersion]
 
-	// If the library with this name is already present as one of the unconditional top-level
-	// components, do not re-add it.
+	// Check if the library with this name is already present in unconditional top-level CLC.
 	for _, clc := range clcMap[sdkVer] {
-		if clc.Name == lib {
+		if clc.Name != lib {
+			// Ok, a different library.
+		} else if clc.Host == hostPath && clc.Device == devicePath {
+			// Ok, the same library with the same paths. Don't re-add it, but don't raise an error
+			// either, as the same library may be reachable via different transitional dependencies.
 			return nil
+		} else {
+			// Fail, as someone is trying to add the same library with different paths. This likely
+			// indicates an error somewhere else, like trying to add a stub library.
+			return fmt.Errorf("a <uses-library> named %q is already in class loader context,"+
+				"but the library paths are different:\t\n", lib)
 		}
 	}
 
@@ -360,6 +372,15 @@
 	return ulibs
 }
 
+func (clcMap ClassLoaderContextMap) Dump() string {
+	jsonCLC := toJsonClassLoaderContext(clcMap)
+	bytes, err := json.MarshalIndent(jsonCLC, "", "  ")
+	if err != nil {
+		panic(err)
+	}
+	return string(bytes)
+}
+
 // Now that the full unconditional context is known, reconstruct conditional context.
 // Apply filters for individual libraries, mirroring what the PackageManager does when it
 // constructs class loader context on device.
diff --git a/java/app.go b/java/app.go
index fc1ace0..4e967ad 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1213,7 +1213,7 @@
 }
 
 func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
-	if !ctx.Config().UnbundledBuild() {
+	if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() {
 		ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
 		ctx.AddVariationDependencies(nil, usesLibTag, u.presentOptionalUsesLibs(ctx)...)
 		// Only add these extra dependencies if the module depends on framework libs. This avoids
@@ -1245,36 +1245,52 @@
 	}
 }
 
-// Returns a map of module names of shared library dependencies to the paths
-// to their dex jars on host and on device.
+// Returns a map of module names of shared library dependencies to the paths to their dex jars on
+// host and on device.
 func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext) dexpreopt.ClassLoaderContextMap {
 	clcMap := make(dexpreopt.ClassLoaderContextMap)
 
-	if !ctx.Config().UnbundledBuild() {
-		ctx.VisitDirectDeps(func(m android.Module) {
-			if tag, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
-				dep := ctx.OtherModuleName(m)
-				if lib, ok := m.(UsesLibraryDependency); ok {
-					libName := dep
-					if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil {
-						libName = *ulib.ProvidesUsesLib()
-						// Replace module name with library name in `uses_libs`/`optional_uses_libs`
-						// in order to pass verify_uses_libraries check (which compares these
-						// properties against library names written in the manifest).
-						replaceInList(u.usesLibraryProperties.Uses_libs, dep, libName)
-						replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName)
-					}
-					clcMap.AddContext(ctx, tag.sdkVersion, libName,
-						lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
-				} else if ctx.Config().AllowMissingDependencies() {
-					ctx.AddMissingDependencies([]string{dep})
-				} else {
-					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
-				}
-			}
-		})
+	// Skip when UnbundledBuild() is true, but UnbundledBuildImage() is false. With
+	// UnbundledBuildImage() it is necessary to generate dexpreopt.config for post-dexpreopting.
+	if ctx.Config().UnbundledBuild() && !ctx.Config().UnbundledBuildImage() {
+		return clcMap
 	}
 
+	ctx.VisitDirectDeps(func(m android.Module) {
+		tag, isUsesLibTag := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag)
+		if !isUsesLibTag {
+			return
+		}
+
+		dep := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(m))
+
+		// Skip stub libraries. A dependency on the implementation library has been added earlier,
+		// so it will be added to CLC, but the stub shouldn't be. Stub libraries can be distingushed
+		// from implementation libraries by their name, which is different as it has a suffix.
+		if comp, ok := m.(SdkLibraryComponentDependency); ok {
+			if impl := comp.OptionalSdkLibraryImplementation(); impl != nil && *impl != dep {
+				return
+			}
+		}
+
+		if lib, ok := m.(UsesLibraryDependency); ok {
+			libName := dep
+			if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil {
+				libName = *ulib.ProvidesUsesLib()
+				// Replace module name with library name in `uses_libs`/`optional_uses_libs` in
+				// order to pass verify_uses_libraries check (which compares these properties
+				// against library names written in the manifest).
+				replaceInList(u.usesLibraryProperties.Uses_libs, dep, libName)
+				replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName)
+			}
+			clcMap.AddContext(ctx, tag.sdkVersion, libName,
+				lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
+		} else if ctx.Config().AllowMissingDependencies() {
+			ctx.AddMissingDependencies([]string{dep})
+		} else {
+			ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
+		}
+	})
 	return clcMap
 }
 
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bdf0dae..503c31f 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -579,25 +579,9 @@
 	// Create hidden API input structure.
 	input := b.createHiddenAPIFlagInput(ctx, contents, fragments)
 
-	var output *HiddenAPIOutput
-
-	// Hidden API processing is conditional as a temporary workaround as not all
-	// bootclasspath_fragments provide the appropriate information needed for hidden API processing
-	// which leads to breakages of the build.
-	// TODO(b/179354495): Stop hidden API processing being conditional once all bootclasspath_fragment
-	//  modules have been updated to support it.
-	if input.canPerformHiddenAPIProcessing(ctx, b.properties) {
-		// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
-		common := ctx.Module().(commonBootclasspathFragment)
-		output = common.produceHiddenAPIOutput(ctx, contents, input)
-	} else {
-		// As hidden API processing cannot be performed fall back to trying to retrieve the legacy
-		// encoded boot dex files, i.e. those files encoded by the individual libraries and returned
-		// from the DexJarBuildPath() method.
-		output = &HiddenAPIOutput{
-			EncodedBootDexFilesByModule: retrieveLegacyEncodedBootDexFiles(ctx, contents),
-		}
-	}
+	// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
+	common := ctx.Module().(commonBootclasspathFragment)
+	output := common.produceHiddenAPIOutput(ctx, contents, input)
 
 	// Initialize a HiddenAPIInfo structure.
 	hiddenAPIInfo := HiddenAPIInfo{
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 2e46d74..0faae36 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -141,10 +141,9 @@
 		}
 	}
 
-	// If it is neither app nor test, make config files regardless of its dexpreopt setting.
+	// If it is test, make config files regardless of its dexpreopt setting.
 	// The config files are required for apps defined in make which depend on the lib.
-	// TODO(b/158843648): The config for apps should be generated as well regardless of setting.
-	if (d.isApp || d.isTest) && d.dexpreoptDisabled(ctx) {
+	if d.isTest && d.dexpreoptDisabled(ctx) {
 		return
 	}
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 19c65ca..dff9543 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -154,12 +154,23 @@
 // PRODUCT_BOOT_JARS_EXTRA variables. The AOSP makefiles specify some common Framework libraries,
 // but more product-specific libraries can be added in the product makefiles.
 //
-// Each component of the PRODUCT_BOOT_JARS and PRODUCT_BOOT_JARS_EXTRA variables is either a simple
-// name (if the library is a part of the Platform), or a colon-separated pair <apex, name> (if the
-// library is a part of a non-updatable APEX).
+// Each component of the PRODUCT_BOOT_JARS and PRODUCT_BOOT_JARS_EXTRA variables is a
+// colon-separated pair <apex>:<library>, where <apex> is the variant name of a non-updatable APEX,
+// "platform" if the library is a part of the platform in the system partition, or "system_ext" if
+// it's in the system_ext partition.
+//
+// In these variables APEXes are identified by their "variant names", i.e. the names they get
+// mounted as in /apex on device. In Soong modules that is the name set in the "apex_name"
+// properties, which default to the "name" values. For example, many APEXes have both
+// com.android.xxx and com.google.android.xxx modules in Soong, but take the same place
+// /apex/com.android.xxx at runtime. In these cases the variant name is always com.android.xxx,
+// regardless which APEX goes into the product. See also android.ApexInfo.ApexVariationName and
+// apex.apexBundleProperties.Apex_name.
 //
 // A related variable PRODUCT_UPDATABLE_BOOT_JARS contains bootclasspath libraries that are in
-// updatable APEXes. They are not included in the boot image.
+// APEXes. They are not included in the boot image. The only exception here is core-icu4j.jar that
+// has been historically part of the boot image and is now in a non updatable apex; it is treated
+// as being part of PRODUCT_BOOT_JARS and is in the boot image.
 //
 // One exception to the above rules are "coverage" builds (a special build flavor which requires
 // setting environment variable EMMA_INSTRUMENT_FRAMEWORK=true). In coverage builds the Java code in
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index c4832d2..654ebb7 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -20,7 +20,6 @@
 
 	"android/soong/android"
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
 )
 
 // Contains support for processing hiddenAPI in a modular fashion.
@@ -712,42 +711,6 @@
 	return input
 }
 
-// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
-//
-// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
-// appropriate information needed for hidden API processing breaking the build.
-// TODO(b/179354495): Remove this workaround.
-func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
-	// Performing hidden API processing without stubs is not supported and it is unlikely to ever be
-	// required as the whole point of adding something to the bootclasspath fragment is to add it to
-	// the bootclasspath in order to be used by something else in the system. Without any stubs it
-	// cannot do that.
-	if len(i.StubDexJarsByScope) == 0 {
-		return false
-	}
-
-	// Hidden API processing is always enabled in tests.
-	if ctx.Config().TestProductVariables != nil {
-		return true
-	}
-
-	// A module that has fragments should have access to the information it needs in order to perform
-	// hidden API processing.
-	if len(properties.Fragments) != 0 {
-		return true
-	}
-
-	// The art bootclasspath fragment does not depend on any other fragments but already supports
-	// hidden API processing.
-	imageName := proptools.String(properties.Image_name)
-	if imageName == "art" {
-		return true
-	}
-
-	// Disable it for everything else.
-	return false
-}
-
 // gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
 // dependencies added in hiddenAPIAddStubLibDependencies.
 //
diff --git a/java/java.go b/java/java.go
index be1ad87..e38a714 100644
--- a/java/java.go
+++ b/java/java.go
@@ -21,7 +21,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"strings"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -131,11 +130,19 @@
 			PropertyName: "java_boot_libs",
 			SupportsSdk:  true,
 		},
-		// Temporarily export implementation classes jar for java_boot_libs as it is required for the
-		// hiddenapi processing.
-		// TODO(b/179354495): Revert once hiddenapi processing has been modularized.
-		exportImplementationClassesJar,
-		sdkSnapshotFilePathForJar,
+		func(ctx android.SdkMemberContext, j *Library) android.Path {
+			// Java boot libs are only provided in the SDK to provide access to their dex implementation
+			// jar for use by dexpreopting and boot jars package check. They do not need to provide an
+			// actual implementation jar but the java_import will need a file that exists so just copy an
+			// empty file. Any attempt to use that file as a jar will cause a build error.
+			return ctx.SnapshotBuilder().EmptyFile()
+		},
+		func(osPrefix, name string) string {
+			// Create a special name for the implementation jar to try and provide some useful information
+			// to a developer that attempts to compile against this.
+			// TODO(b/175714559): Provide a proper error message in Soong not ninja.
+			return filepath.Join(osPrefix, "java_boot_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix)
+		},
 		onlyCopyJarToSnapshot,
 	}
 
@@ -581,6 +588,10 @@
 
 	JarToExport     android.Path `android:"arch_variant"`
 	AidlIncludeDirs android.Paths
+
+	// The list of permitted packages that need to be passed to the prebuilts as they are used to
+	// create the updatable-bcp-packages.txt file.
+	PermittedPackages []string
 }
 
 func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -589,6 +600,8 @@
 	p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(ctx, j)
 
 	p.AidlIncludeDirs = j.AidlIncludeDirs()
+
+	p.PermittedPackages = j.PermittedPackagesForUpdatableBootJars()
 }
 
 func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -607,6 +620,10 @@
 		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
 	}
 
+	if len(p.PermittedPackages) > 0 {
+		propertySet.AddProperty("permitted_packages", p.PermittedPackages)
+	}
+
 	// Do not copy anything else to the snapshot.
 	if memberType.onlyCopyJarToSnapshot {
 		return
@@ -1127,6 +1144,10 @@
 
 	Installable *bool
 
+	// If not empty, classes are restricted to the specified packages and their sub-packages.
+	// This information is used to generate the updatable-bcp-packages.txt file.
+	Permitted_packages []string
+
 	// List of shared java libs that this module has dependencies to
 	Libs []string
 
@@ -1166,7 +1187,8 @@
 	properties ImportProperties
 
 	// output file containing classes.dex and resources
-	dexJarFile android.Path
+	dexJarFile        android.Path
+	dexJarInstallFile android.Path
 
 	combinedClasspathFile android.Path
 	classLoaderContexts   dexpreopt.ClassLoaderContextMap
@@ -1178,6 +1200,12 @@
 	minSdkVersion android.SdkSpec
 }
 
+var _ PermittedPackagesForUpdatableBootJars = (*Import)(nil)
+
+func (j *Import) PermittedPackagesForUpdatableBootJars() []string {
+	return j.properties.Permitted_packages
+}
+
 func (j *Import) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
 	return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version))
 }
@@ -1311,6 +1339,7 @@
 			di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
 			if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(j.BaseModuleName())); dexOutputPath != nil {
 				j.dexJarFile = dexOutputPath
+				j.dexJarInstallFile = android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName()))
 
 				// Initialize the hiddenapi structure.
 				j.initHiddenAPI(ctx, dexOutputPath, outputFile, nil)
@@ -1351,6 +1380,7 @@
 			dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
 
 			j.dexJarFile = dexOutputFile
+			j.dexJarInstallFile = android.PathForModuleInstall(ctx, "framework", jarName)
 		}
 	}
 
@@ -1392,7 +1422,7 @@
 }
 
 func (j *Import) DexJarInstallPath() android.Path {
-	return nil
+	return j.dexJarInstallFile
 }
 
 func (j *Import) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
@@ -1462,11 +1492,7 @@
 	// TODO(b/113562217): Extract the base module name from the Import name, often the Import name
 	// has a prefix "prebuilt_". Remove the prefix explicitly if needed until we find a better
 	// solution to get the Import name.
-	name := j.Name()
-	if strings.HasPrefix(name, removedPrefix) {
-		name = strings.TrimPrefix(name, removedPrefix)
-	}
-	return name
+	return android.RemoveOptionalPrebuiltPrefix(j.Name())
 }
 
 var _ android.PrebuiltInterface = (*Import)(nil)
@@ -1768,22 +1794,16 @@
 		return
 	}
 
-	// Find out if the dependency is either an SDK library or an ordinary library that is disguised
-	// as an SDK library by the means of `provides_uses_lib` property. If yes, the library is itself
-	// a <uses-library> and should be added as a node in the CLC tree, and its CLC should be added
-	// as subtree of that node. Otherwise the library is not a <uses_library> and should not be
-	// added to CLC, but the transitive <uses-library> dependencies from its CLC should be added to
-	// the current CLC.
-	var implicitSdkLib *string
-	comp, isComp := depModule.(SdkLibraryComponentDependency)
-	if isComp {
-		implicitSdkLib = comp.OptionalImplicitSdkLibrary()
-		// OptionalImplicitSdkLibrary() may be nil so need to fall through to ProvidesUsesLib().
-	}
-	if implicitSdkLib == nil {
-		if ulib, ok := depModule.(ProvidesUsesLib); ok {
-			implicitSdkLib = ulib.ProvidesUsesLib()
-		}
+	depName := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(depModule))
+
+	var sdkLib *string
+	if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() {
+		// A shared SDK library. This should be added as a top-level CLC element.
+		sdkLib = &depName
+	} else if ulib, ok := depModule.(ProvidesUsesLib); ok {
+		// A non-SDK library disguised as an SDK library by the means of `provides_uses_lib`
+		// property. This should be handled in the same way as a shared SDK library.
+		sdkLib = ulib.ProvidesUsesLib()
 	}
 
 	depTag := ctx.OtherModuleDependencyTag(depModule)
@@ -1793,7 +1813,7 @@
 		// Propagate <uses-library> through static library dependencies, unless it is a component
 		// library (such as stubs). Component libraries have a dependency on their SDK library,
 		// which should not be pulled just because of a static component library.
-		if implicitSdkLib != nil {
+		if sdkLib != nil {
 			return
 		}
 	} else {
@@ -1801,11 +1821,14 @@
 		return
 	}
 
-	if implicitSdkLib != nil {
-		clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *implicitSdkLib,
+	// If this is an SDK (or SDK-like) library, then it should be added as a node in the CLC tree,
+	// and its CLC should be added as subtree of that node. Otherwise the library is not a
+	// <uses_library> and should not be added to CLC, but the transitive <uses-library> dependencies
+	// from its CLC should be added to the current CLC.
+	if sdkLib != nil {
+		clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib,
 			dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
 	} else {
-		depName := ctx.OtherModuleName(depModule)
 		clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
 	}
 }
diff --git a/java/lint.go b/java/lint.go
index dd5e4fb..fe3218e 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -391,8 +391,9 @@
 	rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
 
 	var apiVersionsName, apiVersionsPrebuilt string
-	if l.compileSdkKind == android.SdkModule {
-		// When compiling an SDK module we use the filtered database because otherwise lint's
+	if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
+		// When compiling an SDK module (or system server) we use the filtered
+		// database because otherwise lint's
 		// NewApi check produces too many false positives; This database excludes information
 		// about classes created in mainline modules hence removing those false positives.
 		apiVersionsName = "api_versions_public_filtered.xml"
diff --git a/java/lint_test.go b/java/lint_test.go
index 9cf1c33..456e6ba 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -261,6 +261,9 @@
 }
 
 func TestJavaLintDatabaseSelectionPublicFiltered(t *testing.T) {
+	testCases := []string{
+		"module_current", "system_server_current",
+	}
 	bp := `
 		java_library {
 			name: "foo",
@@ -274,17 +277,20 @@
 			},
 		}
 `
-	result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
-		RunTestWithBp(t, bp)
+	for _, testCase := range testCases {
+		thisBp := strings.Replace(bp, "XXX", testCase, 1)
+		result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
+			RunTestWithBp(t, thisBp)
 
-	foo := result.ModuleForTests("foo", "android_common")
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command,
-		"/api_versions_public_filtered.xml") {
-		t.Error("did not use public-filtered lint api database", *sboxProto.Commands[0].Command)
-	}
-	if strings.Contains(*sboxProto.Commands[0].Command,
-		"/api_versions.xml") {
-		t.Error("used full api database")
+		foo := result.ModuleForTests("foo", "android_common")
+		sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
+		if !strings.Contains(*sboxProto.Commands[0].Command,
+			"/api_versions_public_filtered.xml") {
+			t.Error("did not use public-filtered lint api database for case", testCase)
+		}
+		if strings.Contains(*sboxProto.Commands[0].Command,
+			"/api_versions.xml") {
+			t.Error("used full api database for case", testCase)
+		}
 	}
 }
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index c1e14b2..8bed3e9 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -423,8 +423,13 @@
 	// Generate the framework profile rule
 	bootFrameworkProfileRule(ctx, imageConfig)
 
-	// Generate the updatable bootclasspath packages rule.
-	generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
+	// If always using prebuilt sdks then do not generate the updatable-bcp-packages.txt file as it
+	// will break because the prebuilts do not yet specify a permitted_packages property.
+	// TODO(b/193889859): Remove when the prebuilts have been updated.
+	if !ctx.Config().AlwaysUsePrebuiltSdks() {
+		// Generate the updatable bootclasspath packages rule.
+		generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
+	}
 
 	// Copy non-updatable module dex jars to their predefined locations.
 	nonUpdatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, nonUpdatableModules)
diff --git a/java/robolectric.go b/java/robolectric.go
index 00f233e..a37a118 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -179,7 +179,7 @@
 			continue
 		} else if strings.HasSuffix(s, "/BaseRobolectricTest.java") {
 			continue
-		} else if strings.HasPrefix(s, "src/") {
+		} else {
 			s = strings.TrimPrefix(s, "src/")
 		}
 		r.tests = append(r.tests, s)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index ed9aeff..268e797 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -981,13 +981,15 @@
 }
 
 // to satisfy SdkLibraryComponentDependency
-func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string {
-	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
-}
-
-// to satisfy SdkLibraryComponentDependency
 func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string {
-	// Currently implementation library name is the same as the SDK library name.
+	// For shared libraries, this is the same as the SDK library name. If a Java library or app
+	// depends on a component library (e.g. a stub library) it still needs to know the name of the
+	// run-time library and the corresponding module that provides the implementation. This name is
+	// passed to manifest_fixer (to be added to AndroidManifest.xml) and added to CLC (to be used
+	// in dexpreopt).
+	//
+	// For non-shared SDK (component or not) libraries this returns `nil`, as they are not
+	// <uses-library> and should not be added to the manifest or to CLC.
 	return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
 }
 
@@ -999,12 +1001,6 @@
 	// SdkLibraryName returns the name of the java_sdk_library/_import module.
 	SdkLibraryName() *string
 
-	// The optional name of the sdk library that should be implicitly added to the
-	// AndroidManifest of an app that contains code which references the sdk library.
-	//
-	// Returns the name of the optional implicit SDK library or nil, if there isn't one.
-	OptionalImplicitSdkLibrary() *string
-
 	// The name of the implementation library for the optional SDK library or nil, if there isn't one.
 	OptionalSdkLibraryImplementation() *string
 }
@@ -1897,6 +1893,10 @@
 
 	// If set to true, compile dex files for the stubs. Defaults to false.
 	Compile_dex *bool
+
+	// If not empty, classes are restricted to the specified packages and their sub-packages.
+	// This information is used to generate the updatable-bcp-packages.txt file.
+	Permitted_packages []string
 }
 
 type SdkLibraryImport struct {
@@ -1923,8 +1923,12 @@
 	// Is nil if the source module does not exist.
 	xmlPermissionsFileModule *sdkLibraryXml
 
-	// Path to the dex implementation jar obtained from the prebuilt_apex, if any.
+	// Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
 	dexJarFile android.Path
+
+	// Expected install file path of the source module(sdk_library)
+	// or dex implementation jar obtained from the prebuilt_apex, if any.
+	installFile android.Path
 }
 
 var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
@@ -1991,6 +1995,12 @@
 	return module
 }
 
+var _ PermittedPackagesForUpdatableBootJars = (*SdkLibraryImport)(nil)
+
+func (module *SdkLibraryImport) PermittedPackagesForUpdatableBootJars() []string {
+	return module.properties.Permitted_packages
+}
+
 func (module *SdkLibraryImport) Prebuilt() *android.Prebuilt {
 	return &module.prebuilt
 }
@@ -2136,6 +2146,9 @@
 
 	var deapexerModule android.Module
 
+	// Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework
+	module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar")
+
 	// Record the paths to the prebuilt stubs library and stubs source.
 	ctx.VisitDirectDeps(func(to android.Module) {
 		tag := ctx.OtherModuleDependencyTag(to)
@@ -2195,6 +2208,7 @@
 			di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
 			if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(module.BaseModuleName())); dexOutputPath != nil {
 				module.dexJarFile = dexOutputPath
+				module.installFile = android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(module.BaseModuleName()))
 				module.initHiddenAPI(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
 			} else {
 				// This should never happen as a variant for a prebuilt_apex is only created if the
@@ -2249,11 +2263,7 @@
 
 // to satisfy UsesLibraryDependency interface
 func (module *SdkLibraryImport) DexJarInstallPath() android.Path {
-	if module.implLibraryModule == nil {
-		return nil
-	} else {
-		return module.implLibraryModule.DexJarInstallPath()
-	}
+	return module.installFile
 }
 
 // to satisfy UsesLibraryDependency interface
@@ -2506,6 +2516,8 @@
 
 	// The paths to the doctag files to add to the prebuilt.
 	Doctag_paths android.Paths
+
+	Permitted_packages []string
 }
 
 type scopeProperties struct {
@@ -2546,6 +2558,7 @@
 	s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
 	s.Compile_dex = sdk.dexProperties.Compile_dex
 	s.Doctag_paths = sdk.doctagPaths
+	s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars()
 }
 
 func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -2558,6 +2571,9 @@
 	if s.Compile_dex != nil {
 		propertySet.AddProperty("compile_dex", *s.Compile_dex)
 	}
+	if len(s.Permitted_packages) > 0 {
+		propertySet.AddProperty("permitted_packages", s.Permitted_packages)
+	}
 
 	for _, apiScope := range allApiScopes {
 		if properties, ok := s.Scopes[apiScope]; ok {
diff --git a/rust/androidmk.go b/rust/androidmk.go
index ea45ebd..630805a 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -205,24 +205,24 @@
 	ctx.SubAndroidMk(entries, fuzz.binaryDecorator)
 
 	var fuzzFiles []string
-	for _, d := range fuzz.corpus {
+	for _, d := range fuzz.fuzzPackagedModule.Corpus {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.corpusIntermediateDir.String())+":corpus/"+d.Base())
+			filepath.Dir(fuzz.fuzzPackagedModule.CorpusIntermediateDir.String())+":corpus/"+d.Base())
 	}
 
-	for _, d := range fuzz.data {
+	for _, d := range fuzz.fuzzPackagedModule.Data {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.dataIntermediateDir.String())+":data/"+d.Rel())
+			filepath.Dir(fuzz.fuzzPackagedModule.DataIntermediateDir.String())+":data/"+d.Rel())
 	}
 
-	if fuzz.dictionary != nil {
+	if fuzz.fuzzPackagedModule.Dictionary != nil {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.dictionary.String())+":"+fuzz.dictionary.Base())
+			filepath.Dir(fuzz.fuzzPackagedModule.Dictionary.String())+":"+fuzz.fuzzPackagedModule.Dictionary.Base())
 	}
 
-	if fuzz.config != nil {
+	if fuzz.fuzzPackagedModule.Config != nil {
 		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.config.String())+":config.json")
+			filepath.Dir(fuzz.fuzzPackagedModule.Config.String())+":config.json")
 	}
 
 	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext,
diff --git a/rust/benchmark.go b/rust/benchmark.go
index b89f5cd..0e84243 100644
--- a/rust/benchmark.go
+++ b/rust/benchmark.go
@@ -101,6 +101,7 @@
 func (benchmark *benchmarkDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
 	deps = benchmark.binaryDecorator.compilerDeps(ctx, deps)
 
+	deps.Rustlibs = append(deps.Rustlibs, "libtest")
 	deps.Rustlibs = append(deps.Rustlibs, "libcriterion")
 
 	return deps
diff --git a/rust/config/global.go b/rust/config/global.go
index 43b49d1..1b56237 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -29,7 +29,6 @@
 	DefaultEdition     = "2018"
 	Stdlibs            = []string{
 		"libstd",
-		"libtest",
 	}
 
 	// Mapping between Soong internal arch types and std::env constants.
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 7e1c55a..18b2513 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -32,13 +32,7 @@
 type fuzzDecorator struct {
 	*binaryDecorator
 
-	Properties            cc.FuzzProperties
-	dictionary            android.Path
-	corpus                android.Paths
-	corpusIntermediateDir android.Path
-	config                android.Path
-	data                  android.Paths
-	dataIntermediateDir   android.Path
+	fuzzPackagedModule cc.FuzzPackagedModule
 }
 
 var _ compiler = (*binaryDecorator)(nil)
@@ -88,7 +82,7 @@
 
 func (fuzzer *fuzzDecorator) compilerProps() []interface{} {
 	return append(fuzzer.binaryDecorator.compilerProps(),
-		&fuzzer.Properties)
+		&fuzzer.fuzzPackagedModule.FuzzProperties)
 }
 
 func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage {
@@ -102,32 +96,19 @@
 // Responsible for generating GNU Make rules that package fuzz targets into
 // their architecture & target/host specific zip file.
 type rustFuzzPackager struct {
-	packages    android.Paths
-	fuzzTargets map[string]bool
+	cc.FuzzPackager
 }
 
 func rustFuzzPackagingFactory() android.Singleton {
 	return &rustFuzzPackager{}
 }
 
-type fileToZip struct {
-	SourceFilePath        android.Path
-	DestinationPathPrefix string
-}
-
-type archOs struct {
-	hostOrTarget string
-	arch         string
-	dir          string
-}
-
 func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
-
 	// Map between each architecture + host/device combination.
-	archDirs := make(map[archOs][]fileToZip)
+	archDirs := make(map[cc.ArchOs][]cc.FileToZip)
 
 	// List of individual fuzz targets.
-	s.fuzzTargets = make(map[string]bool)
+	s.FuzzTargets = make(map[string]bool)
 
 	ctx.VisitAllModules(func(module android.Module) {
 		// Discard non-fuzz targets.
@@ -136,23 +117,15 @@
 			return
 		}
 
+		if ok := cc.IsValid(rustModule.FuzzModule); !ok || rustModule.Properties.PreventInstall {
+			return
+		}
+
 		fuzzModule, ok := rustModule.compiler.(*fuzzDecorator)
 		if !ok {
 			return
 		}
 
-		// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
-		// fuzz targets we're going to package anyway.
-		if !rustModule.Enabled() || rustModule.Properties.PreventInstall ||
-			rustModule.InRamdisk() || rustModule.InVendorRamdisk() || rustModule.InRecovery() {
-			return
-		}
-
-		// Discard modules that are in an unavailable namespace.
-		if !rustModule.ExportedToMake() {
-			return
-		}
-
 		hostOrTargetString := "target"
 		if rustModule.Host() {
 			hostOrTargetString = "host"
@@ -160,126 +133,34 @@
 
 		archString := rustModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
-		archOs := archOs{hostOrTarget: hostOrTargetString, arch: archString, dir: archDir.String()}
+		archOs := cc.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
 
-		var files []fileToZip
+		var files []cc.FileToZip
 		builder := android.NewRuleBuilder(pctx, ctx)
 
-		// Package the corpora into a zipfile.
-		if fuzzModule.corpus != nil {
-			corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip")
-			command := builder.Command().BuiltTool("soong_zip").
-				Flag("-j").
-				FlagWithOutput("-o ", corpusZip)
-			rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
-			command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.corpus)
-			files = append(files, fileToZip{corpusZip, ""})
-		}
-
-		// Package the data into a zipfile.
-		if fuzzModule.data != nil {
-			dataZip := archDir.Join(ctx, module.Name()+"_data.zip")
-			command := builder.Command().BuiltTool("soong_zip").
-				FlagWithOutput("-o ", dataZip)
-			for _, f := range fuzzModule.data {
-				intermediateDir := strings.TrimSuffix(f.String(), f.Rel())
-				command.FlagWithArg("-C ", intermediateDir)
-				command.FlagWithInput("-f ", f)
-			}
-			files = append(files, fileToZip{dataZip, ""})
-		}
+		// Package the artifacts (data, corpus, config and dictionary into a zipfile.
+		files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
 
 		// The executable.
-		files = append(files, fileToZip{rustModule.unstrippedOutputFile.Path(), ""})
+		files = append(files, cc.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
 
-		// The dictionary.
-		if fuzzModule.dictionary != nil {
-			files = append(files, fileToZip{fuzzModule.dictionary, ""})
+		archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
+		if !ok {
+			return
 		}
 
-		// Additional fuzz config.
-		if fuzzModule.config != nil {
-			files = append(files, fileToZip{fuzzModule.config, ""})
-		}
-
-		fuzzZip := archDir.Join(ctx, module.Name()+".zip")
-
-		command := builder.Command().BuiltTool("soong_zip").
-			Flag("-j").
-			FlagWithOutput("-o ", fuzzZip)
-
-		for _, file := range files {
-			if file.DestinationPathPrefix != "" {
-				command.FlagWithArg("-P ", file.DestinationPathPrefix)
-			} else {
-				command.Flag("-P ''")
-			}
-			command.FlagWithInput("-f ", file.SourceFilePath)
-		}
-
-		builder.Build("create-"+fuzzZip.String(),
-			"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
-
-		// Don't add modules to 'make haiku-rust' that are set to not be
-		// exported to the fuzzing infrastructure.
-		if config := fuzzModule.Properties.Fuzz_config; config != nil {
-			if rustModule.Host() && !BoolDefault(config.Fuzz_on_haiku_host, true) {
-				return
-			} else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
-				return
-			}
-		}
-
-		s.fuzzTargets[module.Name()] = true
-		archDirs[archOs] = append(archDirs[archOs], fileToZip{fuzzZip, ""})
 	})
-
-	var archOsList []archOs
-	for archOs := range archDirs {
-		archOsList = append(archOsList, archOs)
-	}
-	sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].dir < archOsList[j].dir })
-
-	for _, archOs := range archOsList {
-		filesToZip := archDirs[archOs]
-		arch := archOs.arch
-		hostOrTarget := archOs.hostOrTarget
-		builder := android.NewRuleBuilder(pctx, ctx)
-		outputFile := android.PathForOutput(ctx, "fuzz-rust-"+hostOrTarget+"-"+arch+".zip")
-		s.packages = append(s.packages, outputFile)
-
-		command := builder.Command().BuiltTool("soong_zip").
-			Flag("-j").
-			FlagWithOutput("-o ", outputFile).
-			Flag("-L 0") // No need to try and re-compress the zipfiles.
-
-		for _, fileToZip := range filesToZip {
-			if fileToZip.DestinationPathPrefix != "" {
-				command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
-			} else {
-				command.Flag("-P ''")
-			}
-			command.FlagWithInput("-f ", fileToZip.SourceFilePath)
-		}
-		builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget,
-			"Create fuzz target packages for "+arch+"-"+hostOrTarget)
-	}
-
+	s.CreateFuzzPackage(ctx, archDirs, cc.Rust)
 }
 
 func (s *rustFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
-	packages := s.packages.Strings()
+	packages := s.Packages.Strings()
 	sort.Strings(packages)
 
 	ctx.Strict("SOONG_RUST_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
 
-	// Preallocate the slice of fuzz targets to minimise memory allocations.
-	fuzzTargets := make([]string, 0, len(s.fuzzTargets))
-	for target, _ := range s.fuzzTargets {
-		fuzzTargets = append(fuzzTargets, target)
-	}
-	sort.Strings(fuzzTargets)
-	ctx.Strict("ALL_RUST_FUZZ_TARGETS", strings.Join(fuzzTargets, " "))
+	// Preallocate the slice of fuzz targets to minimize memory allocations.
+	s.PreallocateSlice(ctx, "ALL_RUST_FUZZ_TARGETS")
 }
 
 func (fuzz *fuzzDecorator) install(ctx ModuleContext) {
@@ -289,13 +170,13 @@
 		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
 	fuzz.binaryDecorator.baseCompiler.install(ctx)
 
-	if fuzz.Properties.Corpus != nil {
-		fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
+	if fuzz.fuzzPackagedModule.FuzzProperties.Corpus != nil {
+		fuzz.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Corpus)
 	}
-	if fuzz.Properties.Data != nil {
-		fuzz.data = android.PathsForModuleSrc(ctx, fuzz.Properties.Data)
+	if fuzz.fuzzPackagedModule.FuzzProperties.Data != nil {
+		fuzz.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Data)
 	}
-	if fuzz.Properties.Dictionary != nil {
-		fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
+	if fuzz.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
+		fuzz.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzz.fuzzPackagedModule.FuzzProperties.Dictionary)
 	}
 }
diff --git a/rust/library.go b/rust/library.go
index 747a29d..5a36bd1 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -431,6 +431,12 @@
 
 func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
+	if library.dylib() {
+		// We need to add a dependency on std in order to link crates as dylibs.
+		// The hack to add this dependency is guarded by the following cfg so
+		// that we don't force a dependency when it isn't needed.
+		library.baseCompiler.Properties.Cfgs = append(library.baseCompiler.Properties.Cfgs, "android_dylib")
+	}
 	flags = library.baseCompiler.compilerFlags(ctx, flags)
 	if library.shared() || library.static() {
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
diff --git a/rust/library_test.go b/rust/library_test.go
index 54cd2a5..cb4ef7e 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -85,6 +85,22 @@
 	}
 }
 
+// Check that we are passing the android_dylib config flag
+func TestAndroidDylib(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_host_dylib {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
+		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+	}
+}
+
 func TestValidateLibraryStem(t *testing.T) {
 	testRustError(t, "crate_name must be defined.", `
 			rust_library_host {
diff --git a/rust/rust.go b/rust/rust.go
index 38f1742..52b4094 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -119,9 +119,7 @@
 }
 
 type Module struct {
-	android.ModuleBase
-	android.DefaultableModuleBase
-	android.ApexModuleBase
+	cc.FuzzModule
 
 	VendorProperties cc.VendorProperties
 
diff --git a/rust/test.go b/rust/test.go
index 6caa7b1..e95b47c 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -169,3 +169,11 @@
 func (test *testDecorator) stdLinkage(ctx *depsContext) RustLinkage {
 	return RlibLinkage
 }
+
+func (test *testDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+	deps = test.binaryDecorator.compilerDeps(ctx, deps)
+
+	deps.Rustlibs = append(deps.Rustlibs, "libtest")
+
+	return deps
+}
diff --git a/rust/testing.go b/rust/testing.go
index 72f87e1..94cdd9d 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -170,12 +170,10 @@
 			name: "libtest",
 			crate_name: "test",
 			srcs: ["foo.rs"],
-			no_stdlibs: true,
 			host_supported: true,
 			vendor_available: true,
 			vendor_ramdisk_available: true,
 			native_coverage: false,
-			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
 			min_sdk_version: "29",
 		}
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 815f80e..60ddb65 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -569,7 +569,6 @@
 				],
 				rlibs: [
 					"libstd",
-					"libtest",
 					"librust_vendor_available",
 				],
 				binaries: [
@@ -597,7 +596,6 @@
 				],
 				rlibs: [
 					"libstd",
-					"libtest",
 					"librust_vendor_available",
 				],
 				binaries: [
@@ -665,22 +663,6 @@
 	}
 
 	vendor_snapshot_rlib {
-		name: "libtest",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		sysroot: true,
-		arch: {
-			arm64: {
-				src: "libtest.rlib",
-			},
-			arm: {
-				src: "libtest.rlib",
-			},
-		},
-	}
-
-	vendor_snapshot_rlib {
 		name: "librust_vendor_available",
 		version: "30",
 		target_arch: "arm64",
@@ -917,7 +899,6 @@
 		"vendor/lib64.so":                               nil,
 		"vendor/liblog.so":                              nil,
 		"vendor/libstd.rlib":                            nil,
-		"vendor/libtest.rlib":                           nil,
 		"vendor/librust_vendor_available.rlib":          nil,
 		"vendor/crtbegin_so.o":                          nil,
 		"vendor/crtend_so.o":                            nil,
@@ -962,7 +943,7 @@
 	}
 
 	libclientAndroidMkRlibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkRlibs
-	if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64", "libtest.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
+	if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
 	}
 
@@ -977,7 +958,7 @@
 	}
 
 	libclientRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibVariant).Module().(*Module).Properties.AndroidMkRlibs
-	if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64", "libtest.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
+	if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
 	}
 
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index a458cba..efd2b5b 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -133,6 +133,13 @@
     apex_available: ["com.android.art"],
     image_name: "art",
     contents: ["mybootlib"],
+    hidden_api: {
+        stub_flags: "hiddenapi/stub-flags.csv",
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        all_flags: "hiddenapi/all-flags.csv",
+    },
 }
 
 java_import {
@@ -140,7 +147,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
 }
 `),
 		checkVersionedAndroidBpContents(`
@@ -153,6 +160,13 @@
     apex_available: ["com.android.art"],
     image_name: "art",
     contents: ["mysdk_mybootlib@current"],
+    hidden_api: {
+        stub_flags: "hiddenapi/stub-flags.csv",
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        all_flags: "hiddenapi/all-flags.csv",
+    },
 }
 
 java_import {
@@ -160,7 +174,7 @@
     sdk_member_name: "mybootlib",
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
 }
 
 sdk_snapshot {
@@ -171,8 +185,13 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
-`),
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+		`),
 		snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
 
 		// Check the behavior of the snapshot without the source.
@@ -326,7 +345,8 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
+    permitted_packages: ["mybootlib"],
 }
 
 java_sdk_library_import {
@@ -336,6 +356,7 @@
     apex_available: ["myapex"],
     shared_library: true,
     compile_dex: true,
+    permitted_packages: ["myothersdklibrary"],
     public: {
         jars: ["sdk_library/public/myothersdklibrary-stubs.jar"],
         stub_srcs: ["sdk_library/public/myothersdklibrary_stub_sources"],
@@ -408,7 +429,8 @@
     sdk_member_name: "mybootlib",
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
+    permitted_packages: ["mybootlib"],
 }
 
 java_sdk_library_import {
@@ -418,6 +440,7 @@
     apex_available: ["myapex"],
     shared_library: true,
     compile_dex: true,
+    permitted_packages: ["myothersdklibrary"],
     public: {
         jars: ["sdk_library/public/myothersdklibrary-stubs.jar"],
         stub_srcs: ["sdk_library/public/myothersdklibrary_stub_sources"],
@@ -476,7 +499,7 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
 .intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
@@ -509,6 +532,12 @@
 				out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
         snapshot/hiddenapi/index.csv
 			`, rule)
+
+			// Make sure that the permitted packages from the prebuilts end up in the
+			// updatable-bcp-packages.txt file.
+			rule = module.Output("updatable-bcp-packages.txt")
+			expectedContents := `'mybootlib\nmyothersdklibrary\n'`
+			android.AssertStringEquals(t, "updatable-bcp-packages.txt", expectedContents, rule.Args["content"])
 		}),
 		snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
 		snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
@@ -779,6 +808,7 @@
 				srcs: ["Test.java"],
 				compile_dex: true,
 				public: {enabled: true},
+				permitted_packages: ["mysdklibrary"],
 			}
 		`),
 	).RunTest(t)
@@ -821,7 +851,8 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    jars: ["java/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
+    permitted_packages: ["mybootlib"],
 }
 
 java_sdk_library_import {
@@ -831,6 +862,7 @@
     apex_available: ["//apex_available:platform"],
     shared_library: true,
     compile_dex: true,
+    permitted_packages: ["mysdklibrary"],
     public: {
         jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
         stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
@@ -854,7 +886,7 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
 .intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
 .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index a2cfe6d..9efb3a4 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -175,6 +175,7 @@
 			sdk_version: "none",
 			compile_dex: true,
 			host_supported: true,
+			permitted_packages: ["pkg.myjavalib"],
 		}
 	`)
 
@@ -188,6 +189,7 @@
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
+    permitted_packages: ["pkg.myjavalib"],
 }
 `),
 		checkVersionedAndroidBpContents(`
@@ -199,6 +201,7 @@
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
+    permitted_packages: ["pkg.myjavalib"],
 }
 
 sdk_snapshot {
@@ -437,6 +440,7 @@
 			system_modules: "none",
 			sdk_version: "none",
 			compile_dex: true,
+			permitted_packages: ["pkg.myjavalib"],
 		}
 	`)
 
@@ -449,7 +453,8 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: ["java/myjavalib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar"],
+    permitted_packages: ["pkg.myjavalib"],
 }
 `),
 		checkVersionedAndroidBpContents(`
@@ -460,7 +465,8 @@
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: ["java/myjavalib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar"],
+    permitted_packages: ["pkg.myjavalib"],
 }
 
 module_exports_snapshot {
@@ -468,9 +474,10 @@
     visibility: ["//visibility:public"],
     java_boot_libs: ["myexports_myjavalib@current"],
 }
+
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib/android_common/withres/myjavalib.jar -> java/myjavalib.jar
+.intermediates/myexports/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
 `),
 	)
 }
@@ -1045,6 +1052,7 @@
 			shared_library: false,
 			stubs_library_visibility: ["//other"],
 			stubs_source_visibility: ["//another"],
+			permitted_packages: ["pkg.myjavalib"],
 		}
 	`)
 
@@ -1058,6 +1066,7 @@
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:anyapex"],
     shared_library: false,
+    permitted_packages: ["pkg.myjavalib"],
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1090,6 +1099,7 @@
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:anyapex"],
     shared_library: false,
+    permitted_packages: ["pkg.myjavalib"],
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index a13b0d7..97fb248 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -565,6 +565,49 @@
 		)
 	})
 
+	t.Run("SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR=module:build_from_source", func(t *testing.T) {
+		result := android.GroupFixturePreparers(
+			preparer,
+			android.FixtureMergeEnv(map[string]string{
+				"SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR": "module:build_from_source",
+			}),
+		).RunTest(t)
+
+		checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
+
+		CheckSnapshot(t, result, "mysdk", "",
+			checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+    name: "myjavalib",
+    prefer: false,
+    use_source_config_var: {
+        config_namespace: "module",
+        var_name: "build_from_source",
+    },
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    visibility: ["//visibility:public"],
+    java_header_libs: ["mysdk_myjavalib@current"],
+}
+			`),
+		)
+	})
+
 	t.Run("SOONG_SDK_SNAPSHOT_VERSION=unversioned", func(t *testing.T) {
 		result := android.GroupFixturePreparers(
 			preparer,
diff --git a/sdk/update.go b/sdk/update.go
index b146b62..3ec1bfa 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -35,6 +35,37 @@
 //     By default every unversioned module in the generated snapshot has prefer: false. Building it
 //     with SOONG_SDK_SNAPSHOT_PREFER=true will force them to use prefer: true.
 //
+// SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR
+//     If set this specifies the Soong config var that can be used to control whether the prebuilt
+//     modules from the generated snapshot or the original source modules. Values must be a colon
+//     separated pair of strings, the first of which is the Soong config namespace, and the second
+//     is the name of the variable within that namespace.
+//
+//     The config namespace and var name are used to set the `use_source_config_var` property. That
+//     in turn will cause the generated prebuilts to use the soong config variable to select whether
+//     source or the prebuilt is used.
+//     e.g. If an sdk snapshot is built using:
+//       m SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR=acme:build_from_source sdkextensions-sdk
+//     Then the resulting snapshot will include:
+//       use_source_config_var: {
+//         config_namespace: "acme",
+//         var_name: "build_from_source",
+//       }
+//
+//     Assuming that the config variable is defined in .mk using something like:
+//       $(call add_soong_config_namespace,acme)
+//       $(call add_soong_config_var_value,acme,build_from_source,true)
+//
+//     Then when the snapshot is unpacked in the repository it will have the following behavior:
+//       m droid - will use the sdkextensions-sdk prebuilts if present. Otherwise, it will use the
+//           sources.
+//       m SOONG_CONFIG_acme_build_from_source=true droid - will use the sdkextensions-sdk
+//            sources, if present. Otherwise, it will use the prebuilts.
+//
+//     This is a temporary mechanism to control the prefer flags and will be removed once a more
+//     maintainable solution has been implemented.
+//     TODO(b/174997203): Remove when no longer necessary.
+//
 // SOONG_SDK_SNAPSHOT_VERSION
 //     This provides control over the version of the generated snapshot.
 //
@@ -760,6 +791,8 @@
 	module.insertAfter("name", "sdk_member_name", name)
 	// Remove the prefer property if present as versioned modules never need marking with prefer.
 	module.removeProperty("prefer")
+	// Ditto for use_source_config_var
+	module.removeProperty("use_source_config_var")
 	return module
 }
 
@@ -996,6 +1029,9 @@
 	filesToZip  android.Paths
 	zipsToMerge android.Paths
 
+	// The path to an empty file.
+	emptyFile android.WritablePath
+
 	prebuiltModules map[string]*bpModule
 	prebuiltOrder   []*bpModule
 
@@ -1046,6 +1082,19 @@
 	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
 }
 
+func (s *snapshotBuilder) EmptyFile() android.Path {
+	if s.emptyFile == nil {
+		ctx := s.ctx
+		s.emptyFile = android.PathForModuleOut(ctx, "empty")
+		s.ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Touch,
+			Output: s.emptyFile,
+		})
+	}
+
+	return s.emptyFile
+}
+
 func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
 	name := member.Name()
 	if s.prebuiltModules[name] != nil {
@@ -1627,13 +1676,24 @@
 		// snapshot to be created that sets prefer: true.
 		// TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
 		//  dynamically at build time not at snapshot generation time.
-		prefer := ctx.sdkMemberContext.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
+		config := ctx.sdkMemberContext.Config()
+		prefer := config.IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
 
 		// Set prefer. Setting this to false is not strictly required as that is the default but it does
 		// provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
 		// check the behavior when a prebuilt is preferred. It also makes it explicit what the default
 		// behavior is for the module.
 		bpModule.insertAfter("name", "prefer", prefer)
+
+		configVar := config.Getenv("SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR")
+		if configVar != "" {
+			parts := strings.Split(configVar, ":")
+			cfp := android.ConfigVarProperties{
+				Config_namespace: proptools.StringPtr(parts[0]),
+				Var_name:         proptools.StringPtr(parts[1]),
+			}
+			bpModule.insertAfter("prefer", "use_source_config_var", cfp)
+		}
 	}
 
 	// Group the variants by os type.
diff --git a/ui/build/config.go b/ui/build/config.go
index 7370627..cd6d549 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -345,12 +345,7 @@
 		return
 	}
 
-	b := &smpb.BuildConfig{
-		ForceUseGoma: proto.Bool(config.ForceUseGoma()),
-		UseGoma:      proto.Bool(config.UseGoma()),
-		UseRbe:       proto.Bool(config.UseRBE()),
-	}
-	ctx.Metrics.BuildConfig(b)
+	ctx.Metrics.BuildConfig(buildConfig(config))
 
 	s := &smpb.SystemResourceInfo{
 		TotalPhysicalMemory: proto.Uint64(config.TotalRAM()),
@@ -359,6 +354,16 @@
 	ctx.Metrics.SystemResourceInfo(s)
 }
 
+func buildConfig(config Config) *smpb.BuildConfig {
+	return &smpb.BuildConfig{
+		ForceUseGoma:    proto.Bool(config.ForceUseGoma()),
+		UseGoma:         proto.Bool(config.UseGoma()),
+		UseRbe:          proto.Bool(config.UseRBE()),
+		BazelAsNinja:    proto.Bool(config.UseBazel()),
+		BazelMixedBuild: proto.Bool(config.bazelBuildMode() == mixedBuild),
+	}
+}
+
 // getConfigArgs processes the command arguments based on the build action and creates a set of new
 // arguments to be accepted by Config.
 func getConfigArgs(action BuildAction, dir string, ctx Context, args []string) []string {
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 7b14c47..7d4c76b 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -26,7 +26,10 @@
 	"testing"
 
 	"android/soong/ui/logger"
+	smpb "android/soong/ui/metrics/metrics_proto"
 	"android/soong/ui/status"
+
+	"github.com/golang/protobuf/proto"
 )
 
 func testContext() Context {
@@ -995,3 +998,111 @@
 		})
 	}
 }
+
+func TestBuildConfig(t *testing.T) {
+	tests := []struct {
+		name                string
+		environ             Environment
+		useBazel            bool
+		expectedBuildConfig *smpb.BuildConfig
+	}{
+		{
+			name:    "none set",
+			environ: Environment{},
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:    proto.Bool(false),
+				UseGoma:         proto.Bool(false),
+				UseRbe:          proto.Bool(false),
+				BazelAsNinja:    proto.Bool(false),
+				BazelMixedBuild: 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),
+				BazelAsNinja:    proto.Bool(false),
+				BazelMixedBuild: 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),
+				BazelAsNinja:    proto.Bool(false),
+				BazelMixedBuild: 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),
+				BazelAsNinja:    proto.Bool(false),
+				BazelMixedBuild: proto.Bool(false),
+			},
+		},
+		{
+			name:     "use bazel as ninja",
+			environ:  Environment{},
+			useBazel: true,
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:    proto.Bool(false),
+				UseGoma:         proto.Bool(false),
+				UseRbe:          proto.Bool(false),
+				BazelAsNinja:    proto.Bool(true),
+				BazelMixedBuild: proto.Bool(false),
+			},
+		},
+		{
+			name:    "bazel mixed build",
+			environ: Environment{"USE_BAZEL_ANALYSIS=1"},
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:    proto.Bool(false),
+				UseGoma:         proto.Bool(false),
+				UseRbe:          proto.Bool(false),
+				BazelAsNinja:    proto.Bool(false),
+				BazelMixedBuild: proto.Bool(true),
+			},
+		},
+		{
+			name: "all set",
+			environ: Environment{
+				"FORCE_USE_GOMA=1",
+				"USE_GOMA=1",
+				"USE_RBE=1",
+				"USE_BAZEL_ANALYSIS=1",
+			},
+			useBazel: true,
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:    proto.Bool(true),
+				UseGoma:         proto.Bool(true),
+				UseRbe:          proto.Bool(true),
+				BazelAsNinja:    proto.Bool(true),
+				BazelMixedBuild: proto.Bool(true),
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			c := &configImpl{
+				environ:  &tc.environ,
+				useBazel: tc.useBazel,
+			}
+			config := Config{c}
+			actualBuildConfig := buildConfig(config)
+			if expected := tc.expectedBuildConfig; !proto.Equal(expected, actualBuildConfig) {
+				t.Errorf("Expected build config != actual build config: %#v != %#v", *expected, *actualBuildConfig)
+			}
+		})
+	}
+}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 83c8865..f3c442e 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -163,6 +163,7 @@
 	"AUX_OS_VARIANT_LIST",
 	"PRODUCT_SOONG_NAMESPACES",
 	"SOONG_SDK_SNAPSHOT_PREFER",
+	"SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR",
 	"SOONG_SDK_SNAPSHOT_VERSION",
 }
 
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index fc2cfa4..1063337 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -433,9 +433,14 @@
 }
 
 type BuildConfig struct {
-	UseGoma              *bool    `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"`
-	UseRbe               *bool    `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"`
-	ForceUseGoma         *bool    `protobuf:"varint,3,opt,name=force_use_goma,json=forceUseGoma" json:"force_use_goma,omitempty"`
+	UseGoma      *bool `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"`
+	UseRbe       *bool `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"`
+	ForceUseGoma *bool `protobuf:"varint,3,opt,name=force_use_goma,json=forceUseGoma" json:"force_use_goma,omitempty"`
+	// Whether the Bazel is acting as the Ninja executor for this build.
+	BazelAsNinja *bool `protobuf:"varint,4,opt,name=bazel_as_ninja,json=bazelAsNinja" json:"bazel_as_ninja,omitempty"`
+	// Whether build is occurring in a mixed build mode, where Bazel maintains the
+	// definition and build of some modules in cooperation with Soong.
+	BazelMixedBuild      *bool    `protobuf:"varint,5,opt,name=bazel_mixed_build,json=bazelMixedBuild" json:"bazel_mixed_build,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -487,6 +492,20 @@
 	return false
 }
 
+func (m *BuildConfig) GetBazelAsNinja() bool {
+	if m != nil && m.BazelAsNinja != nil {
+		return *m.BazelAsNinja
+	}
+	return false
+}
+
+func (m *BuildConfig) GetBazelMixedBuild() bool {
+	if m != nil && m.BazelMixedBuild != nil {
+		return *m.BazelMixedBuild
+	}
+	return false
+}
+
 type SystemResourceInfo struct {
 	// The total physical memory in bytes.
 	TotalPhysicalMemory *uint64 `protobuf:"varint,1,opt,name=total_physical_memory,json=totalPhysicalMemory" json:"total_physical_memory,omitempty"`
@@ -990,92 +1009,94 @@
 }
 
 var fileDescriptor_6039342a2ba47b72 = []byte{
-	// 1380 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xef, 0x52, 0x1b, 0x37,
-	0x10, 0x8f, 0xc1, 0x60, 0x7b, 0xfd, 0x07, 0x23, 0xa0, 0x5c, 0x48, 0xd2, 0x52, 0xb7, 0x49, 0x99,
-	0x4e, 0x43, 0x32, 0x34, 0xc3, 0x64, 0x98, 0x4c, 0xa7, 0xe0, 0xd0, 0x34, 0x65, 0xc0, 0x8c, 0x08,
-	0x69, 0xda, 0x7e, 0x50, 0xe5, 0xb3, 0x0c, 0x97, 0xdc, 0x9d, 0x6e, 0x24, 0x1d, 0xc5, 0x79, 0xb3,
-	0x7e, 0xee, 0x4b, 0xf4, 0x05, 0xfa, 0x04, 0x7d, 0x81, 0x8e, 0x56, 0x77, 0xe6, 0x20, 0x6e, 0xc2,
-	0xe4, 0xdb, 0xe9, 0xb7, 0xbf, 0xdf, 0x6a, 0xb5, 0xd2, 0xee, 0xda, 0xd0, 0x8c, 0x84, 0x51, 0x81,
-	0xaf, 0xd7, 0x13, 0x25, 0x8d, 0x24, 0x0b, 0x5a, 0xca, 0xf8, 0x84, 0xf5, 0xd3, 0x20, 0x1c, 0xb0,
-	0xcc, 0xd4, 0xf9, 0xbb, 0x01, 0xf5, 0x7d, 0xf7, 0xbd, 0xc3, 0xb5, 0x20, 0x0f, 0x61, 0xd1, 0x11,
-	0x06, 0xdc, 0x08, 0x66, 0x82, 0x48, 0x68, 0xc3, 0xa3, 0xc4, 0x2b, 0xad, 0x96, 0xd6, 0xa6, 0x29,
-	0x41, 0xdb, 0x53, 0x6e, 0xc4, 0x8b, 0xdc, 0x42, 0x6e, 0x42, 0xd5, 0x29, 0x82, 0x81, 0x37, 0xb5,
-	0x5a, 0x5a, 0xab, 0xd1, 0x0a, 0xae, 0x9f, 0x0f, 0xc8, 0x16, 0xdc, 0x4c, 0x42, 0x6e, 0x86, 0x52,
-	0x45, 0xec, 0x4c, 0x28, 0x1d, 0xc8, 0x98, 0xf9, 0x72, 0x20, 0x62, 0x1e, 0x09, 0x6f, 0x1a, 0xb9,
-	0xcb, 0x39, 0xe1, 0xa5, 0xb3, 0x77, 0x33, 0x33, 0xb9, 0x0b, 0x2d, 0xc3, 0xd5, 0x89, 0x30, 0x2c,
-	0x51, 0x72, 0x90, 0xfa, 0xc6, 0x2b, 0xa3, 0xa0, 0xe9, 0xd0, 0x43, 0x07, 0x92, 0x01, 0x2c, 0x66,
-	0x34, 0x17, 0xc4, 0x19, 0x57, 0x01, 0x8f, 0x8d, 0x37, 0xb3, 0x5a, 0x5a, 0x6b, 0x6d, 0xdc, 0x5f,
-	0x9f, 0x70, 0xe6, 0xf5, 0xc2, 0x79, 0xd7, 0x77, 0xac, 0xe5, 0xa5, 0x13, 0x6d, 0x4d, 0xef, 0x1e,
-	0x3c, 0xa3, 0xc4, 0xf9, 0x2b, 0x1a, 0x48, 0x0f, 0xea, 0xd9, 0x2e, 0x5c, 0xf9, 0xa7, 0xde, 0x2c,
-	0x3a, 0xbf, 0xfb, 0x41, 0xe7, 0xdb, 0xca, 0x3f, 0xdd, 0xaa, 0x1c, 0x1f, 0xec, 0x1d, 0xf4, 0x7e,
-	0x3e, 0xa0, 0xe0, 0x5c, 0x58, 0x90, 0xac, 0xc3, 0x42, 0xc1, 0xe1, 0x38, 0xea, 0x0a, 0x1e, 0x71,
-	0xfe, 0x82, 0x98, 0x07, 0xf0, 0x0d, 0x64, 0x61, 0x31, 0x3f, 0x49, 0xc7, 0xf4, 0x2a, 0xd2, 0xdb,
-	0xce, 0xd2, 0x4d, 0xd2, 0x9c, 0xbd, 0x07, 0xb5, 0x53, 0xa9, 0xb3, 0x60, 0x6b, 0x1f, 0x15, 0x6c,
-	0xd5, 0x3a, 0xc0, 0x50, 0x29, 0x34, 0xd1, 0xd9, 0x46, 0x3c, 0x70, 0x0e, 0xe1, 0xa3, 0x1c, 0xd6,
-	0xad, 0x93, 0x8d, 0x78, 0x80, 0x3e, 0x97, 0xa1, 0x82, 0x3e, 0xa5, 0xf6, 0xea, 0x78, 0x86, 0x59,
-	0xbb, 0xec, 0x69, 0xd2, 0xc9, 0x36, 0x93, 0x9a, 0x89, 0x73, 0xa3, 0xb8, 0xd7, 0x40, 0x73, 0xdd,
-	0x99, 0x77, 0x2d, 0x34, 0xe6, 0xf8, 0x4a, 0x6a, 0x6d, 0x5d, 0x34, 0x2f, 0x38, 0x5d, 0x8b, 0xf5,
-	0x34, 0xb9, 0x07, 0x73, 0x05, 0x0e, 0x86, 0xdd, 0x72, 0xcf, 0x67, 0xcc, 0xc2, 0x40, 0xee, 0xc3,
-	0x42, 0x81, 0x37, 0x3e, 0xe2, 0x9c, 0x4b, 0xec, 0x98, 0x5b, 0x88, 0x5b, 0xa6, 0x86, 0x0d, 0x02,
-	0xe5, 0xb5, 0x5d, 0xdc, 0x32, 0x35, 0x4f, 0x03, 0x45, 0xbe, 0x83, 0xba, 0x16, 0x26, 0x4d, 0x98,
-	0x91, 0x32, 0xd4, 0xde, 0xfc, 0xea, 0xf4, 0x5a, 0x7d, 0xe3, 0xce, 0xc4, 0x14, 0x1d, 0x0a, 0x35,
-	0x7c, 0x1e, 0x0f, 0x25, 0x05, 0x54, 0xbc, 0xb0, 0x02, 0xb2, 0x05, 0xb5, 0x37, 0xdc, 0x04, 0x4c,
-	0xa5, 0xb1, 0xf6, 0xc8, 0x75, 0xd4, 0x55, 0xcb, 0xa7, 0x69, 0xac, 0xc9, 0x13, 0x00, 0xc7, 0x44,
-	0xf1, 0xc2, 0x75, 0xc4, 0x35, 0xb4, 0xe6, 0xea, 0x38, 0x88, 0x5f, 0x73, 0xa7, 0x5e, 0xbc, 0x96,
-	0x1a, 0x05, 0xa8, 0xfe, 0x16, 0x66, 0x8c, 0x34, 0x3c, 0xf4, 0x96, 0x56, 0x4b, 0x1f, 0x16, 0x3a,
-	0x2e, 0x79, 0x09, 0x93, 0x5a, 0x91, 0xf7, 0x09, 0xba, 0xb8, 0x37, 0xd1, 0xc5, 0x91, 0xc5, 0xb0,
-	0x24, 0xb3, 0x17, 0x46, 0xe7, 0xf5, 0x55, 0x88, 0x74, 0xa1, 0xe1, 0x54, 0xbe, 0x8c, 0x87, 0xc1,
-	0x89, 0xb7, 0x8c, 0x0e, 0x57, 0x27, 0x3a, 0x44, 0x61, 0x17, 0x79, 0xb4, 0xde, 0xbf, 0x58, 0x90,
-	0x15, 0xc0, 0xa7, 0x8f, 0x2d, 0xca, 0xc3, 0x3b, 0x1e, 0xaf, 0xc9, 0x2f, 0xb0, 0xa8, 0x47, 0xda,
-	0x88, 0x88, 0x29, 0xa1, 0x65, 0xaa, 0x7c, 0xc1, 0x82, 0x78, 0x28, 0xbd, 0x9b, 0xb8, 0xd1, 0x57,
-	0x93, 0x23, 0x47, 0x01, 0xcd, 0xf8, 0x98, 0x06, 0xa2, 0xdf, 0xc1, 0xc8, 0x17, 0xd0, 0xcc, 0x63,
-	0x8f, 0x22, 0x1e, 0x0f, 0xbc, 0x15, 0xdc, 0xbb, 0x91, 0x85, 0x86, 0x98, 0xbd, 0xab, 0x3e, 0x7f,
-	0x2b, 0x42, 0x77, 0x57, 0xb7, 0xae, 0x75, 0x57, 0x28, 0xb0, 0x77, 0xd5, 0x79, 0x08, 0x8d, 0x4b,
-	0x4d, 0xad, 0x0a, 0xe5, 0xe3, 0xa3, 0x5d, 0xda, 0xbe, 0x41, 0x9a, 0x50, 0xb3, 0x5f, 0x4f, 0x77,
-	0x77, 0x8e, 0x9f, 0xb5, 0x4b, 0xa4, 0x02, 0xb6, 0x11, 0xb6, 0xa7, 0x3a, 0x4f, 0xa0, 0x8c, 0xcf,
-	0xbe, 0x0e, 0x79, 0x19, 0xb7, 0x6f, 0x58, 0xeb, 0x36, 0xdd, 0x6f, 0x97, 0x48, 0x0d, 0x66, 0xb6,
-	0xe9, 0xfe, 0xe6, 0xa3, 0xf6, 0x94, 0xc5, 0x5e, 0x3d, 0xde, 0x6c, 0x4f, 0x13, 0x80, 0xd9, 0x57,
-	0x8f, 0x37, 0xd9, 0xe6, 0xa3, 0x76, 0xb9, 0x73, 0x02, 0xf5, 0x42, 0x96, 0xed, 0x9c, 0x48, 0xb5,
-	0x60, 0x27, 0x32, 0xe2, 0x38, 0x4d, 0xaa, 0xb4, 0x92, 0x6a, 0xf1, 0x4c, 0x46, 0xdc, 0x96, 0x95,
-	0x35, 0xa9, 0xbe, 0xc0, 0x09, 0x52, 0xa5, 0xb3, 0xa9, 0x16, 0xb4, 0x2f, 0xc8, 0x97, 0xd0, 0x1a,
-	0x4a, 0x9b, 0xe6, 0xb1, 0x72, 0x1a, 0xed, 0x0d, 0x44, 0x8f, 0x9d, 0xbc, 0x23, 0x81, 0xbc, 0x9b,
-	0x65, 0xb2, 0x01, 0x4b, 0xf8, 0xdc, 0x58, 0x72, 0x3a, 0xd2, 0x81, 0xcf, 0x43, 0x16, 0x89, 0x48,
-	0xaa, 0x11, 0x6e, 0x5e, 0xa6, 0x0b, 0x68, 0x3c, 0xcc, 0x6c, 0xfb, 0x68, 0xb2, 0x43, 0x87, 0x9f,
-	0xf1, 0x20, 0xe4, 0xfd, 0x50, 0xd8, 0x4e, 0xab, 0x31, 0x9e, 0x19, 0xda, 0x1c, 0xa3, 0xdd, 0x24,
-	0xd5, 0x9d, 0x7f, 0x4b, 0x50, 0xcd, 0x33, 0x4c, 0x08, 0x94, 0x07, 0x42, 0xfb, 0xe8, 0xb6, 0x46,
-	0xf1, 0xdb, 0x62, 0xf8, 0x80, 0xdc, 0x3c, 0xc4, 0x6f, 0x72, 0x07, 0x40, 0x1b, 0xae, 0x0c, 0x0e,
-	0x55, 0x3c, 0x47, 0x99, 0xd6, 0x10, 0xb1, 0xb3, 0x94, 0xdc, 0x82, 0x9a, 0x12, 0x3c, 0x74, 0xd6,
-	0x32, 0x5a, 0xab, 0x16, 0x40, 0xe3, 0xe7, 0x00, 0x2e, 0x78, 0x9b, 0x08, 0x9c, 0x6d, 0xe5, 0x9d,
-	0x29, 0xaf, 0x44, 0x6b, 0x0e, 0x3d, 0xd6, 0x82, 0xfc, 0x0e, 0xcb, 0x89, 0x92, 0xbe, 0xd0, 0x5a,
-	0xe8, 0x2b, 0xcf, 0x73, 0x16, 0x1f, 0xca, 0xda, 0xe4, 0x87, 0xe2, 0x34, 0x97, 0xde, 0xe7, 0xd2,
-	0xd8, 0x51, 0x11, 0xee, 0xfc, 0x39, 0x0d, 0x0b, 0x13, 0xe8, 0xe3, 0xc3, 0x96, 0x0a, 0x87, 0x5d,
-	0x83, 0x76, 0xaa, 0x85, 0xc2, 0xd3, 0xb0, 0x28, 0xb0, 0xed, 0x15, 0x93, 0x51, 0xa6, 0x2d, 0x8b,
-	0xdb, 0x43, 0xed, 0x23, 0x6a, 0x27, 0x5b, 0x56, 0x53, 0x45, 0xae, 0x4b, 0x4f, 0xdb, 0x59, 0x0a,
-	0xec, 0xdb, 0x00, 0x11, 0x3f, 0x67, 0x4a, 0x6b, 0xf6, 0xa6, 0x9f, 0xa7, 0x29, 0xe2, 0xe7, 0x54,
-	0xeb, 0xbd, 0x3e, 0xf9, 0x1a, 0xe6, 0xa3, 0x20, 0x96, 0x8a, 0x25, 0xfc, 0x44, 0xb0, 0x21, 0x4f,
-	0x43, 0xa3, 0x5d, 0xb6, 0xe8, 0x1c, 0x1a, 0x0e, 0xf9, 0x89, 0xf8, 0x01, 0x61, 0xe4, 0xf2, 0xd7,
-	0x57, 0xb8, 0xb3, 0x19, 0xd7, 0x1a, 0x0a, 0xdc, 0x4f, 0xa1, 0x1e, 0x48, 0x16, 0xc4, 0x49, 0x6a,
-	0xec, 0xb6, 0x15, 0x77, 0x77, 0x81, 0x7c, 0x6e, 0x91, 0xbd, 0x3e, 0x59, 0x85, 0x46, 0x20, 0x99,
-	0x4c, 0x4d, 0x46, 0xa8, 0x22, 0x01, 0x02, 0xd9, 0x43, 0x68, 0xaf, 0x4f, 0x9e, 0xc0, 0xca, 0x99,
-	0x0c, 0xd3, 0xd8, 0x70, 0x35, 0xb2, 0xed, 0xc9, 0x88, 0x73, 0xc3, 0xf4, 0x1f, 0x81, 0xf1, 0x4f,
-	0x85, 0xc6, 0x11, 0x5d, 0xa6, 0xde, 0x98, 0xd1, 0x75, 0x84, 0xa3, 0xcc, 0x4e, 0xbe, 0x87, 0xdb,
-	0x41, 0xfc, 0x1e, 0x3d, 0xa0, 0x7e, 0xa5, 0xc0, 0xb9, 0xe2, 0xa1, 0xf3, 0x4f, 0x09, 0x5a, 0xfb,
-	0x72, 0x90, 0x86, 0xe2, 0xc5, 0x28, 0x71, 0xd7, 0xf6, 0x5b, 0xde, 0x2d, 0x5d, 0x92, 0xf1, 0xfa,
-	0x5a, 0x1b, 0x0f, 0x26, 0x8f, 0xf5, 0x4b, 0x52, 0xd7, 0x3c, 0x5d, 0xc9, 0x15, 0x06, 0x7c, 0xff,
-	0x02, 0x25, 0x9f, 0x41, 0x3d, 0x42, 0x0d, 0x33, 0xa3, 0x24, 0xaf, 0x03, 0x88, 0xc6, 0x6e, 0x6c,
-	0x65, 0xc7, 0x69, 0xc4, 0xe4, 0x90, 0x39, 0xd0, 0x5d, 0x79, 0x93, 0x36, 0xe2, 0x34, 0xea, 0x0d,
-	0xdd, 0x7e, 0xba, 0xf3, 0x20, 0x6b, 0x21, 0x99, 0xd7, 0x4b, 0x7d, 0xa8, 0x06, 0x33, 0x47, 0xbd,
-	0xde, 0x81, 0x6d, 0x58, 0x55, 0x28, 0xef, 0x6f, 0xef, 0xed, 0xb6, 0xa7, 0x3a, 0x21, 0xac, 0x74,
-	0x55, 0x60, 0x6c, 0x49, 0x1f, 0x6b, 0xa1, 0x7e, 0x92, 0xa9, 0x8a, 0xc5, 0x28, 0x1f, 0x10, 0x93,
-	0x5e, 0xea, 0x16, 0x54, 0xf2, 0x01, 0x34, 0xf5, 0x9e, 0x79, 0x51, 0xf8, 0x61, 0x43, 0x73, 0x41,
-	0xa7, 0x0f, 0xb7, 0x26, 0xec, 0xa6, 0x2f, 0xe6, 0x51, 0xd9, 0x4f, 0x5f, 0x6b, 0xaf, 0x84, 0xf5,
-	0x37, 0x39, 0xb3, 0xff, 0x1f, 0x2d, 0x45, 0x71, 0xe7, 0xaf, 0x12, 0xcc, 0xbf, 0x33, 0xfd, 0x88,
-	0x07, 0x95, 0x3c, 0x6f, 0x25, 0xcc, 0x5b, 0xbe, 0xb4, 0xf3, 0x2b, 0xfb, 0x79, 0xe8, 0x0e, 0xd4,
-	0xa4, 0xe3, 0xb5, 0x7d, 0xf3, 0xae, 0x25, 0xf2, 0x30, 0x94, 0x3e, 0xf3, 0x65, 0x1a, 0x9b, 0xac,
-	0xd4, 0xe6, 0xd0, 0xb0, 0x6d, 0xf1, 0xae, 0x85, 0x6d, 0x05, 0x17, 0xb9, 0x3a, 0x78, 0x9b, 0xb7,
-	0xa5, 0xd6, 0x05, 0xf5, 0x28, 0x78, 0x2b, 0xec, 0xef, 0x31, 0x5b, 0x93, 0xa7, 0x82, 0x27, 0x8e,
-	0xe6, 0x2a, 0xae, 0x1e, 0xf1, 0xf3, 0x1f, 0x05, 0x4f, 0x2c, 0x67, 0x67, 0xe9, 0xd7, 0x6c, 0xe4,
-	0x67, 0xe7, 0x66, 0xf8, 0x97, 0xe4, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0xfb, 0x8e, 0xf5,
-	0xa2, 0x0c, 0x00, 0x00,
+	// 1423 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdd, 0x52, 0x1b, 0xc7,
+	0x12, 0xb6, 0x40, 0x20, 0xa9, 0xf5, 0x83, 0x18, 0xe0, 0xb0, 0xc6, 0xf6, 0x39, 0x1c, 0xc5, 0x76,
+	0xa8, 0x54, 0x8c, 0x5d, 0xc4, 0x45, 0xb9, 0x28, 0x57, 0x2a, 0x20, 0x13, 0xc7, 0xa1, 0x84, 0xa8,
+	0xc1, 0x38, 0x4e, 0x72, 0x31, 0x19, 0xad, 0x46, 0xb0, 0xf6, 0xee, 0xce, 0xd6, 0xcc, 0x2c, 0x01,
+	0xbf, 0x99, 0xaf, 0xf3, 0x12, 0x79, 0x81, 0x3c, 0x41, 0x5e, 0x20, 0x35, 0x3d, 0xbb, 0x62, 0xc1,
+	0x8a, 0x4d, 0xf9, 0x4e, 0xfb, 0xf5, 0xf7, 0xf5, 0x76, 0xf7, 0xf4, 0x74, 0xaf, 0xa0, 0x19, 0x09,
+	0xa3, 0x02, 0x5f, 0xaf, 0x27, 0x4a, 0x1a, 0x49, 0x16, 0xb4, 0x94, 0xf1, 0x31, 0x1b, 0xa4, 0x41,
+	0x38, 0x64, 0x99, 0xa9, 0xf3, 0x67, 0x03, 0xea, 0x3d, 0xf7, 0x7b, 0x87, 0x6b, 0x41, 0x1e, 0xc1,
+	0xa2, 0x23, 0x0c, 0xb9, 0x11, 0xcc, 0x04, 0x91, 0xd0, 0x86, 0x47, 0x89, 0x57, 0x5a, 0x2d, 0xad,
+	0x4d, 0x53, 0x82, 0xb6, 0x67, 0xdc, 0x88, 0x97, 0xb9, 0x85, 0xdc, 0x84, 0xaa, 0x53, 0x04, 0x43,
+	0x6f, 0x6a, 0xb5, 0xb4, 0x56, 0xa3, 0x15, 0x7c, 0x7e, 0x31, 0x24, 0x5b, 0x70, 0x33, 0x09, 0xb9,
+	0x19, 0x49, 0x15, 0xb1, 0x53, 0xa1, 0x74, 0x20, 0x63, 0xe6, 0xcb, 0xa1, 0x88, 0x79, 0x24, 0xbc,
+	0x69, 0xe4, 0x2e, 0xe7, 0x84, 0x57, 0xce, 0xde, 0xcd, 0xcc, 0xe4, 0x1e, 0xb4, 0x0c, 0x57, 0xc7,
+	0xc2, 0xb0, 0x44, 0xc9, 0x61, 0xea, 0x1b, 0xaf, 0x8c, 0x82, 0xa6, 0x43, 0x0f, 0x1c, 0x48, 0x86,
+	0xb0, 0x98, 0xd1, 0x5c, 0x10, 0xa7, 0x5c, 0x05, 0x3c, 0x36, 0xde, 0xcc, 0x6a, 0x69, 0xad, 0xb5,
+	0xf1, 0x60, 0x7d, 0x42, 0xce, 0xeb, 0x85, 0x7c, 0xd7, 0x77, 0xac, 0xe5, 0x95, 0x13, 0x6d, 0x4d,
+	0xef, 0xee, 0x3f, 0xa7, 0xc4, 0xf9, 0x2b, 0x1a, 0x48, 0x1f, 0xea, 0xd9, 0x5b, 0xb8, 0xf2, 0x4f,
+	0xbc, 0x59, 0x74, 0x7e, 0xef, 0x93, 0xce, 0xb7, 0x95, 0x7f, 0xb2, 0x55, 0x39, 0xda, 0xdf, 0xdb,
+	0xef, 0xff, 0xb4, 0x4f, 0xc1, 0xb9, 0xb0, 0x20, 0x59, 0x87, 0x85, 0x82, 0xc3, 0x71, 0xd4, 0x15,
+	0x4c, 0x71, 0xfe, 0x82, 0x98, 0x07, 0xf0, 0x35, 0x64, 0x61, 0x31, 0x3f, 0x49, 0xc7, 0xf4, 0x2a,
+	0xd2, 0xdb, 0xce, 0xd2, 0x4d, 0xd2, 0x9c, 0xbd, 0x07, 0xb5, 0x13, 0xa9, 0xb3, 0x60, 0x6b, 0x9f,
+	0x15, 0x6c, 0xd5, 0x3a, 0xc0, 0x50, 0x29, 0x34, 0xd1, 0xd9, 0x46, 0x3c, 0x74, 0x0e, 0xe1, 0xb3,
+	0x1c, 0xd6, 0xad, 0x93, 0x8d, 0x78, 0x88, 0x3e, 0x97, 0xa1, 0x82, 0x3e, 0xa5, 0xf6, 0xea, 0x98,
+	0xc3, 0xac, 0x7d, 0xec, 0x6b, 0xd2, 0xc9, 0x5e, 0x26, 0x35, 0x13, 0x67, 0x46, 0x71, 0xaf, 0x81,
+	0xe6, 0xba, 0x33, 0xef, 0x5a, 0x68, 0xcc, 0xf1, 0x95, 0xd4, 0xda, 0xba, 0x68, 0x5e, 0x70, 0xba,
+	0x16, 0xeb, 0x6b, 0x72, 0x1f, 0xe6, 0x0a, 0x1c, 0x0c, 0xbb, 0xe5, 0xda, 0x67, 0xcc, 0xc2, 0x40,
+	0x1e, 0xc0, 0x42, 0x81, 0x37, 0x4e, 0x71, 0xce, 0x15, 0x76, 0xcc, 0x2d, 0xc4, 0x2d, 0x53, 0xc3,
+	0x86, 0x81, 0xf2, 0xda, 0x2e, 0x6e, 0x99, 0x9a, 0x67, 0x81, 0x22, 0xdf, 0x42, 0x5d, 0x0b, 0x93,
+	0x26, 0xcc, 0x48, 0x19, 0x6a, 0x6f, 0x7e, 0x75, 0x7a, 0xad, 0xbe, 0x71, 0x67, 0x62, 0x89, 0x0e,
+	0x84, 0x1a, 0xbd, 0x88, 0x47, 0x92, 0x02, 0x2a, 0x5e, 0x5a, 0x01, 0xd9, 0x82, 0xda, 0x5b, 0x6e,
+	0x02, 0xa6, 0xd2, 0x58, 0x7b, 0xe4, 0x3a, 0xea, 0xaa, 0xe5, 0xd3, 0x34, 0xd6, 0xe4, 0x29, 0x80,
+	0x63, 0xa2, 0x78, 0xe1, 0x3a, 0xe2, 0x1a, 0x5a, 0x73, 0x75, 0x1c, 0xc4, 0x6f, 0xb8, 0x53, 0x2f,
+	0x5e, 0x4b, 0x8d, 0x02, 0x54, 0x7f, 0x03, 0x33, 0x46, 0x1a, 0x1e, 0x7a, 0x4b, 0xab, 0xa5, 0x4f,
+	0x0b, 0x1d, 0x97, 0xbc, 0x82, 0x49, 0xa3, 0xc8, 0xfb, 0x0f, 0xba, 0xb8, 0x3f, 0xd1, 0xc5, 0xa1,
+	0xc5, 0xf0, 0x4a, 0x66, 0x1d, 0x46, 0xe7, 0xf5, 0x55, 0x88, 0x74, 0xa1, 0xe1, 0x54, 0xbe, 0x8c,
+	0x47, 0xc1, 0xb1, 0xb7, 0x8c, 0x0e, 0x57, 0x27, 0x3a, 0x44, 0x61, 0x17, 0x79, 0xb4, 0x3e, 0xb8,
+	0x78, 0x20, 0x2b, 0x80, 0xad, 0x8f, 0x23, 0xca, 0xc3, 0x33, 0x1e, 0x3f, 0x93, 0x9f, 0x61, 0x51,
+	0x9f, 0x6b, 0x23, 0x22, 0xa6, 0x84, 0x96, 0xa9, 0xf2, 0x05, 0x0b, 0xe2, 0x91, 0xf4, 0x6e, 0xe2,
+	0x8b, 0xbe, 0x9c, 0x1c, 0x39, 0x0a, 0x68, 0xc6, 0xc7, 0x32, 0x10, 0xfd, 0x01, 0x46, 0xbe, 0x80,
+	0x66, 0x1e, 0x7b, 0x14, 0xf1, 0x78, 0xe8, 0xad, 0xe0, 0xbb, 0x1b, 0x59, 0x68, 0x88, 0xd9, 0xb3,
+	0x1a, 0xf0, 0x77, 0x22, 0x74, 0x67, 0x75, 0xeb, 0x5a, 0x67, 0x85, 0x02, 0x7b, 0x56, 0x9d, 0x47,
+	0xd0, 0xb8, 0x34, 0xd4, 0xaa, 0x50, 0x3e, 0x3a, 0xdc, 0xa5, 0xed, 0x1b, 0xa4, 0x09, 0x35, 0xfb,
+	0xeb, 0xd9, 0xee, 0xce, 0xd1, 0xf3, 0x76, 0x89, 0x54, 0xc0, 0x0e, 0xc2, 0xf6, 0x54, 0xe7, 0x29,
+	0x94, 0xb1, 0xed, 0xeb, 0x90, 0x5f, 0xe3, 0xf6, 0x0d, 0x6b, 0xdd, 0xa6, 0xbd, 0x76, 0x89, 0xd4,
+	0x60, 0x66, 0x9b, 0xf6, 0x36, 0x1f, 0xb7, 0xa7, 0x2c, 0xf6, 0xfa, 0xc9, 0x66, 0x7b, 0x9a, 0x00,
+	0xcc, 0xbe, 0x7e, 0xb2, 0xc9, 0x36, 0x1f, 0xb7, 0xcb, 0x9d, 0xf7, 0x25, 0xa8, 0x17, 0xca, 0x6c,
+	0x17, 0x45, 0xaa, 0x05, 0x3b, 0x96, 0x11, 0xc7, 0x75, 0x52, 0xa5, 0x95, 0x54, 0x8b, 0xe7, 0x32,
+	0xe2, 0xf6, 0x5e, 0x59, 0x93, 0x1a, 0x08, 0x5c, 0x21, 0x55, 0x3a, 0x9b, 0x6a, 0x41, 0x07, 0x82,
+	0xdc, 0x85, 0xd6, 0x48, 0xda, 0x3a, 0x8f, 0x95, 0xd3, 0x68, 0x6f, 0x20, 0x7a, 0x94, 0xc9, 0xef,
+	0x42, 0xcb, 0xd5, 0x85, 0x6b, 0x86, 0xbd, 0x89, 0xbb, 0xa2, 0x4a, 0x1b, 0x88, 0x6e, 0xeb, 0x7d,
+	0x8b, 0x91, 0xaf, 0x60, 0xde, 0xb1, 0xa2, 0xe0, 0x4c, 0x0c, 0x5d, 0xc1, 0x70, 0x4f, 0x54, 0xe9,
+	0x1c, 0x1a, 0x7a, 0x16, 0xc7, 0x88, 0x3b, 0x12, 0xc8, 0x87, 0x07, 0x47, 0x36, 0x60, 0x09, 0x3b,
+	0x98, 0x25, 0x27, 0xe7, 0x3a, 0xf0, 0x79, 0xc8, 0x22, 0x11, 0x49, 0x75, 0x8e, 0xe9, 0x94, 0xe9,
+	0x02, 0x1a, 0x0f, 0x32, 0x5b, 0x0f, 0x4d, 0x76, 0x8f, 0xf1, 0x53, 0x1e, 0x84, 0x7c, 0x10, 0x0a,
+	0x3b, 0xbc, 0x35, 0x66, 0x38, 0x43, 0x9b, 0x63, 0xb4, 0x9b, 0xa4, 0xba, 0xf3, 0x77, 0x09, 0xaa,
+	0xf9, 0xa1, 0x11, 0x02, 0xe5, 0xa1, 0xd0, 0x3e, 0xba, 0xad, 0x51, 0xfc, 0x6d, 0x31, 0xec, 0x49,
+	0xb7, 0x62, 0xf1, 0x37, 0xb9, 0x03, 0xa0, 0x0d, 0x57, 0x06, 0xf7, 0x34, 0x56, 0xa6, 0x4c, 0x6b,
+	0x88, 0xd8, 0xf5, 0x4c, 0x6e, 0x41, 0x4d, 0x09, 0x1e, 0x3a, 0x6b, 0x19, 0xad, 0x55, 0x0b, 0xa0,
+	0xf1, 0xff, 0x00, 0x2e, 0x78, 0x5b, 0x5a, 0x2c, 0x43, 0x79, 0x67, 0xca, 0x2b, 0xd1, 0x9a, 0x43,
+	0x8f, 0xb4, 0x20, 0xbf, 0xc1, 0x72, 0xa2, 0xa4, 0x2f, 0xb4, 0x16, 0xfa, 0x4a, 0xc7, 0xcf, 0x62,
+	0xef, 0xad, 0x4d, 0xee, 0x3d, 0xa7, 0xb9, 0xd4, 0xf2, 0x4b, 0x63, 0x47, 0x45, 0xb8, 0xf3, 0x7e,
+	0x1a, 0x16, 0x26, 0xd0, 0xc7, 0xc9, 0x96, 0x0a, 0xc9, 0xae, 0x41, 0x3b, 0xd5, 0x42, 0x61, 0x36,
+	0x2c, 0x0a, 0xec, 0xc4, 0xc6, 0x62, 0x94, 0x69, 0xcb, 0xe2, 0x36, 0xa9, 0x1e, 0xa2, 0x76, 0x59,
+	0x66, 0xd7, 0xb4, 0xc8, 0x75, 0xe5, 0x69, 0x3b, 0x4b, 0x81, 0x7d, 0x1b, 0x20, 0xe2, 0x67, 0x4c,
+	0x69, 0xcd, 0xde, 0x0e, 0xf2, 0x32, 0x45, 0xfc, 0x8c, 0x6a, 0xbd, 0x37, 0xb0, 0x4d, 0x13, 0x05,
+	0xb1, 0x54, 0x2c, 0xe1, 0xc7, 0x82, 0x8d, 0x78, 0x1a, 0x1a, 0xed, 0xaa, 0x45, 0xe7, 0xd0, 0x70,
+	0xc0, 0x8f, 0xc5, 0xf7, 0x08, 0x23, 0x97, 0xbf, 0xb9, 0xc2, 0x9d, 0xcd, 0xb8, 0xd6, 0x50, 0xe0,
+	0xfe, 0x17, 0xea, 0x81, 0x64, 0x41, 0x9c, 0xa4, 0xc6, 0xbe, 0xb6, 0xe2, 0xce, 0x2e, 0x90, 0x2f,
+	0x2c, 0xb2, 0x37, 0x20, 0xab, 0xd0, 0x08, 0x24, 0x93, 0xa9, 0xc9, 0x08, 0x55, 0x24, 0x40, 0x20,
+	0xfb, 0x08, 0xed, 0x0d, 0xc8, 0x53, 0x58, 0x39, 0x95, 0x61, 0x1a, 0x1b, 0xae, 0xce, 0xed, 0xc4,
+	0x33, 0xe2, 0xcc, 0x30, 0xfd, 0x7b, 0x60, 0xfc, 0x13, 0xa1, 0x71, 0xeb, 0x97, 0xa9, 0x37, 0x66,
+	0x74, 0x1d, 0xe1, 0x30, 0xb3, 0x93, 0xef, 0xe0, 0x76, 0x10, 0x7f, 0x44, 0x0f, 0xa8, 0x5f, 0x29,
+	0x70, 0xae, 0x78, 0xe8, 0xfc, 0x55, 0x82, 0x56, 0x4f, 0x0e, 0xd3, 0x50, 0xbc, 0x3c, 0x4f, 0xdc,
+	0xb1, 0xfd, 0x9a, 0x0f, 0x60, 0x57, 0x64, 0x3c, 0xbe, 0xd6, 0xc6, 0xc3, 0xc9, 0x5f, 0x0a, 0x97,
+	0xa4, 0x6e, 0x1e, 0xbb, 0x2b, 0x57, 0xf8, 0x66, 0x18, 0x5c, 0xa0, 0xe4, 0x7f, 0x50, 0x8f, 0x50,
+	0xc3, 0xcc, 0x79, 0x92, 0xdf, 0x03, 0x88, 0xc6, 0x6e, 0xec, 0x14, 0x88, 0xd3, 0x88, 0xc9, 0x11,
+	0x73, 0xa0, 0x3b, 0xf2, 0x26, 0x6d, 0xc4, 0x69, 0xd4, 0x1f, 0xb9, 0xf7, 0xe9, 0xce, 0xc3, 0x6c,
+	0x28, 0x65, 0x5e, 0x2f, 0x8d, 0xb6, 0x1a, 0xcc, 0x1c, 0xf6, 0xfb, 0xfb, 0x76, 0x06, 0x56, 0xa1,
+	0xdc, 0xdb, 0xde, 0xdb, 0x6d, 0x4f, 0x75, 0x42, 0x58, 0xe9, 0xaa, 0xc0, 0xd8, 0x2b, 0x7d, 0xa4,
+	0x85, 0xfa, 0x51, 0xa6, 0x2a, 0x16, 0xe7, 0xf9, 0xce, 0x99, 0xd4, 0xa9, 0x5b, 0x50, 0xc9, 0x77,
+	0xda, 0xd4, 0x47, 0x56, 0x50, 0xe1, 0x5b, 0x89, 0xe6, 0x82, 0xce, 0x00, 0x6e, 0x4d, 0x78, 0x9b,
+	0xbe, 0x58, 0x71, 0x65, 0x3f, 0x7d, 0xa3, 0xbd, 0x12, 0xde, 0xbf, 0xc9, 0x95, 0xfd, 0xf7, 0x68,
+	0x29, 0x8a, 0x3b, 0x7f, 0x94, 0x60, 0xfe, 0x83, 0x85, 0x4a, 0x3c, 0xa8, 0xe4, 0x75, 0x2b, 0x61,
+	0xdd, 0xf2, 0x47, 0xbb, 0x12, 0xb3, 0x2f, 0x4e, 0x97, 0x50, 0x93, 0x8e, 0x9f, 0x6d, 0xcf, 0xbb,
+	0x91, 0xc8, 0xc3, 0x50, 0xfa, 0xcc, 0x97, 0x69, 0x6c, 0xb2, 0xab, 0x36, 0x87, 0x86, 0x6d, 0x8b,
+	0x77, 0x2d, 0x6c, 0x6f, 0x70, 0x91, 0xab, 0x83, 0x77, 0xf9, 0x58, 0x6a, 0x5d, 0x50, 0x0f, 0x83,
+	0x77, 0xc2, 0x7e, 0xe2, 0xd9, 0x3b, 0x79, 0x22, 0x78, 0xe2, 0x68, 0xee, 0xc6, 0xd5, 0x23, 0x7e,
+	0xf6, 0x83, 0xe0, 0x89, 0xe5, 0xec, 0x2c, 0xfd, 0x92, 0x7d, 0x45, 0x64, 0x79, 0x33, 0xfc, 0x97,
+	0xf3, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x63, 0x09, 0x14, 0xf5, 0x0c, 0x00, 0x00,
 }
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 91d8dd9..b284bf9 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -116,6 +116,13 @@
   optional bool use_rbe = 2;
 
   optional bool force_use_goma = 3;
+
+  // Whether the Bazel is acting as the Ninja executor for this build.
+  optional bool bazel_as_ninja = 4;
+
+  // Whether build is occurring in a mixed build mode, where Bazel maintains the
+  // definition and build of some modules in cooperation with Soong.
+  optional bool bazel_mixed_build = 5;
 }
 
 message SystemResourceInfo {