Merge "Switch boot jars package check to use dexdump xml output"
diff --git a/android/apex.go b/android/apex.go
index e70ec4f..276f7a4 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -598,36 +598,22 @@
 	var fullContent strings.Builder
 	var flatContent strings.Builder
 
-	fmt.Fprintf(&fullContent, "%s(minSdkVersion:%s):\\n", ctx.ModuleName(), minSdkVersion)
+	fmt.Fprintf(&fullContent, "%s(minSdkVersion:%s):\n", ctx.ModuleName(), minSdkVersion)
 	for _, key := range FirstUniqueStrings(SortedStringKeys(depInfos)) {
 		info := depInfos[key]
 		toName := fmt.Sprintf("%s(minSdkVersion:%s)", info.To, info.MinSdkVersion)
 		if info.IsExternal {
 			toName = toName + " (external)"
 		}
-		fmt.Fprintf(&fullContent, "  %s <- %s\\n", toName, strings.Join(SortedUniqueStrings(info.From), ", "))
-		fmt.Fprintf(&flatContent, "%s\\n", toName)
+		fmt.Fprintf(&fullContent, "  %s <- %s\n", toName, strings.Join(SortedUniqueStrings(info.From), ", "))
+		fmt.Fprintf(&flatContent, "%s\n", toName)
 	}
 
 	d.fullListPath = PathForModuleOut(ctx, "depsinfo", "fulllist.txt").OutputPath
-	ctx.Build(pctx, BuildParams{
-		Rule:        WriteFile,
-		Description: "Full Dependency Info",
-		Output:      d.fullListPath,
-		Args: map[string]string{
-			"content": fullContent.String(),
-		},
-	})
+	WriteFileRule(ctx, d.fullListPath, fullContent.String())
 
 	d.flatListPath = PathForModuleOut(ctx, "depsinfo", "flatlist.txt").OutputPath
-	ctx.Build(pctx, BuildParams{
-		Rule:        WriteFile,
-		Description: "Flat Dependency Info",
-		Output:      d.flatListPath,
-		Args: map[string]string{
-			"content": flatContent.String(),
-		},
-	})
+	WriteFileRule(ctx, d.flatListPath, flatContent.String())
 }
 
 // TODO(b/158059172): remove minSdkVersion allowlist
diff --git a/android/api_levels.go b/android/api_levels.go
index bace3d4..08328e1 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -225,14 +225,7 @@
 		ctx.Errorf(err.Error())
 	}
 
-	ctx.Build(pctx, BuildParams{
-		Rule:        WriteFile,
-		Description: "generate " + file.Base(),
-		Output:      file,
-		Args: map[string]string{
-			"content": string(jsonStr[:]),
-		},
-	})
+	WriteFileRule(ctx, file, string(jsonStr))
 }
 
 func GetApiLevelsJson(ctx PathContext) WritablePath {
diff --git a/android/defs.go b/android/defs.go
index 2b1bd85..631dfe8 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -15,8 +15,12 @@
 package android
 
 import (
+	"strings"
+	"testing"
+
 	"github.com/google/blueprint"
 	_ "github.com/google/blueprint/bootstrap"
+	"github.com/google/blueprint/proptools"
 )
 
 var (
@@ -91,9 +95,9 @@
 	// ubuntu 14.04 offcially use dash for /bin/sh, and its builtin echo command
 	// doesn't support -e option. Therefore we force to use /bin/bash when writing out
 	// content to file.
-	WriteFile = pctx.AndroidStaticRule("WriteFile",
+	writeFile = pctx.AndroidStaticRule("writeFile",
 		blueprint.RuleParams{
-			Command:     "/bin/bash -c 'echo -e $$0 > $out' '$content'",
+			Command:     `/bin/bash -c 'echo -e "$$0" > $out' $content`,
 			Description: "writing file $out",
 		},
 		"content")
@@ -111,3 +115,64 @@
 func init() {
 	pctx.Import("github.com/google/blueprint/bootstrap")
 }
+
+var (
+	// echoEscaper escapes a string such that passing it to "echo -e" will produce the input value.
+	echoEscaper = strings.NewReplacer(
+		`\`, `\\`, // First escape existing backslashes so they aren't interpreted by `echo -e`.
+		"\n", `\n`, // Then replace newlines with \n
+	)
+
+	// echoEscaper reverses echoEscaper.
+	echoUnescaper = strings.NewReplacer(
+		`\n`, "\n",
+		`\\`, `\`,
+	)
+
+	// shellUnescaper reverses the replacer in proptools.ShellEscape
+	shellUnescaper = strings.NewReplacer(`'\''`, `'`)
+)
+
+// WriteFileRule creates a ninja rule to write contents to a file.  The contents will be escaped
+// so that the file contains exactly the contents passed to the function, plus a trailing newline.
+func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
+	content = echoEscaper.Replace(content)
+	content = proptools.ShellEscape(content)
+	if content == "" {
+		content = "''"
+	}
+	ctx.Build(pctx, BuildParams{
+		Rule:        writeFile,
+		Output:      outputFile,
+		Description: "write " + outputFile.Base(),
+		Args: map[string]string{
+			"content": content,
+		},
+	})
+}
+
+// shellUnescape reverses proptools.ShellEscape
+func shellUnescape(s string) string {
+	// Remove leading and trailing quotes if present
+	if len(s) >= 2 && s[0] == '\'' {
+		s = s[1 : len(s)-1]
+	}
+	s = shellUnescaper.Replace(s)
+	return s
+}
+
+// ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
+// in tests.
+func ContentFromFileRuleForTests(t *testing.T, params TestingBuildParams) string {
+	t.Helper()
+	if g, w := params.Rule, writeFile; g != w {
+		t.Errorf("expected params.Rule to be %q, was %q", w, g)
+		return ""
+	}
+
+	content := params.Args["content"]
+	content = shellUnescape(content)
+	content = echoUnescaper.Replace(content)
+
+	return content
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 524549a..33e5077 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5447,7 +5447,7 @@
 		}
 		`, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"}))
 
-	bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("Bundle Config")
+	bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("bundle_config.json")
 	content := bundleConfigRule.Args["content"]
 
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
@@ -5473,7 +5473,7 @@
 			set: "AppSet.apks",
 		}`)
 	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
-	bundleConfigRule := mod.Description("Bundle Config")
+	bundleConfigRule := mod.Output("bundle_config.json")
 	content := bundleConfigRule.Args["content"]
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
 	s := mod.Rule("apexRule").Args["copy_commands"]
diff --git a/apex/builder.go b/apex/builder.go
index ad673d6..acfb8c5 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -373,14 +373,7 @@
 		panic(fmt.Errorf("error while marshalling to %q: %#v", output, err))
 	}
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      output,
-		Description: "Bundle Config " + output.String(),
-		Args: map[string]string{
-			"content": string(j),
-		},
-	})
+	android.WriteFileRule(ctx, output, string(j))
 
 	return output.OutputPath
 }
