Merge "Allowlist bazel-built partition directories"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index d42c78c..ccfad00 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -210,7 +210,6 @@
 		"system/sepolicy/apex":                               Bp2BuildDefaultTrueRecursively,
 		"system/timezone/apex":                               Bp2BuildDefaultTrueRecursively,
 		"system/timezone/output_data":                        Bp2BuildDefaultTrueRecursively,
-		"system/unwinding/libbacktrace":                      Bp2BuildDefaultTrueRecursively,
 		"system/unwinding/libunwindstack":                    Bp2BuildDefaultTrueRecursively,
 		"tools/apksig":                                       Bp2BuildDefaultTrue,
 		"tools/platform-compat/java/android/compat":          Bp2BuildDefaultTrueRecursively,
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 8834c11..27255d1 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -21,6 +21,7 @@
 	"io/ioutil"
 	"os"
 	"os/exec"
+	"path"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -528,7 +529,7 @@
 	configNodesSection := ""
 
 	labelsByConfig := map[string][]string{}
-	for val, _ := range context.requests {
+	for val := range context.requests {
 		labelString := fmt.Sprintf("\"@%s\"", val.label)
 		configString := getConfigString(val)
 		labelsByConfig[configString] = append(labelsByConfig[configString], labelString)
@@ -566,7 +567,7 @@
 // request type.
 func (context *bazelContext) cqueryStarlarkFileContents() []byte {
 	requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
-	for val, _ := range context.requests {
+	for val := range context.requests {
 		cqueryId := getCqueryId(val)
 		mapEntryString := fmt.Sprintf("%q : True", cqueryId)
 		requestTypeToCqueryIdEntries[val.requestType] =
@@ -870,53 +871,14 @@
 		})
 	}
 
-	// Register bazel-owned build statements (obtained from the aquery invocation).
+	executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
+	bazelOutDir := path.Join(executionRoot, "bazel-out")
 	for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
 		if len(buildStatement.Command) < 1 {
 			panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
 		}
 		rule := NewRuleBuilder(pctx, ctx)
-		cmd := rule.Command()
-
-		// cd into Bazel's execution root, which is the action cwd.
-		cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ &&", ctx.Config().BazelContext.OutputBase()))
-
-		// Remove old outputs, as some actions might not rerun if the outputs are detected.
-		if len(buildStatement.OutputPaths) > 0 {
-			cmd.Text("rm -f")
-			for _, outputPath := range buildStatement.OutputPaths {
-				cmd.Text(outputPath)
-			}
-			cmd.Text("&&")
-		}
-
-		for _, pair := range buildStatement.Env {
-			// Set per-action env variables, if any.
-			cmd.Flag(pair.Key + "=" + pair.Value)
-		}
-
-		// The actual Bazel action.
-		cmd.Text(buildStatement.Command)
-
-		for _, outputPath := range buildStatement.OutputPaths {
-			cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
-		}
-		for _, inputPath := range buildStatement.InputPaths {
-			cmd.Implicit(PathForBazelOut(ctx, inputPath))
-		}
-		for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
-			otherDepsetName := bazelDepsetName(inputDepsetHash)
-			cmd.Implicit(PathForPhony(ctx, otherDepsetName))
-		}
-
-		if depfile := buildStatement.Depfile; depfile != nil {
-			cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
-		}
-
-		for _, symlinkPath := range buildStatement.SymlinkPaths {
-			cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
-		}
-
+		createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
 		// This is required to silence warnings pertaining to unexpected timestamps. Particularly,
 		// some Bazel builtins (such as files in the bazel_tools directory) have far-future
 		// timestamps. Without restat, Ninja would emit warnings that the input files of a
@@ -928,6 +890,58 @@
 	}
 }
 
