Merge "Upload build metrics after a build is completed."
diff --git a/Android.bp b/Android.bp
index ec7d13a..73fad25 100644
--- a/Android.bp
+++ b/Android.bp
@@ -289,6 +289,7 @@
         "soong-dexpreopt",
         "soong-genrule",
         "soong-java-config",
+        "soong-remoteexec",
         "soong-tradefed",
     ],
     srcs: [
diff --git a/android/module.go b/android/module.go
index 6239d27..82321f4 100644
--- a/android/module.go
+++ b/android/module.go
@@ -111,6 +111,8 @@
 	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
 	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
 	OtherModuleExists(name string) bool
+	OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
+	OtherModuleReverseDependencyVariantExists(name string) bool
 	OtherModuleType(m blueprint.Module) string
 
 	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
@@ -1433,6 +1435,12 @@
 	return b.bp.OtherModuleDependencyTag(m)
 }
 func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
+func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
+	return b.bp.OtherModuleDependencyVariantExists(variations, name)
+}
+func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
+	return b.bp.OtherModuleReverseDependencyVariantExists(name)
+}
 func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
 	return b.bp.OtherModuleType(m)
 }
diff --git a/android/paths.go b/android/paths.go
index fcea65c..3ad27ac 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -485,6 +485,15 @@
 	return firstUniquePathsList(list)
 }
 
+// SortedUniquePaths returns what its name says
+func SortedUniquePaths(list Paths) Paths {
+	unique := FirstUniquePaths(list)
+	sort.Slice(unique, func(i, j int) bool {
+		return unique[i].String() < unique[j].String()
+	})
+	return unique
+}
+
 func firstUniquePathsList(list Paths) Paths {
 	k := 0
 outer:
diff --git a/android/prebuilt.go b/android/prebuilt.go
index ee4a13a..a29ec91 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -52,6 +52,9 @@
 
 	SourceExists bool `blueprint:"mutated"`
 	UsePrebuilt  bool `blueprint:"mutated"`
+
+	// Set if the module has been renamed to remove the "prebuilt_" prefix.
+	PrebuiltRenamedToSource bool `blueprint:"mutated"`
 }
 
 type Prebuilt struct {
@@ -188,25 +191,38 @@
 }
 
 func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("prebuilts", PrebuiltMutator).Parallel()
+	ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
 }
 
 func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel()
 	ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
 	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
 }
 
-// PrebuiltMutator ensures that there is always a module with an undecorated name, and marks
-// prebuilt modules that have both a prebuilt and a source module.
-func PrebuiltMutator(ctx BottomUpMutatorContext) {
+// PrebuiltRenameMutator ensures that there always is a module with an
+// undecorated name.
+func PrebuiltRenameMutator(ctx BottomUpMutatorContext) {
+	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
+		name := m.base().BaseModuleName()
+		if !ctx.OtherModuleExists(name) {
+			ctx.Rename(name)
+			m.Prebuilt().properties.PrebuiltRenamedToSource = true
+		}
+	}
+}
+
+// PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the
+// corresponding source module, if one exists for the same variant.
+func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
 	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
 		p := m.Prebuilt()
-		name := m.base().BaseModuleName()
-		if ctx.OtherModuleExists(name) {
-			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
-			p.properties.SourceExists = true
-		} else {
-			ctx.Rename(name)
+		if !p.properties.PrebuiltRenamedToSource {
+			name := m.base().BaseModuleName()
+			if ctx.OtherModuleReverseDependencyVariantExists(name) {
+				ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
+				p.properties.SourceExists = true
+			}
 		}
 	}
 }
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 3dea6d8..f0c0767 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -49,6 +49,9 @@
 
 	// Whether this module is directly installable to one of the partitions. Default: true.
 	Installable *bool
+
+	// Install symlinks to the installed file.
+	Symlinks []string `android:"arch_variant"`
 }
 
 type PrebuiltEtcModule interface {
@@ -201,10 +204,13 @@
 				entries.SetString("LOCAL_MODULE_TAGS", "optional")
 				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
 				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+				if len(p.properties.Symlinks) > 0 {
+					entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
+				}
 				entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
 				if p.additionalDependencies != nil {
 					for _, path := range *p.additionalDependencies {
-						entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
+						entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
 					}
 				}
 			},
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 8ff5c40..b568f78 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -24,7 +24,7 @@
 var prebuiltsTests = []struct {
 	name     string
 	modules  string
-	prebuilt bool
+	prebuilt []OsClass
 }{
 	{
 		name: "no prebuilt",
@@ -32,7 +32,7 @@
 			source {
 				name: "bar",
 			}`,
-		prebuilt: false,
+		prebuilt: nil,
 	},
 	{
 		name: "no source prebuilt not preferred",
@@ -42,7 +42,7 @@
 				prefer: false,
 				srcs: ["prebuilt_file"],
 			}`,
-		prebuilt: true,
+		prebuilt: []OsClass{Device, Host},
 	},
 	{
 		name: "no source prebuilt preferred",
@@ -52,7 +52,7 @@
 				prefer: true,
 				srcs: ["prebuilt_file"],
 			}`,
-		prebuilt: true,
+		prebuilt: []OsClass{Device, Host},
 	},
 	{
 		name: "prebuilt not preferred",
@@ -60,13 +60,13 @@
 			source {
 				name: "bar",
 			}
-			
+
 			prebuilt {
 				name: "bar",
 				prefer: false,
 				srcs: ["prebuilt_file"],
 			}`,
-		prebuilt: false,
+		prebuilt: nil,
 	},
 	{
 		name: "prebuilt preferred",
@@ -74,13 +74,13 @@
 			source {
 				name: "bar",
 			}
-			
+
 			prebuilt {
 				name: "bar",
 				prefer: true,
 				srcs: ["prebuilt_file"],
 			}`,
-		prebuilt: true,
+		prebuilt: []OsClass{Device, Host},
 	},
 	{
 		name: "prebuilt no file not preferred",
@@ -88,12 +88,12 @@
 			source {
 				name: "bar",
 			}
-			
+
 			prebuilt {
 				name: "bar",
 				prefer: false,
 			}`,
-		prebuilt: false,
+		prebuilt: nil,
 	},
 	{
 		name: "prebuilt no file preferred",
@@ -101,12 +101,12 @@
 			source {
 				name: "bar",
 			}
-			
+
 			prebuilt {
 				name: "bar",
 				prefer: true,
 			}`,
-		prebuilt: false,
+		prebuilt: nil,
 	},
 	{
 		name: "prebuilt file from filegroup preferred",
@@ -120,7 +120,40 @@
 				prefer: true,
 				srcs: [":fg"],
 			}`,
-		prebuilt: true,
+		prebuilt: []OsClass{Device, Host},
+	},
+	{
+		name: "prebuilt module for device only",
+		modules: `
+			source {
+				name: "bar",
+			}
+
+			prebuilt {
+				name: "bar",
+				host_supported: false,
+				prefer: true,
+				srcs: ["prebuilt_file"],
+			}`,
+		prebuilt: []OsClass{Device},
+	},
+	{
+		name: "prebuilt file for host only",
+		modules: `
+			source {
+				name: "bar",
+			}
+
+			prebuilt {
+				name: "bar",
+				prefer: true,
+				target: {
+					host: {
+						srcs: ["prebuilt_file"],
+					},
+				},
+			}`,
+		prebuilt: []OsClass{Host},
 	},
 }
 