diff --git a/apex/key.go b/apex/key.go
index d2d5786..43764da 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -116,7 +116,7 @@
 		partition             string
 	}
 	toString := func(e apexKeyEntry) string {
-		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n"
+		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\n"
 		if e.presigned {
 			return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition)
 		} else {
@@ -173,17 +173,9 @@
 
 	var filecontent strings.Builder
 	for _, name := range moduleNames {
-		fmt.Fprintf(&filecontent, "%s", toString(apexKeyMap[name]))
+		filecontent.WriteString(toString(apexKeyMap[name]))
 	}
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Description: "apexkeys.txt",
-		Output:      s.output,
-		Args: map[string]string{
-			"content": filecontent.String(),
-		},
-	})
+	android.WriteFileRule(ctx, s.output, filecontent.String())
 }
 
 func apexKeysTextFactory() android.Singleton {
diff --git a/cc/binary.go b/cc/binary.go
index 70cf5ff..da29412 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -95,6 +95,10 @@
 	// Names of symlinks to be installed for use in LOCAL_MODULE_SYMLINKS
 	symlinks []string
 
+	// If the module has symlink_preferred_arch set, the name of the symlink to the
+	// binary for the preferred arch.
+	preferredArchSymlink string
+
 	// Output archive of gcno coverage information
 	coverageOutputFile android.OptionalPath
 
@@ -402,7 +406,9 @@
 			ctx.PropertyErrorf("symlink_preferred_arch", "must also specify suffix")
 		}
 		if ctx.TargetPrimary() {
-			binary.symlinks = append(binary.symlinks, binary.getStemWithoutSuffix(ctx))
+			symlinkName := binary.getStemWithoutSuffix(ctx)
+			binary.symlinks = append(binary.symlinks, symlinkName)
+			binary.preferredArchSymlink = symlinkName
 		}
 	}
 
@@ -455,12 +461,26 @@
 		binary.baseInstaller.subDir = "bootstrap"
 	}
 	binary.baseInstaller.install(ctx, file)
+
+	var preferredArchSymlinkPath android.OptionalPath
 	for _, symlink := range binary.symlinks {
-		ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink, binary.baseInstaller.path)
+		installedSymlink := ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink,
+			binary.baseInstaller.path)
+		if symlink == binary.preferredArchSymlink {
+			// If this is the preferred arch symlink, save the installed path for use as the
+			// tool path.
+			preferredArchSymlinkPath = android.OptionalPathForPath(installedSymlink)
+		}
 	}
 
 	if ctx.Os().Class == android.Host {
-		binary.toolPath = android.OptionalPathForPath(binary.baseInstaller.path)
+		// If the binary is multilib with a symlink to the preferred architecture, use the
+		// symlink instead of the binary because that's the more "canonical" name.
+		if preferredArchSymlinkPath.Valid() {
+			binary.toolPath = preferredArchSymlinkPath
+		} else {
+			binary.toolPath = android.OptionalPathForPath(binary.baseInstaller.path)
+		}
 	}
 }
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index b803cba..f616cf3 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -296,8 +296,8 @@
 
 func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
 	t.Helper()
-	assertString(t, params.Rule.String(), android.WriteFile.String())
-	actual := strings.FieldsFunc(strings.ReplaceAll(params.Args["content"], "\\n", "\n"), func(r rune) bool { return r == '\n' })
+	content := android.ContentFromFileRuleForTests(t, params)
+	actual := strings.FieldsFunc(content, func(r rune) bool { return r == '\n' })
 	assertArrayString(t, actual, expected)
 }
 
diff --git a/cc/fuzz.go b/cc/fuzz.go
index fe3c12b..dddfe94 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -278,14 +278,7 @@
 
 	if fuzz.Properties.Fuzz_config != nil {
 		configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        android.WriteFile,
-			Description: "fuzzer infrastructure configuration",
-			Output:      configPath,
-			Args: map[string]string{
-				"content": fuzz.Properties.Fuzz_config.String(),
-			},
-		})
+		android.WriteFileRule(ctx, configPath, fuzz.Properties.Fuzz_config.String())
 		fuzz.config = configPath
 	}
 
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 238508d..05c06ac 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -93,13 +93,6 @@
 
 func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath {
 	outPath := android.PathForOutput(ctx, out)
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      outPath,
-		Description: "WriteFile " + out,
-		Args: map[string]string{
-			"content": content,
-		},
-	})
+	android.WriteFileRule(ctx, outPath, content)
 	return outPath
 }
diff --git a/cc/vndk.go b/cc/vndk.go
index 2cac03c..4a005f3 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -487,14 +487,7 @@
 	}
 
 	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      txt.outputFile,
-		Description: "Writing " + txt.outputFile.String(),
-		Args: map[string]string{
-			"content": strings.Join(list, "\\n"),
-		},
-	})
+	android.WriteFileRule(ctx, txt.outputFile, strings.Join(list, "\n"))
 
 	installPath := android.PathForModuleInstall(ctx, "etc")
 	ctx.InstallFile(installPath, filename, txt.outputFile)
@@ -825,14 +818,7 @@
 	merged = append(merged, addPrefix(filterOutLibClangRt(vndkcore), "VNDK-core: ")...)
 	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
 	c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Output:      c.vndkLibrariesFile,
-		Description: "Writing " + c.vndkLibrariesFile.String(),
-		Args: map[string]string{
-			"content": strings.Join(merged, "\\n"),
-		},
-	})
+	android.WriteFileRule(ctx, c.vndkLibrariesFile, strings.Join(merged, "\n"))
 }
 
 func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index 8d61901..b910a70 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -71,6 +71,10 @@
 
 	// Nested class loader subcontexts for dependencies.
 	Subcontexts []*ClassLoaderContext
+
+	// If the library is a shared library. This affects which elements of class loader context are
+	// added as <uses-library> tags by the manifest_fixer (dependencies of shared libraries aren't).
+	IsSharedLibrary bool
 }
 
 // ClassLoaderContextMap is a map from SDK version to a class loader context.
@@ -81,7 +85,7 @@
 
 // Add class loader context for the given library to the map entry for the given SDK version.
 func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
-	hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) error {
+	shared bool, hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) error {
 
 	// If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is
 	// not found. However, this is likely to result is disabling dexpreopt, as it won't be
@@ -110,6 +114,13 @@
 		devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
 	}
 
+	// Nested class loader context shouldn't have conditional part (it is allowed only at the top level).
+	for ver, _ := range nestedClcMap {
+		if ver != AnySdkVersion {
+			clcStr, _ := ComputeClassLoaderContext(nestedClcMap)
+			return fmt.Errorf("nested class loader context shouldn't have conditional part: %s", clcStr)
+		}
+	}
 	subcontexts := nestedClcMap[AnySdkVersion]
 
 	// If the library with this name is already present as one of the unconditional top-level
