Merge "Interpret CRT object's min_sdk_version with ApiLevel"
diff --git a/android/bazel.go b/android/bazel.go
index 8c68055..d396561 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -221,6 +221,8 @@
 	// still be generated via bp2build.
 	mixedBuildsDisabledList = []string{
 		// Currently empty, though should remain present to facilitate granular bp2build migration.
+		"libdl",         // missing libbionic_Slinker_Slibld-android_Ubp2build_Ucc_Ulibrary_Ushared.so
+		"libdl_android", // missing libbionic_Slinker_Slibld-android_Ubp2build_Ucc_Ulibrary_Ushared.so
 	}
 
 	// Used for quicker lookups
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index f4b2a7c..f93fe2b 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -100,6 +100,22 @@
 	return labels
 }
 
+// BazelLabelForModuleDeps expects two lists: modules (containing modules to include in the list),
+// and excludes (modules to exclude from the list). Both of these should contain references to other
+// modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label list which corresponds
+// to dependencies on the module within the given ctx, and the excluded dependencies.
+func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+	moduleLabels := BazelLabelForModuleDeps(ctx, RemoveListFromList(modules, excludes))
+	if len(excludes) == 0 {
+		return moduleLabels
+	}
+	excludeLabels := BazelLabelForModuleDeps(ctx, excludes)
+	return bazel.LabelList{
+		Includes: moduleLabels.Includes,
+		Excludes: excludeLabels.Includes,
+	}
+}
+
 func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label {
 	return BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes[0]
 }
diff --git a/android/paths.go b/android/paths.go
index b192a35..128ec12 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1591,6 +1591,18 @@
 // PathForModuleInstall returns a Path representing the install path for the
 // module appended with paths...
 func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
+	os, arch := osAndArch(ctx)
+	partition := modulePartition(ctx, os)
+	return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
+}
+
+// PathForModuleInPartitionInstall is similar to PathForModuleInstall but partition is provided by the caller
+func PathForModuleInPartitionInstall(ctx ModuleInstallPathContext, partition string, pathComponents ...string) InstallPath {
+	os, arch := osAndArch(ctx)
+	return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
+}
+
+func osAndArch(ctx ModuleInstallPathContext) (OsType, ArchType) {
 	os := ctx.Os()
 	arch := ctx.Arch().ArchType
 	forceOS, forceArch := ctx.InstallForceOS()
@@ -1600,14 +1612,14 @@
 	if forceArch != nil {
 		arch = *forceArch
 	}
-	partition := modulePartition(ctx, os)
+	return os, arch
+}
 
-	ret := pathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
-
+func makePathForInstall(ctx ModuleInstallPathContext, os OsType, arch ArchType, partition string, debug bool, pathComponents ...string) InstallPath {
+	ret := pathForInstall(ctx, os, arch, partition, debug, pathComponents...)
 	if ctx.InstallBypassMake() && ctx.Config().KatiEnabled() {
 		ret = ret.ToMakePath()
 	}
-
 	return ret
 }
 
diff --git a/android/variable.go b/android/variable.go
index 6d235d6..c766120 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -458,12 +458,13 @@
 // with the appropriate ProductConfigVariable.
 type ProductConfigProperty struct {
 	ProductConfigVariable string
+	FullConfig            string
 	Property              interface{}
 }
 
 // ProductConfigProperties is a map of property name to a slice of ProductConfigProperty such that
 // all it all product variable-specific versions of a property are easily accessed together
-type ProductConfigProperties map[string][]ProductConfigProperty
+type ProductConfigProperties map[string]map[string]ProductConfigProperty
 
 // ProductVariableProperties returns a ProductConfigProperties containing only the properties which
 // have been set for the module in the given context.
@@ -512,11 +513,15 @@
 
 			// e.g. Asflags, Cflags, Enabled, etc.
 			propertyName := variableValue.Type().Field(j).Name
-			(*productConfigProperties)[propertyName] = append((*productConfigProperties)[propertyName],
-				ProductConfigProperty{
-					ProductConfigVariable: productVariableName + suffix,
-					Property:              property.Interface(),
-				})
+			if (*productConfigProperties)[propertyName] == nil {
+				(*productConfigProperties)[propertyName] = make(map[string]ProductConfigProperty)
+			}
+			config := productVariableName + suffix
+			(*productConfigProperties)[propertyName][config] = ProductConfigProperty{
+				ProductConfigVariable: productVariableName,
+				FullConfig:            config,
+				Property:              property.Interface(),
+			}
 		}
 	}
 }
diff --git a/bazel/configurability.go b/bazel/configurability.go
index df9c9bf..282c606 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -56,7 +56,7 @@
 	// This is consistently named "conditions_default" to mirror the Soong
 	// config variable default key in an Android.bp file, although there's no
 	// integration with Soong config variables (yet).
-	ConditionsDefault = "conditions_default"
+	conditionsDefault = "conditions_default"
 
 	ConditionsDefaultSelectKey = "//conditions:default"
 
@@ -76,7 +76,7 @@
 		archArm64:         "//build/bazel/platforms/arch:arm64",
 		archX86:           "//build/bazel/platforms/arch:x86",
 		archX86_64:        "//build/bazel/platforms/arch:x86_64",
-		ConditionsDefault: ConditionsDefaultSelectKey, // The default condition of as arch select map.
+		conditionsDefault: ConditionsDefaultSelectKey, // The default condition of as arch select map.
 	}
 
 	// A map of target operating systems to the Bazel label of the
@@ -88,7 +88,7 @@
 		osLinux:           "//build/bazel/platforms/os:linux",
 		osLinuxBionic:     "//build/bazel/platforms/os:linux_bionic",
 		osWindows:         "//build/bazel/platforms/os:windows",
-		ConditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
+		conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
 	}
 
 	platformOsArchMap = map[string]string{
@@ -105,7 +105,7 @@
 		osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
 		osArchWindowsX86:        "//build/bazel/platforms/os_arch:windows_x86",
 		osArchWindowsX86_64:     "//build/bazel/platforms/os_arch:windows_x86_64",
-		ConditionsDefault:       ConditionsDefaultSelectKey, // The default condition of an os select map.
+		conditionsDefault:       ConditionsDefaultSelectKey, // The default condition of an os select map.
 	}
 )
 
@@ -168,7 +168,7 @@
 	case osArch:
 		return platformOsArchMap[config]
 	case productVariables:
-		if config == ConditionsDefault {
+		if config == conditionsDefault {
 			return ConditionsDefaultSelectKey
 		}
 		return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(config))
diff --git a/bazel/properties.go b/bazel/properties.go
index c55de95..99119cd 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -68,6 +68,13 @@
 	return ll.Includes == nil && ll.Excludes == nil
 }
 
+func (ll *LabelList) deepCopy() LabelList {
+	return LabelList{
+		Includes: ll.Includes[:],
+		Excludes: ll.Excludes[:],
+	}
+}
+
 // uniqueParentDirectories returns a list of the unique parent directories for
 // all files in ll.Includes.
 func (ll *LabelList) uniqueParentDirectories() []string {
@@ -469,6 +476,39 @@
 	return len(lla.ConfigurableValues) > 0
 }
 
