Merge "Fix missing headers of vendor snapshot"
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/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..728a0ff 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: {
+					linux_glibc: {
+						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/apex/androidmk.go b/apex/androidmk.go
index 6b168fe..08d190c 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 {
diff --git a/apex/apex.go b/apex/apex.go
index 4fee6e2..a91dc29 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,11 @@
 
 // Path() returns path of this apex file relative to the APEX root
 func (af *apexFile) Path() string {
-	return af.apexRelativePath(af.builtFile.Base())
+	stem := af.builtFile.Base()
+	if af.stem != "" {
+		stem = af.stem
+	}
+	return af.apexRelativePath(stem)
 }
 
 // SymlinkPaths() returns paths of the symlinks (if any) relative to the APEX root
@@ -1702,11 +1644,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
 }
 
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..a6a347b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -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
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/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_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/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/java.go b/java/java.go
index 466132e..162141d 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)
 	}
@@ -1878,7 +1884,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 +2734,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 9266d29..8ea34d9 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -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/remoteexec/remoteexec.go b/remoteexec/remoteexec.go
index 11fc282..d6e2c0a 100644
--- a/remoteexec/remoteexec.go
+++ b/remoteexec/remoteexec.go
@@ -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/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/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"],