@@ -121,50 +132,66 @@
 	}
 
 	clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{
-		Name:        lib,
-		Host:        hostPath,
-		Device:      devicePath,
-		Subcontexts: subcontexts,
+		Name:            lib,
+		Host:            hostPath,
+		Device:          devicePath,
+		Subcontexts:     subcontexts,
+		IsSharedLibrary: shared,
 	})
 	return nil
 }
 
 // Wrapper around addContext that reports errors.
 func (clcMap ClassLoaderContextMap) addContextOrReportError(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
-	hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) {
+	shared bool, hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) {
 
-	err := clcMap.addContext(ctx, sdkVer, lib, hostPath, installPath, strict, nestedClcMap)
+	err := clcMap.addContext(ctx, sdkVer, lib, shared, hostPath, installPath, strict, nestedClcMap)
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
-		android.ReportPathErrorf(ctx, err.Error())
 	}
 }
 
 // Add class loader context. Fail on unknown build/install paths.
 func (clcMap ClassLoaderContextMap) AddContext(ctx android.ModuleInstallPathContext, lib string,
-	hostPath, installPath android.Path) {
+	shared bool, hostPath, installPath android.Path) {
 
-	clcMap.addContextOrReportError(ctx, AnySdkVersion, lib, hostPath, installPath, true, nil)
+	clcMap.addContextOrReportError(ctx, AnySdkVersion, lib, shared, hostPath, installPath, true, nil)
 }
 
 // Add class loader context if the library exists. Don't fail on unknown build/install paths.
 func (clcMap ClassLoaderContextMap) MaybeAddContext(ctx android.ModuleInstallPathContext, lib *string,
-	hostPath, installPath android.Path) {
+	shared bool, hostPath, installPath android.Path) {
 
 	if lib != nil {
-		clcMap.addContextOrReportError(ctx, AnySdkVersion, *lib, hostPath, installPath, false, nil)
+		clcMap.addContextOrReportError(ctx, AnySdkVersion, *lib, shared, hostPath, installPath, false, nil)
 	}
 }
 
 // Add class loader context for the given SDK version. Fail on unknown build/install paths.
 func (clcMap ClassLoaderContextMap) AddContextForSdk(ctx android.ModuleInstallPathContext, sdkVer int,
-	lib string, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
+	lib string, shared bool, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
 
-	clcMap.addContextOrReportError(ctx, sdkVer, lib, hostPath, installPath, true, nestedClcMap)
+	clcMap.addContextOrReportError(ctx, sdkVer, lib, shared, hostPath, installPath, true, nestedClcMap)
 }
 
 // Merge the other class loader context map into this one, do not override existing entries.