@@ -138,9 +171,9 @@
 					deps: [":bar"],
 				}
 				` + test.modules
-			config := TestConfig(buildDir, nil, bp, fs)
+			config := TestArchConfig(buildDir, nil, bp, fs)
 
-			ctx := NewTestContext()
+			ctx := NewTestArchContext()
 			registerTestPrebuiltBuildComponents(ctx)
 			ctx.RegisterModuleType("filegroup", FileGroupFactory)
 			ctx.Register(config)
@@ -150,61 +183,71 @@
 			_, errs = ctx.PrepareBuildActions(config)
 			FailIfErrored(t, errs)
 
-			foo := ctx.ModuleForTests("foo", "")
+			for _, variant := range ctx.ModuleVariantsForTests("foo") {
+				foo := ctx.ModuleForTests("foo", variant)
+				t.Run(foo.Module().Target().Os.Class.String(), func(t *testing.T) {
+					var dependsOnSourceModule, dependsOnPrebuiltModule bool
+					ctx.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
+						if _, ok := m.(*sourceModule); ok {
+							dependsOnSourceModule = true
+						}
+						if p, ok := m.(*prebuiltModule); ok {
+							dependsOnPrebuiltModule = true
+							if !p.Prebuilt().properties.UsePrebuilt {
+								t.Errorf("dependency on prebuilt module not marked used")
+							}
+						}
+					})
 
-			var dependsOnSourceModule, dependsOnPrebuiltModule bool
-			ctx.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
-				if _, ok := m.(*sourceModule); ok {
-					dependsOnSourceModule = true
-				}
-				if p, ok := m.(*prebuiltModule); ok {
-					dependsOnPrebuiltModule = true
-					if !p.Prebuilt().properties.UsePrebuilt {
-						t.Errorf("dependency on prebuilt module not marked used")
+					deps := foo.Module().(*sourceModule).deps
+					if deps == nil || len(deps) != 1 {
+						t.Errorf("deps does not have single path, but is %v", deps)
 					}
-				}
-			})
+					var usingSourceFile, usingPrebuiltFile bool
+					if deps[0].String() == "source_file" {
+						usingSourceFile = true
+					}
+					if deps[0].String() == "prebuilt_file" {
+						usingPrebuiltFile = true
+					}
 
-			deps := foo.Module().(*sourceModule).deps
-			if deps == nil || len(deps) != 1 {
-				t.Errorf("deps does not have single path, but is %v", deps)
-			}
-			var usingSourceFile, usingPrebuiltFile bool
-			if deps[0].String() == "source_file" {
-				usingSourceFile = true
-			}
-			if deps[0].String() == "prebuilt_file" {
-				usingPrebuiltFile = true
-			}
+					prebuilt := false
+					for _, os := range test.prebuilt {
+						if os == foo.Module().Target().Os.Class {
+							prebuilt = true
+						}
+					}
 
-			if test.prebuilt {
-				if !dependsOnPrebuiltModule {
-					t.Errorf("doesn't depend on prebuilt module")
-				}
-				if !usingPrebuiltFile {
-					t.Errorf("doesn't use prebuilt_file")
-				}
+					if prebuilt {
+						if !dependsOnPrebuiltModule {
+							t.Errorf("doesn't depend on prebuilt module")
+						}
+						if !usingPrebuiltFile {
+							t.Errorf("doesn't use prebuilt_file")
+						}
 
-				if dependsOnSourceModule {
-					t.Errorf("depends on source module")
-				}
-				if usingSourceFile {
-					t.Errorf("using source_file")
-				}
-			} else {
-				if dependsOnPrebuiltModule {
-					t.Errorf("depends on prebuilt module")
-				}
-				if usingPrebuiltFile {
-					t.Errorf("using prebuilt_file")
-				}
+						if dependsOnSourceModule {
+							t.Errorf("depends on source module")
+						}
+						if usingSourceFile {
+							t.Errorf("using source_file")
+						}
+					} else {
+						if dependsOnPrebuiltModule {
+							t.Errorf("depends on prebuilt module")
+						}
+						if usingPrebuiltFile {
+							t.Errorf("using prebuilt_file")
+						}
 
-				if !dependsOnSourceModule {
-					t.Errorf("doesn't depend on source module")
-				}
-				if !usingSourceFile {
-					t.Errorf("doesn't use source_file")
-				}
+						if !dependsOnSourceModule {
+							t.Errorf("doesn't depend on source module")
+						}
+						if !usingSourceFile {
+							t.Errorf("doesn't use source_file")
+						}
+					}
+				})
 			}
 		})
 	}
@@ -221,7 +264,7 @@
 	ModuleBase
 	prebuilt   Prebuilt
 	properties struct {
-		Srcs []string `android:"path"`
+		Srcs []string `android:"path,arch_variant"`
 	}
 	src Path
 }
@@ -230,7 +273,7 @@
 	m := &prebuiltModule{}
 	m.AddProperties(&m.properties)
 	InitPrebuiltModule(m, &m.properties.Srcs)
-	InitAndroidModule(m)
+	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
 	return m
 }
 
@@ -260,7 +303,7 @@
 type sourceModule struct {
 	ModuleBase
 	properties struct {
-		Deps []string `android:"path"`
+		Deps []string `android:"path,arch_variant"`
 	}
 	dependsOnSourceModule, dependsOnPrebuiltModule bool
 	deps                                           Paths
@@ -270,7 +313,7 @@
 func newSourceModule() Module {
 	m := &sourceModule{}
 	m.AddProperties(&m.properties)
-	InitAndroidModule(m)
+	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
 	return m
 }
 
diff --git a/android/testing.go b/android/testing.go
index 90989ef..696efb6 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"path/filepath"
 	"regexp"
+	"sort"
 	"strings"
 	"testing"
 
@@ -122,9 +123,10 @@
 		ctx.VisitAllModules(func(m blueprint.Module) {
 			allModuleNames = append(allModuleNames, m.(Module).Name()+"("+ctx.ModuleSubDir(m)+")")
 		})
+		sort.Strings(allModuleNames)
 
-		panic(fmt.Errorf("failed to find module %q variant %q."+
-			"\nall modules: %v", name, variant, allModuleNames))
+		panic(fmt.Errorf("failed to find module %q variant %q. All modules:\n  %s",
+			name, variant, strings.Join(allModuleNames, "\n  ")))
 	}
 
 	return TestingModule{module}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 6b168fe..9321ad2 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -78,6 +78,8 @@
 		}
 	}
 
+	seenDataOutPaths := make(map[string]bool)
+
 	for _, fi := range a.filesInfo {
 		if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
 			continue
@@ -112,16 +114,24 @@
 		pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir)
 		if apexType == flattenedApex {
 			// /system/apex/<name>/{lib|framework|...}
-			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(),
-				apexBundleName, fi.installDir))
+			modulePath := filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.installDir)
+			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
 			if a.primaryApexType && !symbolFilesNotNeeded {
 				fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
 			}
 			if len(fi.symlinks) > 0 {
 				fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " "))
 			}
-			if len(fi.dataPaths) > 0 {
-				fmt.Fprintln(w, "LOCAL_TEST_DATA :=", strings.Join(cc.AndroidMkDataPaths(fi.dataPaths), " "))
+			newDataPaths := []android.Path{}
+			for _, path := range fi.dataPaths {
+				dataOutPath := modulePath + ":" + path.Rel()
+				if ok := seenDataOutPaths[dataOutPath]; !ok {
+					newDataPaths = append(newDataPaths, path)
+					seenDataOutPaths[dataOutPath] = true
+				}
+			}
+			if len(newDataPaths) > 0 {
+				fmt.Fprintln(w, "LOCAL_TEST_DATA :=", strings.Join(cc.AndroidMkDataPaths(newDataPaths), " "))
 			}
 
 			if fi.module != nil && len(fi.module.NoticeFiles()) > 0 {
@@ -173,7 +183,7 @@
 			// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
 			// we will have foo.jar.jar
-			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".jar"))
+			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.Stem(), ".jar"))
 			fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
 			fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
 			fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
@@ -184,13 +194,13 @@
 			// soong_app_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .apk  Therefore
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
 			// we will have foo.apk.apk
-			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".apk"))
+			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.Stem(), ".apk"))
 			if app, ok := fi.module.(*java.AndroidApp); ok && len(app.JniCoverageOutputs()) > 0 {
 				fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " "))
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk")
 		} else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest {
-			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
+			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem())
 			if cc, ok := fi.module.(*cc.Module); ok {
 				if cc.UnstrippedOutputFile() != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
@@ -202,7 +212,7 @@
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
 		} else {
-			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
+			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem())
 			if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
 				if a.primaryApexType {
 					// Make apex_manifest.pb module for this APEX to override all other
diff --git a/apex/apex.go b/apex/apex.go
index 4fee6e2..10c16f5 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -93,69 +93,6 @@
 	//
 	// Module separator
 	//
-	artApexContents := []string{
-		"art_cmdlineparser_headers",
-		"art_disassembler_headers",
-		"art_libartbase_headers",
-		"bionic_libc_platform_headers",
-		"core-repackaged-icu4j",
-		"cpp-define-generator-asm-support",
-		"cpp-define-generator-definitions",
-		"crtbegin_dynamic",
-		"crtbegin_dynamic1",
-		"crtbegin_so1",
-		"crtbrand",
-		"dex2oat_headers",
-		"dt_fd_forward_export",
-		"icu4c_extra_headers",
-		"javavm_headers",
-		"jni_platform_headers",
-		"libPlatformProperties",
-		"libadbconnection_client",
-		"libadbconnection_server",
-		"libandroidicuinit",
-		"libart_runtime_headers_ndk",
-		"libartd-disassembler",
-		"libdexfile_all_headers",
-		"libdexfile_external_headers",
-		"libdexfile_support",
-		"libdmabufinfo",
-		"libexpat",
-		"libfdlibm",
-		"libicui18n_headers",
-		"libicuuc",
-		"libicuuc_headers",
-		"libicuuc_stubdata",
-		"libjdwp_headers",
-		"liblz4",
-		"liblzma",
-		"libmeminfo",
-		"libnativebridge-headers",
-		"libnativehelper_header_only",
-		"libnativeloader-headers",
-		"libnpt_headers",
-		"libopenjdkjvmti_headers",
-		"libperfetto_client_experimental",
-		"libprocinfo",
-		"libunwind_llvm",
-		"libunwindstack",
-		"libv8",
-		"libv8base",
-		"libv8gen",
-		"libv8platform",
-		"libv8sampler",
-		"libv8src",
-		"libvixl",
-		"libvixld",
-		"libz",
-		"libziparchive",
-		"perfetto_trace_protos",
-	}
-	m["com.android.art.debug"] = artApexContents
-	m["com.android.art.release"] = artApexContents
-	//
-	// Module separator
-	//
 	m["com.android.bluetooth.updatable"] = []string{
 		"android.hardware.audio.common@5.0",
 		"android.hardware.bluetooth.a2dp@1.0",
@@ -1207,6 +1144,7 @@
 // apexFile represents a file in an APEX bundle
 type apexFile struct {
 	builtFile  android.Path
+	stem       string
 	moduleName string
 	installDir string
 	class      apexFileClass
@@ -1255,7 +1193,14 @@
 
 // Path() returns path of this apex file relative to the APEX root
 func (af *apexFile) Path() string {
-	return af.apexRelativePath(af.builtFile.Base())
+	return af.apexRelativePath(af.Stem())
+}
+
+func (af *apexFile) Stem() string {
+	if af.stem != "" {
+		return af.stem
+	}
+	return af.builtFile.Base()
 }
 
 // SymlinkPaths() returns paths of the symlinks (if any) relative to the APEX root
@@ -1702,11 +1647,17 @@
 	return af
 }
 
-func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib java.Dependency, module android.Module) apexFile {
+type javaDependency interface {
+	java.Dependency
+	Stem() string
+}
+
+func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile {
 	dirInApex := "javalib"
 	fileToCopy := lib.DexJar()
 	af := newApexFile(ctx, fileToCopy, module.Name(), dirInApex, javaSharedLib, module)
 	af.jacocoReportClassesFile = lib.JacocoReportClassesFile()
+	af.stem = lib.Stem() + ".jar"
 	return af
 }
 
@@ -1995,13 +1946,13 @@
 			case sharedLibTag, jniLibTag:
 				isJniLib := depTag == jniLibTag
 				if c, ok := child.(*cc.Module); ok {
-					// bootstrap bionic libs are treated as provided by system
-					if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
-						provideNativeLibs = append(provideNativeLibs, c.OutputFile().Path().Base())
-					}
 					fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
 					fi.isJniLib = isJniLib
 					filesInfo = append(filesInfo, fi)
+					// bootstrap bionic libs are treated as provided by system
+					if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
+						provideNativeLibs = append(provideNativeLibs, fi.Stem())
+					}
 					return true // track transitive dependencies
 				} else {
 					propertyName := "native_shared_libs"
@@ -2121,6 +2072,8 @@
 							// don't include it in this APEX
 							return false
 						}
+						af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
+						af.transitiveDep = true
 						if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), ctx.OtherModuleName(cc)) && (cc.IsStubs() || cc.HasStubsVariants()) {
 							// If the dependency is a stubs lib, don't include it in this APEX,
 							// but make sure that the lib is installed on the device.
@@ -2132,12 +2085,10 @@
 							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.BaseModuleName(), a.requiredDeps) {
 								a.requiredDeps = append(a.requiredDeps, cc.BaseModuleName())
 							}
-							requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
+							requireNativeLibs = append(requireNativeLibs, af.Stem())
 							// Don't track further
 							return false
 						}
-						af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
-						af.transitiveDep = true
 						filesInfo = append(filesInfo, af)
 						return true // track transitive dependencies
 					}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 9633f27..29bd087 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -184,6 +184,7 @@
 		"dummy.txt":                                  nil,
 		"baz":                                        nil,
 		"bar/baz":                                    nil,
+		"testdata/baz":                               nil,
 	}
 
 	cc.GatherRequiredFilesForTest(fs)
@@ -274,6 +275,15 @@
 	}
 }
 
+// ensure that 'result' contains 'expected' exactly one time
+func ensureContainsOnce(t *testing.T, result string, expected string) {
+	t.Helper()
+	count := strings.Count(result, expected)
+	if count != 1 {
+		t.Errorf("%q is found %d times (expected 1 time) in %q", expected, count, result)
+	}
+}
+
 // ensures that 'result' does not contain 'notExpected'
 func ensureNotContains(t *testing.T, result string, notExpected string) {
 	t.Helper()
@@ -414,6 +424,7 @@
 		java_library {
 			name: "myjar",
 			srcs: ["foo/bar/MyClass.java"],
+			stem: "myjar_stem",
 			sdk_version: "none",
 			system_modules: "none",
 			static_libs: ["myotherjar"],
@@ -468,7 +479,7 @@
 	// Ensure that both direct and indirect deps are copied into apex
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib2.so")
-	ensureContains(t, copyCmds, "image.apex/javalib/myjar.jar")
+	ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar")
 	// .. but not for java libs
 	ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
 	ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
@@ -3423,6 +3434,13 @@
 			stl: "none",
 		}
 
+		filegroup {
+			name: "fg2",
+			srcs: [
+				"testdata/baz"
+			],
+		}
+
 		cc_test {
 			name: "mytests",
 			gtest: false,
@@ -3436,6 +3454,10 @@
 			system_shared_libs: [],
 			static_executable: true,
 			stl: "none",
+			data: [
+				":fg",
+				":fg2",
+			],
 		}
 	`)
 