+// Register bazel-owned build statements (obtained from the aquery invocation).
+func createCommand(cmd *RuleBuilderCommand, buildStatement bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx PathContext) {
+	// executionRoot is the action cwd.
+	cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot))
+
+	// Remove old outputs, as some actions might not rerun if the outputs are detected.
+	if len(buildStatement.OutputPaths) > 0 {
+		cmd.Text("rm -f")
+		for _, outputPath := range buildStatement.OutputPaths {
+			cmd.Text(outputPath)
+		}
+		cmd.Text("&&")
+	}
+
+	for _, pair := range buildStatement.Env {
+		// Set per-action env variables, if any.
+		cmd.Flag(pair.Key + "=" + pair.Value)
+	}
+
+	// The actual Bazel action.
+	cmd.Text(buildStatement.Command)
+
+	for _, outputPath := range buildStatement.OutputPaths {
+		cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
+	}
+	for _, inputPath := range buildStatement.InputPaths {
+		cmd.Implicit(PathForBazelOut(ctx, inputPath))
+	}
+	for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
+		otherDepsetName := bazelDepsetName(inputDepsetHash)
+		cmd.Implicit(PathForPhony(ctx, otherDepsetName))
+	}
+
+	if depfile := buildStatement.Depfile; depfile != nil {
+		// The paths in depfile are relative to `executionRoot`.
+		// Hence, they need to be corrected by replacing "bazel-out"
+		// with the full `bazelOutDir`.
+		// Otherwise, implicit outputs and implicit inputs under "bazel-out/"
+		// would be deemed missing.
+		// (Note: The regexp uses a capture group because the version of sed
+		//  does not support a look-behind pattern.)
+		replacement := fmt.Sprintf(`&& sed -i'' -E 's@(^|\s|")bazel-out/@\1%s/@g' '%s'`,
+			bazelOutDir, *depfile)
+		cmd.Text(replacement)
+		cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
+	}
+
+	for _, symlinkPath := range buildStatement.SymlinkPaths {
+		cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
+	}
+}
+
 func getCqueryId(key cqueryKey) string {
 	return key.label + "|" + getConfigString(key)
 }
@@ -938,12 +952,12 @@
 		// Use host platform, which is currently hardcoded to be x86_64.
 		arch = "x86_64"
 	}
-	os := key.configKey.osType.Name
-	if len(os) == 0 || os == "common_os" || os == "linux_glibc" {
+	osName := key.configKey.osType.Name
+	if len(osName) == 0 || osName == "common_os" || osName == "linux_glibc" {
 		// Use host OS, which is currently hardcoded to be linux.
-		os = "linux"
+		osName = "linux"
 	}
-	return arch + "|" + os
+	return arch + "|" + osName
 }
 
 func GetConfigKey(ctx BaseModuleContext) configKey {
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index dd9a7ed..935ce4e 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -57,8 +57,13 @@
 }
 
 func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
-		bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: `
+	type testCase struct {
+		input   string
+		command string
+	}
+
+	var testCases = []testCase{
+		{`
 {
   "artifacts": [{
     "id": 1,
@@ -88,15 +93,60 @@
     "label": "two"
   }]
 }`,
-	})
-	err := bazelContext.InvokeBazel(testConfig)
-	if err != nil {
-		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+			"cd 'er' && rm -f one && touch foo",
+		}, {`
+{
+  "artifacts": [{
+    "id": 1,
+    "pathFragmentId": 10
+  }, {
+    "id": 2,
+    "pathFragmentId": 20
+  }],
+  "actions": [{
+    "targetId": 100,
+    "actionKey": "x",
+    "mnemonic": "x",
+    "arguments": ["bogus", "command"],
+    "outputIds": [1, 2],
+    "primaryOutputId": 1
+  }],
+  "pathFragments": [{
+    "id": 10,
+    "label": "one",
+    "parentId": 30
+  }, {
+    "id": 20,
+    "label": "one.d",
+    "parentId": 30
+  }, {
+    "id": 30,
+    "label": "parent"
+  }]
+}`,
+			`cd 'er' && rm -f parent/one && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1bo/@g' 'parent/one.d'`,
+		},
 	}
 