-func (clcMap ClassLoaderContextMap) AddContextMap(otherClcMap ClassLoaderContextMap) {
+// The implicitRootLib parameter is the name of the library for which the other class loader
+// context map was constructed. If the implicitRootLib is itself a <uses-library>, it should be
+// already present in the class loader context (with the other context as its subcontext) -- in
+// that case do not re-add the other context. Otherwise add the other context at the top-level.
+func (clcMap ClassLoaderContextMap) AddContextMap(otherClcMap ClassLoaderContextMap, implicitRootLib string) {
+	if otherClcMap == nil {
+		return
+	}
+
+	// If the implicit root of the merged map is already present as one of top-level subtrees, do
+	// not merge it second time.
+	for _, clc := range clcMap[AnySdkVersion] {
+		if clc.Name == implicitRootLib {
+			return
+		}
+	}
+
 	for sdkVer, otherClcs := range otherClcMap {
 		for _, otherClc := range otherClcs {
 			alreadyHave := false
@@ -181,7 +208,9 @@
 	}
 }
 
-// List of libraries in the unconditional class loader context, excluding dependencies of shared libraries.
+// List of libraries in the unconditional class loader context, excluding dependencies of shared
+// libraries. These libraries should be in the <uses-library> tags in the manifest. Some of them may
+// be present in the original manifest, others are added by the manifest_fixer.
 func (clcMap ClassLoaderContextMap) UsesLibs() (ulibs []string) {
 	if clcMap != nil {
 		// compatibility libraries (those in conditional context) are not added to <uses-library> tags
@@ -194,7 +223,12 @@
 func usesLibsRec(clcs []*ClassLoaderContext) (ulibs []string) {
 	for _, clc := range clcs {
 		ulibs = append(ulibs, clc.Name)
-		ulibs = append(ulibs, usesLibsRec(clc.Subcontexts)...)
+		// <uses-library> tags in the manifest should not include dependencies of shared libraries,
+		// because PackageManager already tracks all such dependencies and automatically adds their
+		// class loader contexts as subcontext of the shared library.
+		if !clc.IsSharedLibrary {
+			ulibs = append(ulibs, usesLibsRec(clc.Subcontexts)...)
+		}
 	}
 	return ulibs
 }
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 269a0db..abfca27 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -25,6 +25,11 @@
 	"android/soong/android"
 )
 
+const (
+	shared    = true  // dependencies are not added to uses libs
+	nonshared = false // dependencies are added to uses libs
+)
+
 func TestCLC(t *testing.T) {
 	// Construct class loader context with the following structure:
 	// .
@@ -50,45 +55,50 @@
 
 	m := make(ClassLoaderContextMap)
 
-	m.AddContext(ctx, "a", buildPath(ctx, "a"), installPath(ctx, "a"))
-	m.AddContext(ctx, "b", buildPath(ctx, "b"), installPath(ctx, "b"))
+	m.AddContext(ctx, "a", nonshared, buildPath(ctx, "a"), installPath(ctx, "a"))
+	m.AddContext(ctx, "b", shared, buildPath(ctx, "b"), installPath(ctx, "b"))
 
 	// "Maybe" variant in the good case: add as usual.
 	c := "c"
-	m.MaybeAddContext(ctx, &c, buildPath(ctx, "c"), installPath(ctx, "c"))
+	m.MaybeAddContext(ctx, &c, nonshared, buildPath(ctx, "c"), installPath(ctx, "c"))
 
 	// "Maybe" variant in the bad case: don't add library with unknown name, keep going.
-	m.MaybeAddContext(ctx, nil, nil, nil)
+	m.MaybeAddContext(ctx, nil, nonshared, nil, nil)
 
 	// Add some libraries with nested subcontexts.
 
 	m1 := make(ClassLoaderContextMap)
-	m1.AddContext(ctx, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"))
-	m1.AddContext(ctx, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"))
+	m1.AddContext(ctx, "a1", nonshared, buildPath(ctx, "a1"), installPath(ctx, "a1"))
+	m1.AddContext(ctx, "b1", shared, buildPath(ctx, "b1"), installPath(ctx, "b1"))
 
 	m2 := make(ClassLoaderContextMap)
-	m2.AddContext(ctx, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"))
-	m2.AddContext(ctx, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"))
-	m2.AddContextForSdk(ctx, AnySdkVersion, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
+	m2.AddContext(ctx, "a2", nonshared, buildPath(ctx, "a2"), installPath(ctx, "a2"))
+	m2.AddContext(ctx, "b2", shared, buildPath(ctx, "b2"), installPath(ctx, "b2"))
+	m2.AddContextForSdk(ctx, AnySdkVersion, "c2", shared, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
 
 	m3 := make(ClassLoaderContextMap)
-	m3.AddContext(ctx, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"))
-	m3.AddContext(ctx, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"))
+	m3.AddContext(ctx, "a3", nonshared, buildPath(ctx, "a3"), installPath(ctx, "a3"))
+	m3.AddContext(ctx, "b3", shared, buildPath(ctx, "b3"), installPath(ctx, "b3"))
 
-	m.AddContextForSdk(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
+	m.AddContextForSdk(ctx, AnySdkVersion, "d", nonshared, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
 	// When the same library is both in conditional and unconditional context, it should be removed
 	// from conditional context.
-	m.AddContextForSdk(ctx, 42, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
-	m.AddContextForSdk(ctx, AnySdkVersion, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
-	m.AddContextMap(m3)
+	m.AddContextForSdk(ctx, 42, "f", nonshared, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+	m.AddContextForSdk(ctx, AnySdkVersion, "f", nonshared, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+
+	// Merge map with implicit root library that is among toplevel contexts => does nothing.
+	m.AddContextMap(m1, "c")
+	// Merge map with implicit root library that is not among toplevel contexts => all subcontexts
+	// of the other map are added as toplevel contexts.
+	m.AddContextMap(m3, "m_g")
 
 	// Compatibility libraries with unknown install paths get default paths.
-	m.AddContextForSdk(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
-	m.AddContextForSdk(ctx, 29, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil, nil)
+	m.AddContextForSdk(ctx, 29, AndroidHidlManager, nonshared, buildPath(ctx, AndroidHidlManager), nil, nil)
+	m.AddContextForSdk(ctx, 29, AndroidHidlBase, nonshared, buildPath(ctx, AndroidHidlBase), nil, nil)
 
 	// Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
 	// needed as a compatibility library if "android.test.runner" is in CLC as well.
-	m.AddContextForSdk(ctx, 30, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil, nil)
+	m.AddContextForSdk(ctx, 30, AndroidTestMock, nonshared, buildPath(ctx, AndroidTestMock), nil, nil)
 
 	valid, validationError := validateClassLoaderContext(m)
 
@@ -148,7 +158,7 @@
 
 	// Test for libraries that are added by the manifest_fixer.
 	t.Run("uses libs", func(t *testing.T) {
-		wantUsesLibs := []string{"a", "b", "c", "d", "a2", "b2", "c2", "a1", "b1", "f", "a3", "b3"}
+		wantUsesLibs := []string{"a", "b", "c", "d", "a2", "b2", "c2", "f", "a3", "b3"}
 		if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
 			t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
 		}
@@ -159,7 +169,7 @@
 func TestCLCUnknownBuildPath(t *testing.T) {
 	ctx := testContext()
 	m := make(ClassLoaderContextMap)
-	err := m.addContext(ctx, AnySdkVersion, "a", nil, nil, true, nil)
+	err := m.addContext(ctx, AnySdkVersion, "a", nonshared, nil, nil, true, nil)
 	checkError(t, err, "unknown build path to <uses-library> \"a\"")
 }
 
@@ -167,7 +177,7 @@
 func TestCLCUnknownInstallPath(t *testing.T) {
 	ctx := testContext()
 	m := make(ClassLoaderContextMap)
-	err := m.addContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, true, nil)
+	err := m.addContext(ctx, AnySdkVersion, "a", nonshared, buildPath(ctx, "a"), nil, true, nil)
 	checkError(t, err, "unknown install path to <uses-library> \"a\"")
 }
 
@@ -176,7 +186,7 @@
 
 	m := make(ClassLoaderContextMap)
 	a := "a"
-	m.MaybeAddContext(ctx, &a, nil, nil)
+	m.MaybeAddContext(ctx, &a, nonshared, nil, nil)
 
 	// The library should be added to <uses-library> tags by the manifest_fixer.
 	t.Run("maybe add", func(t *testing.T) {
@@ -194,6 +204,16 @@
 	})
 }
 
+// An attempt to add conditional nested subcontext should fail.
+func TestCLCNestedConditional(t *testing.T) {
+	ctx := testContext()
+	m1 := make(ClassLoaderContextMap)
+	m1.AddContextForSdk(ctx, 42, "a", nonshared, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+	m := make(ClassLoaderContextMap)
+	err := m.addContext(ctx, AnySdkVersion, "b", nonshared, buildPath(ctx, "b"), installPath(ctx, "b"), true, m1)
+	checkError(t, err, "nested class loader context shouldn't have conditional part")
+}
+
 func checkError(t *testing.T, have error, want string) {
 	if have == nil {
 		t.Errorf("\nwant error: '%s'\nhave: none", want)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index cfa4c55..f52ecb4 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -486,13 +486,7 @@
 		return
 	}
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   android.WriteFile,
-		Output: android.PathForOutput(ctx, "dexpreopt_soong.config"),
-		Args: map[string]string{
-			"content": string(data),
-		},
-	})
+	android.WriteFileRule(ctx, android.PathForOutput(ctx, "dexpreopt_soong.config"), string(data))
 }
 
 func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) {
diff --git a/java/aar.go b/java/aar.go
index c8faed0..051715d 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -109,7 +109,6 @@
 	useEmbeddedNativeLibs   bool
 	useEmbeddedDex          bool
 	usesNonSdkApis          bool
-	sdkLibraries            dexpreopt.ClassLoaderContextMap
 	hasNoCode               bool
 	LoggingParent           string
 	resourceFiles           android.Paths
@@ -259,18 +258,17 @@
 		CommandDeps: []string{"${config.Zip2ZipCmd}"},
 	})
 
-func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
+func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext,
+	classLoaderContexts dexpreopt.ClassLoaderContextMap, extraLinkFlags ...string) {
 
-	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries :=
-		aaptLibs(ctx, sdkContext)
-
-	a.sdkLibraries = sdkLibraries
+	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags :=
+		aaptLibs(ctx, sdkContext, classLoaderContexts)
 
 	// App manifest file
 	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
-	manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
+	manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, classLoaderContexts,
 		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
 		a.LoggingParent)
 
@@ -391,29 +389,31 @@
 }
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
-func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
-	staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.ClassLoaderContextMap) {
+func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) (
+	transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) {
 
 	var sharedLibs android.Paths
 
+	if classLoaderContexts == nil {
+		// Not all callers need to compute class loader context, those who don't just pass nil.
+		// Create a temporary class loader context here (it will be computed, but not used).
+		classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
+	}
+
 	sdkDep := decodeSdkDep(ctx, sdkContext)
 	if sdkDep.useFiles {
 		sharedLibs = append(sharedLibs, sdkDep.jars...)
 	}
 
-	sdkLibraries = make(dexpreopt.ClassLoaderContextMap)
-
 	ctx.VisitDirectDeps(func(module android.Module) {
+		depName := ctx.OtherModuleName(module)
+
 		var exportPackage android.Path
 		aarDep, _ := module.(AndroidLibraryDependency)
 		if aarDep != nil {
 			exportPackage = aarDep.ExportPackage()
 		}
 
-		if dep, ok := module.(Dependency); ok {
-			sdkLibraries.AddContextMap(dep.ExportedSdkLibs())
-		}
-
 		switch ctx.OtherModuleDependencyTag(module) {
 		case instrumentationForTag:
 			// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
@@ -426,7 +426,7 @@
 			// (including the java_sdk_library) itself then append any implicit sdk library
 			// names to the list of sdk libraries to be added to the manifest.
 			if component, ok := module.(SdkLibraryComponentDependency); ok {
-				sdkLibraries.MaybeAddContext(ctx, component.OptionalImplicitSdkLibrary(),
+				classLoaderContexts.MaybeAddContext(ctx, component.OptionalImplicitSdkLibrary(), true,
 					component.DexJarBuildPath(), component.DexJarInstallPath())
 			}
 
@@ -439,7 +439,7 @@
 				transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
 				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
 				transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
-				sdkLibraries.AddContextMap(aarDep.ExportedSdkLibs())
+				classLoaderContexts.AddContextMap(aarDep.ClassLoaderContexts(), depName)
 				if aarDep.ExportedAssets().Valid() {
 					assets = append(assets, aarDep.ExportedAssets().Path())
 				}
@@ -457,6 +457,12 @@
 				}
 			}
 		}
+
+		// 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)
+		}
 	})
 
 	deps = append(deps, sharedLibs...)
@@ -473,7 +479,7 @@
 	transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
 	transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
 
-	return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries
+	return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags
 }
 
 type AndroidLibrary struct {
@@ -508,8 +514,8 @@
 
 func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.aapt.isLibrary = true
-	a.aapt.buildActions(ctx, sdkContext(a))
-	a.exportedSdkLibs = a.aapt.sdkLibraries
+	a.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
+	a.aapt.buildActions(ctx, sdkContext(a), a.classLoaderContexts)
 
 	a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
 
@@ -781,12 +787,11 @@
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags, sdkLibraries :=
-		aaptLibs(ctx, sdkContext(a))
+	transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags :=
+		aaptLibs(ctx, sdkContext(a), nil)
 
 	_ = staticLibManifests
 	_ = staticRRODirs
-	_ = sdkLibraries
 
 	linkDeps = append(linkDeps, libDeps...)
 	linkFlags = append(linkFlags, libFlags...)
@@ -827,7 +832,7 @@
 	return nil
 }
 
-func (a *AARImport) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
+func (a *AARImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
 	return nil
 }
 
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 6b39c35..c76bb2f 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -44,7 +44,7 @@
 
 // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
 func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
-	sdkLibraries dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
+	classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
 	useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
 
 	var args []string
@@ -71,7 +71,7 @@
 		args = append(args, "--use-embedded-dex")
 	}
 
-	for _, usesLib := range sdkLibraries.UsesLibs() {
+	for _, usesLib := range classLoaderContexts.UsesLibs() {
 		if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
 			args = append(args, "--optional-uses-library", usesLib)
 		} else {
diff --git a/java/androidmk.go b/java/androidmk.go
index c606245..f263cb8 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -115,7 +115,7 @@
 						entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
 					}
 
-					entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs.UsesLibs()...)
+					entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.classLoaderContexts.UsesLibs()...)
 
 					if len(library.additionalCheckedModules) != 0 {
 						entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
diff --git a/java/app.go b/java/app.go
index 4848fae..17de8b9 100755
--- a/java/app.go
+++ b/java/app.go
@@ -565,9 +565,8 @@
 	aaptLinkFlags = append(aaptLinkFlags, a.additionalAaptFlags...)
 
 	a.aapt.splitNames = a.appProperties.Package_splits
-	a.aapt.sdkLibraries = a.exportedSdkLibs
 	a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
-	a.aapt.buildActions(ctx, sdkContext(a), aaptLinkFlags...)
+	a.aapt.buildActions(ctx, sdkContext(a), a.classLoaderContexts, aaptLinkFlags...)
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -601,7 +600,7 @@
 	return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
 }
 
-func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.ClassLoaderContextMap) android.Path {
+func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
 	a.dexpreopter.installPath = a.installPath(ctx)
 	if a.dexProperties.Uncompress_dex == nil {
 		// If the value was not force-set by the user, use reasonable default based on the module.
@@ -609,10 +608,8 @@
 	}
 	a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex
 	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
-	a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
-	a.dexpreopter.classLoaderContexts.AddContextMap(sdkLibs)
+	a.dexpreopter.classLoaderContexts = a.classLoaderContexts
 	a.dexpreopter.manifestFile = a.mergedManifestFile
-	a.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
 
 	if ctx.ModuleName() != "framework-res" {
 		a.Module.compile(ctx, a.aaptSrcJar)
@@ -782,6 +779,8 @@
 		a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput
 	}
 
+	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+
 	// Process all building blocks, from AAPT to certificates.
 	a.aaptBuildActions(ctx)
 
@@ -789,7 +788,7 @@
 	a.usesLibrary.freezeEnforceUsesLibraries()
 
 	// Add implicit SDK libraries to <uses-library> list.
-	for _, usesLib := range a.aapt.sdkLibraries.UsesLibs() {
+	for _, usesLib := range a.classLoaderContexts.UsesLibs() {
 		a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs))
 	}
 
@@ -806,7 +805,7 @@
 	a.linter.resources = a.aapt.resourceFiles
 	a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
 
-	dexJarFile := a.dexBuildActions(ctx, a.aapt.sdkLibraries)
+	dexJarFile := a.dexBuildActions(ctx)
 
 	jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
 	jniJarFile := a.jniBuildActions(jniLibs, ctx)
@@ -1848,7 +1847,7 @@
 		aaptLinkFlags = append(aaptLinkFlags,
 			"--rename-overlay-target-package "+*r.overridableProperties.Target_package_name)
 	}
-	r.aapt.buildActions(ctx, r, aaptLinkFlags...)
+	r.aapt.buildActions(ctx, r, nil, aaptLinkFlags...)
 
 	// Sign the built package
 	_, certificates := collectAppDeps(ctx, r, false, false)
@@ -1982,8 +1981,8 @@
 			if tag, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
 				dep := ctx.OtherModuleName(m)
 				if lib, ok := m.(Dependency); ok {
-					clcMap.AddContextForSdk(ctx, tag.sdkVersion, dep,
-						lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ExportedSdkLibs())
+					clcMap.AddContextForSdk(ctx, tag.sdkVersion, dep, isSharedSdkLibrary(m),
+						lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
 				} else if ctx.Config().AllowMissingDependencies() {
 					ctx.AddMissingDependencies([]string{dep})
 				} else {
@@ -1996,6 +1995,11 @@
 	return clcMap
 }
 
+func isSharedSdkLibrary(m android.Module) bool {
+	lib, ok := m.(SdkLibraryDependency)
+	return ok && lib.IsSharedLibrary()
+}
+
 // enforceUsesLibraries returns true of <uses-library> tags should be checked against uses_libs and optional_uses_libs
 // properties.  Defaults to true if either of uses_libs or optional_uses_libs is specified.  Will default to true
 // unconditionally in the future.
diff --git a/java/builder.go b/java/builder.go
index 3043e46..cd35245 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -572,14 +572,7 @@
 }
 
 func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.WritablePath, mainClass string) {
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.WriteFile,
-		Description: "manifest",
-		Output:      outputFile,
-		Args: map[string]string{
-			"content": "Main-Class: " + mainClass + "\n",
-		},
-	})
+	android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n")
 }
 
 func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path) {
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index d8b617e..cd395b1 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -163,7 +163,7 @@
 	return nil
 }
 
-func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
+func (d *DeviceHostConverter) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
 	return nil
 }
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 629d34f..f9975ba 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -651,14 +651,8 @@
 		updatableBcpPackagesName := "updatable-bcp-packages.txt"
 		updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
 
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.WriteFile,
-			Output: updatableBcpPackages,
-			Args: map[string]string{
-				// WriteFile automatically adds the last end-of-line.
-				"content": strings.Join(updatablePackages, "\\n"),
-			},
-		})
+		// WriteFileRule automatically adds the last end-of-line.
+		android.WriteFileRule(ctx, updatableBcpPackages, strings.Join(updatablePackages, "\n"))
 
 		rule := android.NewRuleBuilder()
 		rule.MissingDeps(missingDeps)