@@ -3475,7 +3497,8 @@
 	data = android.AndroidMkDataForTest(t, config, "", flatBundle)
 	data.Custom(&builder, name, prefix, "", data)
 	flatAndroidMk := builder.String()
-	ensureContains(t, flatAndroidMk, "LOCAL_TEST_DATA := :baz :bar/baz\n")
+	ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :baz :bar/baz\n")
+	ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :testdata/baz\n")
 }
 
 func TestInstallExtraFlattenedApexes(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index 11652bc..0108d06 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -190,7 +190,7 @@
 	var jniLibs []string
 	for _, fi := range a.filesInfo {
 		if fi.isJniLib {
-			jniLibs = append(jniLibs, fi.builtFile.Base())
+			jniLibs = append(jniLibs, fi.Stem())
 		}
 	}
 	if len(jniLibs) > 0 {
@@ -247,7 +247,7 @@
 		return android.NoticeOutputs{}
 	}
 
-	return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles))
+	return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.SortedUniquePaths(noticeFiles))
 }
 
 func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath {
@@ -417,7 +417,7 @@
 		var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
 		var executablePaths []string // this also includes dirs
 		for _, f := range a.filesInfo {
-			pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
+			pathInApex := f.Path()
 			if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
 				executablePaths = append(executablePaths, pathInApex)
 				for _, d := range f.dataPaths {
@@ -582,19 +582,27 @@
 	}
 
 	a.outputFile = android.PathForModuleOut(ctx, a.Name()+suffix)
+	rule := java.Signapk
+	args := map[string]string{
+		"certificates": a.container_certificate_file.String() + " " + a.container_private_key_file.String(),
+		"flags":        "-a 4096", //alignment
+	}
+	implicits := android.Paths{
+		a.container_certificate_file,
+		a.container_private_key_file,
+	}
+	if ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
+		rule = java.SignapkRE
+		args["implicits"] = strings.Join(implicits.Strings(), ",")
+		args["outCommaList"] = a.outputFile.String()
+	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        java.Signapk,
+		Rule:        rule,
 		Description: "signapk",
 		Output:      a.outputFile,
 		Input:       unsignedOutputFile,
-		Implicits: []android.Path{
-			a.container_certificate_file,
-			a.container_private_key_file,
-		},
-		Args: map[string]string{
-			"certificates": a.container_certificate_file.String() + " " + a.container_private_key_file.String(),
-			"flags":        "-a 4096", //alignment
-		},
+		Implicits:   implicits,
+		Args:        args,
 	})
 
 	// Install to $OUT/soong/{target,host}/.../apex