+// 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() {
+	for axis, configToLabels := range lla.ConfigurableValues {
+		baseLabels := lla.Value.deepCopy()
+		for config, val := range configToLabels {
+			// Exclude config-specific excludes from base value
+			lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes})
+
+			// add base values to config specific to add labels excluded by others in this axis
+			// then remove all config-specific excludes
+			allLabels := baseLabels.deepCopy()
+			allLabels.Append(val)
+			lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: val.Excludes})
+		}
+
+		// After going through all configs, delete the duplicates in the config
+		// values that are already in the base Value.
+		for config, val := range configToLabels {
+			lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value)
+		}
+
+		// Now that the Value list is finalized for this axis, compare it with the original
+		// list, and put the difference into the default condition for the axis.
+		lla.ConfigurableValues[axis][conditionsDefault] = SubtractBazelLabelList(baseLabels, lla.Value)
+
+		// if everything ends up without includes, just delete the axis
+		if !lla.ConfigurableValues[axis].HasConfigurableValues() {
+			delete(lla.ConfigurableValues, axis)
+		}
+	}
+}
+
 // StringListAttribute corresponds to the string_list Bazel attribute type with
 // support for additional metadata, like configurations.
 type StringListAttribute struct {
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index bc556bf..9464245 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -205,3 +205,91 @@
 		}
 	}
 }