@@ -720,13 +714,7 @@
 func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
 	data := dexpreopt.GetGlobalConfigRawData(ctx)
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   android.WriteFile,
-		Output: path,
-		Args: map[string]string{
-			"content": string(data),
-		},
-	})
+	android.WriteFileRule(ctx, path, string(data))
 }
 
 // Export paths for default boot image to Make
diff --git a/java/java.go b/java/java.go
index 31466b0..5ded041 100644
--- a/java/java.go
+++ b/java/java.go
@@ -417,7 +417,7 @@
 	overrideManifest android.OptionalPath
 
 	// map of SDK version to class loader context
-	exportedSdkLibs dexpreopt.ClassLoaderContextMap
+	classLoaderContexts dexpreopt.ClassLoaderContextMap
 
 	// list of plugins that this java module is exporting
 	exportedPluginJars android.Paths
@@ -509,7 +509,7 @@
 	ImplementationJars() android.Paths
 	ResourceJars() android.Paths
 	AidlIncludeDirs() android.Paths
-	ExportedSdkLibs() dexpreopt.ClassLoaderContextMap
+	ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
 	ExportedPlugins() (android.Paths, []string)
 	SrcJarArgs() ([]string, android.Paths)
 	BaseModuleName() string
@@ -1027,7 +1027,7 @@
 			case libTag:
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
 				// names of sdk libs that are directly depended are exported