@@ -659,7 +667,7 @@
 			apexBundleName := a.Name()
 			for _, fi := range a.filesInfo {
 				dir := filepath.Join("apex", apexBundleName, fi.installDir)
-				target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
+				target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.Stem(), fi.builtFile)
 				for _, sym := range fi.symlinks {
 					ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target)
 				}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 88ac513..372a72e 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -20,6 +20,7 @@
 	"android/soong/android"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -65,7 +66,15 @@
 }
 
 func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
-	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
+	pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
+
+	ccModule := member.Variants()[0].(*Module)
+
+	if stl := ccModule.stl.Properties.Stl; stl != nil {
+		pbm.AddProperty("stl", proptools.String(stl))
+	}
+
+	return pbm
 }
 
 func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
@@ -105,6 +114,10 @@
 	//
 	// This field is exported as its contents may not be arch specific.
 	SystemSharedLibs []string
+
+	// Arch specific flags.
+	StaticExecutable bool
+	Nocrt            bool
 }
 
 func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -113,6 +126,10 @@
 	p.archType = ccModule.Target().Arch.ArchType.String()
 	p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
 
+	binaryLinker := ccModule.linker.(*binaryDecorator)
+	p.StaticExecutable = binaryLinker.static()
+	p.Nocrt = Bool(binaryLinker.baseLinker.Properties.Nocrt)
+
 	if ccModule.linker != nil {
 		specifiedDeps := specifiedDeps{}
 		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
@@ -143,4 +160,11 @@
 	if p.SystemSharedLibs != nil {
 		propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
 	}
+
+	if p.StaticExecutable {
+		propertySet.AddProperty("static_executable", p.StaticExecutable)
+	}
+	if p.Nocrt {
+		propertySet.AddProperty("nocrt", p.Nocrt)
+	}
 }
diff --git a/cc/library.go b/cc/library.go
index 47485ce..ba8b0f4 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -407,6 +407,31 @@
 		if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
 			continue
 		}
+		// libeigen wrongly exports the root directory "external/eigen". But only two
+		// subdirectories "Eigen" and "unsupported" contain exported header files. Even worse
+		// some of them have no extension. So we need special treatment for libeigen in order
+		// to glob correctly.
+		if dir == "external/eigen" {
+			// Only these two directories contains exported headers.
+			for _, subdir := range []string{"Eigen", "unsupported/Eigen"} {
+				glob, err := ctx.GlobWithDeps("external/eigen/"+subdir+"/**/*", nil)
+				if err != nil {
+					ctx.ModuleErrorf("glob failed: %#v", err)
+					return
+				}
+				for _, header := range glob {
+					if strings.HasSuffix(header, "/") {
+						continue
+					}
+					ext := filepath.Ext(header)
+					if ext != "" && ext != ".h" {
+						continue
+					}
+					ret = append(ret, android.PathForSource(ctx, header))
+				}
+			}
+			continue
+		}
 		exts := headerExts
 		// Glob all files under this special directory, because of C++ headers.
 		if strings.HasPrefix(dir, "external/libcxx/include") {
diff --git a/cmd/host_bionic_inject/host_bionic_inject.go b/cmd/host_bionic_inject/host_bionic_inject.go
index f7163d7..629f6cc 100644
--- a/cmd/host_bionic_inject/host_bionic_inject.go
+++ b/cmd/host_bionic_inject/host_bionic_inject.go
@@ -105,7 +105,9 @@
 
 	err = checkLinker(file, linker, symbols)
 	if err != nil {
-		return 0, err
+		return 0, fmt.Errorf("Linker executable failed verification against app embedded linker: %s\n"+
+			"linker might not be in sync with crtbegin_dynamic.o.",
+			err)
 	}
 
 	start, err := findSymbol(symbols, "_start")
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index 191b919..d341b8c 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -213,10 +213,14 @@
 	return hostAndDeviceModuleNames.IsHostAndDeviceModule(p.GroupId, p.ArtifactId)
 }
 
+func (p Pom) IsHostOnly() bool {
+	return p.IsHostModule() && !p.IsHostAndDeviceModule()
+}
+
 func (p Pom) ModuleType() string {
 	if p.IsAar() {
 		return "android_library"
-	} else if p.IsHostModule() && !p.IsHostAndDeviceModule() {
+	} else if p.IsHostOnly() {
 		return "java_library_host"
 	} else {
 		return "java_library_static"
@@ -226,7 +230,7 @@
 func (p Pom) ImportModuleType() string {
 	if p.IsAar() {
 		return "android_library_import"
-	} else if p.IsHostModule() && !p.IsHostAndDeviceModule() {
+	} else if p.IsHostOnly() {
 		return "java_import_host"
 	} else {
 		return "java_import"
@@ -366,6 +370,12 @@
     {{- if .IsHostAndDeviceModule}}
     host_supported: true,
     {{- end}}
+    {{- if not .IsHostOnly}}
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    {{- end}}
     {{- if .IsAar}}
     min_sdk_version: "{{.MinSdkVersion}}",
     static_libs: [
@@ -401,6 +411,12 @@
     {{- if .IsHostAndDeviceModule}}
     host_supported: true,
     {{- end}}
+    {{- if not .IsHostOnly}}
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    {{- end}}
     {{- if .IsAar}}
     min_sdk_version: "{{.MinSdkVersion}}",
     static_libs: [
@@ -431,9 +447,17 @@
     {{- if .IsHostAndDeviceModule}}
     host_supported: true,
     {{- end}}
+    {{- if not .IsHostOnly}}
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    {{- end}}
     {{- if .IsAar}}
     min_sdk_version: "{{.MinSdkVersion}}",
     manifest: "manifests/{{.BpName}}/AndroidManifest.xml",
+    {{- else if not .IsHostOnly}}
+    min_sdk_version: "24",
     {{- end}}
     {{- end}}
     static_libs: [
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index fc03563..de696da 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -241,6 +241,10 @@
 	var conditionalClassLoaderContextHost29 android.Paths
 	var conditionalClassLoaderContextTarget29 []string
 
+	// Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 30
+	var conditionalClassLoaderContextHost30 android.Paths
+	var conditionalClassLoaderContextTarget30 []string
+
 	// A flag indicating if the '&' class loader context is used.
 	unknownClassLoaderContext := false
 
@@ -256,28 +260,22 @@
 				filepath.Join("/system/framework", l+".jar"))
 		}
 
+		// org.apache.http.legacy contains classes that were in the default classpath until API 28.
+		// If the targetSdkVersion in the manifest or APK is < 28, and the module does not explicitly
+		// depend on org.apache.http.legacy, then implicitly add it to the classpath for dexpreopt.
 		const httpLegacy = "org.apache.http.legacy"
-		const httpLegacyImpl = "org.apache.http.legacy.impl"
-
-		// org.apache.http.legacy contains classes that were in the default classpath until API 28.  If the
-		// targetSdkVersion in the manifest or APK is < 28, and the module does not explicitly depend on
-		// org.apache.http.legacy, then implicitly add the classes to the classpath for dexpreopt.  One the
-		// device the classes will be in a file called org.apache.http.legacy.impl.jar.
-		module.LibraryPaths[httpLegacyImpl] = module.LibraryPaths[httpLegacy]
-
-		if !contains(module.UsesLibraries, httpLegacy) && !contains(module.PresentOptionalUsesLibraries, httpLegacy) {
+		if !contains(usesLibs, httpLegacy) {
 			conditionalClassLoaderContextHost28 = append(conditionalClassLoaderContextHost28,
-				pathForLibrary(module, httpLegacyImpl))
+				pathForLibrary(module, httpLegacy))
 			conditionalClassLoaderContextTarget28 = append(conditionalClassLoaderContextTarget28,
-				filepath.Join("/system/framework", httpLegacyImpl+".jar"))
+				filepath.Join("/system/framework", httpLegacy+".jar"))
 		}
 
-		const hidlBase = "android.hidl.base-V1.0-java"
-		const hidlManager = "android.hidl.manager-V1.0-java"
-
 		// android.hidl.base-V1.0-java and android.hidl.manager-V1.0 contain classes that were in the default
 		// classpath until API 29.  If the targetSdkVersion in the manifest or APK is < 29 then implicitly add
 		// the classes to the classpath for dexpreopt.
+		const hidlBase = "android.hidl.base-V1.0-java"
+		const hidlManager = "android.hidl.manager-V1.0-java"
 		conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
 			pathForLibrary(module, hidlManager))
 		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
@@ -286,6 +284,17 @@
 			pathForLibrary(module, hidlBase))
 		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
 			filepath.Join("/system/framework", hidlBase+".jar"))
+
+		// android.test.base contains classes that were in the default classpath until API 30.
+		// If the targetSdkVersion in the manifest or APK is < 30 then implicitly add it to the
+		// classpath for dexpreopt.
+		const testBase = "android.test.base"
+		if !contains(usesLibs, testBase) {
+			conditionalClassLoaderContextHost30 = append(conditionalClassLoaderContextHost30,
+				pathForLibrary(module, testBase))
+			conditionalClassLoaderContextTarget30 = append(conditionalClassLoaderContextTarget30,
+				filepath.Join("/system/framework", testBase+".jar"))
+		}
 	} else if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
 		// System server jars should be dexpreopted together: class loader context of each jar
 		// should include all preceding jars on the system server classpath.