-	got := bazelContext.BuildStatementsToRegister()
-	if want := 1; len(got) != want {
-		t.Errorf("Expected %d registered build statements, got %#v", want, got)
+	for _, testCase := range testCases {
+		bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+			bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: testCase.input})
+
+		err := bazelContext.InvokeBazel(testConfig)
+		if err != nil {
+			t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+		}
+
+		got := bazelContext.BuildStatementsToRegister()
+		if want := 1; len(got) != want {
+			t.Errorf("expected %d registered build statements, but got %#v", want, got)
+		}
+
+		cmd := RuleBuilderCommand{}
+		createCommand(&cmd, got[0], "er", "bo", PathContextForTesting(TestConfig("out", nil, "", nil)))
+		if actual := cmd.buf.String(); testCase.command != actual {
+			t.Errorf("expected: [%s], actual: [%s]", testCase.command, actual)
+		}
 	}
 }
 
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 48c1383..f2ab0a4 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -105,7 +105,7 @@
 
 	if p := base.commonProperties.Effective_package_name; p != nil {
 		args = append(args,
-			`-p "`+proptools.NinjaAndShellEscape(*p)+`"`)
+			`-p `+proptools.NinjaAndShellEscapeIncludingSpaces(*p))
 	}
 
 	args = append(args,
diff --git a/android/mutator.go b/android/mutator.go
index 7f93baf..9e4aa59 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -440,6 +440,64 @@
 	// reached
 	DepTag() blueprint.DependencyTag
 }