+
+func makeLabels(labels ...string) []Label {
+	var ret []Label
+	for _, l := range labels {
+		ret = append(ret, Label{Label: l})
+	}
+	return ret
+}
+
+func makeLabelList(includes, excludes []string) LabelList {
+	return LabelList{
+		Includes: makeLabels(includes...),
+		Excludes: makeLabels(excludes...),
+	}
+}
+
+func TestResolveExcludes(t *testing.T) {
+	attr := LabelListAttribute{
+		Value: makeLabelList(
+			[]string{
+				"all_include",
+				"arm_exclude",
+				"android_exclude",
+			},
+			[]string{"all_exclude"},
+		),
+		ConfigurableValues: configurableLabelLists{
+			ArchConfigurationAxis: labelListSelectValues{
+				"arm": makeLabelList([]string{}, []string{"arm_exclude"}),
+				"x86": makeLabelList([]string{"x86_include"}, []string{}),
+			},
+			OsConfigurationAxis: labelListSelectValues{
+				"android": makeLabelList([]string{}, []string{"android_exclude"}),
+				"linux":   makeLabelList([]string{"linux_include"}, []string{}),
+			},
+			OsArchConfigurationAxis: labelListSelectValues{
+				"linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
+			},
+			ProductVariableConfigurationAxis("a"): labelListSelectValues{
+				"a": makeLabelList([]string{}, []string{"not_in_value"}),
+			},
+		},
+	}
+
+	attr.ResolveExcludes()
+
+	expectedBaseIncludes := []Label{Label{Label: "all_include"}}
+	if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) {
+		t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes)
+	}
+	var nilLabels []Label
+	expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{
+		ArchConfigurationAxis: map[string][]Label{
+			"arm":                nilLabels,
+			"x86":                makeLabels("arm_exclude", "x86_include"),
+			"conditions_default": makeLabels("arm_exclude"),
+		},
+		OsConfigurationAxis: map[string][]Label{
+			"android":            nilLabels,
+			"linux":              makeLabels("android_exclude", "linux_include"),
+			"conditions_default": makeLabels("android_exclude"),
+		},
+		OsArchConfigurationAxis: map[string][]Label{
+			"linux_x86":          makeLabels("linux_x86_include"),
+			"conditions_default": nilLabels,
+		},
+	}
+	for _, axis := range attr.SortedConfigurationAxes() {
+		if _, ok := expectedConfiguredIncludes[axis]; !ok {
+			t.Errorf("Found unexpected axis %s", axis)
+			continue
+		}
+		expectedForAxis := expectedConfiguredIncludes[axis]
+		gotForAxis := attr.ConfigurableValues[axis]
+		if len(expectedForAxis) != len(gotForAxis) {
+			t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
+		}
+		for config, value := range gotForAxis {
+			if expected, ok := expectedForAxis[config]; ok {
+				if !reflect.DeepEqual(expected, value.Includes) {
+					t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value.Includes)
+				}
+			} else {
+				t.Errorf("Got unexpected config %q for %s", config, axis)
+			}
+		}
+	}
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index c8ae031..d84a7bb 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -985,3 +985,117 @@
 )`},
 	})
 }
+
+func TestCcLibraryExcludeLibs(t *testing.T) {
+	runCcLibraryTestCase(t, bp2buildTestCase{
+		moduleTypeUnderTest:                "cc_library",
+		moduleTypeUnderTestFactory:         cc.LibraryFactory,
+		moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+		depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+		filesystem:                         map[string]string{},
+		blueprint: soongCcLibraryStaticPreamble + `
+cc_library {
+    name: "foo_static",
+    srcs: ["common.c"],
+    whole_static_libs: [
+        "arm_whole_static_lib_excludes",
+        "malloc_not_svelte_whole_static_lib_excludes"
+    ],
+    static_libs: [
+        "arm_static_lib_excludes",
+        "malloc_not_svelte_static_lib_excludes"
+    ],
+    shared_libs: [
+        "arm_shared_lib_excludes",
+    ],
+    arch: {
+        arm: {
+            exclude_shared_libs: [
+                 "arm_shared_lib_excludes",
+            ],
+            exclude_static_libs: [
+                "arm_static_lib_excludes",
+                "arm_whole_static_lib_excludes",
+            ],
+        },
+    },
+    product_variables: {
+        malloc_not_svelte: {
+            shared_libs: ["malloc_not_svelte_shared_lib"],
+            whole_static_libs: ["malloc_not_svelte_whole_static_lib"],
+            exclude_static_libs: [
+                "malloc_not_svelte_static_lib_excludes",
+                "malloc_not_svelte_whole_static_lib_excludes",
+            ],
+        },
+    },
+}
+
+cc_library {
+    name: "arm_whole_static_lib_excludes",
+    bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+    name: "malloc_not_svelte_whole_static_lib",
+    bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+    name: "malloc_not_svelte_whole_static_lib_excludes",
+    bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+    name: "arm_static_lib_excludes",
+    bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+    name: "malloc_not_svelte_static_lib_excludes",
+    bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+    name: "arm_shared_lib_excludes",
+    bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+    name: "malloc_not_svelte_shared_lib",
+    bazel_module: { bp2build_available: false },
+}
+`,
+		expectedBazelTargets: []string{
+			`cc_library(
+    name = "foo_static",
+    copts = [
+        "-I.",
+        "-I$(BINDIR)/.",
+    ],
+    dynamic_deps = select({
+        "//build/bazel/platforms/arch:arm": [],
+        "//conditions:default": [":arm_shared_lib_excludes"],
+    }) + select({
+        "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
+        "//conditions:default": [],
+    }),
+    implementation_deps = select({
+        "//build/bazel/platforms/arch:arm": [],
+        "//conditions:default": [":arm_static_lib_excludes"],
+    }) + select({
+        "//build/bazel/product_variables:malloc_not_svelte": [],
+        "//conditions:default": [":malloc_not_svelte_static_lib_excludes"],
+    }),
+    srcs_c = ["common.c"],
+    whole_archive_deps = select({
+        "//build/bazel/platforms/arch:arm": [],
+        "//conditions:default": [":arm_whole_static_lib_excludes"],
+    }) + select({
+        "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib"],
+        "//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes"],
+    }),
+)`,
+		},
+	})
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 31e69d8..752d43b 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -112,6 +112,30 @@
 		}
 	}
 
+	// product variables only support a limited set of fields, this is the full list of field names
+	// related to cc module dependency management that are supported.
+	productVariableDepFields := [4]string{
+		"Shared_libs",
+		"Static_libs",
+		"Exclude_static_libs",
+		"Whole_static_libs",
+	}
+
+	productVariableProps := android.ProductVariableProperties(ctx)
+	for _, name := range productVariableDepFields {
+		props, exists := productVariableProps[name]
+		if !exists {
+			continue
+		}
+		for _, prop := range props {
+			if p, ok := prop.Property.([]string); !ok {
+				ctx.ModuleErrorf("Could not convert product variable %s property", name)
+			} else {
+				allDeps = append(allDeps, p...)
+			}
+		}
+	}
+
 	ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
 }
 
@@ -372,29 +396,15 @@
 		return copts
 	}
 
-	// baseSrcs contain the list of src files that are used for every configuration.
-	var baseSrcs []string
-	// baseExcludeSrcs contain the list of src files that are excluded for every configuration.
-	var baseExcludeSrcs []string
-	// baseSrcsLabelList is a clone of the base srcs LabelList, used for computing the
-	// arch or os specific srcs later.
-	var baseSrcsLabelList bazel.LabelList
-
-	// Parse srcs from an arch or OS's props value, taking the base srcs and
-	// exclude srcs into account.
+	// Parse srcs from an arch or OS's props value.
 	parseSrcs := func(baseCompilerProps *BaseCompilerProperties) bazel.LabelList {
-		// Combine the base srcs and arch-specific srcs
-		allSrcs := append(baseSrcs, baseCompilerProps.Srcs...)
 		// Add srcs-like dependencies such as generated files.
 		// First create a LabelList containing these dependencies, then merge the values with srcs.
 		generatedHdrsAndSrcs := baseCompilerProps.Generated_headers
 		generatedHdrsAndSrcs = append(generatedHdrsAndSrcs, baseCompilerProps.Generated_sources...)
-
 		generatedHdrsAndSrcsLabelList := android.BazelLabelForModuleDeps(ctx, generatedHdrsAndSrcs)
 
-		// Combine the base exclude_srcs and configuration-specific exclude_srcs
-		allExcludeSrcs := append(baseExcludeSrcs, baseCompilerProps.Exclude_srcs...)
-		allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, allSrcs, allExcludeSrcs)
+		allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, baseCompilerProps.Srcs, baseCompilerProps.Exclude_srcs)
 		return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedHdrsAndSrcsLabelList)
 	}
 
@@ -406,10 +416,6 @@
 			conlyFlags.Value = parseCommandLineFlags(baseCompilerProps.Conlyflags)
 			cppFlags.Value = parseCommandLineFlags(baseCompilerProps.Cppflags)
 
-			// Used for arch-specific srcs later.
-			baseSrcs = baseCompilerProps.Srcs
-			baseSrcsLabelList = parseSrcs(baseCompilerProps)
-			baseExcludeSrcs = baseCompilerProps.Exclude_srcs
 			break
 		}
 	}
@@ -433,8 +439,6 @@
 				if len(baseCompilerProps.Srcs) > 0 || len(baseCompilerProps.Exclude_srcs) > 0 {
 					srcsList := parseSrcs(baseCompilerProps)
 					srcs.SetSelectValue(axis, config, srcsList)
-					// The base srcs value should not contain any arch-specific excludes.
-					srcs.SetValue(bazel.SubtractBazelLabelList(srcs.Value, bazel.LabelList{Includes: srcsList.Excludes}))
 				}
 
 				copts.SetSelectValue(axis, config, parseCopts(baseCompilerProps))
@@ -445,24 +449,7 @@
 		}
 	}
 
-	// After going through all archs, delete the duplicate files in the arch
-	// values that are already in the base srcs.Value.
-	for axis, configToProps := range archVariantCompilerProps {
-		for config, props := range configToProps {
-			if _, ok := props.(*BaseCompilerProperties); ok {
-				// TODO: handle non-arch
-				srcs.SetSelectValue(axis, config, bazel.SubtractBazelLabelList(srcs.SelectValue(axis, config), srcs.Value))
-			}
-		}
-	}
-
-	// Now that the srcs.Value list is finalized, compare it with the original
-	// list, and put the difference into the default condition for the arch
-	// select.
-	for axis := range archVariantCompilerProps {
-		defaultsSrcs := bazel.SubtractBazelLabelList(baseSrcsLabelList, srcs.Value)
-		srcs.SetSelectValue(axis, bazel.ConditionsDefault, defaultsSrcs)
-	}
+	srcs.ResolveExcludes()
 
 	productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{
 		"Cflags":   &copts,
@@ -478,7 +465,7 @@
 					ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
 				}
 				newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
-				attr.SetSelectValue(bazel.ProductVariableConfigurationAxis(prop.ProductConfigVariable), prop.ProductConfigVariable, newFlags)
+				attr.SetSelectValue(bazel.ProductVariableConfigurationAxis(prop.FullConfig), prop.FullConfig, newFlags)
 			}
 		}
 	}
@@ -518,37 +505,37 @@
 // bp2BuildParseLinkerProps parses the linker properties of a module, including
 // configurable attribute values.
 func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
-	var deps bazel.LabelListAttribute
+	var headerDeps bazel.LabelListAttribute
+	var staticDeps bazel.LabelListAttribute
 	var exportedDeps bazel.LabelListAttribute
 	var dynamicDeps bazel.LabelListAttribute
 	var wholeArchiveDeps bazel.LabelListAttribute
 	var linkopts bazel.StringListAttribute
 	var versionScript bazel.LabelAttribute
 
-	getLibs := func(baseLinkerProps *BaseLinkerProperties) []string {
-		libs := baseLinkerProps.Header_libs
-		libs = append(libs, baseLinkerProps.Static_libs...)
-		libs = android.SortedUniqueStrings(libs)
-		return libs
-	}
-
 	for _, linkerProps := range module.linker.linkerProps() {
 		if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
-			libs := getLibs(baseLinkerProps)
-			exportedLibs := baseLinkerProps.Export_header_lib_headers
-			wholeArchiveLibs := baseLinkerProps.Whole_static_libs
-			deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs))
-			exportedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, exportedLibs))
-			linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps)
-			wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
+			// Excludes to parallel Soong:
+			// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0
+			staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs)
+			staticDeps.Value = android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs)
+			wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
+			wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
+			sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
+			dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
 
+			headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs)
+			headerDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, headerLibs))
+			// TODO(b/188796939): also handle export_static_lib_headers, export_shared_lib_headers,
+			// export_generated_headers
+			exportedLibs := android.FirstUniqueStrings(baseLinkerProps.Export_header_lib_headers)
+			exportedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, exportedLibs))
+
+			linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps)
 			if baseLinkerProps.Version_script != nil {
 				versionScript.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
 			}
 
-			sharedLibs := baseLinkerProps.Shared_libs
-			dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, sharedLibs))
-
 			break
 		}
 	}
@@ -556,26 +543,83 @@
 	for axis, configToProps := range module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) {
 		for config, props := range configToProps {
 			if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok {
-				libs := getLibs(baseLinkerProps)
-				exportedLibs := baseLinkerProps.Export_header_lib_headers
-				wholeArchiveLibs := baseLinkerProps.Whole_static_libs
-				deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, libs))
-				exportedDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, exportedLibs))
-				linkopts.SetSelectValue(axis, config, getBp2BuildLinkerFlags(baseLinkerProps))
-				wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
+				staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs)
+				staticDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs))
+				wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
+				wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
+				sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
+				dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
 
+				headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs)
+				headerDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, headerLibs))
+				exportedLibs := android.FirstUniqueStrings(baseLinkerProps.Export_header_lib_headers)
+				exportedDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, exportedLibs))
+
+				linkopts.SetSelectValue(axis, config, getBp2BuildLinkerFlags(baseLinkerProps))
 				if baseLinkerProps.Version_script != nil {
 					versionScript.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
 				}
-
-				sharedLibs := baseLinkerProps.Shared_libs
-				dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, sharedLibs))
 			}
 		}
 	}
 
+	type productVarDep struct {
+		// the name of the corresponding excludes field, if one exists
+		excludesField string
+		// reference to the bazel attribute that should be set for the given product variable config
+		attribute *bazel.LabelListAttribute
+	}
+
+	productVarToDepFields := map[string]productVarDep{
+		// product variables do not support exclude_shared_libs
+		"Shared_libs":       productVarDep{attribute: &dynamicDeps},
+		"Static_libs":       productVarDep{"Exclude_static_libs", &staticDeps},
+		"Whole_static_libs": productVarDep{"Exclude_static_libs", &wholeArchiveDeps},
+	}
+
+	productVariableProps := android.ProductVariableProperties(ctx)
+	for name, dep := range productVarToDepFields {
+		props, exists := productVariableProps[name]
+		excludeProps, excludesExists := productVariableProps[dep.excludesField]
+		// if neither an include or excludes property exists, then skip it
+		if !exists && !excludesExists {
+			continue
+		}
+		// collect all the configurations that an include or exclude property exists for.
+		// we want to iterate all configurations rather than either the include or exclude because for a
+		// particular configuration we may have only and include or only an exclude to handle
+		configs := make(map[string]bool, len(props)+len(excludeProps))
+		for config := range props {
+			configs[config] = true
+		}
+		for config := range excludeProps {
+			configs[config] = true
+		}
+
+		for config := range configs {
+			prop, includesExists := props[config]
+			excludesProp, excludesExists := excludeProps[config]
+			var includes, excludes []string
+			var ok bool
+			// if there was no includes/excludes property, casting fails and that's expected
+			if includes, ok = prop.Property.([]string); includesExists && !ok {
+				ctx.ModuleErrorf("Could not convert product variable %s property", name)
+			}
+			if excludes, ok = excludesProp.Property.([]string); excludesExists && !ok {
+				ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField)
+			}
+			dep.attribute.SetSelectValue(bazel.ProductVariableConfigurationAxis(config), config, android.BazelLabelForModuleDepsExcludes(ctx, android.FirstUniqueStrings(includes), excludes))
+		}
+	}
+
+	staticDeps.ResolveExcludes()
+	dynamicDeps.ResolveExcludes()
+	wholeArchiveDeps.ResolveExcludes()
+
+	headerDeps.Append(staticDeps)
+
 	return linkerAttributes{
-		deps:             deps,
+		deps:             headerDeps,
 		exportedDeps:     exportedDeps,
 		dynamicDeps:      dynamicDeps,
 		wholeArchiveDeps: wholeArchiveDeps,
diff --git a/cc/library.go b/cc/library.go
index 0ff78a5..c88c29a 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -111,9 +111,6 @@
 		Check_all_apis *bool
 	}
 
-	// Order symbols in .bss section by their sizes.  Only useful for shared libraries.
-	Sort_bss_symbols_by_size *bool
-
 	// Inject boringssl hash into the shared library.  This is only intended for use by external/boringssl.
 	Inject_bssl_hash *bool `android:"arch_variant"`
 
@@ -1342,19 +1339,6 @@
 	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
 	linkerDeps = append(linkerDeps, objs.tidyFiles...)
-
-	if Bool(library.Properties.Sort_bss_symbols_by_size) && !library.buildStubs() {
-		unsortedOutputFile := android.PathForModuleOut(ctx, "unsorted", fileName)
-		transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
-			deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
-			linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, unsortedOutputFile, implicitOutputs)
-
-		symbolOrderingFile := android.PathForModuleOut(ctx, "unsorted", fileName+".symbol_order")
-		symbolOrderingFlag := library.baseLinker.sortBssSymbolsBySize(ctx, unsortedOutputFile, symbolOrderingFile, builderFlags)
-		builderFlags.localLdFlags += " " + symbolOrderingFlag
-		linkerDeps = append(linkerDeps, symbolOrderingFile)
-	}
-
 	transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
 		deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
 		linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs)
diff --git a/cc/linker.go b/cc/linker.go
index 5bd21ed..1d8c649 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -594,28 +594,3 @@
 		},
 	})
 }
-
-// Rule to generate .bss symbol ordering file.
-
-var (
-	_                   = pctx.SourcePathVariable("genSortedBssSymbolsPath", "build/soong/scripts/gen_sorted_bss_symbols.sh")
-	genSortedBssSymbols = pctx.AndroidStaticRule("gen_sorted_bss_symbols",
-		blueprint.RuleParams{
-			Command:     "CLANG_BIN=${clangBin} $genSortedBssSymbolsPath ${in} ${out}",
-			CommandDeps: []string{"$genSortedBssSymbolsPath", "${clangBin}/llvm-nm"},
-		},
-		"clangBin")
-)
-
-func (linker *baseLinker) sortBssSymbolsBySize(ctx ModuleContext, in android.Path, symbolOrderingFile android.ModuleOutPath, flags builderFlags) string {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        genSortedBssSymbols,
-		Description: "generate bss symbol order " + symbolOrderingFile.Base(),
-		Output:      symbolOrderingFile,
-		Input:       in,
-		Args: map[string]string{
-			"clangBin": "${config.ClangBin}",
-		},
-	})
-	return "-Wl,--symbol-ordering-file," + symbolOrderingFile.String()
-}
diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go
index b9b57af..927fa2e 100644
--- a/cc/ndk_abi.go
+++ b/cc/ndk_abi.go
@@ -46,7 +46,7 @@
 
 		if m, ok := module.(*Module); ok {
 			if installer, ok := m.installer.(*stubDecorator); ok {
-				if canDumpAbi(m) {
+				if canDumpAbi() {
 					depPaths = append(depPaths, installer.abiDumpPath)
 				}
 			}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index f3d2ba1..a458380 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"sync"
 
@@ -332,12 +333,12 @@
 }
 
 // Feature flag.
-func canDumpAbi(module android.Module) bool {
-	return true
+func canDumpAbi() bool {
+	return runtime.GOOS != "darwin"
 }
 
 // Feature flag to disable diffing against prebuilts.
-func canDiffAbi(module android.Module) bool {
+func canDiffAbi() bool {
 	return false
 }
 
@@ -452,9 +453,9 @@
 	nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "")
 	objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
 	c.versionScriptPath = nativeAbiResult.versionScript
-	if canDumpAbi(ctx.Module()) {
+	if canDumpAbi() {
 		c.dumpAbi(ctx, nativeAbiResult.symbolList)
-		if canDiffAbi(ctx.Module()) {
+		if canDiffAbi() {
 			c.diffAbi(ctx)
 		}
 	}
diff --git a/cc/sabi.go b/cc/sabi.go
index 384dcc1..1f331cb 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -192,7 +192,7 @@
 			// Mark all of its static library dependencies.
 			mctx.VisitDirectDeps(func(child android.Module) {
 				depTag := mctx.OtherModuleDependencyTag(child)
-				if libDepTag, ok := depTag.(libraryDependencyTag); ok && libDepTag.static() {
+				if IsStaticDepTag(depTag) || depTag == reuseObjTag {
 					if c, ok := child.(*Module); ok && c.sabi != nil {
 						// Mark this module so that .sdump for this static library can be generated.
 						c.sabi.Properties.ShouldCreateSourceAbiDump = true
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 20f146a..55a5470 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -460,19 +460,21 @@
 		}
 	}()
 
-	buildWhat := build.BuildProductConfig
+	config.SetSkipNinja(true)
+
+	buildWhat := build.RunProductConfig
 	if !*onlyConfig {
-		buildWhat |= build.BuildSoong
+		buildWhat |= build.RunSoong
 		if !*onlySoong {
-			buildWhat |= build.BuildKati
+			buildWhat |= build.RunKati
 		}
 	}
 
 	before := time.Now()
-	build.Build(ctx, config, buildWhat)
+	build.Build(ctx, config)
 
 	// Save std_full.log if Kati re-read the makefiles
-	if buildWhat&build.BuildKati != 0 {
+	if buildWhat&build.RunKati != 0 {
 		if after, err := os.Stat(config.KatiBuildNinjaFile()); err == nil && after.ModTime().After(before) {
 			err := copyFile(stdLog, filepath.Join(filepath.Dir(stdLog), "std_full.log"))
 			if err != nil {
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 390a9ec..22922c0 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -59,12 +59,10 @@
 	run func(ctx build.Context, config build.Config, args []string, logsDir string)
 }
 
-const makeModeFlagName = "--make-mode"
-
 // list of supported commands (flags) supported by soong ui
 var commands []command = []command{
 	{
-		flag:        makeModeFlagName,
+		flag:        "--make-mode",
 		description: "build the modules by the target name (i.e. soong_docs)",
 		config: func(ctx build.Context, args ...string) build.Config {
 			return build.NewConfig(ctx, args...)
@@ -506,15 +504,7 @@
 		ctx.Fatal("done")
 	}
 
-	toBuild := build.BuildAll
-	if config.UseBazel() {
-		toBuild = build.BuildAllWithBazel
-	}
-
-	if config.Checkbuild() {
-		toBuild |= build.RunBuildTests
-	}
-	build.Build(ctx, config, toBuild)
+	build.Build(ctx, config)
 }
 
 // getCommand finds the appropriate command based on args[1] flag. args[0]
diff --git a/cuj/cuj.go b/cuj/cuj.go
index 3333012..b4ae9a2 100644
--- a/cuj/cuj.go
+++ b/cuj/cuj.go
@@ -115,7 +115,7 @@
 	defer f.Shutdown()
 	build.FindSources(buildCtx, config, f)
 
-	build.Build(buildCtx, config, build.BuildAll)
+	build.Build(buildCtx, config)
 
 	t.results.metrics = met
 }
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 792193f..1c7ad78 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -516,7 +516,16 @@
 	// Only create configs for updatable boot jars. Non-updatable boot jars must be part of the
 	// platform_bootclasspath's classpath proto config to guarantee that they come before any
 	// updatable jars at runtime.
-	return global.UpdatableBootJars.Filter(stems)
+	jars := global.UpdatableBootJars.Filter(stems)
+
+	// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
+	// config. However, any test specific jars would not be present in UpdatableBootJars. Instead,
+	// we should check if we are creating a config for apex_test via ApexInfo and amend the values.
+	// This is an exception to support end-to-end test for SdkExtensions, until such support exists.
+	if android.InList("test_framework-sdkextensions", stems) {
+		jars = jars.Append("com.android.sdkext", "test_framework-sdkextensions")
+	}
+	return jars
 }
 
 func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 56e6247..869a598 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -425,23 +425,6 @@
 	}
 	srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages)
 
-	// While metalava needs package html files, it does not need them to be explicit on the command
-	// line. javadoc complains if it receives html files on the command line. The filter
-	// below excludes html files from the rsp file metalava. Note that the html
-	// files are still included as implicit inputs for successful remote execution and correct
-	// incremental builds.
-	filterHtml := func(srcs []android.Path) []android.Path {
-		filtered := []android.Path{}
-		for _, src := range srcs {
-			if src.Ext() == ".html" {
-				continue
-			}
-			filtered = append(filtered, src)
-		}
-		return filtered
-	}
-	srcFiles = filterHtml(srcFiles)
-
 	aidlFlags := j.collectAidlFlags(ctx, deps)
 	srcFiles = j.genSources(ctx, srcFiles, aidlFlags)
 
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 17c7a7b..d348b55 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -392,8 +392,7 @@
 }
 
 func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
-	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths,
-	homeDir android.WritablePath) *android.RuleBuilderCommand {
+	srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
 	rule.Command().Text("rm -rf").Flag(homeDir.String())
 	rule.Command().Text("mkdir -p").Flag(homeDir.String())
 
@@ -430,12 +429,6 @@
 		cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
 	}
 
-	if len(sourcepaths) > 0 {
-		cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":")
-	} else {
-		cmd.FlagWithArg("-sourcepath ", `""`)
-	}
-
 	cmd.Flag("--no-banner").
 		Flag("--color").
 		Flag("--quiet").
@@ -479,7 +472,7 @@
 
 	homeDir := android.PathForModuleOut(ctx, "metalava", "home")
 	cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
-		deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, homeDir)
+		deps.bootClasspath, deps.classpath, homeDir)
 	cmd.Implicits(d.Javadoc.implicits)
 
 	d.stubsFlags(ctx, cmd, stubsDir)
diff --git a/java/rro.go b/java/rro.go
index 2e58c04..0b4d091 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -90,6 +90,22 @@
 	Theme() string
 }
 
+// RRO's partition logic is different from the partition logic of other modules defined in soong/android/paths.go
+// The default partition for RRO is "/product" and not "/system"
+func rroPartition(ctx android.ModuleContext) string {
+	var partition string
+	if ctx.DeviceSpecific() {
+		partition = ctx.DeviceConfig().OdmPath()
+	} else if ctx.SocSpecific() {
+		partition = ctx.DeviceConfig().VendorPath()
+	} else if ctx.SystemExtSpecific() {
+		partition = ctx.DeviceConfig().SystemExtPath()
+	} else {
+		partition = ctx.DeviceConfig().ProductPath()
+	}
+	return partition
+}
+
 func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
 	sdkDep := decodeSdkDep(ctx, android.SdkContext(r))
 	if sdkDep.hasFrameworkLibs() {
@@ -137,7 +153,8 @@
 	r.certificate = certificates[0]
 
 	r.outputFile = signed
-	r.installDir = android.PathForModuleInstall(ctx, "overlay", String(r.properties.Theme))
+	partition := rroPartition(ctx)
+	r.installDir = android.PathForModuleInPartitionInstall(ctx, partition, "overlay", String(r.properties.Theme))
 	ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile)
 }
 
diff --git a/java/rro_test.go b/java/rro_test.go
index bad60bc..27abbe4 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -177,7 +177,7 @@
 
 	// Check device location.
 	path = android.AndroidMkEntriesForTest(t, ctx, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
-	expectedPath = []string{shared.JoinPath("out/target/product/test_device/system/overlay")}
+	expectedPath = []string{shared.JoinPath("out/target/product/test_device/product/overlay")}
 	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", config, expectedPath, path)
 }
 
@@ -343,3 +343,57 @@
 		})
 	}
 }
+
+func TestRuntimeResourceOverlayPartition(t *testing.T) {
+	bp := `
+		runtime_resource_overlay {
+			name: "device_specific",
+			device_specific: true,
+		}
+		runtime_resource_overlay {
+			name: "soc_specific",
+			soc_specific: true,
+		}
+		runtime_resource_overlay {
+			name: "system_ext_specific",
+			system_ext_specific: true,
+		}
+		runtime_resource_overlay {
+			name: "product_specific",
+			product_specific: true,
+		}
+		runtime_resource_overlay {
+			name: "default"
+		}
+	`
+	testCases := []struct {
+		name         string
+		expectedPath string
+	}{
+		{
+			name:         "device_specific",
+			expectedPath: "out/soong/target/product/test_device/odm/overlay",
+		},
+		{
+			name:         "soc_specific",
+			expectedPath: "out/soong/target/product/test_device/vendor/overlay",
+		},
+		{
+			name:         "system_ext_specific",
+			expectedPath: "out/soong/target/product/test_device/system_ext/overlay",
+		},
+		{
+			name:         "product_specific",
+			expectedPath: "out/soong/target/product/test_device/product/overlay",
+		},
+		{
+			name:         "default",
+			expectedPath: "out/soong/target/product/test_device/product/overlay",
+		},
+	}
+	for _, testCase := range testCases {
+		ctx, _ := testJava(t, bp)
+		mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*RuntimeResourceOverlay)
+		android.AssertPathRelativeToTopEquals(t, "Install dir is not correct for "+testCase.name, testCase.expectedPath, mod.installDir)
+	}
+}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index ecf2b1a..9492729 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -435,9 +435,6 @@
 	// a list of top-level directories containing Java stub files to merge show/hide annotations from.
 	Merge_inclusion_annotations_dirs []string
 
-	// If set to true, the path of dist files is apistubs/core. Defaults to false.
-	Core_lib *bool
-
 	// If set to true then don't create dist rules.
 	No_dist *bool
 
@@ -458,7 +455,7 @@
 	Dist_stem *string
 
 	// The subdirectory for the artifacts that are copied to the dist directory.  If not specified
-	// then defaults to "android".  Should be set to "android" for anything that should be published
+	// then defaults to "unknown".  Should be set to "android" for anything that should be published
 	// in the public Android SDK.
 	Dist_group *string
 
@@ -1203,11 +1200,7 @@
 
 // The dist path of the stub artifacts
 func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
-	if Bool(module.sdkLibraryProperties.Core_lib) {
-		return path.Join("apistubs", "core", apiScope.name)
-	} else {
-		return path.Join("apistubs", module.distGroup(), apiScope.name)
-	}
+	return path.Join("apistubs", module.distGroup(), apiScope.name)
 }
 
 // Get the sdk version for use when compiling the stubs library.
@@ -1233,15 +1226,7 @@
 
 // distGroup returns the subdirectory of the dist path of the stub artifacts.
 func (module *SdkLibrary) distGroup() string {
-	if group := proptools.String(module.sdkLibraryProperties.Dist_group); group != "" {
-		return group
-	}
-	// TODO(b/186723288): Remove this once everything uses dist_group.
-	if owner := module.ModuleBase.Owner(); owner != "" {
-		return owner
-	}
-	// TODO(b/186723288): Make this "unknown".
-	return "android"
+	return proptools.StringDefault(module.sdkLibraryProperties.Dist_group, "unknown")
 }
 
 func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 0fe6e72..2520dde 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -844,40 +844,34 @@
 		PrepareForTestWithJavaBuildComponents,
 		PrepareForTestWithJavaDefaultModules,
 		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis(
+			"sdklib_no_group",
+			"sdklib_group_foo",
+			"sdklib_owner_foo",
+			"foo"),
 	).RunTestWithBp(t, `
 		java_sdk_library {
-			name: "sdklib_no_owner",
-			unsafe_ignore_missing_latest_api: true,
+			name: "sdklib_no_group",
 			srcs: ["foo.java"],
 		}
 
 		java_sdk_library {
 			name: "sdklib_group_foo",
-			unsafe_ignore_missing_latest_api: true,
 			srcs: ["foo.java"],
 			dist_group: "foo",
 		}
 
 		java_sdk_library {
 			name: "sdklib_owner_foo",
-			unsafe_ignore_missing_latest_api: true,
 			srcs: ["foo.java"],
 			owner: "foo",
 		}
 
 		java_sdk_library {
 			name: "sdklib_stem_foo",
-			unsafe_ignore_missing_latest_api: true,
 			srcs: ["foo.java"],
 			dist_stem: "foo",
 		}