@@ -351,6 +360,11 @@
 			Implicits(conditionalClassLoaderContextHost29)
 		rule.Command().Textf(`conditional_target_libs_29="%s"`,
 			strings.Join(conditionalClassLoaderContextTarget29, " "))
+		rule.Command().Textf(`conditional_host_libs_30="%s"`,
+			strings.Join(conditionalClassLoaderContextHost30.Strings(), " ")).
+			Implicits(conditionalClassLoaderContextHost30)
+		rule.Command().Textf(`conditional_target_libs_30="%s"`,
+			strings.Join(conditionalClassLoaderContextTarget30, " "))
 		rule.Command().Text("source").Tool(globalSoong.ConstructContext).Input(module.DexPath)
 	}
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 5e3b7d2..62cf169 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -69,7 +69,26 @@
 	if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
 		hideFromMake = true
 	}
-	if !hideFromMake {
+	if hideFromMake {
+		// May still need to add some additional dependencies. This will be called
+		// once for the platform variant (even if it is not being used) and once each
+		// for the APEX specific variants. In order to avoid adding the dependency
+		// multiple times only add it for the platform variant.
+		checkedModulePaths := library.additionalCheckedModules
+		if library.IsForPlatform() && len(checkedModulePaths) != 0 {
+			mainEntries = android.AndroidMkEntries{
+				Class: "FAKE",
+				// Need at least one output file in order for this to take effect.
+				OutputFile: android.OptionalPathForPath(checkedModulePaths[0]),
+				Include:    "$(BUILD_PHONY_PACKAGE)",
+				ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+					func(entries *android.AndroidMkEntries) {
+						entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...)
+					},
+				},
+			}
+		}
+	} else {
 		mainEntries = android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
 			DistFile:   android.OptionalPathForPath(library.distFile),
diff --git a/java/app.go b/java/app.go
index 40815de..a45ab6f 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1692,6 +1692,9 @@
 	// module name in the form ":module".
 	Certificate *string
 
+	// Name of the signing certificate lineage file.
+	Lineage *string
+
 	// optional theme name. If specified, the overlay package will be applied
 	// only when the ro.boot.vendor.overlay.theme system property is set to the same value.
 	Theme *string
@@ -1766,7 +1769,11 @@
 	_, certificates := collectAppDeps(ctx, r, false, false)
 	certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
 	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
-	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil)
+	var lineageFile android.Path
+	if lineage := String(r.properties.Lineage); lineage != "" {
+		lineageFile = android.PathForModuleSrc(ctx, lineage)
+	}
+	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, lineageFile)
 	r.certificate = certificates[0]
 
 	r.outputFile = signed
@@ -1856,6 +1863,7 @@
 				"org.apache.http.legacy",
 				"android.hidl.base-V1.0-java",
 				"android.hidl.manager-V1.0-java")
+			ctx.AddVariationDependencies(nil, usesLibTag, optionalUsesLibs...)
 		}
 	}
 }
