Merge changes I1d6750db,Ie2c197bb,I6a51c89a

* changes:
  Add TransitivePackagingSpecs
  Add executable flag to sbox copy requests
  Export files to install as a depset
diff --git a/android/androidmk.go b/android/androidmk.go
index 42c5d00..b32048a 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -141,7 +141,7 @@
 }
 
 type AndroidMkExtraEntriesFunc func(entries *AndroidMkEntries)
-type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries)
+type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string)
 
 // Utility funcs to manipulate Android.mk variable entries.
 
@@ -554,7 +554,7 @@
 	fmt.Fprintln(&a.footer, "include "+a.Include)
 	blueprintDir := filepath.Dir(bpPath)
 	for _, footerFunc := range a.ExtraFooters {
-		footerFunc(&a.footer, name, prefix, blueprintDir, a)
+		footerFunc(&a.footer, name, prefix, blueprintDir)
 	}
 }
 
diff --git a/android/config.go b/android/config.go
index 9882d55..453e074 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1272,6 +1272,10 @@
 	return Bool(c.productVariables.Flatten_apex)
 }
 
+func (c *config) CompressedApex() bool {
+	return Bool(c.productVariables.CompressedApex)
+}
+
 func (c *config) EnforceSystemCertificate() bool {
 	return Bool(c.productVariables.EnforceSystemCertificate)
 }
diff --git a/android/makefile_goal.go b/android/makefile_goal.go
index b5d9d69..07354a6 100644
--- a/android/makefile_goal.go
+++ b/android/makefile_goal.go
@@ -80,7 +80,7 @@
 		Class:      "ETC",
 		OutputFile: OptionalPathForPath(p.outputFilePath),
 		ExtraFooters: []AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) {
+			func(w io.Writer, name, prefix, moduleDir string) {
 				// Can't use Cp because inputPath() is not a valid Path.
 				fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
 			},
diff --git a/android/mutator.go b/android/mutator.go
index 7a10477..31edea3 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -44,6 +44,11 @@
 	}
 }
 
+func registerMutatorsForBazelConversion(ctx *blueprint.Context) {
+	// FIXME(b/171263886): Start bringing in mutators to make the Bionic
+	// module subgraph suitable for automated conversion.
+}
+
 func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) {
 	mctx := &registerMutatorsContext{}
 
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 294a6e0..bb98ed4 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -178,6 +178,9 @@
 	srcPropertyName := proptools.PropertyNameForField(srcField)
 
 	srcsSupplier := func(ctx BaseModuleContext) []string {
+		if !module.Enabled() {
+			return nil
+		}
 		value := srcPropsValue.FieldByIndex(srcFieldIndex)
 		if value.Kind() == reflect.Ptr {
 			value = value.Elem()
diff --git a/android/queryview.go b/android/queryview.go
index 970ae01..1b7e77d 100644
--- a/android/queryview.go
+++ b/android/queryview.go
@@ -26,15 +26,40 @@
 // for calling the soong_build primary builder in the main build.ninja file.
 func init() {
 	RegisterSingletonType("bazel_queryview", BazelQueryViewSingleton)
+	RegisterSingletonType("bazel_converter", BazelConverterSingleton)
 }
 
+// BazelQueryViewSingleton is the singleton responsible for registering the
+// soong_build build statement that will convert the Soong module graph after
+// applying *all* mutators, enabing the feature to query the final state of the
+// Soong graph. This mode is meant for querying the build graph state, and not meant
+// for generating BUILD files to be checked in.
 func BazelQueryViewSingleton() Singleton {
 	return &bazelQueryViewSingleton{}
 }
 
-type bazelQueryViewSingleton struct{}
+// BazelConverterSingleton is the singleton responsible for registering the soong_build
+// build statement that will convert the Soong module graph by applying an alternate
+// pipeline of mutators, with the goal of reaching semantic equivalence between the original
+// Blueprint and final BUILD files. Using this mode, the goal is to be able to
+// build with these BUILD files directly in the source tree.
+func BazelConverterSingleton() Singleton {
+	return &bazelConverterSingleton{}
+}
 
-func (c *bazelQueryViewSingleton) GenerateBuildActions(ctx SingletonContext) {
+type bazelQueryViewSingleton struct{}
+type bazelConverterSingleton struct{}
+
+func generateBuildActionsForBazelConversion(ctx SingletonContext, converterMode bool) {
+	name := "queryview"
+	additionalEnvVars := ""
+	descriptionTemplate := "[EXPERIMENTAL, PRE-PRODUCTION] Creating the Bazel QueryView workspace with %s at $outDir"
+	if converterMode {
+		name = "bp2build"
+		additionalEnvVars = "CONVERT_TO_BAZEL=true"
+		descriptionTemplate = "[EXPERIMENTAL, PRE-PRODUCTION] Converting all Android.bp to Bazel BUILD files with %s at $outDir"
+	}
+
 	// Create a build and rule statement, using the Bazel QueryView's WORKSPACE
 	// file as the output file marker.
 	var deps Paths
@@ -42,22 +67,23 @@
 	deps = append(deps, moduleListFilePath)
 	deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName))
 
-	bazelQueryViewDirectory := PathForOutput(ctx, "queryview")
+	bazelQueryViewDirectory := PathForOutput(ctx, name)
 	bazelQueryViewWorkspaceFile := bazelQueryViewDirectory.Join(ctx, "WORKSPACE")
 	primaryBuilder := primaryBuilderPath(ctx)
 	bazelQueryView := ctx.Rule(pctx, "bazelQueryView",
 		blueprint.RuleParams{
 			Command: fmt.Sprintf(
 				"rm -rf ${outDir}/* && "+
-					"%s --bazel_queryview_dir ${outDir} %s && "+
+					"%s %s --bazel_queryview_dir ${outDir} %s && "+
 					"echo WORKSPACE: `cat %s` > ${outDir}/.queryview-depfile.d",
+				additionalEnvVars,
 				primaryBuilder.String(),
 				strings.Join(os.Args[1:], " "),
 				moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile.
 			),
 			CommandDeps: []string{primaryBuilder.String()},
 			Description: fmt.Sprintf(
-				"[EXPERIMENTAL, PRE-PRODUCTION] Creating the Bazel QueryView workspace with %s at $outDir",
+				descriptionTemplate,
 				primaryBuilder.Base()),
 			Deps:    blueprint.DepsGCC,
 			Depfile: "${outDir}/.queryview-depfile.d",
@@ -73,6 +99,14 @@
 		},
 	})
 
-	// Add a phony target for building the Bazel QueryView
-	ctx.Phony("queryview", bazelQueryViewWorkspaceFile)
+	// Add a phony target for generating the workspace
+	ctx.Phony(name, bazelQueryViewWorkspaceFile)
+}
+
+func (c *bazelQueryViewSingleton) GenerateBuildActions(ctx SingletonContext) {
+	generateBuildActionsForBazelConversion(ctx, false)
+}
+
+func (c *bazelConverterSingleton) GenerateBuildActions(ctx SingletonContext) {
+	generateBuildActionsForBazelConversion(ctx, true)
 }
diff --git a/android/register.go b/android/register.go
index 08e47b3..b26f9b9 100644
--- a/android/register.go
+++ b/android/register.go
@@ -90,6 +90,21 @@
 	return ctx
 }
 
+// RegisterForBazelConversion registers an alternate shadow pipeline of
+// singletons, module types and mutators to register for converting Blueprint
+// files to semantically equivalent BUILD files.
+func (ctx *Context) RegisterForBazelConversion() {
+	for _, t := range moduleTypes {
+		ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
+	}
+
+	bazelConverterSingleton := singleton{"bp2build", BazelConverterSingleton}
+	ctx.RegisterSingletonType(bazelConverterSingleton.name,
+		SingletonFactoryAdaptor(ctx, bazelConverterSingleton.factory))
+
+	registerMutatorsForBazelConversion(ctx.Context)
+}
+
 func (ctx *Context) Register() {
 	for _, t := range preSingletons {
 		ctx.RegisterPreSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
diff --git a/android/variable.go b/android/variable.go
index 0df5272..aed145c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -319,8 +319,9 @@
 	Ndk_abis               *bool `json:",omitempty"`
 	Exclude_draft_ndk_apis *bool `json:",omitempty"`
 
-	Flatten_apex *bool `json:",omitempty"`
-	Aml_abis     *bool `json:",omitempty"`
+	Flatten_apex   *bool `json:",omitempty"`
+	CompressedApex *bool `json:",omitempty"`
+	Aml_abis       *bool `json:",omitempty"`
 
 	DexpreoptGlobalConfig *string `json:",omitempty"`
 
diff --git a/androidmk/parser/make_strings.go b/androidmk/parser/make_strings.go
index 4b782a2..3c4815e 100644
--- a/androidmk/parser/make_strings.go
+++ b/androidmk/parser/make_strings.go
@@ -15,8 +15,10 @@
 package parser
 
 import (
+	"fmt"
 	"strings"
 	"unicode"
+	"unicode/utf8"
 )
 
 // A MakeString is a string that may contain variable substitutions in it.
@@ -130,8 +132,85 @@
 	})
 }
 
+// Words splits MakeString into multiple makeStrings separated by whitespace.
+// Thus, " a $(X)b  c " will be split into ["a", "$(X)b", "c"].
+// Splitting a MakeString consisting solely of whitespace yields empty array.
 func (ms *MakeString) Words() []*MakeString {
-	return ms.splitNFunc(-1, splitWords)
+	var ch rune    // current character
+	const EOF = -1 // no more characters
+	const EOS = -2 // at the end of a string chunk
+
+	// Next character's chunk and position
+	iString := 0
+	iChar := 0
+
+	var words []*MakeString
+	word := SimpleMakeString("", ms.Pos())
+
+	nextChar := func() {
+		if iString >= len(ms.Strings) {
+			ch = EOF
+		} else if iChar >= len(ms.Strings[iString]) {
+			iString++
+			iChar = 0
+			ch = EOS
+		} else {
+			var w int
+			ch, w = utf8.DecodeRuneInString(ms.Strings[iString][iChar:])
+			iChar += w
+		}
+	}
+
+	appendVariableAndAdvance := func() {
+		if iString-1 < len(ms.Variables) {
+			word.appendVariable(ms.Variables[iString-1])
+		}
+		nextChar()
+	}
+
+	appendCharAndAdvance := func(c rune) {
+		if c != EOF {
+			word.appendString(string(c))
+		}
+		nextChar()
+	}
+
+	nextChar()
+	for ch != EOF {
+		// Skip whitespace
+		for ch == ' ' || ch == '\t' {
+			nextChar()
+		}
+		if ch == EOS {
+			// "... $(X)... " case. The current word should be empty.
+			if !word.Empty() {
+				panic(fmt.Errorf("%q: EOS while current word %q is not empty, iString=%d",
+					ms.Dump(), word.Dump(), iString))
+			}
+			appendVariableAndAdvance()
+		}
+		// Copy word
+		for ch != EOF {
+			if ch == ' ' || ch == '\t' {
+				words = append(words, word)
+				word = SimpleMakeString("", ms.Pos())
+				break
+			}
+			if ch == EOS {
+				// "...a$(X)..." case. Append variable to the current word
+				appendVariableAndAdvance()
+			} else {
+				if ch == '\\' {
+					appendCharAndAdvance('\\')
+				}
+				appendCharAndAdvance(ch)
+			}
+		}
+	}
+	if !word.Empty() {
+		words = append(words, word)
+	}
+	return words
 }
 
 func (ms *MakeString) splitNFunc(n int, splitFunc func(s string, n int) []string) []*MakeString {
@@ -166,9 +245,7 @@
 		}
 	}
 
-	if !curMs.Empty() {
-		ret = append(ret, curMs)
-	}
+	ret = append(ret, curMs)
 	return ret
 }
 
@@ -219,44 +296,6 @@
 	return ret
 }
 
-func splitWords(s string, n int) []string {
-	ret := []string{}
-	preserve := ""
-	for n == -1 || n > 1 {
-		index := strings.IndexAny(s, " \t")
-		if index == 0 && len(preserve) == 0 {
-			s = s[1:]
-		} else if index >= 0 {
-			escapeCount := 0
-			for i := index - 1; i >= 0; i-- {
-				if s[i] != '\\' {
-					break
-				}
-				escapeCount += 1
-			}
-
-			if escapeCount%2 == 1 {
-				preserve += s[0 : index+1]
-				s = s[index+1:]
-				continue
-			}
-
-			ret = append(ret, preserve+s[0:index])
-			s = s[index+1:]
-			preserve = ""
-			if n > 0 {
-				n--
-			}
-		} else {
-			break
-		}
-	}
-	if preserve != "" || s != "" || len(ret) == 0 {
-		ret = append(ret, preserve+s)
-	}
-	return ret
-}
-
 func unescape(s string) string {
 	ret := ""
 	for {
diff --git a/androidmk/parser/make_strings_test.go b/androidmk/parser/make_strings_test.go
index 6995e89..fbb289b 100644
--- a/androidmk/parser/make_strings_test.go
+++ b/androidmk/parser/make_strings_test.go
@@ -26,64 +26,53 @@
 	n        int
 }{
 	{
-		in: &MakeString{
-			Strings: []string{
-				"a b c",
-				"d e f",
-				" h i j",
-			},
-			Variables: []Variable{
-				Variable{Name: SimpleMakeString("var1", NoPos)},
-				Variable{Name: SimpleMakeString("var2", NoPos)},
-			},
-		},
+		// "a b c$(var1)d e f$(var2) h i j"
+		in:  genMakeString("a b c", "var1", "d e f", "var2", " h i j"),
 		sep: " ",
 		n:   -1,
 		expected: []*MakeString{
-			SimpleMakeString("a", NoPos),
-			SimpleMakeString("b", NoPos),
-			&MakeString{
-				Strings: []string{"c", "d"},
-				Variables: []Variable{
-					Variable{Name: SimpleMakeString("var1", NoPos)},
-				},
-			},
-			SimpleMakeString("e", NoPos),
-			&MakeString{
-				Strings: []string{"f", ""},
-				Variables: []Variable{
-					Variable{Name: SimpleMakeString("var2", NoPos)},
-				},
-			},
-			SimpleMakeString("h", NoPos),
-			SimpleMakeString("i", NoPos),
-			SimpleMakeString("j", NoPos),
+			genMakeString("a"),
+			genMakeString("b"),
+			genMakeString("c", "var1", "d"),
+			genMakeString("e"),
+			genMakeString("f", "var2", ""),
+			genMakeString("h"),
+			genMakeString("i"),
+			genMakeString("j"),
 		},
 	},
 	{
-		in: &MakeString{
-			Strings: []string{
-				"a b c",
-				"d e f",
-				" h i j",
-			},
-			Variables: []Variable{
-				Variable{Name: SimpleMakeString("var1", NoPos)},
-				Variable{Name: SimpleMakeString("var2", NoPos)},
-			},
-		},
+		// "a b c$(var1)d e f$(var2) h i j"
+		in:  genMakeString("a b c", "var1", "d e f", "var2", " h i j"),
 		sep: " ",
 		n:   3,
 		expected: []*MakeString{
-			SimpleMakeString("a", NoPos),
-			SimpleMakeString("b", NoPos),
-			&MakeString{
-				Strings: []string{"c", "d e f", " h i j"},
-				Variables: []Variable{
-					Variable{Name: SimpleMakeString("var1", NoPos)},
-					Variable{Name: SimpleMakeString("var2", NoPos)},
-				},
-			},
+			genMakeString("a"),
+			genMakeString("b"),
+			genMakeString("c", "var1", "d e f", "var2", " h i j"),
+		},
+	},
+	{
+		// "$(var1) $(var2)"
+		in:  genMakeString("", "var1", " ", "var2", ""),
+		sep: " ",
+		n:   -1,
+		expected: []*MakeString{
+			genMakeString("", "var1", ""),
+			genMakeString("", "var2", ""),
+		},
+	},
+	{
+		// "a,,b,c,"
+		in:  genMakeString("a,,b,c,"),
+		sep: ",",
+		n:   -1,
+		expected: []*MakeString{
+			genMakeString("a"),
+			genMakeString(""),
+			genMakeString("b"),
+			genMakeString("c"),
+			genMakeString(""),
 		},
 	},
 }
@@ -104,15 +93,15 @@
 	expected string
 }{
 	{
-		in:       SimpleMakeString("a b", NoPos),
+		in:       genMakeString("a b"),
 		expected: "a b",
 	},
 	{
-		in:       SimpleMakeString("a\\ \\\tb\\\\", NoPos),
+		in:       genMakeString("a\\ \\\tb\\\\"),
 		expected: "a \tb\\",
 	},
 	{
-		in:       SimpleMakeString("a\\b\\", NoPos),
+		in:       genMakeString("a\\b\\"),
 		expected: "a\\b\\",
 	},
 }