+
+// Transition mutators implement a top-down mechanism where a module tells its
+// direct dependencies what variation they should be built in but the dependency
+// has the final say.
+//
+// When implementing a transition mutator, one needs to implement four methods:
+//   - Split() that tells what variations a module has by itself
+//   - OutgoingTransition() where a module tells what it wants from its
+//     dependency
+//   - IncomingTransition() where a module has the final say about its own
+//     variation
+//   - Mutate() that changes the state of a module depending on its variation
+//
+// That the effective variation of module B when depended on by module A is the
+// composition the outgoing transition of module A and the incoming transition
+// of module B.
+//
+// the outgoing transition should not take the properties of the dependency into
+// account, only those of the module that depends on it. For this reason, the
+// dependency is not even passed into it as an argument. Likewise, the incoming
+// transition should not take the properties of the depending module into
+// account and is thus not informed about it. This makes for a nice
+// decomposition of the decision logic.
+//
+// A given transition mutator only affects its own variation; other variations
+// stay unchanged along the dependency edges.
+//
+// Soong makes sure that all modules are created in the desired variations and
+// that dependency edges are set up correctly. This ensures that "missing
+// variation" errors do not happen and allows for more flexible changes in the
+// value of the variation among dependency edges (as oppposed to bottom-up
+// mutators where if module A in variation X depends on module B and module B
+// has that variation X, A must depend on variation X of B)
+//
+// The limited power of the context objects passed to individual mutators
+// methods also makes it more difficult to shoot oneself in the foot. Complete
+// safety is not guaranteed because no one prevents individual transition
+// mutators from mutating modules in illegal ways and for e.g. Split() or
+// Mutate() to run their own visitations of the transitive dependency of the
+// module and both of these are bad ideas, but it's better than no guardrails at
+// all.
+//
+// This model is pretty close to Bazel's configuration transitions. The mapping
+// between concepts in Soong and Bazel is as follows:
+//   - Module == configured target
+//   - Variant == configuration
+//   - Variation name == configuration flag
+//   - Variation == configuration flag value
+//   - Outgoing transition == attribute transition
+//   - Incoming transition == rule transition
+//
+// The Split() method does not have a Bazel equivalent and Bazel split
+// transitions do not have a Soong equivalent.
+//
+// Mutate() does not make sense in Bazel due to the different models of the
+// two systems: when creating new variations, Soong clones the old module and
+// thus some way is needed to change it state whereas Bazel creates each
+// configuration of a given configured target anew.
 type TransitionMutator interface {
 	// Split returns the set of variations that should be created for a module no
 	// matter who depends on it. Used when Make depends on a particular variation
@@ -448,7 +506,7 @@
 	// called on.
 	Split(ctx BaseModuleContext) []string
 
-	// OutCalled on a module to determine which variation it wants from its direct
+	// Called on a module to determine which variation it wants from its direct
 	// dependencies. The dependency itself can override this decision. This method
 	// should not mutate the module itself.
 	OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 5e4ebf8..6829698 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -167,7 +167,7 @@
 
 	// Map middleman artifact ContentHash to input artifact depset ID.
 	// Middleman artifacts are treated as "substitute" artifacts for mixed builds. For example,
-	// if we find a middleman action which has outputs [foo, bar], and output [baz_middleman], then,
+	// if we find a middleman action which has inputs [foo, bar], and output [baz_middleman], then,
 	// for each other action which has input [baz_middleman], we add [foo, bar] to the inputs for
 	// that action instead.
 	middlemanIdToDepsetIds := map[artifactId][]depsetId{}
@@ -348,7 +348,7 @@
 		if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
 			// Two depsets collide on hash. Ensure that their contents are identical.
 			if !reflect.DeepEqual(aqueryDepset, prevEntry) {
-				return nil, nil, fmt.Errorf("Two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
+				return nil, nil, fmt.Errorf("two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
 			}
 		} else {
 			depsetsByHash[aqueryDepset.ContentHash] = aqueryDepset
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index c9c8909..1da6340 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"reflect"
+	"sort"
 	"testing"
 )
 
@@ -224,7 +225,7 @@
   }]
 }`
 	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
-	expectedBuildStatements := []BuildStatement{}
+	var expectedBuildStatements []BuildStatement
 	for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
 		expectedBuildStatements = append(expectedBuildStatements,
 			BuildStatement{
@@ -235,7 +236,7 @@
 					fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
 				},
 				Env: []KeyValuePair{
-					KeyValuePair{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
+					{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
 				},
 				Mnemonic: "Genrule",
 			})
@@ -747,7 +748,7 @@
 	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
 
 	expectedBuildStatements := []BuildStatement{
-		BuildStatement{
+		{
 			Command:     "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
 			OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
 			Mnemonic:    "Action",
@@ -758,7 +759,7 @@
 	// Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
 	// are given via a deep depset, but the depset is flattened when returned as a
 	// BuildStatement slice.
-	expectedFlattenedInputs := []string{}
+	var expectedFlattenedInputs []string
 	for i := 1; i < 20; i++ {
 		expectedFlattenedInputs = append(expectedFlattenedInputs, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
 	}
@@ -876,7 +877,7 @@
 	for _, depset := range allDepsets {
 		depsetsByHash[depset.ContentHash] = depset
 	}
-	result := []string{}
+	var result []string
 	for _, depsetId := range depsetHashesToFlatten {
 		result = append(result, flattenDepset(depsetId, depsetsByHash)...)
 	}
@@ -886,7 +887,7 @@
 // Returns the contents of a given depset in post order.
 func flattenDepset(depsetHashToFlatten string, allDepsets map[string]AqueryDepset) []string {
 	depset := allDepsets[depsetHashToFlatten]
-	result := []string{}
+	var result []string
 	for _, depsetId := range depset.TransitiveDepSetHashes {
 		result = append(result, flattenDepset(depsetId, allDepsets)...)
 	}
@@ -897,7 +898,7 @@
 func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expectedDepsetFiles [][]string) {
 	t.Helper()
 	if len(actualDepsets) != len(expectedDepsetFiles) {
-		t.Errorf("Expected %s depsets, but got %s depsets", expectedDepsetFiles, actualDepsets)
+		t.Errorf("Expected %d depsets, but got %d depsets", len(expectedDepsetFiles), len(actualDepsets))
 	}
 	for i, actualDepset := range actualDepsets {
 		actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
@@ -958,7 +959,7 @@
 	}
 
 	expectedBuildStatements := []BuildStatement{
-		BuildStatement{
+		{
 			Command: "mkdir -p one/symlink_subdir && " +
 				"rm -f one/symlink_subdir/symlink && " +
 				"ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
@@ -1022,7 +1023,7 @@
 	}
 
 	expectedBuildStatements := []BuildStatement{
-		BuildStatement{
+		{
 			Command: "mkdir -p 'one/symlink subdir' && " +
 				"rm -f 'one/symlink subdir/symlink' && " +
 				"ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
@@ -1154,7 +1155,7 @@
 	}
 
 	expectedBuildStatements := []BuildStatement{
-		BuildStatement{
+		{
 			Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
 				"chmod a+x template_file'",
 			OutputPaths: []string{"template_file"},
@@ -1320,14 +1321,14 @@
 	}
 
 	expectedBuildStatements := []BuildStatement{
-		BuildStatement{
+		{
 			Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
 				"chmod a+x python_binary'",
 			InputPaths:  []string{"python_binary.zip"},
 			OutputPaths: []string{"python_binary"},
 			Mnemonic:    "TemplateExpand",
 		},
-		BuildStatement{
+		{
 			Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
 				"__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py  && " +
 				"../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
@@ -1484,50 +1485,54 @@
 			len(expected), len(actual), expected, actual)
 		return
 	}
-ACTUAL_LOOP:
-	for _, actualStatement := range actual {
-		for _, expectedStatement := range expected {
-			if buildStatementEquals(actualStatement, expectedStatement) {
-				continue ACTUAL_LOOP
-			}
+	type compareFn = func(i int, j int) bool
+	byCommand := func(slice []BuildStatement) compareFn {
+		return func(i int, j int) bool {
+			return slice[i].Command < slice[j].Command
 		}
-		t.Errorf("unexpected build statement %#v.\n expected: %#v",
-			actualStatement, expected)
-		return
+	}
+	sort.SliceStable(expected, byCommand(expected))
+	sort.SliceStable(actual, byCommand(actual))
+	for i, actualStatement := range actual {
+		expectedStatement := expected[i]
+		if differingField := buildStatementEquals(actualStatement, expectedStatement); differingField != "" {
+			t.Errorf("%s differs\nunexpected build statement %#v.\nexpected: %#v",
+				differingField, actualStatement, expected)
+			return
+		}
 	}
 }
 
-func buildStatementEquals(first BuildStatement, second BuildStatement) bool {
+func buildStatementEquals(first BuildStatement, second BuildStatement) string {
 	if first.Mnemonic != second.Mnemonic {
-		return false
+		return "Mnemonic"
 	}
 	if first.Command != second.Command {
-		return false
+		return "Command"
 	}
 	// Ordering is significant for environment variables.
 	if !reflect.DeepEqual(first.Env, second.Env) {
-		return false
+		return "Env"
 	}
 	// Ordering is irrelevant for input and output paths, so compare sets.
-	if !reflect.DeepEqual(stringSet(first.InputPaths), stringSet(second.InputPaths)) {
-		return false
+	if !reflect.DeepEqual(sortedStrings(first.InputPaths), sortedStrings(second.InputPaths)) {
+		return "InputPaths"
 	}
-	if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
-		return false
+	if !reflect.DeepEqual(sortedStrings(first.OutputPaths), sortedStrings(second.OutputPaths)) {
+		return "OutputPaths"
 	}
-	if !reflect.DeepEqual(stringSet(first.SymlinkPaths), stringSet(second.SymlinkPaths)) {
-		return false
+	if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
+		return "SymlinkPaths"
 	}
 	if first.Depfile != second.Depfile {
-		return false
+		return "Depfile"
 	}
-	return true
+	return ""
 }
 
-func stringSet(stringSlice []string) map[string]struct{} {
-	stringMap := make(map[string]struct{})
-	for _, s := range stringSlice {
-		stringMap[s] = struct{}{}
-	}
-	return stringMap
+func sortedStrings(stringSlice []string) []string {
+	sorted := make([]string, len(stringSlice))
+	copy(sorted, stringSlice)
+	sort.Strings(sorted)
+	return sorted
 }
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index e5bb120..2b54d45 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -84,18 +84,6 @@
 		},
 		blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
-    name: "lib-1",
-    export_include_dirs: ["lib-1"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_headers {
-    name: "lib-2",
-    export_include_dirs: ["lib-2"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_headers {
     name: "foo_headers",
     export_include_dirs: ["dir-1", "dir-2"],
     header_libs: ["lib-1", "lib-2"],
@@ -128,12 +116,8 @@
         "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
         "//conditions:default": [],
     })`,