-				j.exportedSdkLibs.MaybeAddContext(ctx, dep.OptionalImplicitSdkLibrary(),
+				j.classLoaderContexts.MaybeAddContext(ctx, dep.OptionalImplicitSdkLibrary(), true,
 					dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			case staticLibTag:
 				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
@@ -1039,7 +1039,7 @@
 			case libTag, instrumentationForTag:
 				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
 				// sdk lib names from dependencies are re-exported
-				j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs())
+				j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 				pluginJars, pluginClasses := dep.ExportedPlugins()
 				addPlugins(&deps, pluginJars, pluginClasses...)
@@ -1051,7 +1051,7 @@
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
 				deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
 				// sdk lib names from dependencies are re-exported
-				j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs())
+				j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 				pluginJars, pluginClasses := dep.ExportedPlugins()
 				addPlugins(&deps, pluginJars, pluginClasses...)
@@ -1903,8 +1903,8 @@
 	return j.exportAidlIncludeDirs
 }
 
-func (j *Module) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
-	return j.exportedSdkLibs
+func (j *Module) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
+	return j.classLoaderContexts
 }
 
 func (j *Module) ExportedPlugins() (android.Paths, []string) {
@@ -2042,7 +2042,7 @@
 		j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
 	}
 	j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
-	j.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
+	j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
 	j.compile(ctx, nil)
 
 	// Collect the module directory for IDE info in java/jdeps.go.
@@ -2062,12 +2062,12 @@
 	// add the name of that java_sdk_library to the exported sdk libs to make sure
 	// that, if necessary, a <uses-library> element for that java_sdk_library is
 	// added to the Android manifest.
-	j.exportedSdkLibs.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
+	j.classLoaderContexts.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(), true,
 		j.DexJarBuildPath(), j.DexJarInstallPath())
 
 	// A non-SDK library may provide a <uses-library> (the name may be different from the module name).
 	if lib := proptools.String(j.usesLibraryProperties.Provides_uses_lib); lib != "" {
-		j.exportedSdkLibs.AddContext(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
+		j.classLoaderContexts.AddContext(ctx, lib, true, j.DexJarBuildPath(), j.DexJarInstallPath())
 	}
 
 	j.distFiles = j.GenerateTaggedDistFiles(ctx)
@@ -2646,7 +2646,7 @@
 	dexJarFile android.Path
 
 	combinedClasspathFile android.Path
-	exportedSdkLibs       dexpreopt.ClassLoaderContextMap
+	classLoaderContexts   dexpreopt.ClassLoaderContextMap
 	exportAidlIncludeDirs android.Paths
 
 	hideApexVariantFromMake bool
@@ -2721,7 +2721,7 @@
 		TransformJetifier(ctx, outputFile, inputFile)
 	}
 	j.combinedClasspathFile = outputFile
-	j.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
+	j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
 
 	var flags javaBuilderFlags
 
@@ -2735,7 +2735,7 @@
 			case libTag, staticLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars()...)
 				// sdk lib names from dependencies are re-exported
-				j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs())
+				j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
 			case bootClasspathTag:
 				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
 			}
@@ -2744,7 +2744,7 @@
 			case libTag:
 				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
 				// names of sdk libs that are directly depended are exported
-				j.exportedSdkLibs.AddContext(ctx, otherName,
+				j.classLoaderContexts.AddContext(ctx, otherName, dep.IsSharedLibrary(),
 					dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			}
 		}
@@ -2760,7 +2760,7 @@
 	// add the name of that java_sdk_library to the exported sdk libs to make sure
 	// that, if necessary, a <uses-library> element for that java_sdk_library is
 	// added to the Android manifest.
-	j.exportedSdkLibs.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
+	j.classLoaderContexts.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(), true,
 		outputFile, installFile)
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -2843,8 +2843,8 @@
 	return j.exportAidlIncludeDirs
 }
 
-func (j *Import) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
-	return j.exportedSdkLibs
+func (j *Import) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
+	return j.classLoaderContexts
 }
 
 func (j *Import) ExportedPlugins() (android.Paths, []string) {
diff --git a/java/java_test.go b/java/java_test.go
index 4594b81..87d6ebb 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1593,7 +1593,7 @@
 	// test if baz has exported SDK lib names foo and bar to qux
 	qux := ctx.ModuleForTests("qux", "android_common")
 	if quxLib, ok := qux.Module().(*Library); ok {
-		sdkLibs := quxLib.ExportedSdkLibs().UsesLibs()
+		sdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
 		if w := []string{"foo", "bar", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
 			t.Errorf("qux should export %q but exports %q", w, sdkLibs)
 		}
diff --git a/java/robolectric.go b/java/robolectric.go
index 04fc117..62d1d99 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -389,8 +389,10 @@
 		}
 		runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "")
 
+		// TODO(murj) Update this to ctx.Config().PlatformSdkCodename() once the platform
+		// classes like android.os.Build are updated to S.
 		runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar",
-			ctx.Config().PlatformSdkCodename())
+			"R")
 		installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar)
 		r.runtimes = append(r.runtimes, installedRuntime)
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 21c03cd..13cd5f9 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -673,6 +673,11 @@
 	return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName())
 }
 
+// If the SDK library is a shared library.
+func (c *commonToSdkLibraryAndImport) IsSharedLibrary() bool {
+	return c.sharedLibrary()
+}
+
 // The component names for different outputs of the java_sdk_library.
 //
 // They are similar to the names used for the child modules it creates
@@ -918,6 +923,9 @@
 	// jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
 	// they are identical to the corresponding header jars.
 	SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