@@ -131,31 +120,88 @@
 	expected []*MakeString
 }{
 	{
-		in:       SimpleMakeString("", NoPos),
+		in:       genMakeString(""),
 		expected: []*MakeString{},
 	},
 	{
-		in: SimpleMakeString(" a b\\ c d", NoPos),
+		in: genMakeString(` a b\ c d`),
 		expected: []*MakeString{
-			SimpleMakeString("a", NoPos),
-			SimpleMakeString("b\\ c", NoPos),
-			SimpleMakeString("d", NoPos),
+			genMakeString("a"),
+			genMakeString(`b\ c`),
+			genMakeString("d"),
 		},
 	},
 	{
-		in: SimpleMakeString("  a\tb\\\t\\ c d  ", NoPos),
+		in: SimpleMakeString("  a\tb"+`\`+"\t"+`\ c d  `, NoPos),
 		expected: []*MakeString{
-			SimpleMakeString("a", NoPos),
-			SimpleMakeString("b\\\t\\ c", NoPos),
-			SimpleMakeString("d", NoPos),
+			genMakeString("a"),
+			genMakeString("b" + `\` + "\t" + `\ c`),
+			genMakeString("d"),
 		},
 	},
 	{
-		in: SimpleMakeString(`a\\ b\\\ c d`, NoPos),
+		in: genMakeString(`a\\ b\\\ c d`),
 		expected: []*MakeString{
-			SimpleMakeString(`a\\`, NoPos),
-			SimpleMakeString(`b\\\ c`, NoPos),
-			SimpleMakeString("d", NoPos),
+			genMakeString(`a\\`),
+			genMakeString(`b\\\ c`),
+			genMakeString("d"),
+		},
+	},
+	{
+		in: genMakeString(`\\ a`),
+		expected: []*MakeString{
+			genMakeString(`\\`),
+			genMakeString("a"),
+		},
+	},
+	{
+		// "  "
+		in: &MakeString{
+			Strings:   []string{" \t \t"},
+			Variables: nil,
+		},
+		expected: []*MakeString{},
+	},
+	{
+		// " a $(X)b c "
+		in: genMakeString(" a ", "X", "b c "),
+		expected: []*MakeString{
+			genMakeString("a"),
+			genMakeString("", "X", "b"),
+			genMakeString("c"),
+		},
+	},
+	{
+		// " a b$(X)c d"
+		in: genMakeString(" a b", "X", "c d"),
+		expected: []*MakeString{
+			genMakeString("a"),
+			genMakeString("b", "X", "c"),
+			genMakeString("d"),
+		},
+	},
+	{
+		// "$(X) $(Y)"
+		in: genMakeString("", "X", " ", "Y", ""),
+		expected: []*MakeString{
+			genMakeString("", "X", ""),
+			genMakeString("", "Y", ""),
+		},
+	},
+	{
+		// " a$(X) b"
+		in: genMakeString(" a", "X", " b"),
+		expected: []*MakeString{
+			genMakeString("a", "X", ""),
+			genMakeString("b"),
+		},
+	},
+	{
+		// "a$(X) b$(Y) "
+		in: genMakeString("a", "X", " b", "Y", " "),
+		expected: []*MakeString{
+			genMakeString("a", "X", ""),
+			genMakeString("b", "Y", ""),
 		},
 	},
 }
@@ -180,3 +226,20 @@
 
 	return strings.Join(ret, "|||")
 }
+
+// generates MakeString from alternating string chunks and variable names,
+// e.g., genMakeString("a", "X", "b") returns MakeString for "a$(X)b"
+func genMakeString(items ...string) *MakeString {
+	n := len(items) / 2
+	if len(items) != (2*n + 1) {
+		panic("genMakeString expects odd number of arguments")
+	}
+
+	ms := &MakeString{Strings: make([]string, n+1), Variables: make([]Variable, n)}
+	ms.Strings[0] = items[0]
+	for i := 1; i <= n; i++ {
+		ms.Variables[i-1] = Variable{Name: SimpleMakeString(items[2*i-1], NoPos)}
+		ms.Strings[i] = items[2*i]
+	}
+	return ms
+}
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index c14910a..5afef65 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -553,12 +553,14 @@
 	"else",
 	"endef",
 	"endif",
+	"export",
 	"ifdef",
 	"ifeq",
 	"ifndef",
 	"ifneq",
 	"include",
 	"-include",
+	"unexport",
 }
 
 var functions = [...]string{
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 5b8563d..a2f8797 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -132,6 +132,7 @@
 brotli-java(minSdkVersion:current)
 captiveportal-lib(minSdkVersion:29)
 car-ui-lib(minSdkVersion:28)
+car-ui-lib-overlayable(minSdkVersion:28)
 CellBroadcastApp(minSdkVersion:29)
 CellBroadcastServiceModule(minSdkVersion:29)
 codecs_g711dec(minSdkVersion:29)
@@ -333,6 +334,7 @@
 libminijail_gen_syscall_obj(minSdkVersion:29)
 libminijail_generated(minSdkVersion:29)
 libmkvextractor(minSdkVersion:29)
+libmodules-utils-build(minSdkVersion:29)
 libmp3extractor(minSdkVersion:29)
 libmp4extractor(minSdkVersion:29)
 libmpeg2dec(minSdkVersion:29)
@@ -446,6 +448,7 @@
 neuralnetworks_utils_hal_1_2(minSdkVersion:30)
 neuralnetworks_utils_hal_1_3(minSdkVersion:30)
 neuralnetworks_utils_hal_common(minSdkVersion:30)
+neuralnetworks_utils_hal_service(minSdkVersion:30)
 PermissionController(minSdkVersion:28)
 permissioncontroller-statsd(minSdkVersion:current)
 philox_random(minSdkVersion:(no version))
diff --git a/apex/androidmk.go b/apex/androidmk.go
index da38c2a..6c76ad3f 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -360,7 +360,11 @@
 				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
 				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
 				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
-				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
+				stemSuffix := apexType.suffix()
+				if a.isCompressed {
+					stemSuffix = ".capex"
+				}
+				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+stemSuffix)
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
 
 				// Because apex writes .mk with Custom(), we need to write manually some common properties
diff --git a/apex/apex.go b/apex/apex.go
index 72f3db1..dae0f26 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -120,6 +120,12 @@
 	// Default: true.
 	Installable *bool
 
+	// Whether this APEX can be compressed or not. Setting this property to false means this
+	// APEX will never be compressed. When set to true, APEX will be compressed if other
+	// conditions, e.g, target device needs to support APEX compression, are also fulfilled.
+	// Default: true.
+	Compressible *bool
+
 	// For native libraries and binaries, use the vendor variant instead of the core (platform)
 	// variant. Default is false. DO NOT use this for APEXes that are installed to the system or
 	// system_ext partition.
@@ -354,6 +360,8 @@
 
 	prebuiltFileToDelete string
 
+	isCompressed bool
+
 	// Path of API coverage generate file
 	coverageOutputPath android.ModuleOutPath
 }
@@ -1666,7 +1674,7 @@
 							// system libraries.
 							if !am.DirectlyInAnyApex() {
 								// we need a module name for Make
-								name := cc.ImplementationModuleName(ctx)
+								name := cc.ImplementationModuleNameForMake(ctx)
 
 								if !proptools.Bool(a.properties.Use_vendor) {
 									// we don't use subName(.vendor) for a "use_vendor: true" apex
@@ -1681,6 +1689,19 @@
 							// Don't track further
 							return false
 						}
+
+						// If the dep is not considered to be in the same
+						// apex, don't add it to filesInfo so that it is not
+						// included in this APEX.
+						// TODO(jiyong): move this to at the top of the
+						// else-if clause for the indirect dependencies.
+						// Currently, that's impossible because we would
+						// like to record requiredNativeLibs even when
+						// DepIsInSameAPex is false.
+						if !am.DepIsInSameApex(ctx, am) {
+							return false
+						}
+
 						filesInfo = append(filesInfo, af)
 						return true // track transitive dependencies
 					}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index cc05fd4..16c01ca 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -346,6 +346,13 @@
 	}
 }
 
+func ensureListNotEmpty(t *testing.T, result []string) {
+	t.Helper()
+	if len(result) == 0 {
+		t.Errorf("%q is expected to be not empty", result)
+	}
+}
+
 // Minimal test
 func TestBasicApex(t *testing.T) {
 	ctx, config := testApex(t, `
@@ -5964,9 +5971,27 @@
 			srcs: ["mylib.cpp"],
 			system_shared_libs: [],
 			stl: "none",
-			shared_libs: ["mylib", "myprivlib"],
+			shared_libs: ["mylib", "myprivlib", "mytestlib"],
 			test_for: ["myapex"]
 		}
+
+		cc_library {
+			name: "mytestlib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			shared_libs: ["mylib", "myprivlib"],
+			stl: "none",
+			test_for: ["myapex"],
+		}
+
+		cc_benchmark {
+			name: "mybench",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			shared_libs: ["mylib", "myprivlib"],
+			stl: "none",
+			test_for: ["myapex"],
+		}
 	`)
 
 	// the test 'mytest' is a test for the apex, therefore is linked to the
@@ -5974,6 +5999,16 @@
 	ldFlags := ctx.ModuleForTests("mytest", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
 	ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so")
 	ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
+
+	// The same should be true for cc_library
+	ldFlags = ctx.ModuleForTests("mytestlib", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
+	ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so")
+	ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
+
+	// ... and for cc_benchmark
+	ldFlags = ctx.ModuleForTests("mybench", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
+	ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so")
+	ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
 }
 
 // TODO(jungjw): Move this to proptools
@@ -6186,6 +6221,140 @@
 	`)
 }
 
+func TestCompressedApex(t *testing.T) {
+	ctx, config := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			compressible: true,
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`, func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.CompressedApex = proptools.BoolPtr(true)
+	})
+
+	compressRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("compressRule")
+	ensureContains(t, compressRule.Output.String(), "myapex.capex.unsigned")
+
+	signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("sign compressedApex")
+	ensureEquals(t, signApkRule.Input.String(), compressRule.Output.String())
+
+	// Make sure output of bundle is .capex
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	ensureContains(t, ab.outputFile.String(), "myapex.capex")
+
+	// Verify android.mk rules
+	data := android.AndroidMkDataForTest(t, config, "", ab)
+	var builder strings.Builder
+	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.capex\n")
+}
+
+func TestPreferredPrebuiltSharedLibDep(t *testing.T) {
+	ctx, config := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			apex_available: ["myapex"],
+			shared_libs: ["otherlib"],
+			system_shared_libs: [],
+		}
+
+		cc_library {
+			name: "otherlib",
+			srcs: ["mylib.cpp"],
+			stubs: {
+				versions: ["current"],
+			},
+		}
+
+		cc_prebuilt_library_shared {
+			name: "otherlib",
+			prefer: true,
+			srcs: ["prebuilt.so"],
+			stubs: {
+				versions: ["current"],
+			},
+		}
+	`)
+
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	data := android.AndroidMkDataForTest(t, config, "", ab)
+	var builder strings.Builder
+	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
+	androidMk := builder.String()
+
+	// The make level dependency needs to be on otherlib - prebuilt_otherlib isn't
+	// a thing there.
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherlib\n")
+}
+
+func TestExcludeDependency(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: ["myapex"],
+			shared_libs: ["mylib2"],
+			target: {
+				apex: {
+					exclude_shared_libs: ["mylib2"],
+				},
+			},
+		}
+
+		cc_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	// Check if mylib is linked to mylib2 for the non-apex target
+	ldFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
+	ensureContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+
+	// Make sure that the link doesn't occur for the apex target
+	ldFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
+	ensureNotContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared_apex10000/mylib2.so")
+
+	// It shouldn't appear in the copy cmd as well.
+	copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule").Args["copy_commands"]
+	ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 66eaff1..9db8e59 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -66,6 +66,7 @@
 	pctx.HostBinToolVariable("extract_apks", "extract_apks")
 	pctx.HostBinToolVariable("make_f2fs", "make_f2fs")
 	pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
+	pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool")
 	pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
 }
 
@@ -738,7 +739,7 @@
 
 	////////////////////////////////////////////////////////////////////////////////////
 	// Step 4: Sign the APEX using signapk
-	a.outputFile = android.PathForModuleOut(ctx, a.Name()+suffix)
+	signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix)
 
 	pem, key := a.getCertificateAndPrivateKey(ctx)
 	rule := java.Signapk
@@ -750,16 +751,47 @@
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
 		rule = java.SignapkRE
 		args["implicits"] = strings.Join(implicits.Strings(), ",")
-		args["outCommaList"] = a.outputFile.String()
+		args["outCommaList"] = signedOutputFile.String()
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "signapk",
-		Output:      a.outputFile,
+		Output:      signedOutputFile,
 		Input:       unsignedOutputFile,
 		Implicits:   implicits,
 		Args:        args,
 	})