-				"implementation_deps": `[
-        ":lib-1",
-        ":lib-2",
-    ]`,
-        "sdk_version": `"current"`,
-        "min_sdk_version": `"29"`,
+				"sdk_version":     `"current"`,
+				"min_sdk_version": `"29"`,
 			}),
 		},
 	})
@@ -173,18 +157,34 @@
 cc_library_headers {
     name: "foo_headers",
     header_libs: ["base-lib"],
+		export_header_lib_headers: ["base-lib"],
     target: {
-        android: { header_libs: ["android-lib"] },
-        darwin: { header_libs: ["darwin-lib"] },
-        linux_bionic: { header_libs: ["linux_bionic-lib"] },
-        linux_glibc: { header_libs: ["linux-lib"] },
-        windows: { header_libs: ["windows-lib"] },
+        android: {
+						header_libs: ["android-lib"],
+						export_header_lib_headers: ["android-lib"],
+				},
+        darwin: {
+						header_libs: ["darwin-lib"],
+						export_header_lib_headers: ["darwin-lib"],
+				},
+        linux_bionic: {
+						header_libs: ["linux_bionic-lib"],
+						export_header_lib_headers: ["linux_bionic-lib"],
+				},
+        linux_glibc: {
+						header_libs: ["linux-lib"],
+						export_header_lib_headers: ["linux-lib"],
+				},
+        windows: {
+						header_libs: ["windows-lib"],
+						export_header_lib_headers: ["windows-lib"],
+				},
     },
     include_build_directory: false,
 }`,
 		expectedBazelTargets: []string{
 			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
-				"implementation_deps": `[":base-lib"] + select({
+				"deps": `[":base-lib"] + select({
         "//build/bazel/platforms/os:android": [":android-lib"],
         "//build/bazel/platforms/os:darwin": [":darwin-lib"],
         "//build/bazel/platforms/os:linux": [":linux-lib"],
@@ -228,10 +228,6 @@
         "//build/bazel/platforms/os:android": [":exported-lib"],
         "//conditions:default": [],
     })`,
-				"implementation_deps": `select({
-        "//build/bazel/platforms/os:android": [":android-lib"],
-        "//conditions:default": [],
-    })`,
 			}),
 		},
 	})