diff --git a/java/app_builder.go b/java/app_builder.go
index fb9ab42..014bd54 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -26,16 +26,23 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/remoteexec"
 )
 
 var (
-	Signapk = pctx.AndroidStaticRule("signapk",
+	Signapk, SignapkRE = remoteexec.StaticRules(pctx, "signapk",
 		blueprint.RuleParams{
-			Command: `${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` +
+			Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` +
 				`-jar ${config.SignapkCmd} $flags $certificates $in $out`,
 			CommandDeps: []string{"${config.SignapkCmd}", "${config.SignapkJniLibrary}"},
 		},
-		"flags", "certificates")
+		&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "signapk"},
+			ExecStrategy:    "${config.RESignApkExecStrategy}",
+			Inputs:          []string{"${config.SignapkCmd}", "$in", "$$(dirname ${config.SignapkJniLibrary})", "$implicits"},
+			OutputFiles:     []string{"$outCommaList"},
+			ToolchainInputs: []string{"${config.JavaCmd}"},
+			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		}, []string{"flags", "certificates"}, []string{"implicits", "outCommaList"})
 )
 
 var combineApk = pctx.AndroidStaticRule("combineApk",
@@ -78,22 +85,30 @@
 		deps = append(deps, c.Pem, c.Key)
 	}
 
+	outputFiles := android.WritablePaths{signedApk}
 	var flags []string
 	if lineageFile != nil {
 		flags = append(flags, "--lineage", lineageFile.String())
 		deps = append(deps, lineageFile)
 	}
 
+	rule := Signapk
+	args := map[string]string{
+		"certificates": strings.Join(certificateArgs, " "),
+		"flags":        strings.Join(flags, " "),
+	}
+	if ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
+		rule = SignapkRE
+		args["implicits"] = strings.Join(deps.Strings(), ",")
+		args["outCommaList"] = strings.Join(outputFiles.Strings(), ",")
+	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        Signapk,
+		Rule:        rule,
 		Description: "signapk",
-		Output:      signedApk,
+		Outputs:     outputFiles,
 		Input:       unsignedApk,
 		Implicits:   deps,
-		Args: map[string]string{
-			"certificates": strings.Join(certificateArgs, " "),
-			"flags":        strings.Join(flags, " "),
-		},
+		Args:        args,
 	})
 }
 
@@ -217,14 +232,20 @@
 			"-f", j.path.String())
 	}
 
+	rule := zip
+	args := map[string]string{
+		"jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
+	}
+	if ctx.Config().IsEnvTrue("RBE_ZIP") {
+		rule = zipRE
+		args["implicits"] = strings.Join(deps.Strings(), ",")
+	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        zip,
+		Rule:        rule,
 		Description: "zip jni libs",
 		Output:      outputFile,
 		Implicits:   deps,
-		Args: map[string]string{
-			"jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
-		},
+		Args:        args,
 	})
 }
 
diff --git a/java/app_test.go b/java/app_test.go
index 105afd2..eb583be 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2895,6 +2895,7 @@
 		runtime_resource_overlay {
 			name: "foo",
 			certificate: "platform",
+			lineage: "lineage.bin",
 			product_specific: true,
 			static_libs: ["bar"],
 			resource_libs: ["baz"],
@@ -2949,6 +2950,11 @@
 
 	// Check cert signing flag.
 	signedApk := m.Output("signed/foo.apk")
+	lineageFlag := signedApk.Args["flags"]
+	expectedLineageFlag := "--lineage lineage.bin"
+	if expectedLineageFlag != lineageFlag {
+		t.Errorf("Incorrect signing lineage flags, expected: %q, got: %q", expectedLineageFlag, lineageFlag)
+	}
 	signingFlag := signedApk.Args["certificates"]
 	expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
 	if expected != signingFlag {
diff --git a/java/builder.go b/java/builder.go
index b6cb2ae..a27e5c3 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -40,17 +40,17 @@
 	// (if the rule produces .class files) or a .srcjar file (if the rule produces .java files).
 	// .srcjar files are unzipped into a temporary directory when compiled with javac.
 	// TODO(b/143658984): goma can't handle the --system argument to javac.
-	javac, javacRE = remoteexec.StaticRules(pctx, "javac",
+	javac, javacRE = remoteexec.MultiCommandStaticRules(pctx, "javac",
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
 				`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
-				`${config.SoongJavacWrapper} $reTemplate${config.JavacCmd} ` +
+				`${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
 				`${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` +
 				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
 				`-source $javaVersion -target $javaVersion ` +
 				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
-				`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
+				`$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
 				`rm -rf "$srcJarDir"`,
 			CommandDeps: []string{
 				"${config.JavacCmd}",
@@ -60,10 +60,19 @@
 			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
 			Rspfile:          "$out.rsp",
 			RspfileContent:   "$in",
-		}, &remoteexec.REParams{
-			Labels:       map[string]string{"type": "compile", "lang": "java", "compiler": "javac"},
-			ExecStrategy: "${config.REJavacExecStrategy}",
-			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		}, map[string]*remoteexec.REParams{
+			"$javaTemplate": &remoteexec.REParams{
+				Labels:       map[string]string{"type": "compile", "lang": "java", "compiler": "javac"},
+				ExecStrategy: "${config.REJavacExecStrategy}",
+				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+			},
+			"$zipTemplate": &remoteexec.REParams{
+				Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
+				Inputs:       []string{"${config.SoongZipCmd}", "$outDir"},
+				OutputFiles:  []string{"$out"},
+				ExecStrategy: "${config.REJavacExecStrategy}",
+				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+			},
 		}, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
 			"outDir", "annoDir", "javaVersion"}, nil)
 
@@ -144,23 +153,35 @@
 			Platform:          map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 		}, []string{"javacFlags", "bootClasspath", "classpath", "srcJars", "outDir", "javaVersion"}, []string{"implicits"})
 
-	jar = pctx.AndroidStaticRule("jar",
+	jar, jarRE = remoteexec.StaticRules(pctx, "jar",
 		blueprint.RuleParams{
-			Command:        `${config.SoongZipCmd} -jar -o $out @$out.rsp`,
+			Command:        `$reTemplate${config.SoongZipCmd} -jar -o $out @$out.rsp`,
 			CommandDeps:    []string{"${config.SoongZipCmd}"},
 			Rspfile:        "$out.rsp",
 			RspfileContent: "$jarArgs",
 		},
-		"jarArgs")
+		&remoteexec.REParams{
+			ExecStrategy: "${config.REJarExecStrategy}",
+			Inputs:       []string{"${config.SoongZipCmd}", "${out}.rsp"},
+			RSPFile:      "${out}.rsp",
+			OutputFiles:  []string{"$out"},
+			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		}, []string{"jarArgs"}, nil)
 
-	zip = pctx.AndroidStaticRule("zip",
+	zip, zipRE = remoteexec.StaticRules(pctx, "zip",
 		blueprint.RuleParams{
 			Command:        `${config.SoongZipCmd} -o $out @$out.rsp`,
 			CommandDeps:    []string{"${config.SoongZipCmd}"},
 			Rspfile:        "$out.rsp",
 			RspfileContent: "$jarArgs",
 		},
-		"jarArgs")
+		&remoteexec.REParams{
+			ExecStrategy: "${config.REZipExecStrategy}",
+			Inputs:       []string{"${config.SoongZipCmd}", "${out}.rsp", "$implicits"},
+			RSPFile:      "${out}.rsp",
+			OutputFiles:  []string{"$out"},
+			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		}, []string{"jarArgs"}, []string{"implicits"})
 
 	combineJar = pctx.AndroidStaticRule("combineJar",
 		blueprint.RuleParams{
@@ -457,8 +478,12 @@
 func TransformResourcesToJar(ctx android.ModuleContext, outputFile android.WritablePath,
 	jarArgs []string, deps android.Paths) {
 
+	rule := jar
+	if ctx.Config().IsEnvTrue("RBE_JAR") {
+		rule = jarRE
+	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        jar,
+		Rule:        rule,
 		Description: "jar",
 		Output:      outputFile,
 		Implicits:   deps,
diff --git a/java/config/config.go b/java/config/config.go
index fa19afb..edaed2a 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -149,6 +149,9 @@
 	pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
 	pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
 	pctx.VariableFunc("RETurbineExecStrategy", remoteexec.EnvOverrideFunc("RBE_TURBINE_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+	pctx.VariableFunc("RESignApkExecStrategy", remoteexec.EnvOverrideFunc("RBE_SIGNAPK_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+	pctx.VariableFunc("REJarExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAR_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+	pctx.VariableFunc("REZipExecStrategy", remoteexec.EnvOverrideFunc("RBE_ZIP_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
 
 	pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
 
diff --git a/java/dex.go b/java/dex.go
index e2a8e7e..9e61e95 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -24,48 +24,66 @@
 	"android/soong/remoteexec"
 )
 
-var d8, d8RE = remoteexec.StaticRules(pctx, "d8",
+var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-			`$reTemplate${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
-			`${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
+			`$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
+			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
 			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
 		CommandDeps: []string{
 			"${config.D8Cmd}",
 			"${config.SoongZipCmd}",
 			"${config.MergeZipsCmd}",
 		},
-	}, &remoteexec.REParams{
-		Labels:          map[string]string{"type": "compile", "compiler": "d8"},
-		Inputs:          []string{"${config.D8Jar}"},
-		ExecStrategy:    "${config.RED8ExecStrategy}",
-		ToolchainInputs: []string{"${config.JavaCmd}"},
-		Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+	}, map[string]*remoteexec.REParams{
+		"$d8Template": &remoteexec.REParams{
+			Labels:          map[string]string{"type": "compile", "compiler": "d8"},
+			Inputs:          []string{"${config.D8Jar}"},
+			ExecStrategy:    "${config.RED8ExecStrategy}",
+			ToolchainInputs: []string{"${config.JavaCmd}"},
+			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
+		"$zipTemplate": &remoteexec.REParams{
+			Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
+			Inputs:       []string{"${config.SoongZipCmd}", "$outDir"},
+			OutputFiles:  []string{"$outDir/classes.dex.jar"},
+			ExecStrategy: "${config.RED8ExecStrategy}",
+			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
 	}, []string{"outDir", "d8Flags", "zipFlags"}, nil)
 
-var r8, r8RE = remoteexec.StaticRules(pctx, "r8",
+var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
 			`rm -f "$outDict" && ` +
-			`$reTemplate${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
+			`$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
 			`--force-proguard-compatibility ` +
 			`--no-data-resources ` +
 			`-printmapping $outDict ` +
 			`$r8Flags && ` +
 			`touch "$outDict" && ` +
-			`${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
+			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
 			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
 		CommandDeps: []string{
 			"${config.R8Cmd}",
 			"${config.SoongZipCmd}",
 			"${config.MergeZipsCmd}",
 		},
-	}, &remoteexec.REParams{
-		Labels:          map[string]string{"type": "compile", "compiler": "r8"},
-		Inputs:          []string{"$implicits", "${config.R8Jar}"},
-		ExecStrategy:    "${config.RER8ExecStrategy}",
-		ToolchainInputs: []string{"${config.JavaCmd}"},
-		Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+	}, map[string]*remoteexec.REParams{
+		"$r8Template": &remoteexec.REParams{
+			Labels:          map[string]string{"type": "compile", "compiler": "r8"},
+			Inputs:          []string{"$implicits", "${config.R8Jar}"},
+			ExecStrategy:    "${config.RER8ExecStrategy}",
+			ToolchainInputs: []string{"${config.JavaCmd}"},
+			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
+		"$zipTemplate": &remoteexec.REParams{
+			Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
+			Inputs:       []string{"${config.SoongZipCmd}", "$outDir"},
+			OutputFiles:  []string{"$outDir/classes.dex.jar"},
+			ExecStrategy: "${config.RER8ExecStrategy}",
+			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
 	}, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"})
 
 func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 90457d0..ed61d4b 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -619,10 +619,10 @@
 		// Collect `permitted_packages` for updatable boot jars.
 		var updatablePackages []string
 		ctx.VisitAllModules(func(module android.Module) {
-			if j, ok := module.(*Library); ok {
+			if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
 				name := ctx.ModuleName(module)
 				if i := android.IndexList(name, updatableModules); i != -1 {
-					pp := j.properties.Permitted_packages
+					pp := j.PermittedPackagesForUpdatableBootJars()
 					if len(pp) > 0 {
 						updatablePackages = append(updatablePackages, pp...)
 					} else {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 821bb6d..b16c9cd 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -376,6 +376,7 @@
 	srcFiles    android.Paths
 	sourcepaths android.Paths
 	argFiles    android.Paths
+	implicits   android.Paths
 
 	args string
 
@@ -575,6 +576,7 @@
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
 	// may contain filegroup or genrule.
 	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+	j.implicits = append(j.implicits, srcFiles...)
 
 	filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path {
 		if filterPackages == nil {
@@ -600,6 +602,24 @@
 	}
 	srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages)
 
+	// While metalava needs package html files, it does not need them to be explicit on the command
+	// line. More importantly, the metalava rsp file is also used by the subsequent jdiff action if
+	// jdiff_enabled=true. javadoc complains if it receives html files on the command line. The filter
+	// below excludes html files from the rsp file for both metalava and jdiff. Note that the html
+	// files are still included as implicit inputs for successful remote execution and correct
+	// incremental builds.
+	filterHtml := func(srcs []android.Path) []android.Path {
+		filtered := []android.Path{}
+		for _, src := range srcs {
+			if src.Ext() == ".html" {
+				continue
+			}
+			filtered = append(filtered, src)
+		}
+		return filtered
+	}
+	srcFiles = filterHtml(srcFiles)
+
 	flags := j.collectAidlFlags(ctx, deps)
 	srcFiles = j.genSources(ctx, srcFiles, flags)
 
@@ -1402,10 +1422,26 @@
 }
 
 func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
-	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
+	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicits android.Paths) *android.RuleBuilderCommand {
 	// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
 	rule.HighMem()
 	cmd := rule.Command()
+
+	rspFile := ""
+	if len(implicits) > 0 {
+		implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
+		rspFile = implicitsRsp.String()
+		impRule := android.NewRuleBuilder()
+		impCmd := impRule.Command()
+		// A dummy action that copies the ninja generated rsp file to a new location. This allows us to
+		// add a large number of inputs to a file without exceeding bash command length limits (which
+		// would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
+		// rsp file to be ${output}.rsp.
+		impCmd.Text("cp").FlagWithRspFileInputList("", implicits).Output(implicitsRsp)
+		impRule.Build(pctx, ctx, "implicitsGen", "implicits generation")
+		cmd.Implicits(implicits)
+		cmd.Implicit(implicitsRsp)
+	}
 	if ctx.Config().IsEnvTrue("RBE_METALAVA") {
 		rule.Remoteable(android.RemoteRuleSupports{RBE: true})
 		execStrategy := remoteexec.LocalExecStrategy
@@ -1417,7 +1453,6 @@
 			pool = v
 		}
 		inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()}
-		inputs = append(inputs, sourcepaths.Strings()...)
 		if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
 			inputs = append(inputs, strings.Split(v, ",")...)
 		}
@@ -1425,6 +1460,7 @@
 			Labels:          map[string]string{"type": "compile", "lang": "java", "compiler": "metalava"},
 			ExecStrategy:    execStrategy,
 			Inputs:          inputs,
+			RSPFile:         rspFile,
 			ToolchainInputs: []string{config.JavaCmd(ctx).String()},
 			Platform:        map[string]string{remoteexec.PoolKey: pool},
 		}).NoVarTemplate(ctx.Config()))
@@ -1482,7 +1518,7 @@
 	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
 
 	cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
-		deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+		deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, d.Javadoc.implicits)
 
 	d.stubsFlags(ctx, cmd, stubsDir)
 
diff --git a/java/java.go b/java/java.go
index 466132e..76bfa86 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1456,13 +1456,19 @@
 			serviceFile := file.String()
 			zipargs = append(zipargs, "-C", filepath.Dir(serviceFile), "-f", serviceFile)
 		}
+		rule := zip
+		args := map[string]string{
+			"jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
+		}
+		if ctx.Config().IsEnvTrue("RBE_ZIP") {
+			rule = zipRE
+			args["implicits"] = strings.Join(services.Strings(), ",")
+		}
 		ctx.Build(pctx, android.BuildParams{
-			Rule:      zip,
+			Rule:      rule,
 			Output:    servicesJar,
 			Implicits: services,
-			Args: map[string]string{
-				"jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
-			},
+			Args:      args,
 		})
 		jars = append(jars, servicesJar)
 	}
@@ -1834,6 +1840,17 @@
 	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
 }
 
+// Provides access to the list of permitted packages from updatable boot jars.
+type PermittedPackagesForUpdatableBootJars interface {
+	PermittedPackagesForUpdatableBootJars() []string
+}
+
+var _ PermittedPackagesForUpdatableBootJars = (*Library)(nil)
+
+func (j *Library) PermittedPackagesForUpdatableBootJars() []string {
+	return j.properties.Permitted_packages
+}
+
 func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool {
 	// Store uncompressed (and aligned) any dex files from jars in APEXes.
 	if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() {
@@ -1878,7 +1895,7 @@
 			extraInstallDeps = j.InstallMixin(ctx, j.outputFile)
 		}
 		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
-			ctx.ModuleName()+".jar", j.outputFile, extraInstallDeps...)
+			j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
 
 	// Verify Dist.Tag is set to a supported output
@@ -2728,7 +2745,7 @@
 	j.maybeStrippedDexJarFile = dexOutputFile
 
 	ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
-		ctx.ModuleName()+".jar", dexOutputFile)
+		j.Stem()+".jar", dexOutputFile)
 }
 
 func (j *DexImport) DexJar() android.Path {
diff --git a/java/java_test.go b/java/java_test.go
index e03e57b..8ea34d9 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1038,7 +1038,7 @@
 	for _, i := range metalavaRule.Implicits {
 		systemJars = append(systemJars, i.Base())
 	}
-	if len(systemJars) != 1 || systemJars[0] != systemJar {
+	if len(systemJars) < 1 || systemJars[0] != systemJar {
 		t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars)
 	}
 }
@@ -1465,6 +1465,33 @@
 		`)
 }
 
+func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			system: {
+				enabled: true,
+			},
+			default_to_stubs: true,
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["a.java"],
+			libs: ["foo"],
+			// does not have sdk_version set, should fallback to module,
+			// which will then fallback to system because the module scope
+			// is not enabled.
+		}
+		`)
+	// The baz library should depend on the system stubs jar.
+	bazLibrary := ctx.ModuleForTests("baz", "android_common").Rule("javac")
+	if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+		t.Errorf("expected %q, found %#q", expected, actual)
+	}
+}
+
 var compilerFlagsTestCases = []struct {
 	in  string
 	out bool
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 237be10..c4d257f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -435,6 +435,14 @@
 	// disabled by default.
 	Module_lib ApiScopeProperties
 
+	// Determines if the stubs are preferred over the implementation library
+	// for linking, even when the client doesn't specify sdk_version. When this
+	// is set to true, such clients are provided with the widest API surface that
+	// this lib provides. Note however that this option doesn't affect the clients
+	// that are in the same APEX as this library. In that case, the clients are
+	// always linked with the implementation library. Default is false.
+	Default_to_stubs *bool
+
 	// Properties related to api linting.
 	Api_lint struct {
 		// Enable api linting.
@@ -1342,6 +1350,13 @@
 }
 
 func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
+	// If the client doesn't set sdk_version, but if this library prefers stubs over
+	// the impl library, let's provide the widest API surface possible. To do so,
+	// force override sdk_version to module_current so that the closest possible API
+	// surface could be found in selectHeaderJarsForSdkVersion
+	if module.defaultsToStubs() && !sdkVersion.specified() {
+		sdkVersion = sdkSpecFrom("module_current")
+	}
 
 	// Only provide access to the implementation library if it is actually built.
 	if module.requiresRuntimeImplementationLibrary() {
@@ -1505,6 +1520,10 @@
 	return !proptools.Bool(module.sdkLibraryProperties.Api_only)
 }
 
+func (module *SdkLibrary) defaultsToStubs() bool {
+	return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs)
+}
+
 // Defines how to name the individual component modules the sdk library creates.
 type sdkLibraryComponentNamingScheme interface {
 	stubsLibraryModuleName(scope *apiScope, baseName string) string
@@ -1987,6 +2006,10 @@
 
 	// The naming scheme.
 	Naming_scheme *string
+
+	// True if the java_sdk_library_import is for a shared library, false
+	// otherwise.
+	Shared_library *bool
 }
 
 type scopeProperties struct {
@@ -2021,12 +2044,16 @@
 
 	s.Libs = sdk.properties.Libs
 	s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
+	s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
 }
 
 func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
 	if s.Naming_scheme != nil {
 		propertySet.AddProperty("naming_scheme", proptools.String(s.Naming_scheme))
 	}
+	if s.Shared_library != nil {
+		propertySet.AddProperty("shared_library", *s.Shared_library)
+	}
 
 	for _, apiScope := range allApiScopes {
 		if properties, ok := s.Scopes[apiScope]; ok {
diff --git a/java/testing.go b/java/testing.go
index 1967148..faf4d32 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -230,6 +230,22 @@
 			system_modules: "core-platform-api-stubs-system-modules",
 			installable: true,
 		}
+
+		java_library {
+			name: "android.test.base",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "core-platform-api-stubs-system-modules",
+			installable: true,
+		}
+  
+		java_library {
+			name: "android.test.mock",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "core-platform-api-stubs-system-modules",
+			installable: true,
+		}
 	`
 
 	systemModules := []string{
diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go
index 2b513b2..d6e2c0a 100644
--- a/remoteexec/remoteexec.go
+++ b/remoteexec/remoteexec.go
@@ -75,8 +75,8 @@
 	// OutputFiles is a list of output file paths or ninja variables as placeholders for rule
 	// outputs.
 	OutputFiles []string
-	// OutputDirectories is a list of output directory paths or ninja variables as placeholders
-	// for rule outputs.
+	// OutputDirectories is a list of output directories or ninja variables as placeholders for
+	// rule output directories.
 	OutputDirectories []string
 	// ToolchainInputs is a list of paths or ninja variables pointing to the location of
 	// toolchain binaries used by the rule.
@@ -102,7 +102,7 @@
 	return "${remoteexec.Wrapper}" + r.wrapperArgs()
 }
 
-// NoVarTemplate generate the remote execution wrapper template without variables, to be used in
+// NoVarTemplate generates the remote execution wrapper template without variables, to be used in
 // RuleBuilder.
 func (r *REParams) NoVarTemplate(cfg android.Config) string {
 	return wrapper(cfg) + r.wrapperArgs()
@@ -178,6 +178,22 @@
 		ctx.AndroidRemoteStaticRule(name+"RE", android.RemoteRuleSupports{RBE: true}, ruleParamsRE, append(commonArgs, reArgs...)...)
 }
 
+// MultiCommandStaticRules returns a pair of rules based on the given RuleParams, where the first
+// rule is a locally executable rule and the second rule is a remotely executable rule. This
+// function supports multiple remote execution wrappers placed in the template when commands are
+// chained together with &&. commonArgs are args used for both the local and remotely executable
+// rules. reArgs are args used only for remote execution.
+func MultiCommandStaticRules(ctx android.PackageContext, name string, ruleParams blueprint.RuleParams, reParams map[string]*REParams, commonArgs []string, reArgs []string) (blueprint.Rule, blueprint.Rule) {
+	ruleParamsRE := ruleParams
+	for k, v := range reParams {
+		ruleParams.Command = strings.ReplaceAll(ruleParams.Command, k, "")
+		ruleParamsRE.Command = strings.ReplaceAll(ruleParamsRE.Command, k, v.Template())
+	}
+
+	return ctx.AndroidStaticRule(name, ruleParams, commonArgs...),
+		ctx.AndroidRemoteStaticRule(name+"RE", android.RemoteRuleSupports{RBE: true}, ruleParamsRE, append(commonArgs, reArgs...)...)
+}
+
 // EnvOverrideFunc retrieves a variable func that evaluates to the value of the given environment
 // variable if set, otherwise the given default.
 func EnvOverrideFunc(envVar, defaultVal string) func(ctx android.PackageVarContext) string {
diff --git a/rust/config/x86_darwin_host.go b/rust/config/x86_darwin_host.go
index 7cfc59c..4c16693 100644
--- a/rust/config/x86_darwin_host.go
+++ b/rust/config/x86_darwin_host.go
@@ -62,7 +62,11 @@
 	return "x86_64-apple-darwin"
 }
 
-func (t *toolchainDarwin) ShlibSuffix() string {
+func (t *toolchainDarwin) SharedLibSuffix() string {
+	return ".dylib"
+}
+
+func (t *toolchainDarwin) ProcMacroSuffix() string {
 	return ".dylib"
 }
 
diff --git a/scripts/package-check.sh b/scripts/package-check.sh
index f982e82..d7e602f 100755
--- a/scripts/package-check.sh
+++ b/scripts/package-check.sh
@@ -52,6 +52,7 @@
 # Check all class file names against the expected prefixes.
 old_ifs=${IFS}
 IFS=$'\n'
+failed=false
 for zip_entry in ${zip_contents}; do
   # Check the suffix.
   if [[ "${zip_entry}" = *.class ]]; then
@@ -65,8 +66,11 @@
     done
     if [[ "${found}" == "false" ]]; then
       echo "Class file ${zip_entry} is outside specified packages."
-      exit 1
+      failed=true
     fi
   fi
 done
+if [[ "${failed}" == "true" ]]; then
+  exit 1
+fi
 IFS=${old_ifs}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index dded153..4a09081 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -401,7 +401,6 @@
 				"Test.cpp",
 			],
 			compile_multilib: "both",
-			stl: "none",
 		}
 	`)
 
@@ -494,6 +493,7 @@
     device_supported: false,
     host_supported: true,
     installable: false,
+    stl: "none",
     target: {
         linux_glibc: {
             compile_multilib: "both",
@@ -518,6 +518,7 @@
     prefer: false,
     device_supported: false,
     host_supported: true,
+    stl: "none",
     target: {
         linux_glibc: {
             compile_multilib: "both",
@@ -557,6 +558,90 @@
 	)
 }
 
+// Test that we support the necessary flags for the linker binary, which is
+// special in several ways.
+func TestSnapshotWithCcStaticNocrtBinary(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		module_exports {
+			name: "mymodule_exports",
+			host_supported: true,
+			device_supported: false,
+			native_binaries: ["linker"],
+		}
+
+		cc_binary {
+			name: "linker",
+			host_supported: true,
+			static_executable: true,
+			nocrt: true,
+			stl: "none",
+			srcs: [
+				"Test.cpp",
+			],
+			compile_multilib: "both",
+		}
+	`)
+
+	result.CheckSnapshot("mymodule_exports", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+    name: "mymodule_exports_linker@current",
+    sdk_member_name: "linker",
+    device_supported: false,
+    host_supported: true,
+    installable: false,
+    stl: "none",
+    static_executable: true,
+    nocrt: true,
+    compile_multilib: "both",
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/bin/linker"],
+        },
+        x86: {
+            srcs: ["x86/bin/linker"],
+        },
+    },
+}
+
+cc_prebuilt_binary {
+    name: "linker",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    stl: "none",
+    static_executable: true,
+    nocrt: true,
+    compile_multilib: "both",
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/bin/linker"],
+        },
+        x86: {
+            srcs: ["x86/bin/linker"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "mymodule_exports@current",
+    device_supported: false,
+    host_supported: true,
+    native_binaries: ["mymodule_exports_linker@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/linker/linux_glibc_x86_64/linker -> x86_64/bin/linker
+.intermediates/linker/linux_glibc_x86/linker -> x86/bin/linker
+`),
+	)
+}
+
 func TestSnapshotWithCcSharedLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index bbd6384..f8e9fc1 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -989,6 +989,7 @@
 			apex_available: ["//apex_available:anyapex"],
 			srcs: ["Test.java"],
 			sdk_version: "current",
+			shared_library: false,
 			stubs_library_visibility: ["//other"],
 			stubs_source_visibility: ["//another"],
 		}
@@ -1002,6 +1003,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     apex_available: ["//apex_available:anyapex"],
+    shared_library: false,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1029,6 +1031,7 @@
     name: "myjavalib",
     prefer: false,
     apex_available: ["//apex_available:anyapex"],
+    shared_library: false,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1097,6 +1100,7 @@
 java_sdk_library_import {
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1109,6 +1113,7 @@
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1159,6 +1164,7 @@
 java_sdk_library_import {
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1171,6 +1177,7 @@
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1225,6 +1232,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     apex_available: ["//apex_available:anyapex"],
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1245,6 +1253,7 @@
     name: "myjavalib",
     prefer: false,
     apex_available: ["//apex_available:anyapex"],
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1313,6 +1322,7 @@
     name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     apex_available: ["//apex_available:anyapex"],
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1340,6 +1350,7 @@
     name: "myjavalib",
     prefer: false,
     apex_available: ["//apex_available:anyapex"],
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1415,6 +1426,7 @@
     sdk_member_name: "myjavalib",
     apex_available: ["//apex_available:anyapex"],
     naming_scheme: "framework-modules",
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
@@ -1429,6 +1441,7 @@
     prefer: false,
     apex_available: ["//apex_available:anyapex"],
     naming_scheme: "framework-modules",
+    shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
         stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],