+	a.outputFile = signedOutputFile
+
+	// Process APEX compression if enabled
+	compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, true)
+	if compressionEnabled && apexType == imageApex {
+		a.isCompressed = true
+		unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+".capex.unsigned")
+
+		compressRule := android.NewRuleBuilder(pctx, ctx)
+		compressRule.Command().
+			Text("rm").
+			FlagWithOutput("-f ", unsignedCompressedOutputFile)
+		compressRule.Command().
+			BuiltTool("apex_compression_tool").
+			Flag("compress").
+			FlagWithArg("--apex_compression_tool ", outHostBinDir+":"+prebuiltSdkToolsBinDir).
+			FlagWithInput("--input ", signedOutputFile).
+			FlagWithOutput("--output ", unsignedCompressedOutputFile)
+		compressRule.Build("compressRule", "Generate unsigned compressed APEX file")
+
+		signedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+".capex")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        rule,
+			Description: "sign compressedApex",
+			Output:      signedCompressedOutputFile,
+			Input:       unsignedCompressedOutputFile,
+			Implicits:   implicits,
+			Args:        args,
+		})
+		a.outputFile = signedCompressedOutputFile
+	}
 
 	// Install to $OUT/soong/{target,host}/.../apex
 	if a.installable() {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 320e69b..9b61e55 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -130,7 +130,7 @@
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			func(w io.Writer, name, prefix, moduleDir string) {
 				if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
 					c.CcLibraryInterface() && c.Shared() {
 					// Using the SDK variant as a JNI library needs a copy of the .so that
@@ -296,7 +296,7 @@
 func (object *objectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	entries.Class = "STATIC_LIBRARIES"
 	entries.ExtraFooters = append(entries.ExtraFooters,
-		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+		func(w io.Writer, name, prefix, moduleDir string) {
 			out := entries.OutputFile.Path()
 			varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
 
@@ -574,7 +574,7 @@
 	}
 
 	entries.ExtraFooters = append(entries.ExtraFooters,
-		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+		func(w io.Writer, name, prefix, moduleDir string) {
 			out := entries.OutputFile.Path()
 			varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
 
diff --git a/cc/builder.go b/cc/builder.go
index 439e372..9cd78d5 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -235,6 +235,7 @@
 		}, &remoteexec.REParams{
 			Labels:       map[string]string{"type": "abi-dump", "tool": "header-abi-dumper"},
 			ExecStrategy: "${config.REAbiDumperExecStrategy}",
+			Inputs:       []string{"$sAbiLinkerLibs"},
 			Platform: map[string]string{
 				remoteexec.PoolKey: "${config.RECXXPool}",
 			},
@@ -568,8 +569,11 @@
 			ccCmd = "clang++"
 			moduleFlags = cppflags
 			moduleToolingFlags = toolingCppflags
+		case ".h", ".hpp":
+			ctx.PropertyErrorf("srcs", "Header file %s is not supported, instead use export_include_dirs or local_include_dirs.", srcFile)
+			continue
 		default:
-			ctx.ModuleErrorf("File %s has unknown extension", srcFile)
+			ctx.PropertyErrorf("srcs", "File %s has unknown extension. Supported extensions: .s, .S, .c, .cpp, .cc, .cxx, .mm", srcFile)
 			continue
 		}
 
diff --git a/cc/cc.go b/cc/cc.go
index f62df3c..ae75c1d 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -129,6 +129,9 @@
 	// Used for host bionic
 	LinkerFlagsFile string
 	DynamicLinker   string
+
+	// List of libs that need to be excluded for APEX variant
+	ExcludeLibsForApex []string
 }
 
 // PathDeps is a struct containing file paths to dependencies of a module.
@@ -332,6 +335,11 @@
 	// framework module from a snapshot.
 	Exclude_from_vendor_snapshot   *bool
 	Exclude_from_recovery_snapshot *bool
+
+	// List of APEXes that this module has private access to for testing purpose. The module
+	// can depend on libraries that are not exported by the APEXes and use private symbols
+	// from the exported libraries.
+	Test_for []string
 }
 
 type VendorProperties struct {
@@ -572,6 +580,9 @@
 	staticUnwinder bool
 
 	makeSuffix string
+
+	// Whether or not this dependency has to be followed for the apex variants
+	excludeInApex bool
 }
 
 // header returns true if the libraryDependencyTag is tagging a header lib dependency.
@@ -1099,6 +1110,19 @@
 	return name
 }
 
+// Similar to ImplementationModuleName, but uses the Make variant of the module
+// name as base name, for use in AndroidMk output. E.g. for a prebuilt module
+// where the Soong name is prebuilt_foo, this returns foo (which works in Make
+// under the premise that the prebuilt module overrides its source counterpart
+// if it is exposed to Make).
+func (c *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
+	name := c.BaseModuleName()
+	if versioned, ok := c.linker.(versionedInterface); ok {
+		name = versioned.implementationModuleName(name)
+	}
+	return name
+}
+
 func (c *Module) bootstrap() bool {
 	return Bool(c.Properties.Bootstrap)
 }
@@ -1937,6 +1961,9 @@
 		if inList(lib, deps.ReexportStaticLibHeaders) {
 			depTag.reexportFlags = true
 		}
+		if inList(lib, deps.ExcludeLibsForApex) {
+			depTag.excludeInApex = true
+		}
 
 		if impl, ok := syspropImplLibraries[lib]; ok {
 			lib = impl
@@ -1974,6 +2001,9 @@
 		if inList(lib, deps.ReexportSharedLibHeaders) {
 			depTag.reexportFlags = true
 		}
+		if inList(lib, deps.ExcludeLibsForApex) {
+			depTag.excludeInApex = true
+		}
 
 		if impl, ok := syspropImplLibraries[lib]; ok {
 			lib = impl
@@ -2257,8 +2287,8 @@
 // For example, with maxSdkVersion is 10 and versionList is [9,11]
 // it returns 9 as string.  The list of stubs must be in order from
 // oldest to newest.
-func (c *Module) chooseSdkVersion(ctx android.PathContext, stubsInfo []SharedLibraryStubsInfo,
-	maxSdkVersion android.ApiLevel) (SharedLibraryStubsInfo, error) {
+func (c *Module) chooseSdkVersion(ctx android.PathContext, stubsInfo []SharedStubLibrary,
+	maxSdkVersion android.ApiLevel) (SharedStubLibrary, error) {
 
 	for i := range stubsInfo {
 		stubInfo := stubsInfo[len(stubsInfo)-i-1]
@@ -2269,7 +2299,7 @@
 			var err error
 			ver, err = android.ApiLevelFromUser(ctx, stubInfo.Version)
 			if err != nil {
-				return SharedLibraryStubsInfo{}, err
+				return SharedStubLibrary{}, err
 			}
 		}
 		if ver.LessThanOrEqualTo(maxSdkVersion) {
@@ -2280,7 +2310,7 @@
 	for _, stubInfo := range stubsInfo {
 		versionList = append(versionList, stubInfo.Version)
 	}
-	return SharedLibraryStubsInfo{}, fmt.Errorf("not found a version(<=%s) in versionList: %v", maxSdkVersion.String(), versionList)
+	return SharedStubLibrary{}, fmt.Errorf("not found a version(<=%s) in versionList: %v", maxSdkVersion.String(), versionList)
 }
 
 // Convert dependencies to paths.  Returns a PathDeps containing paths
@@ -2403,6 +2433,10 @@
 				return
 			}
 
+			if !apexInfo.IsForPlatform() && libDepTag.excludeInApex {
+				return
+			}
+
 			depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
 
 			var ptr *android.Paths
@@ -2422,10 +2456,11 @@
 					}
 					return
 				}
-				sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
-				sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryImplementationStubsInfoProvider).(SharedLibraryImplementationStubsInfo)
 
-				if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedLibraryStubsInfos) > 0 {
+				sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
+				sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo)
+
+				if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
 					useStubs := false
 
 					if lib := moduleLibraryInterface(dep); lib.buildStubs() && c.UseVndk() { // LLNDK
@@ -2460,7 +2495,7 @@
 					// when to use (unspecified) stubs, check min_sdk_version and choose the right one
 					if useStubs {
 						sharedLibraryStubsInfo, err :=
-							c.chooseSdkVersion(ctx, sharedLibraryStubsInfo.SharedLibraryStubsInfos, c.apexSdkVersion)
+							c.chooseSdkVersion(ctx, sharedLibraryStubsInfo.SharedStubLibraries, c.apexSdkVersion)
 						if err != nil {
 							ctx.OtherModuleErrorf(dep, err.Error())
 							return
@@ -2922,13 +2957,7 @@
 }
 
 func (c *Module) TestFor() []string {
-	if test, ok := c.linker.(interface {
-		testFor() []string
-	}); ok {
-		return test.testFor()
-	} else {
-		return c.ApexModuleBase.TestFor()
-	}
+	return c.Properties.Test_for
 }
 
 func (c *Module) UniqueApexVariations() bool {
@@ -3002,6 +3031,10 @@
 			// linked; the dependency is used only during the compilation phase.
 			return false
 		}
+
+		if isLibDepTag && libDepTag.excludeInApex {
+			return false
+		}
 	}
 	if depTag == stubImplDepTag || depTag == llndkImplDep {
 		// We don't track beyond LLNDK or from an implementation library to its stubs.
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 563ce76..a548452 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -21,7 +21,6 @@
 	"android.hardware.automotive.occupant_awareness-ndk_platform",
 	"android.hardware.light-ndk_platform",
 	"android.hardware.identity-ndk_platform",
-	"android.hardware.keymint-ndk_platform",
 	"android.hardware.keymint-unstable-ndk_platform",
 	"android.hardware.nfc@1.2",
 	"android.hardware.power-ndk_platform",
diff --git a/cc/library.go b/cc/library.go
index c626b03..b796aaf 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -28,6 +28,7 @@
 	"android/soong/cc/config"
 )
 
+// LibraryProperties is a collection of properties shared by cc library rules.
 type LibraryProperties struct {
 	// local file name to pass to the linker as -unexported_symbols_list
 	Unexported_symbols_list *string `android:"path,arch_variant"`
@@ -115,14 +116,23 @@
 	Llndk_stubs *string
 }
 
+// StaticProperties is a properties stanza to affect only attributes of the "static" variants of a
+// library module.
 type StaticProperties struct {
 	Static StaticOrSharedProperties `android:"arch_variant"`
 }
 
+// SharedProperties is a properties stanza to affect only attributes of the "shared" variants of a
+// library module.
 type SharedProperties struct {
 	Shared StaticOrSharedProperties `android:"arch_variant"`
 }
 
+// StaticOrSharedProperties is an embedded struct representing properties to affect attributes of
+// either only the "static" variants or only the "shared" variants of a library module. These override
+// the base properties of the same name.
+// Use `StaticProperties` or `SharedProperties`, depending on which variant is needed.
+// `StaticOrSharedProperties` exists only to avoid duplication.
 type StaticOrSharedProperties struct {
 	Srcs []string `android:"path,arch_variant"`
 
@@ -242,16 +252,23 @@
 	return module.Init()
 }
 
+// flagExporter is a separated portion of libraryDecorator pertaining to exported
+// include paths and flags. Keeping this dependency-related information separate
+// from the rest of library information is helpful in keeping data more structured
+// and explicit.
 type flagExporter struct {
 	Properties FlagExporterProperties
 
-	dirs       android.Paths
-	systemDirs android.Paths
-	flags      []string
+	dirs       android.Paths // Include directories to be included with -I
+	systemDirs android.Paths // System include directories to be included with -isystem
+	flags      []string      // Exported raw flags.
 	deps       android.Paths
 	headers    android.Paths
 }
 
+// exportedIncludes returns the effective include paths for this module and
+// any module that links against this module. This is obtained from
+// the export_include_dirs property in the appropriate target stanza.
 func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths {
 	// TODO(b/150902910): product variant must use Target.Product
 	if ctx.useVndk() && f.Properties.Target.Vendor.Override_export_include_dirs != nil {
@@ -261,25 +278,35 @@
 	}
 }
 
+// exportIncludes registers the include directories and system include directories to be exported
+// transitively to modules depending on this module.
 func (f *flagExporter) exportIncludes(ctx ModuleContext) {
 	f.dirs = append(f.dirs, f.exportedIncludes(ctx)...)
 	f.systemDirs = append(f.systemDirs, android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)...)
 }
 
+// exportIncludesAsSystem registers the include directories and system include directories to be
+// exported transitively both as system include directories to modules depending on this module.
 func (f *flagExporter) exportIncludesAsSystem(ctx ModuleContext) {
 	// all dirs are force exported as system
 	f.systemDirs = append(f.systemDirs, f.exportedIncludes(ctx)...)
 	f.systemDirs = append(f.systemDirs, android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)...)
 }
 
+// reexportDirs registers the given directories as include directories to be exported transitively
+// to modules depending on this module.
 func (f *flagExporter) reexportDirs(dirs ...android.Path) {
 	f.dirs = append(f.dirs, dirs...)
 }
 
+// reexportSystemDirs registers the given directories as system include directories
+// to be exported transitively to modules depending on this module.
 func (f *flagExporter) reexportSystemDirs(dirs ...android.Path) {
 	f.systemDirs = append(f.systemDirs, dirs...)
 }
 
+// reexportFlags registers the flags to be exported transitively to modules depending on this
+// module.
 func (f *flagExporter) reexportFlags(flags ...string) {
 	if android.PrefixInList(flags, "-I") || android.PrefixInList(flags, "-isystem") {
 		panic(fmt.Errorf("Exporting invalid flag %q: "+
@@ -457,6 +484,8 @@
 	return l.collectedSnapshotHeaders
 }
 
+// linkerProps returns the list of properties structs relevant for this library. (For example, if
+// the library is cc_shared_library, then static-library properties are omitted.)
 func (library *libraryDecorator) linkerProps() []interface{} {
 	var props []interface{}
 	props = append(props, library.baseLinker.linkerProps()...)
@@ -476,6 +505,9 @@
 	return props
 }
 
+// linkerFlags takes a Flags struct and augments it to contain linker flags that are defined by this
+// library, or that are implied by attributes of this library (such as whether this library is a
+// shared library).
 func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = library.baseLinker.linkerFlags(ctx, flags)
 
@@ -526,6 +558,9 @@
 	return flags
 }
 
+// compilerFlags takes a Flags and augments it to contain compile flags from global values,
+// per-target values, module type values, per-module Blueprints properties, extra flags from
+// `flags`, and generated sources from `deps`.
 func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
 	exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 	if len(exportIncludeDirs) > 0 {
@@ -727,6 +762,8 @@
 	return name + suffix
 }
 
+// getLibName returns the actual canonical name of the library (the name which
+// should be passed to the linker via linker flags).
 func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
 	name := library.getLibNameHelper(ctx.baseModuleName(), ctx.useVndk())
 
@@ -1058,18 +1095,18 @@
 
 	stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
 	if len(stubs) > 0 {
-		var stubsInfo []SharedLibraryStubsInfo
+		var stubsInfo []SharedStubLibrary
 		for _, stub := range stubs {
 			stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
 			flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
-			stubsInfo = append(stubsInfo, SharedLibraryStubsInfo{
+			stubsInfo = append(stubsInfo, SharedStubLibrary{
 				Version:           moduleLibraryInterface(stub).stubsVersion(),
 				SharedLibraryInfo: stubInfo,
 				FlagExporterInfo:  flagInfo,
 			})
 		}
-		ctx.SetProvider(SharedLibraryImplementationStubsInfoProvider, SharedLibraryImplementationStubsInfo{
-			SharedLibraryStubsInfos: stubsInfo,
+		ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+			SharedStubLibraries: stubsInfo,
 
 			IsLLNDK: ctx.isLlndk(ctx.Config()),
 		})
@@ -1158,9 +1195,15 @@
 	}
 }
 
+// link registers actions to link this library, and sets various fields
+// on this library to reflect information that should be exported up the build
+// tree (for example, exported flags and include paths).
 func (library *libraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
+	// Linking this library consists of linking `deps.Objs` (.o files in dependencies
+	// of this library), together with `objs` (.o files created by compiling this
+	// library).
 	objs = deps.Objs.Copy().Append(objs)
 	var out android.Path
 	if library.static() || library.header() {
@@ -1169,6 +1212,7 @@
 		out = library.linkShared(ctx, flags, deps, objs)
 	}
 
+	// Export include paths and flags to be propagated up the tree.
 	library.exportIncludes(ctx)
 	library.reexportDirs(deps.ReexportedDirs...)
 	library.reexportSystemDirs(deps.ReexportedSystemDirs...)
@@ -1176,6 +1220,7 @@
 	library.reexportDeps(deps.ReexportedDeps...)
 	library.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
 
+	// Optionally export aidl headers.
 	if Bool(library.Properties.Aidl.Export_aidl_headers) {
 		if library.baseCompiler.hasSrcExt(".aidl") {
 			dir := android.PathForModuleGen(ctx, "aidl")
@@ -1187,6 +1232,7 @@
 		}
 	}
 
+	// Optionally export proto headers.
 	if Bool(library.Properties.Proto.Export_proto_headers) {
 		if library.baseCompiler.hasSrcExt(".proto") {
 			var includes android.Paths
@@ -1221,25 +1267,30 @@
 			}
 		}
 
+		// Add sysprop-related directories to the exported directories of this library.
 		library.reexportDirs(dir)
 		library.reexportDeps(library.baseCompiler.pathDeps...)
 		library.addExportedGeneratedHeaders(library.baseCompiler.pathDeps...)
 	}
 
+	// Add stub-related flags if this library is a stub library.
 	if library.buildStubs() && !library.skipAPIDefine {
 		library.reexportFlags("-D" + versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx)) + "=" + library.stubsVersion())
 	}
 
+	// Propagate a Provider containing information about exported flags, deps, and include paths.
 	library.flagExporter.setProvider(ctx)
 
 	return out
 }
 
+// buildStatic returns true if this library should be built as a static library.
 func (library *libraryDecorator) buildStatic() bool {
 	return library.MutatedProperties.BuildStatic &&
 		BoolDefault(library.StaticProperties.Static.Enabled, true)
 }
 
+// buildShared returns true if this library should be built as a shared library.
 func (library *libraryDecorator) buildShared() bool {
 	return library.MutatedProperties.BuildShared &&
 		BoolDefault(library.SharedProperties.Shared.Enabled, true)
@@ -1346,36 +1397,46 @@
 	return library.shared() || library.static()
 }
 
+// static returns true if this library is for a "static' variant.
 func (library *libraryDecorator) static() bool {
 	return library.MutatedProperties.VariantIsStatic
 }
 
+// shared returns true if this library is for a "shared' variant.
 func (library *libraryDecorator) shared() bool {
 	return library.MutatedProperties.VariantIsShared
 }
 
+// header returns true if this library is for a header-only variant.
 func (library *libraryDecorator) header() bool {
+	// Neither "static" nor "shared" implies this library is header-only.
 	return !library.static() && !library.shared()
 }
 
+// setStatic marks the library variant as "static".
 func (library *libraryDecorator) setStatic() {
 	library.MutatedProperties.VariantIsStatic = true
 	library.MutatedProperties.VariantIsShared = false
 }
 
+// setShared marks the library variant as "shared".
 func (library *libraryDecorator) setShared() {
 	library.MutatedProperties.VariantIsStatic = false
 	library.MutatedProperties.VariantIsShared = true
 }
 
+// BuildOnlyStatic disables building this library as a shared library.
 func (library *libraryDecorator) BuildOnlyStatic() {
 	library.MutatedProperties.BuildShared = false
 }
 
+// BuildOnlyShared disables building this library as a static library.
 func (library *libraryDecorator) BuildOnlyShared() {
 	library.MutatedProperties.BuildStatic = false
 }
 
+// HeaderOnly disables building this library as a shared or static library;
+// the library only exists to propagate header file dependencies up the build graph.
 func (library *libraryDecorator) HeaderOnly() {
 	library.MutatedProperties.BuildShared = false
 	library.MutatedProperties.BuildStatic = false
@@ -1458,6 +1519,17 @@
 
 var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
 
+// versioningMacroNamesList returns a singleton map, where keys are "version macro names",
+// and values are the module name responsible for registering the version macro name.
+//
+// Version macros are used when building against stubs, to provide version information about
+// the stub. Only stub libraries should have an entry in this list.
+//
+// For example, when building against libFoo#ver, __LIBFOO_API__ macro is set to ver so
+// that headers from libFoo can be conditionally compiled (this may hide APIs
+// that are not available for the version).
+//
+// This map is used to ensure that there aren't conflicts between these version macro names.
 func versioningMacroNamesList(config android.Config) *map[string]string {
 	return config.Once(versioningMacroNamesListKey, func() interface{} {
 		m := make(map[string]string)
@@ -1469,12 +1541,17 @@
 // other characters are all converted to _
 var charsNotForMacro = regexp.MustCompile("[^a-zA-Z0-9_]+")
 
+// versioningMacroName returns the canonical version macro name for the given module.
 func versioningMacroName(moduleName string) string {
 	macroName := charsNotForMacro.ReplaceAllString(moduleName, "_")
 	macroName = strings.ToUpper(macroName)
 	return "__" + macroName + "_API__"
 }
 
+// NewLibrary builds and returns a new Module corresponding to a C++ library.
+// Individual module implementations which comprise a C++ library (or something like
+// a C++ library) should call this function, set some fields on the result, and
+// then call the Init function.
 func NewLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
 	module := newModule(hod, android.MultilibBoth)
 
@@ -1530,6 +1607,8 @@
 	}
 }
 
+// LinkageMutator adds "static" or "shared" variants for modules depending
+// on whether the module can be built as a static library or a shared library.
 func LinkageMutator(mctx android.BottomUpMutatorContext) {
 	cc_prebuilt := false
 	if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
@@ -1607,6 +1686,9 @@
 	}
 }
 
+// normalizeVersions modifies `versions` in place, so that each raw version
+// string becomes its normalized canonical form.
+// Validates that the versions in `versions` are specified in least to greatest order.
 func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
 	var previous android.ApiLevel
 	for i, v := range versions {
diff --git a/cc/linkable.go b/cc/linkable.go
index 0609b28..ddf3950 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -6,6 +6,7 @@
 	"github.com/google/blueprint"
 )
 
+// LinkableInterface is an interface for a type of module that is linkable in a C++ library.
 type LinkableInterface interface {
 	Module() android.Module
 	CcLibrary() bool
@@ -51,23 +52,30 @@
 }
 
 var (
+	// Dependency tag for crtbegin, an object file responsible for initialization.
 	CrtBeginDepTag = dependencyTag{name: "crtbegin"}
-	CrtEndDepTag   = dependencyTag{name: "crtend"}
+	// Dependency tag for crtend, an object file responsible for program termination.
+	CrtEndDepTag = dependencyTag{name: "crtend"}
+	// Dependency tag for coverage library.
 	CoverageDepTag = dependencyTag{name: "coverage"}
 )
 
+// SharedDepTag returns the dependency tag for any C++ shared libraries.
 func SharedDepTag() blueprint.DependencyTag {
 	return libraryDependencyTag{Kind: sharedLibraryDependency}
 }
 
+// StaticDepTag returns the dependency tag for any C++ static libraries.
 func StaticDepTag() blueprint.DependencyTag {
 	return libraryDependencyTag{Kind: staticLibraryDependency}
 }
 
+// HeaderDepTag returns the dependency tag for any C++ "header-only" libraries.
 func HeaderDepTag() blueprint.DependencyTag {
 	return libraryDependencyTag{Kind: headerLibraryDependency}
 }
 
+// SharedLibraryInfo is a provider to propagate information about a shared C++ library.
 type SharedLibraryInfo struct {
 	SharedLibrary           android.Path
 	UnstrippedSharedLibrary android.Path
@@ -80,22 +88,30 @@
 
 var SharedLibraryInfoProvider = blueprint.NewProvider(SharedLibraryInfo{})
 
-type SharedLibraryImplementationStubsInfo struct {
-	SharedLibraryStubsInfos []SharedLibraryStubsInfo
-
-	IsLLNDK bool
-}
-
-var SharedLibraryImplementationStubsInfoProvider = blueprint.NewProvider(SharedLibraryImplementationStubsInfo{})
-
-type SharedLibraryStubsInfo struct {
+// SharedStubLibrary is a struct containing information about a stub shared library.
+// Stub libraries are used for cross-APEX dependencies; when a library is to depend on a shared
+// library in another APEX, it must depend on the stub version of that library.
+type SharedStubLibrary struct {
+	// The version of the stub (corresponding to the stable version of the shared library being
+	// stubbed).
 	Version           string
 	SharedLibraryInfo SharedLibraryInfo
 	FlagExporterInfo  FlagExporterInfo
 }
 
-var SharedLibraryStubsInfoProvider = blueprint.NewProvider(SharedLibraryStubsInfo{})
+// SharedLibraryStubsInfo is a provider to propagate information about all shared library stubs
+// which are dependencies of a library.
+// Stub libraries are used for cross-APEX dependencies; when a library is to depend on a shared
+// library in another APEX, it must depend on the stub version of that library.
+type SharedLibraryStubsInfo struct {
+	SharedStubLibraries []SharedStubLibrary
 
+	IsLLNDK bool
+}
+
+var SharedLibraryStubsProvider = blueprint.NewProvider(SharedLibraryStubsInfo{})
+
+// StaticLibraryInfo is a provider to propagate information about a static C++ library.
 type StaticLibraryInfo struct {
 	StaticLibrary android.Path
 	Objects       Objects
@@ -109,10 +125,12 @@
 
 var StaticLibraryInfoProvider = blueprint.NewProvider(StaticLibraryInfo{})
 
+// FlagExporterInfo is a provider to propagate transitive library information
+// pertaining to exported include paths and flags.
 type FlagExporterInfo struct {
-	IncludeDirs       android.Paths
-	SystemIncludeDirs android.Paths
-	Flags             []string
+	IncludeDirs       android.Paths // Include directories to be included with -I
+	SystemIncludeDirs android.Paths // System include directories to be included with -isystem
+	Flags             []string      // Exported raw flags.
 	Deps              android.Paths
 	GeneratedHeaders  android.Paths
 }
diff --git a/cc/linker.go b/cc/linker.go
index 9d4a643..7bc4105 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -174,6 +174,15 @@
 			// variants.
 			Shared_libs []string
 		}
+		Apex struct {
+			// list of shared libs that should not be used to build the apex variant of
+			// the C/C++ module.
+			Exclude_shared_libs []string
+
+			// list of static libs that should not be used to build the apex ramdisk
+			// variant of the C/C++ module.
+			Exclude_static_libs []string
+		}
 	}
 
 	// make android::build:GetBuildNumber() available containing the build ID.
@@ -240,6 +249,16 @@
 	deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Exclude_static_libs)
 	deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Exclude_static_libs)
 
+	// Record the libraries that need to be excluded when building for APEX. Unlike other
+	// target.*.exclude_* properties, SharedLibs and StaticLibs are not modified here because
+	// this module hasn't yet passed the apexMutator. Therefore, we can't tell whether this is
+	// an apex variant of not. Record the exclude list in the deps struct for now. The info is
+	// used to mark the dependency tag when adding dependencies to the deps. Then inside
+	// GenerateAndroidBuildActions, the marked dependencies are ignored (i.e. not used) for APEX
+	// variants.
+	deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_shared_libs...)
+	deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_static_libs...)
+
 	if Bool(linker.Properties.Use_version_lib) {
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs, "libbuildversion")
 	}