diff --git a/cc/library.go b/cc/library.go
index 0fa01d7..c445a42 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -925,7 +925,6 @@
 		if ctx.Darwin() {
 			f = append(f,
 				"-dynamiclib",
-				"-single_module",
 				"-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(),
 			)
 			if ctx.Arch().ArchType == android.X86 {
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 7232290..77c2523 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -130,7 +130,6 @@
 		Export_includes:          exportedIncludes.Includes,
 		Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
 		Export_system_includes:   exportedIncludes.SystemIncludes,
-		Implementation_deps:      linkerAttrs.implementationDeps,
 		Deps:                     linkerAttrs.deps,
 		System_dynamic_deps:      linkerAttrs.systemDynamicDeps,
 		Hdrs:                     baseAttributes.hdrs,
diff --git a/cc/linker.go b/cc/linker.go
index 78d2d41..76a60ca 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -436,11 +436,6 @@
 }
 
 func (linker *baseLinker) useClangLld(ctx ModuleContext) bool {
-	// Clang lld is not ready for for Darwin host executables yet.
-	// See https://lld.llvm.org/AtomLLD.html for status of lld for Mach-O.
-	if ctx.Darwin() {
-		return false
-	}
 	if linker.Properties.Use_clang_lld != nil {
 		return Bool(linker.Properties.Use_clang_lld)
 	}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e0779c6..ff56058 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -430,7 +430,7 @@
 	}
 
 	// Enable Memtag for all components in the include paths (for Aarch64 only)
-	if ctx.Arch().ArchType == android.Arm64 {
+	if ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
 		if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
 			if s.Memtag_heap == nil {
 				s.Memtag_heap = proptools.BoolPtr(true)
@@ -460,17 +460,17 @@
 	}
 
 	// HWASan requires AArch64 hardware feature (top-byte-ignore).
-	if ctx.Arch().ArchType != android.Arm64 {
+	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
 		s.Hwaddress = nil
 	}
 
 	// SCS is only implemented on AArch64.
-	if ctx.Arch().ArchType != android.Arm64 {
+	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
 		s.Scs = nil
 	}
 
 	// Memtag_heap is only implemented on AArch64.
-	if ctx.Arch().ArchType != android.Arm64 {
+	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
 		s.Memtag_heap = nil
 	}
 
diff --git a/java/app.go b/java/app.go
index c5d88e9..8ff5d91 100755
--- a/java/app.go
+++ b/java/app.go
@@ -583,6 +583,16 @@
 
 	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 
+	var noticeAssetPath android.WritablePath
+	if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+		// The rule to create the notice file can't be generated yet, as the final output path
+		// for the apk isn't known yet.  Add the path where the notice file will be generated to the
+		// aapt rules now before calling aaptBuildActions, the rule to create the notice file will
+		// be generated later.
+		noticeAssetPath = android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+		a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
+	}
+
 	// Process all building blocks, from AAPT to certificates.
 	a.aaptBuildActions(ctx)
 
@@ -654,7 +664,8 @@
 		a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
 	}
 