+
+	// If the SDK library is a shared library.
+	IsSharedLibrary() bool
 }
 
 type SdkLibrary struct {
diff --git a/python/python.go b/python/python.go
index 945e264..e4c8e94 100644
--- a/python/python.go
+++ b/python/python.go
@@ -300,7 +300,7 @@
 }
 
 func (p *Module) hasSrcExt(ctx android.BottomUpMutatorContext, ext string) bool {
-	return hasSrcExt(p.properties.Srcs, protoExt)
+	return hasSrcExt(p.properties.Srcs, ext)
 }
 
 func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 84e4f28..b1eebe9 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -109,6 +109,7 @@
     name: "mysdk_sdkmember@current",
     sdk_member_name: "sdkmember",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     installable: false,
     stl: "none",
@@ -131,6 +132,7 @@
     name: "sdkmember",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     stl: "none",
     compile_multilib: "64",
@@ -353,6 +355,7 @@
     name: "mysdk_crtobj@current",
     sdk_member_name: "crtobj",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     sanitize: {
@@ -372,6 +375,7 @@
     name: "crtobj",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     sanitize: {
@@ -480,6 +484,7 @@
     name: "mysdk_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     stl: "none",
     compile_multilib: "both",
@@ -511,6 +516,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
@@ -575,6 +581,7 @@
     name: "mymodule_exports_mynativebinary@current",
     sdk_member_name: "mynativebinary",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     compile_multilib: "both",
     arch: {
@@ -591,6 +598,7 @@
     name: "mynativebinary",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     compile_multilib: "both",
     arch: {
         arm64: {
@@ -654,6 +662,7 @@
     name: "myexports_mynativebinary@current",
     sdk_member_name: "mynativebinary",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -687,6 +696,7 @@
     name: "mynativebinary",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -802,6 +812,7 @@
     name: "myexports_mynativebinary@current",
     sdk_member_name: "mynativebinary",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -822,6 +833,7 @@
     name: "mynativebinary",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -841,6 +853,7 @@
     name: "myexports_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -861,6 +874,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -933,6 +947,7 @@
     name: "mymodule_exports_linker@current",
     sdk_member_name: "linker",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -959,6 +974,7 @@
     name: "linker",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -1167,6 +1183,7 @@
     name: "mysdk_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     stl: "none",
     compile_multilib: "both",
@@ -1188,6 +1205,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     shared_libs: [
@@ -1208,6 +1226,7 @@
     name: "mysdk_myothernativelib@current",
     sdk_member_name: "myothernativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     stl: "none",
     compile_multilib: "both",
@@ -1226,6 +1245,7 @@
     name: "myothernativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     system_shared_libs: ["libm"],
@@ -1243,6 +1263,7 @@
     name: "mysdk_mysystemnativelib@current",
     sdk_member_name: "mysystemnativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     stl: "none",
     compile_multilib: "both",
@@ -1260,6 +1281,7 @@
     name: "mysystemnativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     arch: {
@@ -1327,6 +1349,7 @@
     name: "mysdk_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -1355,6 +1378,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     sdk_version: "minimum",
@@ -1449,6 +1473,7 @@
     name: "mysdk_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -1482,6 +1507,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -1572,6 +1598,7 @@
     name: "myexports_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     stl: "none",
     compile_multilib: "both",
@@ -1592,6 +1619,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
@@ -1660,6 +1688,7 @@
     name: "myexports_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -1687,6 +1716,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -1769,6 +1799,7 @@
     name: "myexports_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     recovery_available: true,
     vendor_available: true,
@@ -1799,6 +1830,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     recovery_available: true,
     vendor_available: true,
     stl: "none",
@@ -1877,6 +1909,7 @@
     name: "myexports_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     installable: false,
@@ -1899,6 +1932,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -1964,6 +1998,7 @@
     name: "mysdk_mynativeheaders@current",
     sdk_member_name: "mynativeheaders",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
@@ -1973,6 +2008,7 @@
     name: "mynativeheaders",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
@@ -2016,6 +2052,7 @@
     name: "mysdk_mynativeheaders@current",
     sdk_member_name: "mynativeheaders",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -2038,6 +2075,7 @@
     name: "mynativeheaders",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     stl: "none",
@@ -2113,6 +2151,7 @@
     name: "mysdk_mynativeheaders@current",
     sdk_member_name: "mynativeheaders",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     stl: "none",
     compile_multilib: "both",
@@ -2140,6 +2179,7 @@
     name: "mynativeheaders",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     stl: "none",
     compile_multilib: "both",
@@ -2220,6 +2260,7 @@
     name: "mysdk_sslnil@current",
     sdk_member_name: "sslnil",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     compile_multilib: "both",
     arch: {
@@ -2236,6 +2277,7 @@
     name: "sslnil",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     compile_multilib: "both",
     arch: {
         arm64: {
@@ -2251,6 +2293,7 @@
     name: "mysdk_sslempty@current",
     sdk_member_name: "sslempty",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     compile_multilib: "both",
     system_shared_libs: [],
@@ -2268,6 +2311,7 @@
     name: "sslempty",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     compile_multilib: "both",
     system_shared_libs: [],
     arch: {
@@ -2284,6 +2328,7 @@
     name: "mysdk_sslnonempty@current",
     sdk_member_name: "sslnonempty",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     compile_multilib: "both",
     system_shared_libs: ["mysdk_sslnil@current"],
@@ -2301,6 +2346,7 @@
     name: "sslnonempty",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     compile_multilib: "both",
     system_shared_libs: ["sslnil"],
     arch: {
@@ -2350,6 +2396,7 @@
     name: "mysdk_sslvariants@current",
     sdk_member_name: "sslvariants",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     installable: false,
     compile_multilib: "both",
@@ -2381,6 +2428,7 @@
     name: "sslvariants",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     compile_multilib: "both",
     target: {
@@ -2456,6 +2504,7 @@
     name: "mysdk_stubslib@current",
     sdk_member_name: "stubslib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     compile_multilib: "both",
     stubs: {
@@ -2479,6 +2528,7 @@
     name: "stubslib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     compile_multilib: "both",
     stubs: {
         versions: [
@@ -2537,6 +2587,7 @@
     name: "mysdk_stubslib@current",
     sdk_member_name: "stubslib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     installable: false,
     compile_multilib: "both",
@@ -2572,6 +2623,7 @@
     name: "stubslib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     compile_multilib: "both",
     stubs: {
@@ -2645,6 +2697,7 @@
     name: "mysdk_mylib@current",
     sdk_member_name: "mylib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     installable: false,
     unique_host_soname: true,
@@ -2674,6 +2727,7 @@
     name: "mylib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     unique_host_soname: true,
     compile_multilib: "both",
@@ -2755,6 +2809,7 @@
     name: "mysdk_mynativelib@current",
     sdk_member_name: "mynativelib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     installable: false,
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
@@ -2772,6 +2827,7 @@
     name: "mynativelib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
diff --git a/sdk/exports_test.go b/sdk/exports_test.go
index aa1200f..1c59244 100644
--- a/sdk/exports_test.go
+++ b/sdk/exports_test.go
@@ -50,6 +50,7 @@
     name: "myexports_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
@@ -57,6 +58,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 731e528..ec8ebb3 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -122,6 +122,7 @@
     name: "mysdk_sdkmember@current",
     sdk_member_name: "sdkmember",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/sdkmember.jar"],
 }
 
@@ -129,6 +130,7 @@
     name: "sdkmember",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/sdkmember.jar"],
 }
 
@@ -247,6 +249,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
@@ -254,6 +257,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
@@ -302,6 +306,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/myjavalib.jar"],
@@ -311,6 +316,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/myjavalib.jar"],
@@ -357,6 +363,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     target: {
         android: {
@@ -372,6 +379,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     target: {
         android: {
@@ -426,6 +434,7 @@
     name: "myexports_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
@@ -433,6 +442,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
@@ -481,6 +491,7 @@
     name: "myexports_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/myjavalib.jar"],
@@ -490,6 +501,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/myjavalib.jar"],
@@ -535,6 +547,7 @@
     name: "myexports_myjavatests@current",
     sdk_member_name: "myjavatests",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavatests.jar"],
     test_config: "java/myjavatests-AndroidTest.xml",
 }
@@ -543,6 +556,7 @@
     name: "myjavatests",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavatests.jar"],
     test_config: "java/myjavatests-AndroidTest.xml",
 }
@@ -588,6 +602,7 @@
     name: "myexports_myjavatests@current",
     sdk_member_name: "myjavatests",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/myjavatests.jar"],
@@ -598,6 +613,7 @@
     name: "myjavatests",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/myjavatests.jar"],
@@ -655,6 +671,7 @@
     name: "mysdk_exported-system-module@current",
     sdk_member_name: "exported-system-module",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/exported-system-module.jar"],
 }
 
@@ -662,6 +679,7 @@
     name: "exported-system-module",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/exported-system-module.jar"],
 }
 
@@ -669,6 +687,7 @@
     name: "mysdk_system-module@current",
     sdk_member_name: "system-module",
     visibility: ["//visibility:private"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/system-module.jar"],
 }
 
@@ -676,6 +695,7 @@
     name: "mysdk_system-module",
     prefer: false,
     visibility: ["//visibility:private"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/system-module.jar"],
 }
 
@@ -747,6 +767,7 @@
     name: "mysdk_system-module@current",
     sdk_member_name: "system-module",
     visibility: ["//visibility:private"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/system-module.jar"],
@@ -756,6 +777,7 @@
     name: "mysdk_system-module",
     prefer: false,
     visibility: ["//visibility:private"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/system-module.jar"],
@@ -836,6 +858,7 @@
     name: "myexports_hostjavalib@current",
     sdk_member_name: "hostjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/hostjavalib.jar"],
@@ -845,6 +868,7 @@
     name: "hostjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     device_supported: false,
     host_supported: true,
     jars: ["java/hostjavalib.jar"],
@@ -854,6 +878,7 @@
     name: "myexports_androidjavalib@current",
     sdk_member_name: "androidjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/androidjavalib.jar"],
 }
 
@@ -861,6 +886,7 @@
     name: "androidjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/androidjavalib.jar"],
 }
 
@@ -868,6 +894,7 @@
     name: "myexports_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     target: {
         android: {
@@ -883,6 +910,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     host_supported: true,
     target: {
         android: {
@@ -1045,6 +1073,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1059,6 +1088,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1112,6 +1142,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1126,6 +1157,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1547,6 +1579,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     shared_library: true,
     doctag_files: ["doctags/docs/known_doctags"],
     public: {
@@ -1562,6 +1595,7 @@
     name: "myjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     shared_library: true,
     doctag_files: ["doctags/docs/known_doctags"],
     public: {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 2e6c62a..c4dc41b 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -181,6 +181,7 @@
         "//package",
         "//prebuilts/mysdk",
     ],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
@@ -192,6 +193,7 @@
         "//package",
         "//prebuilts/mysdk",
     ],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myjavalib.jar"],
 }
 
@@ -199,6 +201,7 @@
     name: "mysdk_mypublicjavalib@current",
     sdk_member_name: "mypublicjavalib",
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/mypublicjavalib.jar"],
 }
 
@@ -206,6 +209,7 @@
     name: "mypublicjavalib",
     prefer: false,
     visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/mypublicjavalib.jar"],
 }
 
@@ -217,6 +221,7 @@
         "//package",
         "//prebuilts/mysdk",
     ],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/mydefaultedjavalib.jar"],
 }
 
@@ -228,6 +233,7 @@
         "//package",
         "//prebuilts/mysdk",
     ],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/mydefaultedjavalib.jar"],
 }
 
@@ -238,6 +244,7 @@
         "//package",
         "//prebuilts/mysdk",
     ],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myprivatejavalib.jar"],
 }
 
@@ -248,6 +255,7 @@
         "//package",
         "//prebuilts/mysdk",
     ],
+    apex_available: ["//apex_available:platform"],
     jars: ["java/myprivatejavalib.jar"],
 }
 
diff --git a/sdk/update.go b/sdk/update.go
index 7bf5dea..ba63542 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -735,6 +735,24 @@
 		}
 	}
 