diff --git a/cc/test.go b/cc/test.go
index 3772691..a9be6f9 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -29,11 +29,6 @@
 
 	// if set, use the isolated gtest runner. Defaults to false.
 	Isolated *bool
-
-	// List of APEXes that this module tests. The module has access to
-	// the private part of the listed APEXes even when it is not included in the
-	// APEXes.
-	Test_for []string
 }
 
 // Test option struct.
@@ -241,10 +236,6 @@
 	return BoolDefault(test.Properties.Gtest, true)
 }
 
-func (test *testDecorator) testFor() []string {
-	return test.Properties.Test_for
-}
-
 func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
 	if !test.gtest() {
 		return flags
diff --git a/cc/testing.go b/cc/testing.go
index 95a93a0..85f12b7 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -29,6 +29,7 @@
 
 	ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
 	ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)
+	ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
 	ctx.RegisterModuleType("cc_object", ObjectFactory)
 	ctx.RegisterModuleType("cc_genrule", genRuleFactory)
 	ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
@@ -437,6 +438,13 @@
 		ndk_prebuilt_shared_stl {
 			name: "ndk_libc++_shared",
 		}
+
+		cc_library_static {
+			name: "libgoogle-benchmark",
+			sdk_version: "current",
+			stl: "none",
+			system_shared_libs: [],
+		}
 	`
 
 	supportLinuxBionic := false
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index d758de2..907bed3 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -51,10 +51,22 @@
 	return android.NewNameResolver(exportFilter)
 }
 
+// bazelConversionRequested checks that the user is intending to convert
+// Blueprint to Bazel BUILD files.
+func bazelConversionRequested(configuration android.Config) bool {
+	return configuration.IsEnvTrue("CONVERT_TO_BAZEL")
+}
+
 func newContext(srcDir string, configuration android.Config) *android.Context {
 	ctx := android.NewContext(configuration)
-	ctx.Register()
-	if !shouldPrepareBuildActions() {
+	if bazelConversionRequested(configuration) {
+		// Register an alternate set of singletons and mutators for bazel
+		// conversion for Bazel conversion.
+		ctx.RegisterForBazelConversion()
+	} else {
+		ctx.Register()
+	}
+	if !shouldPrepareBuildActions(configuration) {
 		configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
 	}
 	ctx.SetNameInterface(newNameResolver(configuration))
@@ -114,6 +126,8 @@
 		ctx = newContext(srcDir, configuration)
 		bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...)
 	}
+
+	// Convert the Soong module graph into Bazel BUILD files.
 	if bazelQueryViewDir != "" {
 		if err := createBazelQueryView(ctx, bazelQueryViewDir); err != nil {
 			fmt.Fprintf(os.Stderr, "%s", err)
@@ -130,7 +144,7 @@
 
 	// TODO(ccross): make this a command line argument.  Requires plumbing through blueprint
 	//  to affect the command line of the primary builder.
-	if shouldPrepareBuildActions() {
+	if shouldPrepareBuildActions(configuration) {
 		metricsFile := filepath.Join(bootstrap.BuildDir, "soong_build_metrics.pb")
 		err := android.WriteMetrics(configuration, metricsFile)
 		if err != nil {
@@ -140,8 +154,19 @@
 	}
 }
 
-func shouldPrepareBuildActions() bool {
-	// If we're writing soong_docs or queryview, don't write build.ninja or
-	// collect metrics.
-	return docFile == "" && bazelQueryViewDir == ""
+// shouldPrepareBuildActions reads configuration and flags if build actions
+// should be generated.
+func shouldPrepareBuildActions(configuration android.Config) bool {
+	// Generating Soong docs
+	if docFile != "" {
+		return false
+	}
+
+	// Generating a directory for Soong query (queryview)
+	if bazelQueryViewDir != "" {
+		return false
+	}
+
+	// Generating a directory for converted Bazel BUILD files
+	return !bazelConversionRequested(configuration)
 }
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index 5fb6e6b..253979e 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -44,9 +44,10 @@
 	"name":             0,
 	"src":              1,
 	"srcs":             2,
-	"defaults":         3,
-	"host_supported":   4,
-	"device_supported": 5,
+	"exclude_srcs":     3,
+	"defaults":         4,
+	"host_supported":   5,
+	"device_supported": 6,
 }
 
 // For each module type, extract its documentation and convert it to the template data.
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 29030d6..4ffe944 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -174,10 +174,7 @@
 	build.SetupOutDir(buildCtx, config)
 
 	// Set up files to be outputted in the log directory.
-	logsDir := config.OutDir()
-	if config.Dist() {
-		logsDir = filepath.Join(config.DistDir(), "logs")
-	}
+	logsDir := config.LogsDir()
 
 	buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
 	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index 3759217..deaf77f 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -437,7 +437,11 @@
 			if sdkVer == AnySdkVersion {
 				// Return error if dexpreopt doesn't know paths to one of the <uses-library>
 				// dependencies. In the future we may need to relax this and just disable dexpreopt.
-				return false, fmt.Errorf("invalid path for <uses-library> \"%s\"", clc.Name)
+				if clc.Host == nil {
+					return false, fmt.Errorf("invalid build path for <uses-library> \"%s\"", clc.Name)
+				} else {
+					return false, fmt.Errorf("invalid install path for <uses-library> \"%s\"", clc.Name)
+				}
 			} else {
 				// No error for compatibility libraries, as Soong doesn't know if they are needed
 				// (this depends on the targetSdkVersion in the manifest), but the CLC is invalid.
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index df68563..be7d4c6 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -195,7 +195,7 @@
 	// But class loader context in such cases should raise an error on validation.
 	t.Run("validate", func(t *testing.T) {
 		_, err := validateClassLoaderContext(m)
-		checkError(t, err, "invalid path for <uses-library> \"a\"")
+		checkError(t, err, "invalid build path for <uses-library> \"a\"")
 	})
 }
 
diff --git a/java/aar.go b/java/aar.go
index 1940d7f..3b6b34e 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -407,6 +407,7 @@
 
 	ctx.VisitDirectDeps(func(module android.Module) {
 		depName := ctx.OtherModuleName(module)
+		depTag := ctx.OtherModuleDependencyTag(module)
 
 		var exportPackage android.Path
 		aarDep, _ := module.(AndroidLibraryDependency)
@@ -414,7 +415,7 @@
 			exportPackage = aarDep.ExportPackage()
 		}
 
-		switch ctx.OtherModuleDependencyTag(module) {
+		switch depTag {
 		case instrumentationForTag:
 			// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
 		case libTag:
@@ -439,7 +440,6 @@
 				transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
 				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
 				transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
-				classLoaderContexts.AddContextMap(aarDep.ClassLoaderContexts(), depName)
 				if aarDep.ExportedAssets().Valid() {
 					assets = append(assets, aarDep.ExportedAssets().Path())
 				}
@@ -458,11 +458,8 @@
 			}
 		}
 
-		// Add nested dependencies after processing the direct dependency: if it is a <uses-library>,
-		// nested context is added as its subcontext, and should not be re-added at the top-level.
-		if dep, ok := module.(Dependency); ok {
-			classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), depName)
-		}
+		// Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
+		maybeAddCLCFromDep(module, depTag, depName, classLoaderContexts)
 	})
 
 	deps = append(deps, sharedLibs...)
diff --git a/java/androidmk.go b/java/androidmk.go
index fc573c8..aaad44f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -274,7 +274,7 @@
 				},
 			},
 			ExtraFooters: []android.AndroidMkExtraFootersFunc{
-				func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+				func(w io.Writer, name, prefix, moduleDir string) {
 					fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
 				},
 			},
@@ -289,7 +289,7 @@
 				},
 			},
 			ExtraFooters: []android.AndroidMkExtraFootersFunc{
-				func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+				func(w io.Writer, name, prefix, moduleDir string) {
 					// Ensure that the wrapper script timestamp is always updated when the jar is updated
 					fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
 					fmt.Fprintln(w, "jar_installed_module :=")
@@ -393,7 +393,7 @@
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			func(w io.Writer, name, prefix, moduleDir string) {
 				if app.noticeOutputs.Merged.Valid() {
 					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
 						app.installApkName, app.noticeOutputs.Merged.String(), app.installApkName+"_NOTICE")
@@ -548,7 +548,7 @@
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			func(w io.Writer, name, prefix, moduleDir string) {
 				if dstubs.apiFile != nil {
 					fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name())
 					fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.apiFile)
diff --git a/java/app.go b/java/app.go
index 4bf9d33..e6d9550 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1400,6 +1400,13 @@
 	archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName("Arch")
 	archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType
 	MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name)
+
+	if String(a.properties.Apk) == "" {
+		// Disable this module since the apk property is still empty after processing all matching
+		// variants. This likely means there is no matching variant, and the default variant doesn't
+		// have an apk property value either.
+		a.Disable()
+	}
 }
 
 func MergePropertiesFromVariant(ctx android.EarlyModuleContext,
diff --git a/java/app_builder.go b/java/app_builder.go
index 69e462c..b53c15a 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -32,7 +32,7 @@
 var (
 	Signapk, SignapkRE = remoteexec.StaticRules(pctx, "signapk",
 		blueprint.RuleParams{
-			Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` +
+			Command: `rm -f $out && $reTemplate${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` +
 				`-jar ${config.SignapkCmd} $flags $certificates $in $out`,
 			CommandDeps: []string{"${config.SignapkCmd}", "${config.SignapkJniLibrary}"},
 		},