-
-		java_sdk_library {
-			name: "sdklib_core_lib",
-			unsafe_ignore_missing_latest_api: true,
-			srcs: ["foo.java"],
-			core_lib: true,
-		}
 	`)
 
 	type testCase struct {
@@ -887,9 +881,9 @@
 	}
 	testCases := []testCase{
 		{
-			module:   "sdklib_no_owner",
-			distDir:  "apistubs/android/public",
-			distStem: "sdklib_no_owner.jar",
+			module:   "sdklib_no_group",
+			distDir:  "apistubs/unknown/public",
+			distStem: "sdklib_no_group.jar",
 		},
 		{
 			module:   "sdklib_group_foo",
@@ -897,20 +891,16 @@
 			distStem: "sdklib_group_foo.jar",
 		},
 		{
+			// Owner doesn't affect distDir after b/186723288.
 			module:   "sdklib_owner_foo",
-			distDir:  "apistubs/foo/public",
+			distDir:  "apistubs/unknown/public",
 			distStem: "sdklib_owner_foo.jar",
 		},
 		{
 			module:   "sdklib_stem_foo",
-			distDir:  "apistubs/android/public",
+			distDir:  "apistubs/unknown/public",
 			distStem: "foo.jar",
 		},
-		{
-			module:   "sdklib_core_lib",
-			distDir:  "apistubs/core/public",
-			distStem: "sdklib_core_lib.jar",
-		},
 	}
 
 	for _, tt := range testCases {
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index 4b08ac3..8a5513e 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -1,14 +1,24 @@
 #!/bin/bash -e
 
-# This is a wrapper around "m" that builds the given modules in multi-arch mode
-# for all architectures supported by Mainline modules. The make (kati) stage is
-# skipped, so the build targets in the arguments can only be Soong modules or
-# intermediate output files - make targets and normal installed paths are not
-# supported.
+# This script is similar to "m" but builds in --soong-only mode, and handles
+# special cases to make that mode work. All arguments are passed on to
+# build/soong/soong_ui.bash.
 #
-# This script is typically used with "sdk" or "module_export" modules, which
-# Soong will install in $OUT_DIR/soong/mainline-sdks (cf
-# PathForMainlineSdksInstall in android/paths.go).
+# --soong-only bypasses the kati step and hence the make logic that e.g. doesn't
+# handle more than two device architectures. It is particularly intended for use
+# with TARGET_PRODUCT=mainline_sdk to build 'sdk' and 'module_export' Soong
+# modules in TARGET_ARCH_SUITE=mainline_sdk mode so that they get all four
+# device architectures (artifacts get installed in $OUT_DIR/soong/mainline-sdks
+# - cf PathForMainlineSdksInstall in android/paths.go).
+#
+# TODO(b/174315599): Replace this script completely with a 'soong_ui.bash
+# --soong-only' invocation. For now it is still necessary to set up
+# build_number.txt.
+
+if [ ! -e build/soong/soong_ui.bash ]; then
+  echo "$0 must be run from the top of the tree"
+  exit 1
+fi
 
 export OUT_DIR=${OUT_DIR:-out}
 
@@ -23,109 +33,19 @@
   OUT_DIR=${AML_OUT_DIR}
 fi
 
-if [ ! -e "build/envsetup.sh" ]; then
-  echo "$0 must be run from the top of the tree"
-  exit 1
-fi
+mkdir -p ${OUT_DIR}/soong
 
-source build/envsetup.sh
-
-my_get_build_var() {
-  # get_build_var will run Soong in normal in-make mode where it creates
-  # .soong.kati_enabled. That would clobber our real out directory, so we need
-  # to run it in a different one.
-  OUT_DIR=${OUT_DIR}/get_build_var get_build_var "$@"
-}
-
-readonly SOONG_OUT=${OUT_DIR}/soong
-mkdir -p ${SOONG_OUT}
+# The --dumpvars-mode invocation will run Soong in normal make mode where it
+# creates .soong.kati_enabled. That would clobber our real out directory, so we
+# need to use a different OUT_DIR.
+vars="$(OUT_DIR=${OUT_DIR}/dumpvars_mode build/soong/soong_ui.bash \
+        --dumpvars-mode --vars=BUILD_NUMBER)"
+# Assign to a variable and eval that, since bash ignores any error status
+# from the command substitution if it's directly on the eval line.
+eval $vars
 
 # Some Soong build rules may require this, and the failure mode if it's missing
 # is confusing (b/172548608).
-readonly BUILD_NUMBER="$(my_get_build_var BUILD_NUMBER)"
-echo -n ${BUILD_NUMBER} > ${SOONG_OUT}/build_number.txt
+echo -n ${BUILD_NUMBER} > ${OUT_DIR}/soong/build_number.txt
 
-readonly PLATFORM_SDK_VERSION="$(my_get_build_var PLATFORM_SDK_VERSION)"
-readonly PLATFORM_VERSION="$(my_get_build_var PLATFORM_VERSION)"
-PLATFORM_VERSION_ALL_CODENAMES="$(my_get_build_var PLATFORM_VERSION_ALL_CODENAMES)"
-
-# PLATFORM_VERSION_ALL_CODENAMES is a comma separated list like O,P. We need to
-# turn this into ["O","P"].
-PLATFORM_VERSION_ALL_CODENAMES="${PLATFORM_VERSION_ALL_CODENAMES/,/'","'}"
-PLATFORM_VERSION_ALL_CODENAMES="[\"${PLATFORM_VERSION_ALL_CODENAMES}\"]"
-
-# Get the list of missing <uses-library> modules and convert it to a JSON array
-# (quote module names, add comma separator and wrap in brackets).
-MISSING_USES_LIBRARIES="$(my_get_build_var INTERNAL_PLATFORM_MISSING_USES_LIBRARIES)"
-MISSING_USES_LIBRARIES="[$(echo $MISSING_USES_LIBRARIES | sed -e 's/\([^ ]\+\)/\"\1\"/g' -e 's/[ ]\+/, /g')]"
-
-# Logic from build/make/core/goma.mk
-if [ "${USE_GOMA}" = true ]; then
-  if [ -n "${GOMA_DIR}" ]; then
-    goma_dir="${GOMA_DIR}"
-  else
-    goma_dir="${HOME}/goma"
-  fi
-  GOMA_CC="${goma_dir}/gomacc"
-  export CC_WRAPPER="${CC_WRAPPER}${CC_WRAPPER:+ }${GOMA_CC}"
-  export CXX_WRAPPER="${CXX_WRAPPER}${CXX_WRAPPER:+ }${GOMA_CC}"
-  export JAVAC_WRAPPER="${JAVAC_WRAPPER}${JAVAC_WRAPPER:+ }${GOMA_CC}"
-else
-  USE_GOMA=false
-fi
-
-readonly SOONG_VARS=${SOONG_OUT}/soong.variables
-
-# Aml_abis: true
-#   -  This flag configures Soong to compile for all architectures required for
-#      Mainline modules.
-# CrossHost: linux_bionic
-# CrossHostArch: x86_64
-#   -  Enable Bionic on host as ART needs prebuilts for it.
-# VendorVars.art_mdoule.source_build
-#   -  TODO(b/172480615): Change default to false when platform uses ART Module
-#      prebuilts by default.
-cat > ${SOONG_VARS}.new << EOF
-{
-    "BuildNumberFile": "build_number.txt",
-
-    "Platform_version_name": "${PLATFORM_VERSION}",
-    "Platform_sdk_version": ${PLATFORM_SDK_VERSION},
-    "Platform_sdk_codename": "${PLATFORM_VERSION}",
-    "Platform_version_active_codenames": ${PLATFORM_VERSION_ALL_CODENAMES},
-
-    "DeviceName": "generic_arm64",
-    "HostArch": "x86_64",
-    "HostSecondaryArch": "x86",
-    "CrossHost": "linux_bionic",
-    "CrossHostArch": "x86_64",
-    "Aml_abis": true,
-
-    "Allow_missing_dependencies": ${SOONG_ALLOW_MISSING_DEPENDENCIES:-false},
-    "Unbundled_build": ${TARGET_BUILD_UNBUNDLED:-false},
-    "UseGoma": ${USE_GOMA},
-
-    "VendorVars": {
-        "art_module": {
-            "source_build": "${ENABLE_ART_SOURCE_BUILD:-true}"
-        }
-    },
-
-    "MissingUsesLibraries": ${MISSING_USES_LIBRARIES}
-}
-EOF
-
-if [ -f ${SOONG_VARS} ] && cmp -s ${SOONG_VARS} ${SOONG_VARS}.new; then
-  # Don't touch soong.variables if we don't have to, to avoid Soong rebuilding
-  # the ninja file when it isn't necessary.
-  rm ${SOONG_VARS}.new
-else
-  mv ${SOONG_VARS}.new ${SOONG_VARS}
-fi
-
-# We use force building LLVM components flag (even though we actually don't
-# compile them) because we don't have bionic host prebuilts
-# for them.
-export FORCE_BUILD_LLVM_COMPONENTS=true
-
-m --skip-make "$@"
+build/soong/soong_ui.bash --make-mode --soong-only "$@"
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index 39c8fba..7d49492 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -93,11 +93,17 @@
   done
 done
 
+# We use force building LLVM components flag (even though we actually don't
+# compile them) because we don't have bionic host prebuilts
+# for them.
+export FORCE_BUILD_LLVM_COMPONENTS=true
+
 # Create multi-archs SDKs in a different out directory. The multi-arch script
 # uses Soong in --skip-make mode which cannot use the same directory as normal
 # mode with make.
 export OUT_DIR=${OUT_DIR}/aml
-echo_and_run build/soong/scripts/build-aml-prebuilts.sh ${MODULES_SDK_AND_EXPORTS[@]}
+echo_and_run build/soong/scripts/build-aml-prebuilts.sh \
+  TARGET_PRODUCT=mainline_sdk ${MODULES_SDK_AND_EXPORTS[@]}
 
 rm -rf ${DIST_DIR}/mainline-sdks
 echo_and_run cp -R ${OUT_DIR}/soong/mainline-sdks ${DIST_DIR}
diff --git a/scripts/gen_sorted_bss_symbols.sh b/scripts/gen_sorted_bss_symbols.sh
deleted file mode 100755
index a9b61a1..0000000
--- a/scripts/gen_sorted_bss_symbols.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2019 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.
-
-# Script to generate a symbol ordering file that sorts bss section symbols by
-# their sizes.
-# Inputs:
-#  Environment:
-#   CLANG_BIN: path to the clang bin directory
-#  Arguments:
-#   $1: Input ELF file
-#   $2: Output symbol ordering file
-
-set -o pipefail
-
-${CLANG_BIN}/llvm-nm --size-sort $1 | awk '{if ($2 == "b" || $2 == "B") print $3}' > $2
diff --git a/ui/build/build.go b/ui/build/build.go
index c2ad057..8f050d9 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -60,15 +60,15 @@
 {{end -}}
 pool highmem_pool
  depth = {{.HighmemParallel}}
-{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
+{{if and (not .SkipKatiNinja) .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
 subninja {{.KatiPackageNinjaFile}}
 {{end -}}
 subninja {{.SoongNinjaFile}}
 `))
 
 func createCombinedBuildNinjaFile(ctx Context, config Config) {
-	// If we're in SkipKati mode, skip creating this file if it already exists
-	if config.SkipKati() {
+	// If we're in SkipKati mode but want to run kati ninja, skip creating this file if it already exists
+	if config.SkipKati() && !config.SkipKatiNinja() {
 		if _, err := os.Stat(config.CombinedNinjaFile()); err == nil || !os.IsNotExist(err) {
 			return
 		}
@@ -87,15 +87,22 @@
 
 // These are bitmasks which can be used to check whether various flags are set e.g. whether to use Bazel.
 const (
-	BuildNone          = iota
-	BuildProductConfig = 1 << iota
-	BuildSoong         = 1 << iota
-	BuildKati          = 1 << iota
-	BuildNinja         = 1 << iota
-	BuildBazel         = 1 << iota
-	RunBuildTests      = 1 << iota
-	BuildAll           = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
-	BuildAllWithBazel  = BuildProductConfig | BuildSoong | BuildKati | BuildBazel
+	_ = iota
+	// Whether to run the kati config step.
+	RunProductConfig = 1 << iota
+	// Whether to run soong to generate a ninja file.
+	RunSoong = 1 << iota
+	// Whether to run kati to generate a ninja file.
+	RunKati = 1 << iota
+	// Whether to include the kati-generated ninja file in the combined ninja.
+	RunKatiNinja = 1 << iota
+	// Whether to run ninja on the combined ninja.
+	RunNinja = 1 << iota
+	// Whether to run bazel on the combined ninja.
+	RunBazel        = 1 << iota
+	RunBuildTests   = 1 << iota
+	RunAll          = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunNinja
+	RunAllWithBazel = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunBazel
 )
 
 // checkProblematicFiles fails the build if existing Android.mk or CleanSpec.mk files are found at the root of the tree.
@@ -173,7 +180,7 @@
 
 // Build the tree. The 'what' argument can be used to chose which components of
 // the build to run, via checking various bitmasks.
-func Build(ctx Context, config Config, what int) {
+func Build(ctx Context, config Config) {
 	ctx.Verboseln("Starting build with args:", config.Arguments())
 	ctx.Verboseln("Environment:", config.Environment().Environ())
 
@@ -208,33 +215,39 @@
 
 	SetupPath(ctx, config)
 
+	what := RunAll
+	if config.UseBazel() {
+		what = RunAllWithBazel
+	}
+	if config.Checkbuild() {
+		what |= RunBuildTests
+	}
 	if config.SkipConfig() {
 		ctx.Verboseln("Skipping Config as requested")
-		what = what &^ BuildProductConfig
+		what = what &^ RunProductConfig
 	}
-
 	if config.SkipKati() {
 		ctx.Verboseln("Skipping Kati as requested")
-		what = what &^ BuildKati
+		what = what &^ RunKati
 	}
-
+	if config.SkipKatiNinja() {
+		ctx.Verboseln("Skipping use of Kati ninja as requested")
+		what = what &^ RunKatiNinja
+	}
 	if config.SkipNinja() {
 		ctx.Verboseln("Skipping Ninja as requested")
-		what = what &^ BuildNinja
+		what = what &^ RunNinja
 	}
 
 	if config.StartGoma() {
-		// Ensure start Goma compiler_proxy
 		startGoma(ctx, config)
 	}
 
 	if config.StartRBE() {
-		// Ensure RBE proxy is started
 		startRBE(ctx, config)
 	}
 
-	if what&BuildProductConfig != 0 {
-		// Run make for product config
+	if what&RunProductConfig != 0 {
 		runMakeProductConfig(ctx, config)
 	}
 
@@ -254,8 +267,7 @@
 		return
 	}
 
-	if what&BuildSoong != 0 {
-		// Run Soong
+	if what&RunSoong != 0 {
 		runSoong(ctx, config)
 
 		if config.bazelBuildMode() == generateBuildFiles {
@@ -264,15 +276,14 @@
 		}
 	}
 
-	if what&BuildKati != 0 {
-		// Run ckati
+	if what&RunKati != 0 {
 		genKatiSuffix(ctx, config)
 		runKatiCleanSpec(ctx, config)
 		runKatiBuild(ctx, config)
 		runKatiPackage(ctx, config)
 
 		ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw
-	} else {
+	} else if what&RunKatiNinja != 0 {
 		// Load last Kati Suffix if it exists
 		if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
 			ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
@@ -289,17 +300,16 @@
 		testForDanglingRules(ctx, config)
 	}
 
-	if what&BuildNinja != 0 {
-		if what&BuildKati != 0 {
+	if what&RunNinja != 0 {
+		if what&RunKati != 0 {
 			installCleanIfNecessary(ctx, config)
 		}
 
-		// Run ninja
 		runNinjaForBuild(ctx, config)
 	}
 
 	// Currently, using Bazel requires Kati and Soong to run first, so check whether to run Bazel last.
-	if what&BuildBazel != 0 {
+	if what&RunBazel != 0 {
 		runBazel(ctx, config)
 	}
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index f1f5989..220e734 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -48,6 +48,7 @@
 	dist           bool
 	skipConfig     bool
 	skipKati       bool
+	skipKatiNinja  bool
 	skipNinja      bool
 	skipSoongTests bool
 
@@ -567,8 +568,7 @@
 func (c *configImpl) parseArgs(ctx Context, args []string) {
 	for i := 0; i < len(args); i++ {
 		arg := strings.TrimSpace(args[i])
-		if arg == "--make-mode" {
-		} else if arg == "showcommands" {
+		if arg == "showcommands" {
 			c.verbose = true
 		} else if arg == "--skip-ninja" {
 			c.skipNinja = true
@@ -576,7 +576,11 @@
 			c.skipConfig = true
 			c.skipKati = true
 		} else if arg == "--skip-kati" {
+			// TODO: remove --skip-kati once module builds have been migrated to --song-only
 			c.skipKati = true
+		} else if arg == "--soong-only" {
+			c.skipKati = true
+			c.skipKatiNinja = true
 		} else if arg == "--skip-soong-tests" {
 			c.skipSoongTests = true
 		} else if len(arg) > 0 && arg[0] == '-' {
@@ -792,10 +796,18 @@
 	return c.skipKati
 }
 
+func (c *configImpl) SkipKatiNinja() bool {
+	return c.skipKatiNinja
+}
+
 func (c *configImpl) SkipNinja() bool {
 	return c.skipNinja
 }
 
+func (c *configImpl) SetSkipNinja(v bool) {
+	c.skipNinja = v
+}
+
 func (c *configImpl) SkipConfig() bool {
 	return c.skipConfig
 }