+	// Where available copy apex_available properties from the member.
+	if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
+		apexAvailable := apexAware.ApexAvailable()
+		if len(apexAvailable) == 0 {
+			// //apex_available:platform is the default.
+			apexAvailable = []string{android.AvailableToPlatform}
+		}
+
+		// Add in any baseline apex available settings.
+		apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...)
+
+		// Remove duplicates and sort.
+		apexAvailable = android.FirstUniqueStrings(apexAvailable)
+		sort.Strings(apexAvailable)
+
+		m.AddProperty("apex_available", apexAvailable)
+	}
+
 	deviceSupported := false
 	hostSupported := false
 
@@ -749,22 +767,6 @@
 
 	addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
 
-	// Where available copy apex_available properties from the member.
-	if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
-		apexAvailable := apexAware.ApexAvailable()
-
-		// Add in any baseline apex available settings.
-		apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...)
-
-		if len(apexAvailable) > 0 {
-			// Remove duplicates and sort.
-			apexAvailable = android.FirstUniqueStrings(apexAvailable)
-			sort.Strings(apexAvailable)
-
-			m.AddProperty("apex_available", apexAvailable)
-		}
-	}
-
 	// Disable installation in the versioned module of those modules that are ever installable.
 	if installable, ok := variant.(interface{ EverInstallable() bool }); ok {
 		if installable.EverInstallable() {
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index 4b03bc1..7cc7caf 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -24,6 +24,8 @@
 	"android/soong/ui/metrics"
 )
 
+// 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) {
 	ctx.BeginTrace(metrics.RunBazel, "bazel")
 	defer ctx.EndTrace()
@@ -67,6 +69,10 @@
 		"//:"+config.TargetProduct()+"-"+config.TargetBuildVariant(),
 	)
 
+	if pathEnvValue, ok := config.environ.Get("PATH"); ok {
+		cmd.Environment.Set("PATH", pathEnvValue)
+		cmd.Args = append(cmd.Args, "--action_env=PATH="+pathEnvValue)
+	}
 	cmd.Environment.Set("DIST_DIR", config.DistDir())
 	cmd.Environment.Set("SHELL", "/bin/bash")