diff --git a/java/app_test.go b/java/app_test.go
index 6efb0dc..e13c6b9 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2524,6 +2524,24 @@
 			`,
 			expected: "prebuilts/apk/app.apk",
 		},
+		{
+			name: "no matching arch without default",
+			bp: `
+				android_app_import {
+					name: "foo",
+					arch: {
+						arm: {
+							apk: "prebuilts/apk/app_arm.apk",
+						},
+					},
+					presigned: true,
+					dex_preopt: {
+						enabled: true,
+					},
+				}
+			`,
+			expected: "",
+		},
 	}
 
 	jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)")
@@ -2531,6 +2549,12 @@
 		ctx, _ := testJava(t, test.bp)
 
 		variant := ctx.ModuleForTests("foo", "android_common")
+		if test.expected == "" {
+			if variant.Module().Enabled() {
+				t.Error("module should have been disabled, but wasn't")
+			}
+			continue
+		}
 		jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command
 		matches := jniRuleRe.FindStringSubmatch(jniRuleCommand)
 		if len(matches) != 2 {
@@ -2542,6 +2566,34 @@
 	}
 }
 
+func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) {
+	ctx, _ := testJava(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			enabled: false,
+		}
+ 
+ 		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			certificate: "platform",
+			prefer: true,
+		}
+		`)
+
+	variant := ctx.ModuleForTests("prebuilt_foo", "android_common")
+	a := variant.Module().(*AndroidAppImport)
+	// The prebuilt module should still be enabled and active even if the source-based counterpart
+	// is disabled.
+	if !a.prebuilt.UsePrebuilt() {
+		t.Errorf("prebuilt foo module is not active")
+	}
+	if !a.Enabled() {
+		t.Errorf("prebuilt foo module is disabled")
+	}
+}
+
 func TestAndroidTestImport(t *testing.T) {
 	ctx, config := testJava(t, `
 		android_test_import {
@@ -2730,6 +2782,13 @@
 		}
 
 		java_sdk_library {
+			name: "fred",
+			srcs: ["a.java"],
+			api_packages: ["fred"],
+			sdk_version: "current",
+		}
+
+		java_sdk_library {
 			name: "bar",
 			srcs: ["a.java"],
 			api_packages: ["bar"],
@@ -2753,7 +2812,12 @@
 			name: "app",
 			srcs: ["a.java"],
 			libs: ["qux", "quuz.stubs"],
-			static_libs: ["static-runtime-helper"],
+			static_libs: [
+				"static-runtime-helper",
+				// statically linked component libraries should not pull their SDK libraries,
+				// so "fred" should not be added to class loader context
+				"fred.stubs",
+			],
 			uses_libs: ["foo"],
 			sdk_version: "current",
 			optional_uses_libs: [
diff --git a/java/builder.go b/java/builder.go
index cd35245..995160d 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -42,7 +42,7 @@
 	// TODO(b/143658984): goma can't handle the --system argument to javac.
 	javac, javacRE = remoteexec.MultiCommandStaticRules(pctx, "javac",
 		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
+			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" "$out" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
 				`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
 				`${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index f16ddf1..062005b 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -418,43 +418,53 @@
 	dumpOatRules(ctx, d.defaultBootImage)
 }
 
-func isHostdex(module android.Module) bool {
-	if lib, ok := module.(*Library); ok {
-		return Bool(lib.deviceProperties.Hostdex)
-	}
-	return false
-}
-
 // Inspect this module to see if it contains a bootclasspath dex jar.
 // Note that the same jar may occur in multiple modules.
 // This logic is tested in the apex package to avoid import cycle apex <-> java.
 func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
-	// All apex Java libraries have non-installable platform variants, skip them.
-	if module.IsSkipInstall() {
-		return -1, nil
-	}
-
-	jar, hasJar := module.(interface{ DexJarBuildPath() android.Path })
-	if !hasJar {
-		return -1, nil
-	}
-
+	// Ignore any module that is not listed in the boot image configuration.
 	name := ctx.ModuleName(module)
 	index := image.modules.IndexOfJar(name)
 	if index == -1 {
 		return -1, nil
 	}
 
-	// Check that this module satisfies constraints for a particular boot image.
-	_, isApexModule := module.(android.ApexModule)
+	// It is an error if a module configured in the boot image does not support
+	// accessing the dex jar. This is safe because every module that has the same
+	// name has to have the same module type.
+	jar, hasJar := module.(interface{ DexJarBuildPath() android.Path })
+	if !hasJar {
+		ctx.Errorf("module %q configured in boot image %q does not support accessing dex jar", module, image.name)
+		return -1, nil
+	}
+
+	// It is also an error if the module is not an ApexModule.
+	if _, ok := module.(android.ApexModule); !ok {
+		ctx.Errorf("module %q configured in boot image %q does not support being added to an apex", module, image.name)
+		return -1, nil
+	}
+
 	apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
-	fromUpdatableApex := isApexModule && apexInfo.Updatable
-	if image.name == artBootImageName {
-		if isApexModule && len(apexInfo.InApexes) > 0 && allHavePrefix(apexInfo.InApexes, "com.android.art") {
-			// ok: found the jar in the ART apex
-		} else if isApexModule && apexInfo.IsForPlatform() && isHostdex(module) {
-			// exception (skip and continue): special "hostdex" platform variant
+
+	// Now match the apex part of the boot image configuration.
+	requiredApex := image.modules.Apex(index)
+	if requiredApex == "platform" {
+		if len(apexInfo.InApexes) != 0 {
+			// A platform variant is required but this is for an apex so ignore it.
 			return -1, nil
+		}
+	} else if !android.InList(requiredApex, apexInfo.InApexes) {
+		// An apex variant for a specific apex is required but this is the wrong apex.
+		return -1, nil
+	}
+
+	// Check that this module satisfies any boot image specific constraints.
+	fromUpdatableApex := apexInfo.Updatable
+
+	switch image.name {
+	case artBootImageName:
+		if len(apexInfo.InApexes) > 0 && allHavePrefix(apexInfo.InApexes, "com.android.art") {
+			// ok: found the jar in the ART apex
 		} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
 			// exception (skip and continue): Jacoco platform variant for a coverage build
 			return -1, nil
@@ -465,14 +475,15 @@
 			// error: this jar is part of the platform or a non-updatable apex
 			ctx.Errorf("module %q is not allowed in the ART boot image", name)
 		}
-	} else if image.name == frameworkBootImageName {
+
+	case frameworkBootImageName:
 		if !fromUpdatableApex {
 			// ok: this jar is part of the platform or a non-updatable apex
 		} else {
 			// error: this jar is part of an updatable apex
 			ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apexInfo.InApexes)
 		}
-	} else {
+	default:
 		panic("unknown boot image: " + image.name)
 	}
 
@@ -495,6 +506,12 @@
 	bootDexJars := make(android.Paths, image.modules.Len())
 	ctx.VisitAllModules(func(module android.Module) {
 		if i, j := getBootImageJar(ctx, image, module); i != -1 {
+			if existing := bootDexJars[i]; existing != nil {
+				ctx.Errorf("Multiple dex jars found for %s:%s - %s and %s",
+					image.modules.Apex(i), image.modules.Jar(i), existing, j)
+				return
+			}
+
 			bootDexJars[i] = j
 		}
 	})
@@ -506,7 +523,7 @@
 			m := image.modules.Jar(i)
 			if ctx.Config().AllowMissingDependencies() {
 				missingDeps = append(missingDeps, m)
-				bootDexJars[i] = android.PathForOutput(ctx, "missing")
+				bootDexJars[i] = android.PathForOutput(ctx, "missing/module", m, "from/apex", image.modules.Apex(i))
 			} else {
 				ctx.Errorf("failed to find a dex jar path for module '%s'"+
 					", note that some jars may be filtered out by module constraints", m)
@@ -779,7 +796,7 @@
 			bootFrameworkProfile = path.Path()
 		} else {
 			missingDeps = append(missingDeps, defaultProfile)
-			bootFrameworkProfile = android.PathForOutput(ctx, "missing")
+			bootFrameworkProfile = android.PathForOutput(ctx, "missing", defaultProfile)
 		}
 
 		profile := image.dir.Join(ctx, "boot.bprof")
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index ce8410e..419dc34 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -177,12 +177,13 @@
 	for moduleList, pathList := range moduleListToPathList {
 		for i := range pathList {
 			if pathList[i] == nil {
-				pathList[i] = android.PathForOutput(ctx, "missing")
+				moduleName := (*moduleList)[i]
+				pathList[i] = android.PathForOutput(ctx, "missing/module", moduleName)
 				if ctx.Config().AllowMissingDependencies() {
-					missingDeps = append(missingDeps, (*moduleList)[i])
+					missingDeps = append(missingDeps, moduleName)
 				} else {
 					ctx.Errorf("failed to find dex jar path for module %q",
-						(*moduleList)[i])
+						moduleName)
 				}
 			}
 		}
diff --git a/java/java.go b/java/java.go
index 3d121cc..d44719e 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1081,7 +1081,6 @@
 			switch tag {
 			case libTag:
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
-				// names of sdk libs that are directly depended are exported
 				j.classLoaderContexts.MaybeAddContext(ctx, dep.OptionalImplicitSdkLibrary(),
 					dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			case staticLibTag:
@@ -1093,7 +1092,6 @@
 				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
 			case libTag, instrumentationForTag:
 				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-				// sdk lib names from dependencies are re-exported
 				j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 				pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins()
@@ -1106,8 +1104,6 @@
 				deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
 				deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
-				// sdk lib names from dependencies are re-exported
-				j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 				pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins()
 				addPlugins(&deps, pluginJars, pluginClasses...)
@@ -1182,6 +1178,9 @@
 				deps.systemModules = &systemModules{outputDir, outputDeps}
 			}
 		}
+
+		// Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
+		maybeAddCLCFromDep(module, tag, otherName, j.classLoaderContexts)
 	})
 
 	return deps
@@ -2815,8 +2814,6 @@
 			switch tag {
 			case libTag, staticLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars()...)
-				// sdk lib names from dependencies are re-exported
-				j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
 			case bootClasspathTag:
 				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
 			}
@@ -2824,10 +2821,12 @@
 			switch tag {
 			case libTag:
 				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
-				// names of sdk libs that are directly depended are exported
 				j.classLoaderContexts.AddContext(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			}
 		}
+
+		// Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
+		maybeAddCLCFromDep(module, tag, otherName, j.classLoaderContexts)
 	})
 
 	var installFile android.Path
@@ -3248,3 +3247,31 @@
 var BoolDefault = proptools.BoolDefault
 var String = proptools.String
 var inList = android.InList
+
+// Add class loader context of a given dependency to the given class loader context, provided that
+// all the necessary conditions are met.
+func maybeAddCLCFromDep(depModule android.Module, depTag blueprint.DependencyTag,
+	depName string, clcMap dexpreopt.ClassLoaderContextMap) {
+
+	if dep, ok := depModule.(Dependency); ok {
+		if depTag == libTag {
+			// Ok, propagate <uses-library> through non-static library dependencies.
+		} else if depTag == staticLibTag {
+			// 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 comp, isComp := depModule.(SdkLibraryComponentDependency); isComp {
+				if compName := comp.OptionalImplicitSdkLibrary(); compName != nil {
+					dep = nil
+				}
+			}
+		} else {
+			// Don't propagate <uses-library> for other dependency tags.
+			dep = nil
+		}
+
+		if dep != nil {
+			clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
+		}
+	}
+}
diff --git a/java/robolectric.go b/java/robolectric.go
index 419efda..c821e5b 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -260,7 +260,7 @@
 	entries := &entriesList[0]
 
 	entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
-		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+		func(w io.Writer, name, prefix, moduleDir string) {
 			if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 {
 				numShards := int(*s)
 				shardSize := (len(r.tests) + numShards - 1) / numShards
diff --git a/rust/binary.go b/rust/binary.go
index af39d38..c2d97f3 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -24,11 +24,6 @@
 }
 
 type BinaryCompilerProperties struct {
-	// Change the rustlibs linkage to select rlib linkage by default for device targets.
-	// Also link libstd as an rlib as well on device targets.
-	// Note: This is the default behavior for host targets.
-	Prefer_rlib *bool `android:"arch_variant"`
-
 	// Builds this binary as a static binary. Implies prefer_rlib true.
 	//
 	// Static executables currently only support for bionic targets. Non-bionic targets will not produce a fully static
@@ -115,7 +110,7 @@
 }
 
 func (binary *binaryDecorator) preferRlib() bool {
-	return Bool(binary.Properties.Prefer_rlib) || Bool(binary.Properties.Static_executable)
+	return Bool(binary.baseCompiler.Properties.Prefer_rlib) || Bool(binary.Properties.Static_executable)
 }
 
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
@@ -156,8 +151,7 @@
 	// Binaries default to dylib dependencies for device, rlib for host.
 	if binary.preferRlib() {
 		return rlibAutoDep
-	}
-	if ctx.Device() {
+	} else if ctx.Device() {
 		return dylibAutoDep
 	} else {
 		return rlibAutoDep
diff --git a/rust/compiler.go b/rust/compiler.go
index 8d2f09c..4312452 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -122,6 +122,17 @@
 
 	// whether to suppress inclusion of standard crates - defaults to false
 	No_stdlibs *bool
+
+	// Change the rustlibs linkage to select rlib linkage by default for device targets.
+	// Also link libstd as an rlib as well on device targets.
+	// Note: This is the default behavior for host targets.
+	//
+	// This is primarily meant for rust_binary and rust_ffi modules where the default
+	// linkage of libstd might need to be overridden in some use cases. This should
+	// generally be avoided with other module types since it may cause collisions at
+	// linkage if all dependencies of the root binary module do not link against libstd\
+	// the same way.
+	Prefer_rlib *bool `android:"arch_variant"`
 }
 
 type baseCompiler struct {
@@ -154,9 +165,15 @@
 	panic("baseCompiler does not implement coverageOutputZipPath()")
 }
 
+func (compiler *baseCompiler) preferRlib() bool {
+	return Bool(compiler.Properties.Prefer_rlib)
+}
+
 func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage {
 	// For devices, we always link stdlibs in as dylibs by default.
-	if ctx.Device() {
+	if compiler.preferRlib() {
+		return RlibLinkage
+	} else if ctx.Device() {
 		return DylibLinkage
 	} else {
 		return RlibLinkage
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index e0cc4ce..1f0109f 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -13,6 +13,7 @@
         "toolchain.go",
         "allowed_list.go",
         "x86_darwin_host.go",
+        "x86_linux_bionic_host.go",
         "x86_linux_host.go",
         "x86_device.go",
         "x86_64_device.go",
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index e6643f5..df31d60 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -13,6 +13,7 @@
 		"external/rust",
 		"external/vm_tools/p9",
 		"frameworks/native/libs/binder/rust",
+		"packages/modules/DnsResolver",
 		"packages/modules/Virtualization",
 		"prebuilts/rust",
 		"system/bt",
diff --git a/rust/config/x86_linux_bionic_host.go b/rust/config/x86_linux_bionic_host.go
new file mode 100644
index 0000000..b1a2c17
--- /dev/null
+++ b/rust/config/x86_linux_bionic_host.go
@@ -0,0 +1,73 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+	"strings"
+
+	"android/soong/android"
+)
+
+var (
+	LinuxBionicRustFlags     = []string{}
+	LinuxBionicRustLinkFlags = []string{
+		"-B${cc_config.ClangBin}",
+		"-fuse-ld=lld",
+		"-Wl,--undefined-version",
+		"-nostdlib",
+	}
+)
+
+func init() {
+	registerToolchainFactory(android.LinuxBionic, android.X86_64, linuxBionicX8664ToolchainFactory)
+
+	pctx.StaticVariable("LinuxBionicToolchainRustFlags", strings.Join(LinuxBionicRustFlags, " "))
+	pctx.StaticVariable("LinuxBionicToolchainLinkFlags", strings.Join(LinuxBionicRustLinkFlags, " "))
+}
+
+type toolchainLinuxBionicX8664 struct {
+	toolchain64Bit
+}
+
+func (toolchainLinuxBionicX8664) Supported() bool {
+	return true
+}
+
+func (toolchainLinuxBionicX8664) Bionic() bool {
+	return true
+}
+
+func (t *toolchainLinuxBionicX8664) Name() string {
+	return "x86_64"
+}
+
+func (t *toolchainLinuxBionicX8664) RustTriple() string {
+	return "x86_64-linux-android"
+}
+
+func (t *toolchainLinuxBionicX8664) ToolchainLinkFlags() string {
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${cc_config.LinuxBionicLldflags} ${config.LinuxBionicToolchainLinkFlags}"
+}
+
+func (t *toolchainLinuxBionicX8664) ToolchainRustFlags() string {
+	return "${config.LinuxBionicToolchainRustFlags}"
+}
+
+func linuxBionicX8664ToolchainFactory(arch android.Arch) Toolchain {
+	return toolchainLinuxBionicX8664Singleton
+}
+
+var toolchainLinuxBionicX8664Singleton Toolchain = &toolchainLinuxBionicX8664{}
diff --git a/rust/library.go b/rust/library.go
index 971588d..9d731e6 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -159,14 +159,6 @@
 	return library.MutatedProperties.VariantIsStatic
 }
 
-func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
-	// libraries should only request the RlibLinkage when building a static FFI or when variant is StaticStd
-	if library.static() || library.MutatedProperties.VariantIsStaticStd {
-		return RlibLinkage
-	}
-	return DefaultLinkage
-}
-
 func (library *libraryDecorator) source() bool {
 	return library.MutatedProperties.VariantIsSource
 }
@@ -228,7 +220,9 @@
 }
 
 func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep {
-	if library.rlib() || library.static() {
+	if library.preferRlib() {
+		return rlibAutoDep
+	} else if library.rlib() || library.static() {
 		return rlibAutoDep
 	} else if library.dylib() || library.shared() {
 		return dylibAutoDep
@@ -237,6 +231,15 @@
 	}
 }
 
+func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+	if library.static() || library.MutatedProperties.VariantIsStaticStd {
+		return RlibLinkage
+	} else if library.baseCompiler.preferRlib() {
+		return RlibLinkage
+	}
+	return DefaultLinkage
+}
+
 var _ compiler = (*libraryDecorator)(nil)
 var _ libraryInterface = (*libraryDecorator)(nil)
 var _ exportedFlagsProducer = (*libraryDecorator)(nil)
diff --git a/rust/library_test.go b/rust/library_test.go
index fec3992..54cd2a5 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -251,6 +251,13 @@
 			srcs: ["foo.rs"],
 			crate_name: "bar",
 			rustlibs: ["libfoo"],
+		}
+		rust_ffi {
+			name: "libbar.prefer_rlib",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+			rustlibs: ["libfoo"],
+			prefer_rlib: true,
 		}`)
 
 	libfooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
@@ -260,6 +267,9 @@
 	libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module)
 	libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module)
 