-	if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+	if a.aapt.noticeFile.Valid() {
+		// Generating the notice file rule has to be here after a.outputFile is known.
 		noticeFile := android.PathForModuleOut(ctx, "NOTICE.html.gz")
 		android.BuildNoticeHtmlOutputFromLicenseMetadata(
 			ctx, noticeFile, "", "",
@@ -663,13 +674,11 @@
 				android.PathForModuleInstall(ctx).String() + "/",
 				a.outputFile.String(),
 			})
-		noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
 		builder := android.NewRuleBuilder(pctx, ctx)
 		builder.Command().Text("cp").
 			Input(noticeFile).
 			Output(noticeAssetPath)
 		builder.Build("notice_dir", "Building notice dir")
-		a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
 	}
 
 	for _, split := range a.aapt.splits {
diff --git a/java/config/config.go b/java/config/config.go
index e728b7d..1d4b242 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -159,7 +159,7 @@
 	pctx.HostBinToolVariable("ZipSyncCmd", "zipsync")
 	pctx.HostBinToolVariable("ApiCheckCmd", "apicheck")
 	pctx.HostBinToolVariable("D8Cmd", "d8")
-	pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard")
+	pctx.HostBinToolVariable("R8Cmd", "r8")
 	pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
 	pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
 	pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
@@ -177,7 +177,7 @@
 	pctx.HostJavaToolVariable("MetalavaJar", "metalava.jar")
 	pctx.HostJavaToolVariable("DokkaJar", "dokka.jar")
 	pctx.HostJavaToolVariable("JetifierJar", "jetifier.jar")
-	pctx.HostJavaToolVariable("R8Jar", "r8-compat-proguard.jar")
+	pctx.HostJavaToolVariable("R8Jar", "r8.jar")
 	pctx.HostJavaToolVariable("D8Jar", "d8.jar")
 
 	pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")
diff --git a/java/java.go b/java/java.go
index feb49ad..2897fd7 100644
--- a/java/java.go
+++ b/java/java.go
@@ -528,7 +528,7 @@
 	case "11":
 		return JAVA_VERSION_11
 	case "17":
-		return JAVA_VERSION_11
+		return JAVA_VERSION_17
 	case "10", "12", "13", "14", "15", "16":
 		ctx.PropertyErrorf("java_version", "Java language level %s is not supported", javaVersion)
 		return JAVA_VERSION_UNSUPPORTED
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index d1cbd8f..fbb6212 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -35,10 +35,10 @@
 
 	mergeProvenanceMetaData = pctx.AndroidStaticRule("mergeProvenanceMetaData",
 		blueprint.RuleParams{
-			Command: `rm -rf $out $out.temp && ` +
+			Command: `rm -rf $out && ` +
 				`echo "# proto-file: build/soong/provenance/proto/provenance_metadata.proto" > $out && ` +
 				`echo "# proto-message: ProvenanceMetaDataList" >> $out && ` +
-				`touch $out.temp && cat $out.temp $in | grep -v "^#.*" >> $out && rm -rf $out.temp`,
+				`for file in $in; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`,
 		})
 )
 
diff --git a/ui/build/config.go b/ui/build/config.go
index 5765f21..59b01b3 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -211,7 +211,7 @@
 	}
 
 	if err := fetchEnvConfig(ctx, config, bc); err != nil {
-		fmt.Fprintf(os.Stderr, "Failed to fetch config file: %v\n", err)
+		ctx.Verbosef("Failed to fetch config file: %v\n", err)
 	}
 
 	configDirs := []string{