+	// prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here.
+	libbarRlibStd := ctx.ModuleForTests("libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module)
+
 	if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) {
 		t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib")
 	}
@@ -279,4 +289,8 @@
 	if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) {
 		t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
 	}
+	if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) {
+		t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib")
+	}
+
 }
diff --git a/rust/project_json.go b/rust/project_json.go
index 8d9e50c..32ce6f4 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -45,10 +45,11 @@
 }
 
 type rustProjectCrate struct {
-	RootModule string           `json:"root_module"`
-	Edition    string           `json:"edition,omitempty"`
-	Deps       []rustProjectDep `json:"deps"`
-	Cfgs       []string         `json:"cfgs"`
+	DisplayName string           `json:"display_name"`
+	RootModule  string           `json:"root_module"`
+	Edition     string           `json:"edition,omitempty"`
+	Deps        []rustProjectDep `json:"deps"`
+	Cfgs        []string         `json:"cfgs"`
 }
 
 type rustProjectJson struct {
@@ -58,13 +59,13 @@
 
 // crateInfo is used during the processing to keep track of the known crates.
 type crateInfo struct {
-	ID   int
-	Deps map[string]int
+	Idx  int            // Index of the crate in rustProjectJson.Crates slice.
+	Deps map[string]int // The keys are the module names and not the crate names.
 }
 
 type projectGeneratorSingleton struct {
 	project     rustProjectJson
-	knownCrates map[string]crateInfo
+	knownCrates map[string]crateInfo // Keys are module names.
 }
 
 func rustProjectGeneratorSingleton() android.Singleton {
@@ -75,94 +76,190 @@
 	android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
 }
 
-// librarySource finds the main source file (.rs) for a crate.
-func librarySource(ctx android.SingletonContext, rModule *Module, rustLib *libraryDecorator) (string, bool) {
-	srcs := rustLib.baseCompiler.Properties.Srcs
+// sourceProviderVariantSource returns the path to the source file if this
+// module variant should be used as a priority.
+//
+// SourceProvider modules may have multiple variants considered as source
+// (e.g., x86_64 and armv8). For a module available on device, use the source
+// generated for the target. For a host-only module, use the source generated
+// for the host.
+func sourceProviderVariantSource(ctx android.SingletonContext, rModule *Module) (string, bool) {
+	rustLib, ok := rModule.compiler.(*libraryDecorator)
+	if !ok {
+		return "", false
+	}
+	if rustLib.source() {
+		switch rModule.hod {
+		case android.HostSupported, android.HostSupportedNoCross:
+			if rModule.Target().String() == ctx.Config().BuildOSTarget.String() {
+				src := rustLib.sourceProvider.Srcs()[0]
+				return src.String(), true
+			}
+		default:
+			if rModule.Target().String() == ctx.Config().AndroidFirstDeviceTarget.String() {
+				src := rustLib.sourceProvider.Srcs()[0]
+				return src.String(), true
+			}
+		}
+	}
+	return "", false
+}
+
+// sourceProviderSource finds the main source file of a source-provider crate.
+func sourceProviderSource(ctx android.SingletonContext, rModule *Module) (string, bool) {
+	rustLib, ok := rModule.compiler.(*libraryDecorator)
+	if !ok {
+		return "", false
+	}
+	if rustLib.source() {
+		// This is a source-variant, check if we are the right variant
+		// depending on the module configuration.
+		if src, ok := sourceProviderVariantSource(ctx, rModule); ok {
+			return src, true
+		}
+	}
+	foundSource := false
+	sourceSrc := ""
+	// Find the variant with the source and return its.
+	ctx.VisitAllModuleVariants(rModule, func(variant android.Module) {
+		if foundSource {
+			return
+		}
+		// All variants of a source provider library are libraries.
+		rVariant, _ := variant.(*Module)
+		variantLib, _ := rVariant.compiler.(*libraryDecorator)
+		if variantLib.source() {
+			sourceSrc, ok = sourceProviderVariantSource(ctx, rVariant)
+			if ok {
+				foundSource = true
+			}
+		}
+	})
+	if !foundSource {
+		fmt.Errorf("No valid source for source provider found: %v\n", rModule)
+	}
+	return sourceSrc, foundSource
+}
+
+// crateSource finds the main source file (.rs) for a crate.
+func crateSource(ctx android.SingletonContext, rModule *Module, comp *baseCompiler) (string, bool) {
+	// Basic libraries, executables and tests.
+	srcs := comp.Properties.Srcs
 	if len(srcs) != 0 {
 		return path.Join(ctx.ModuleDir(rModule), srcs[0]), true
 	}
-	if !rustLib.source() {
-		return "", false
+	// SourceProvider libraries.
+	if rModule.sourceProvider != nil {
+		return sourceProviderSource(ctx, rModule)
 	}
-	// It is a SourceProvider module. If this module is host only, uses the variation for the host.
-	// Otherwise, use the variation for the primary target.
-	switch rModule.hod {
-	case android.HostSupported:
-	case android.HostSupportedNoCross:
-		if rModule.Target().String() != ctx.Config().BuildOSTarget.String() {
-			return "", false
-		}
-	default:
-		if rModule.Target().String() != ctx.Config().AndroidFirstDeviceTarget.String() {
-			return "", false
-		}
-	}
-	src := rustLib.sourceProvider.Srcs()[0]
-	return src.String(), true
+	return "", false
 }
 
+// mergeDependencies visits all the dependencies for module and updates crate and deps
+// with any new dependency.
 func (singleton *projectGeneratorSingleton) mergeDependencies(ctx android.SingletonContext,
-	module android.Module, crate *rustProjectCrate, deps map[string]int) {
+	module *Module, crate *rustProjectCrate, deps map[string]int) {
 
 	ctx.VisitDirectDeps(module, func(child android.Module) {
-		childId, childCrateName, ok := singleton.appendLibraryAndDeps(ctx, child)
-		if !ok {
-			return
-		}
 		// Skip intra-module dependencies (i.e., generated-source library depending on the source variant).
 		if module.Name() == child.Name() {
 			return
 		}
-		if _, ok = deps[ctx.ModuleName(child)]; ok {
+		// Skip unsupported modules.
+		rChild, compChild, ok := isModuleSupported(ctx, child)
+		if !ok {
 			return
 		}
-		crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childCrateName})
-		deps[ctx.ModuleName(child)] = childId
+		// For unknown dependency, add it first.
+		var childId int
+		cInfo, known := singleton.knownCrates[rChild.Name()]
+		if !known {
+			childId, ok = singleton.addCrate(ctx, rChild, compChild)
+			if !ok {
+				return
+			}
+		} else {
+			childId = cInfo.Idx
+		}
+		// Is this dependency known already?
+		if _, ok = deps[child.Name()]; ok {
+			return
+		}
+		crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: rChild.CrateName()})
+		deps[child.Name()] = childId
 	})
 }
 
-// appendLibraryAndDeps creates a rustProjectCrate for the module argument and appends it to singleton.project.
-// It visits the dependencies of the module depth-first so the dependency ID can be added to the current module. If the
-// current module is already in singleton.knownCrates, its dependencies are merged. Returns a tuple (id, crate_name, ok).
-func (singleton *projectGeneratorSingleton) appendLibraryAndDeps(ctx android.SingletonContext, module android.Module) (int, string, bool) {
+// isModuleSupported returns the RustModule and baseCompiler if the module
+// should be considered for inclusion in rust-project.json.
+func isModuleSupported(ctx android.SingletonContext, module android.Module) (*Module, *baseCompiler, bool) {
 	rModule, ok := module.(*Module)
 	if !ok {
-		return 0, "", false
+		return nil, nil, false
 	}
 	if rModule.compiler == nil {
-		return 0, "", false
+		return nil, nil, false
 	}
-	rustLib, ok := rModule.compiler.(*libraryDecorator)
+	var comp *baseCompiler
+	switch c := rModule.compiler.(type) {
+	case *libraryDecorator:
+		comp = c.baseCompiler
+	case *binaryDecorator:
+		comp = c.baseCompiler
+	case *testDecorator:
+		comp = c.binaryDecorator.baseCompiler
+	default:
+		return nil, nil, false
+	}
+	return rModule, comp, true
+}
+
+// addCrate adds a crate to singleton.project.Crates ensuring that required
+// dependencies are also added. It returns the index of the new crate in
+// singleton.project.Crates
+func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module, comp *baseCompiler) (int, bool) {
+	rootModule, ok := crateSource(ctx, rModule, comp)
 	if !ok {
-		return 0, "", false
+		fmt.Errorf("Unable to find source for valid module: %v", rModule)
+		return 0, false
 	}
-	moduleName := ctx.ModuleName(module)
-	crateName := rModule.CrateName()
-	if cInfo, ok := singleton.knownCrates[moduleName]; ok {
-		// We have seen this crate already; merge any new dependencies.
-		crate := singleton.project.Crates[cInfo.ID]
-		singleton.mergeDependencies(ctx, module, &crate, cInfo.Deps)
-		singleton.project.Crates[cInfo.ID] = crate
-		return cInfo.ID, crateName, true
+
+	crate := rustProjectCrate{
+		DisplayName: rModule.Name(),
+		RootModule:  rootModule,
+		Edition:     comp.edition(),
+		Deps:        make([]rustProjectDep, 0),
+		Cfgs:        make([]string, 0),
 	}
-	crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)}
-	rootModule, ok := librarySource(ctx, rModule, rustLib)
-	if !ok {
-		return 0, "", false
-	}
-	crate.RootModule = rootModule
-	crate.Edition = rustLib.baseCompiler.edition()
 
 	deps := make(map[string]int)
-	singleton.mergeDependencies(ctx, module, &crate, deps)
+	singleton.mergeDependencies(ctx, rModule, &crate, deps)
 
-	id := len(singleton.project.Crates)
-	singleton.knownCrates[moduleName] = crateInfo{ID: id, Deps: deps}
+	idx := len(singleton.project.Crates)
+	singleton.knownCrates[rModule.Name()] = crateInfo{Idx: idx, Deps: deps}
 	singleton.project.Crates = append(singleton.project.Crates, crate)
 	// rust-analyzer requires that all crates belong to at least one root:
 	// https://github.com/rust-analyzer/rust-analyzer/issues/4735.
 	singleton.project.Roots = append(singleton.project.Roots, path.Dir(crate.RootModule))
-	return id, crateName, true
+	return idx, true
+}
+
+// appendCrateAndDependencies creates a rustProjectCrate for the module argument and appends it to singleton.project.
+// It visits the dependencies of the module depth-first so the dependency ID can be added to the current module. If the
+// current module is already in singleton.knownCrates, its dependencies are merged.
+func (singleton *projectGeneratorSingleton) appendCrateAndDependencies(ctx android.SingletonContext, module android.Module) {
+	rModule, comp, ok := isModuleSupported(ctx, module)
+	if !ok {
+		return
+	}
+	// If we have seen this crate already; merge any new dependencies.
+	if cInfo, ok := singleton.knownCrates[module.Name()]; ok {
+		crate := singleton.project.Crates[cInfo.Idx]
+		singleton.mergeDependencies(ctx, rModule, &crate, cInfo.Deps)
+		singleton.project.Crates[cInfo.Idx] = crate
+		return
+	}
+	singleton.addCrate(ctx, rModule, comp)
 }
 
 func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -172,7 +269,7 @@
 
 	singleton.knownCrates = make(map[string]crateInfo)
 	ctx.VisitAllModules(func(module android.Module) {
-		singleton.appendLibraryAndDeps(ctx, module)
+		singleton.appendCrateAndDependencies(ctx, module)
 	})
 
 	path := android.PathForOutput(ctx, rustProjectJsonFileName)
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index 16699c1..ba66215 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -67,6 +67,37 @@
 	return crates
 }
 
+// validateCrate ensures that a crate can be parsed as a map.
+func validateCrate(t *testing.T, crate interface{}) map[string]interface{} {
+	c, ok := crate.(map[string]interface{})
+	if !ok {
+		t.Fatalf("Unexpected type for crate: %v", c)
+	}
+	return c
+}
+
+// validateDependencies parses the dependencies for a crate. It returns a list
+// of the dependencies name.
+func validateDependencies(t *testing.T, crate map[string]interface{}) []string {
+	var dependencies []string
+	deps, ok := crate["deps"].([]interface{})
+	if !ok {
+		t.Errorf("Unexpected format for deps: %v", crate["deps"])
+	}
+	for _, dep := range deps {
+		d, ok := dep.(map[string]interface{})
+		if !ok {
+			t.Errorf("Unexpected format for dependency: %v", dep)
+		}
+		name, ok := d["name"].(string)
+		if !ok {
+			t.Errorf("Dependency is missing the name key: %v", d)
+		}
+		dependencies = append(dependencies, name)
+	}
+	return dependencies
+}
+
 func TestProjectJsonDep(t *testing.T) {
 	bp := `
 	rust_library {
@@ -85,13 +116,36 @@
 	validateJsonCrates(t, jsonContent)
 }
 
+func TestProjectJsonBinary(t *testing.T) {
+	bp := `
+	rust_binary {
+		name: "libz",
+		srcs: ["z/src/lib.rs"],
+		crate_name: "z"
+	}
+	`
+	jsonContent := testProjectJson(t, bp)
+	crates := validateJsonCrates(t, jsonContent)
+	for _, c := range crates {
+		crate := validateCrate(t, c)
+		rootModule, ok := crate["root_module"].(string)
+		if !ok {
+			t.Fatalf("Unexpected type for root_module: %v", crate["root_module"])
+		}
+		if rootModule == "z/src/lib.rs" {
+			return
+		}
+	}
+	t.Errorf("Entry for binary %q not found: %s", "a", jsonContent)
+}
+
 func TestProjectJsonBindGen(t *testing.T) {
 	bp := `
 	rust_library {
-		name: "liba",
-		srcs: ["src/lib.rs"],
+		name: "libd",
+		srcs: ["d/src/lib.rs"],
 		rlibs: ["libbindings1"],
-		crate_name: "a"
+		crate_name: "d"
 	}
 	rust_bindgen {
 		name: "libbindings1",
@@ -101,10 +155,10 @@
 		wrapper_src: "src/any.h",
 	}
 	rust_library_host {
-		name: "libb",
-		srcs: ["src/lib.rs"],
+		name: "libe",
+		srcs: ["e/src/lib.rs"],
 		rustlibs: ["libbindings2"],
-		crate_name: "b"
+		crate_name: "e"
 	}
 	rust_bindgen_host {
 		name: "libbindings2",
@@ -116,10 +170,7 @@
 	jsonContent := testProjectJson(t, bp)
 	crates := validateJsonCrates(t, jsonContent)
 	for _, c := range crates {
-		crate, ok := c.(map[string]interface{})
-		if !ok {
-			t.Fatalf("Unexpected type for crate: %v", c)
-		}
+		crate := validateCrate(t, c)
 		rootModule, ok := crate["root_module"].(string)
 		if !ok {
 			t.Fatalf("Unexpected type for root_module: %v", crate["root_module"])
@@ -133,20 +184,25 @@
 		}
 		// Check that libbindings1 does not depend on itself.
 		if strings.Contains(rootModule, "libbindings1") {
-			deps, ok := crate["deps"].([]interface{})
-			if !ok {
-				t.Errorf("Unexpected format for deps: %v", crate["deps"])
-			}
-			for _, dep := range deps {
-				d, ok := dep.(map[string]interface{})
-				if !ok {
-					t.Errorf("Unexpected format for dep: %v", dep)
-				}
-				if d["name"] == "bindings1" {
+			for _, depName := range validateDependencies(t, crate) {
+				if depName == "bindings1" {
 					t.Errorf("libbindings1 depends on itself")
 				}
 			}
 		}
+		// Check that liba depends on libbindings1
+		if strings.Contains(rootModule, "d/src/lib.rs") {
+			found := false
+			for _, depName := range validateDependencies(t, crate) {
+				if depName == "bindings1" {
+					found = true
+					break
+				}
+			}
+			if !found {
+				t.Errorf("liba does not depend on libbindings1: %v", crate)
+			}
+		}
 	}
 }
 
@@ -171,20 +227,18 @@
 	`
 	jsonContent := testProjectJson(t, bp)
 	crates := validateJsonCrates(t, jsonContent)
-	for _, crate := range crates {
-		c := crate.(map[string]interface{})
-		if c["root_module"] == "b/src/lib.rs" {
-			deps, ok := c["deps"].([]interface{})
-			if !ok {
-				t.Errorf("Unexpected format for deps: %v", c["deps"])
-			}
+	for _, c := range crates {
+		crate := validateCrate(t, c)
+		rootModule, ok := crate["root_module"].(string)
+		if !ok {
+			t.Fatalf("Unexpected type for root_module: %v", crate["root_module"])
+		}
+		// Make sure that b has 2 different dependencies.
+		if rootModule == "b/src/lib.rs" {
 			aCount := 0
-			for _, dep := range deps {
-				d, ok := dep.(map[string]interface{})
-				if !ok {
-					t.Errorf("Unexpected format for dep: %v", dep)
-				}
-				if d["name"] == "a" {
+			deps := validateDependencies(t, crate)
+			for _, depName := range deps {
+				if depName == "a" {
 					aCount++
 				}
 			}
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index 0c868ea..de22c45 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -94,7 +94,13 @@
 
     "Allow_missing_dependencies": ${SOONG_ALLOW_MISSING_DEPENDENCIES:-false},
     "Unbundled_build": ${TARGET_BUILD_UNBUNDLED:-false},
-    "UseGoma": ${USE_GOMA}
+    "UseGoma": ${USE_GOMA},
+
+    "VendorVars": {
+        "art_module": {
+            "source_build": "${ENABLE_ART_SOURCE_BUILD:-false}"
+        }
+    }
 }
 EOF
 
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 50b0886..f3d0750 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -311,7 +311,7 @@
 		DistFiles:  android.MakeDefaultDistFiles(s.snapshotFile.Path()),
 		Include:    "$(BUILD_PHONY_PACKAGE)",
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			func(w io.Writer, name, prefix, moduleDir string) {
 				// Allow the sdk to be built by simply passing its name on the command line.
 				fmt.Fprintln(w, ".PHONY:", s.Name())
 				fmt.Fprintln(w, s.Name()+":", s.snapshotFile.String())
diff --git a/shared/paths.go b/shared/paths.go
index 24ba057..f5dc5dd 100644
--- a/shared/paths.go
+++ b/shared/paths.go
@@ -20,21 +20,23 @@
 	"path/filepath"
 )
 
+// A SharedPaths represents a list of paths that are shared between
+// soong_ui and soong.
+type SharedPaths interface {
+	// BazelMetricsDir returns the path where a set of bazel profile
+	// files are stored for later processed by the metrics pipeline.
+	BazelMetricsDir() string
+}
+
 // Given the out directory, returns the root of the temp directory (to be cleared at the start of each execution of Soong)
 func TempDirForOutDir(outDir string) (tempPath string) {
 	return filepath.Join(outDir, ".temp")
 }
 
-// BazelMetricsDir returns the path where a set of bazel profile
-// files are stored for later processed by the metrics pipeline.
-func BazelMetricsDir(outDir string) string {
-	return filepath.Join(outDir, "bazel_metrics")
-}
-
 // BazelMetricsFilename returns the bazel profile filename based
 // on the action name. This is to help to store a set of bazel
 // profiles since bazel may execute multiple times during a single
 // build.
-func BazelMetricsFilename(outDir, actionName string) string {
-	return filepath.Join(BazelMetricsDir(outDir), actionName+"_bazel_profile.gz")
+func BazelMetricsFilename(s SharedPaths, actionName string) string {
+	return filepath.Join(s.BazelMetricsDir(), actionName+"_bazel_profile.gz")
 }
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index 2d36f67..d9c2266 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -15,6 +15,8 @@
 package build
 
 import (
+	"bytes"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -24,6 +26,29 @@
 	"android/soong/ui/metrics"
 )
 
+func getBazelInfo(ctx Context, config Config, bazelExecutable string, bazelEnv map[string]string, query string) string {
+	infoCmd := Command(ctx, config, "bazel", bazelExecutable)
+
+	if extraStartupArgs, ok := infoCmd.Environment.Get("BAZEL_STARTUP_ARGS"); ok {
+		infoCmd.Args = append(infoCmd.Args, strings.Fields(extraStartupArgs)...)
+	}
+
+	// Obtain the output directory path in the execution root.
+	infoCmd.Args = append(infoCmd.Args,
+		"info",
+		query,
+	)
+
+	for k, v := range bazelEnv {
+		infoCmd.Environment.Set(k, v)
+	}
+
+	infoCmd.Dir = filepath.Join(config.OutDir(), "..")
+
+	queryResult := strings.TrimSpace(string(infoCmd.OutputOrFatal()))
+	return queryResult
+}
+
 // Main entry point to construct the Bazel build command line, environment
 // variables and post-processing steps (e.g. converge output directories)
 func runBazel(ctx Context, config Config) {
@@ -43,14 +68,18 @@
 
 	// Environment variables are the primary mechanism to pass information from
 	// soong_ui configuration or context to Bazel.
-	//
+	bazelEnv := make(map[string]string)
+
 	// Use *_NINJA variables to pass the root-relative path of the combined,
 	// kati-generated, soong-generated, and packaging Ninja files to Bazel.
 	// Bazel reads these from the lunch() repository rule.
-	config.environ.Set("COMBINED_NINJA", config.CombinedNinjaFile())
-	config.environ.Set("KATI_NINJA", config.KatiBuildNinjaFile())
-	config.environ.Set("PACKAGE_NINJA", config.KatiPackageNinjaFile())
-	config.environ.Set("SOONG_NINJA", config.SoongNinjaFile())
+	bazelEnv["COMBINED_NINJA"] = config.CombinedNinjaFile()
+	bazelEnv["KATI_NINJA"] = config.KatiBuildNinjaFile()
+	bazelEnv["PACKAGE_NINJA"] = config.KatiPackageNinjaFile()
+	bazelEnv["SOONG_NINJA"] = config.SoongNinjaFile()
+
+	bazelEnv["DIST_DIR"] = config.DistDir()
+	bazelEnv["SHELL"] = "/bin/bash"
 
 	// `tools/bazel` is the default entry point for executing Bazel in the AOSP
 	// source tree.
@@ -72,20 +101,40 @@
 		// ninja_build target.
 		"--output_groups="+outputGroups,
 		// Generate a performance profile
-		"--profile="+filepath.Join(shared.BazelMetricsFilename(config.OutDir(), actionName)),
+		"--profile="+filepath.Join(shared.BazelMetricsFilename(config, actionName)),
 		"--slim_profile=true",
 	)
 
-	// Append custom build flags to the Bazel command. Changes to these flags
-	// may invalidate Bazel's analysis cache.
-	if extraBuildArgs, ok := cmd.Environment.Get("BAZEL_BUILD_ARGS"); ok {
-		cmd.Args = append(cmd.Args, strings.Fields(extraBuildArgs)...)
-	}
+	if config.UseRBE() {
+		for _, envVar := range []string{
+			// RBE client
+			"RBE_compare",
+			"RBE_exec_strategy",
+			"RBE_invocation_id",
+			"RBE_log_dir",
+			"RBE_platform",
+			"RBE_remote_accept_cache",
+			"RBE_remote_update_cache",
+			"RBE_server_address",
+			// TODO: remove old FLAG_ variables.
+			"FLAG_compare",
+			"FLAG_exec_root",
+			"FLAG_exec_strategy",
+			"FLAG_invocation_id",
+			"FLAG_log_dir",
+			"FLAG_platform",
+			"FLAG_remote_accept_cache",
+			"FLAG_remote_update_cache",
+			"FLAG_server_address",
+		} {
+			cmd.Args = append(cmd.Args,
+				"--action_env="+envVar)
+		}
 
-	// Append the label of the default ninja_build target.
-	cmd.Args = append(cmd.Args,
-		"//:"+config.TargetProduct()+"-"+config.TargetBuildVariant(),
-	)
+		// We need to calculate --RBE_exec_root ourselves
+		ctx.Println("Getting Bazel execution_root...")
+		cmd.Args = append(cmd.Args, "--action_env=RBE_exec_root="+getBazelInfo(ctx, config, bazelExecutable, bazelEnv, "execution_root"))
+	}
 
 	// Ensure that the PATH environment variable value used in the action
 	// environment is the restricted set computed from soong_ui, and not a
@@ -95,15 +144,36 @@
 		cmd.Args = append(cmd.Args, "--action_env=PATH="+pathEnvValue)
 	}
 
-	cmd.Environment.Set("DIST_DIR", config.DistDir())
-	cmd.Environment.Set("SHELL", "/bin/bash")
+	// Append custom build flags to the Bazel command. Changes to these flags
+	// may invalidate Bazel's analysis cache.
+	// These should be appended as the final args, so that they take precedence.
+	if extraBuildArgs, ok := cmd.Environment.Get("BAZEL_BUILD_ARGS"); ok {
+		cmd.Args = append(cmd.Args, strings.Fields(extraBuildArgs)...)
+	}
 
-	// Print the full command line for debugging purposes.
-	ctx.Println(cmd.Cmd)
+	// Append the label of the default ninja_build target.
+	cmd.Args = append(cmd.Args,
+		"//:"+config.TargetProduct()+"-"+config.TargetBuildVariant(),
+	)
 
 	// Execute the command at the root of the directory.
 	cmd.Dir = filepath.Join(config.OutDir(), "..")
-	ctx.Status.Status("Starting Bazel..")
+
+	for k, v := range bazelEnv {
+		cmd.Environment.Set(k, v)
+	}
+
+	// Make a human-readable version of the bazelEnv map
+	bazelEnvStringBuffer := new(bytes.Buffer)
+	for k, v := range bazelEnv {
+		fmt.Fprintf(bazelEnvStringBuffer, "%s=%s ", k, v)
+	}
+
+	// Print the implicit command line
+	ctx.Println("Bazel implicit command line: " + strings.Join(cmd.Environment.Environ(), " ") + " " + cmd.Cmd.String() + "\n")
+
+	// Print the explicit command line too
+	ctx.Println("Bazel explicit command line: " + bazelEnvStringBuffer.String() + cmd.Cmd.String() + "\n")
 
 	// Execute the build command.
 	cmd.RunAndStreamOrFatal()
@@ -113,28 +183,13 @@
 	// Ensure that the $OUT_DIR contains the expected set of files by symlinking
 	// the files from the execution root's output direction into $OUT_DIR.
 
-	// Obtain the Bazel output directory for ninja_build.
-	infoCmd := Command(ctx, config, "bazel", bazelExecutable)
-
-	if extraStartupArgs, ok := infoCmd.Environment.Get("BAZEL_STARTUP_ARGS"); ok {
-		infoCmd.Args = append(infoCmd.Args, strings.Fields(extraStartupArgs)...)
-	}
-
-	// Obtain the output directory path in the execution root.
-	infoCmd.Args = append(infoCmd.Args,
-		"info",
-		"output_path",
-	)
-
-	infoCmd.Environment.Set("DIST_DIR", config.DistDir())
-	infoCmd.Environment.Set("SHELL", "/bin/bash")
-	infoCmd.Dir = filepath.Join(config.OutDir(), "..")
-	ctx.Status.Status("Getting Bazel Info..")
-	outputBasePath := string(infoCmd.OutputOrFatal())
+	ctx.Println("Getting Bazel output_path...")
+	outputBasePath := getBazelInfo(ctx, config, bazelExecutable, bazelEnv, "output_path")
 	// TODO: Don't hardcode out/ as the bazel output directory. This is
 	// currently hardcoded as ninja_build.output_root.
 	bazelNinjaBuildOutputRoot := filepath.Join(outputBasePath, "..", "out")
 
+	ctx.Println("Creating output symlinks..")
 	symlinkOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".")
 }
 
@@ -147,27 +202,39 @@
 	if err != nil {
 		ctx.Fatal(err)
 	}
+
 	for _, f := range files {
+		// The original Bazel file path
 		destPath := filepath.Join(destDir, f.Name())
+
+		// The desired Soong file path
 		srcPath := filepath.Join(config.OutDir(), relativePath, f.Name())
-		if statResult, err := os.Stat(srcPath); err == nil {
-			if statResult.Mode().IsDir() && f.IsDir() {
-				// Directory under OutDir already exists, so recurse on its contents.
+
+		destLstatResult, destLstatErr := os.Lstat(destPath)
+		if destLstatErr != nil {
+			ctx.Fatalf("Unable to Lstat dest %s: %s", destPath, destLstatErr)
+		}
+
+		srcLstatResult, srcLstatErr := os.Lstat(srcPath)
+
+		if srcLstatErr == nil {
+			if srcLstatResult.IsDir() && destLstatResult.IsDir() {
+				// src and dest are both existing dirs - recurse on the dest dir contents...
 				symlinkOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
-			} else if !statResult.Mode().IsDir() && !f.IsDir() {
-				// File exists both in source and destination, and it's not a directory
-				// in either location. Do nothing.
-				// This can arise for files which are generated under OutDir outside of
-				// soong_build, such as .bootstrap files.
 			} else {
-				// File is a directory in one location but not the other. Raise an error.
-				ctx.Fatalf("Could not link %s to %s due to conflict", srcPath, destPath)
+				// Ignore other pre-existing src files (could be pre-existing files, directories, symlinks, ...)
+				// This can arise for files which are generated under OutDir outside of soong_build, such as .bootstrap files.
+				// FIXME: This might cause a problem later e.g. if a symlink in the build graph changes...
 			}
-		} else if os.IsNotExist(err) {
-			// Create symlink srcPath -> fullDestPath.
-			os.Symlink(destPath, srcPath)
 		} else {
-			ctx.Fatalf("Unable to stat %s: %s", srcPath, err)
+			if !os.IsNotExist(srcLstatErr) {
+				ctx.Fatalf("Unable to Lstat src %s: %s", srcPath, srcLstatErr)
+			}
+
+			// src does not exist, so try to create a src -> dest symlink (i.e. a Soong path -> Bazel path symlink)
+			if symlinkErr := os.Symlink(destPath, srcPath); symlinkErr != nil {
+				ctx.Fatalf("Unable to create symlink %s -> %s due to error %s", srcPath, destPath, symlinkErr)
+			}
 		}
 	}
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index c9911f3..72ae3fe 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -275,7 +275,7 @@
 		}
 	}
 
-	bpd := shared.BazelMetricsDir(ret.OutDir())
+	bpd := ret.BazelMetricsDir()
 	if err := os.RemoveAll(bpd); err != nil {
 		ctx.Fatalf("Unable to remove bazel profile directory %q: %v", bpd, err)
 	}
@@ -1121,3 +1121,20 @@
 	}
 	return ""
 }
+
+// LogsDir returns the logs directory where build log and metrics
+// files are located. By default, the logs directory is the out
+// directory. If the argument dist is specified, the logs directory
+// is <dist_dir>/logs.
+func (c *configImpl) LogsDir() string {
+	if c.Dist() {
+		return filepath.Join(c.DistDir(), "logs")
+	}
+	return c.OutDir()
+}
+
+// BazelMetricsDir returns the <logs dir>/bazel_metrics directory
+// where the bazel profiles are located.
+func (c *configImpl) BazelMetricsDir() string {
+	return filepath.Join(c.LogsDir(), "bazel_metrics")
+}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index ffd1ab9..7799766 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -139,15 +139,6 @@
 			// b/147197813 - used by art-check-debug-apex-gen
 			"EMMA_INSTRUMENT_FRAMEWORK",
 
-			// Goma -- gomacc may not need all of these
-			"GOMA_DIR",
-			"GOMA_DISABLED",
-			"GOMA_FAIL_FAST",
-			"GOMA_FALLBACK",
-			"GOMA_GCE_SERVICE_ACCOUNT",
-			"GOMA_TMP_DIR",
-			"GOMA_USE_LOCAL",
-
 			// RBE client
 			"RBE_compare",
 			"RBE_exec_root",
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 3164680..41acc26 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -68,6 +68,7 @@
 	miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
 	modulePathsDir := filepath.Join(outDir, ".module_paths")
 	variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
+
 	// dexpreopt.config is an input to the soong_docs action, which runs the
 	// soong_build primary builder. However, this file is created from $(shell)
 	// invocation at Kati parse time, so it's not an explicit output of any
@@ -75,6 +76,9 @@
 	// treated as an source file.
 	dexpreoptConfigFilePath := filepath.Join(outDir, "soong", "dexpreopt.config")
 
+	// out/build_date.txt is considered a "source file"
+	buildDatetimeFilePath := filepath.Join(outDir, "build_date.txt")
+
 	danglingRules := make(map[string]bool)
 
 	scanner := bufio.NewScanner(stdout)
@@ -88,7 +92,8 @@
 			strings.HasPrefix(line, miniBootstrapDir) ||
 			strings.HasPrefix(line, modulePathsDir) ||
 			line == variablesFilePath ||
-			line == dexpreoptConfigFilePath {
+			line == dexpreoptConfigFilePath ||
+			line == buildDatetimeFilePath {
 			// Leaf node is in one of Soong's bootstrap directories, which do not have
 			// full build rules in the primary build.ninja file.
 			continue