Merge "Set ANDROID_SDK_HOME when running lint"
diff --git a/android/config.go b/android/config.go
index b906108..16f3d73 100644
--- a/android/config.go
+++ b/android/config.go
@@ -406,6 +406,14 @@
 		return Config{}, err
 	}
 
+	if Bool(config.productVariables.GcovCoverage) && Bool(config.productVariables.ClangCoverage) {
+		return Config{}, fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
+	}
+
+	config.productVariables.Native_coverage = proptools.BoolPtr(
+		Bool(config.productVariables.GcovCoverage) ||
+			Bool(config.productVariables.ClangCoverage))
+
 	return Config{config}, nil
 }
 
@@ -1057,18 +1065,20 @@
 	return coverage
 }
 
-func (c *config) NativeLineCoverage() bool {
-	return Bool(c.productVariables.NativeLineCoverage)
-}
-
+// Returns true if gcov or clang coverage is enabled.
 func (c *deviceConfig) NativeCoverageEnabled() bool {
-	return Bool(c.config.productVariables.Native_coverage) || Bool(c.config.productVariables.NativeLineCoverage)
+	return Bool(c.config.productVariables.GcovCoverage) ||
+		Bool(c.config.productVariables.ClangCoverage)
 }
 
 func (c *deviceConfig) ClangCoverageEnabled() bool {
 	return Bool(c.config.productVariables.ClangCoverage)
 }
 
+func (c *deviceConfig) GcovCoverageEnabled() bool {
+	return Bool(c.config.productVariables.GcovCoverage)
+}
+
 // NativeCoverageEnabledForPath returns whether (GCOV- or Clang-based) native
 // code coverage is enabled for path. By default, coverage is not enabled for a
 // given path unless it is part of the NativeCoveragePaths product variable (and
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 6226548..afb5f4e 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -172,7 +172,7 @@
 
 	inputs := make(map[string]Path)
 	for _, c := range r.commands {
-		for _, input := range c.inputs {
+		for _, input := range append(c.inputs, c.implicits...) {
 			inputStr := input.String()
 			if _, isOutput := outputs[inputStr]; !isOutput {
 				if _, isDepFile := depFiles[inputStr]; !isDepFile {
@@ -480,6 +480,7 @@
 type RuleBuilderCommand struct {
 	buf           strings.Builder
 	inputs        Paths
+	implicits     Paths
 	orderOnlys    Paths
 	outputs       WritablePaths
 	depFiles      WritablePaths
@@ -503,6 +504,16 @@
 	return path.String()
 }
 
+func (c *RuleBuilderCommand) addImplicit(path Path) string {
+	if c.sbox {
+		if rel, isRel, _ := maybeRelErr(c.sboxOutDir.String(), path.String()); isRel {
+			return "__SBOX_OUT_DIR__/" + rel
+		}
+	}
+	c.implicits = append(c.implicits, path)
+	return path.String()
+}
+
 func (c *RuleBuilderCommand) addOrderOnly(path Path) {
 	c.orderOnlys = append(c.orderOnlys, path)
 }
@@ -623,7 +634,7 @@
 // Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
 // command line.
 func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand {
-	c.addInput(path)
+	c.addImplicit(path)
 	return c
 }
 
@@ -631,11 +642,16 @@
 // command line.
 func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand {
 	for _, path := range paths {
-		c.addInput(path)
+		c.addImplicit(path)
 	}
 	return c
 }
 
+// GetImplicits returns the command's implicit inputs.
+func (c *RuleBuilderCommand) GetImplicits() Paths {
+	return c.implicits
+}
+
 // OrderOnly adds the specified input path to the dependencies returned by RuleBuilder.OrderOnlys
 // without modifying the command line.
 func (c *RuleBuilderCommand) OrderOnly(path Path) *RuleBuilderCommand {
diff --git a/android/variable.go b/android/variable.go
index b2149c3..2c8bd07 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -270,12 +270,14 @@
 	JavaCoveragePaths        []string `json:",omitempty"`
 	JavaCoverageExcludePaths []string `json:",omitempty"`
 
-	NativeLineCoverage         *bool    `json:",omitempty"`
-	Native_coverage            *bool    `json:",omitempty"`
+	GcovCoverage               *bool    `json:",omitempty"`
 	ClangCoverage              *bool    `json:",omitempty"`
 	NativeCoveragePaths        []string `json:",omitempty"`
 	NativeCoverageExcludePaths []string `json:",omitempty"`
 
+	// Set by NewConfig
+	Native_coverage *bool
+
 	SanitizeHost       []string `json:",omitempty"`
 	SanitizeDevice     []string `json:",omitempty"`
 	SanitizeDeviceDiag []string `json:",omitempty"`
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index 4aadbe8..dcd67d8 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -34,6 +34,7 @@
 	defs              []bpparser.Definition
 	localAssignments  map[string]*bpparser.Property
 	globalAssignments map[string]*bpparser.Expression
+	variableRenames   map[string]string
 	scope             mkparser.Scope
 	module            *bpparser.Module
 
@@ -43,6 +44,10 @@
 	inModule bool
 }
 
+var invalidVariableStringToReplacement = map[string]string{
+	"-": "_dash_",
+}
+
 func (f *bpFile) insertComment(s string) {
 	f.comments = append(f.comments, &bpparser.CommentGroup{
 		Comments: []*bpparser.Comment{
@@ -120,6 +125,7 @@
 		scope:             androidScope(),
 		localAssignments:  make(map[string]*bpparser.Property),
 		globalAssignments: make(map[string]*bpparser.Expression),
+		variableRenames:   make(map[string]string),
 	}
 
 	var conds []*conditional
@@ -224,6 +230,25 @@
 	return string(out), errs
 }
 
+func renameVariableWithInvalidCharacters(name string) string {
+	renamed := ""
+	for invalid, replacement := range invalidVariableStringToReplacement {
+		if strings.Contains(name, invalid) {
+			renamed = strings.ReplaceAll(name, invalid, replacement)
+		}
+	}
+
+	return renamed
+}
+
+func invalidVariableStrings() string {
+	invalidStrings := make([]string, 0, len(invalidVariableStringToReplacement))
+	for s := range invalidVariableStringToReplacement {
+		invalidStrings = append(invalidStrings, "\""+s+"\"")
+	}
+	return strings.Join(invalidStrings, ", ")
+}
+
 func handleAssignment(file *bpFile, assignment *mkparser.Assignment, c *conditional) {
 	if !assignment.Name.Const() {
 		file.errorf(assignment, "unsupported non-const variable name")
@@ -238,6 +263,12 @@
 	name := assignment.Name.Value(nil)
 	prefix := ""
 
+	if newName := renameVariableWithInvalidCharacters(name); newName != "" {
+		file.warnf("Variable names cannot contain: %s. Renamed \"%s\" to \"%s\"", invalidVariableStrings(), name, newName)
+		file.variableRenames[name] = newName
+		name = newName
+	}
+
 	if strings.HasPrefix(name, "LOCAL_") {
 		for _, x := range propertyPrefixes {
 			if strings.HasSuffix(name, "_"+x.mk) {
@@ -341,11 +372,11 @@
 	var err error
 	switch typ {
 	case bpparser.ListType:
-		exp, err = makeToListExpression(val, file.scope)
+		exp, err = makeToListExpression(val, file)
 	case bpparser.StringType:
-		exp, err = makeToStringExpression(val, file.scope)
+		exp, err = makeToStringExpression(val, file)
 	case bpparser.BoolType:
-		exp, err = makeToBoolExpression(val)
+		exp, err = makeToBoolExpression(val, file)
 	default:
 		panic("unknown type")
 	}
@@ -358,7 +389,6 @@
 }
 
 func setVariable(file *bpFile, plusequals bool, prefix, name string, value bpparser.Expression, local bool) error {
-
 	if prefix != "" {
 		name = prefix + "." + name
 	}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 54bd586..4f307c4 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1367,6 +1367,28 @@
 `,
 	},
 	{
+		desc: "dashed_variable gets renamed",
+		in: `
+		include $(CLEAR_VARS)
+
+		dashed-variable:= a.cpp
+
+		LOCAL_MODULE:= test
+		LOCAL_SRC_FILES:= $(dashed-variable)
+		include $(BUILD_EXECUTABLE)
+		`,
+		expected: `
+
+// ANDROIDMK TRANSLATION WARNING: Variable names cannot contain: "-". Renamed "dashed-variable" to "dashed_dash_variable"
+dashed_dash_variable = ["a.cpp"]
+cc_binary {
+
+    name: "test",
+    srcs: dashed_dash_variable,
+}
+`,
+	},
+	{
 		desc: "undefined_boolean_var",
 		in: `
 include $(CLEAR_VARS)
diff --git a/androidmk/androidmk/values.go b/androidmk/androidmk/values.go
index 6b18a65..9618142 100644
--- a/androidmk/androidmk/values.go
+++ b/androidmk/androidmk/values.go
@@ -60,8 +60,7 @@
 	}, nil
 }
 
-func makeToStringExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToStringExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
 	var val bpparser.Expression
 	var err error
 
@@ -70,18 +69,18 @@
 	}
 
 	for i, s := range ms.Strings[1:] {
-		if ret, ok := ms.Variables[i].EvalFunction(scope); ok {
+		if ret, ok := ms.Variables[i].EvalFunction(file.scope); ok {
 			if len(ret) > 1 {
 				return nil, fmt.Errorf("Unexpected list value %s", ms.Dump())
 			}
 			val, err = addValues(val, stringToStringValue(ret[0]))
 		} else {
-			name := ms.Variables[i].Name
-			if !name.Const() {
-				return nil, fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+			name, err := extractVariableName(ms.Variables[i].Name, file)
+			if err != nil {
+				return nil, err
 			}
 			tmp := &bpparser.Variable{
-				Name:  name.Value(nil),
+				Name:  name,
 				Value: &bpparser.String{},
 			}
 
@@ -125,8 +124,7 @@
 
 }
 
-func makeToListExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToListExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
 	fields := ms.Split(" \t")
 
 	var listOfListValues []bpparser.Expression
@@ -135,14 +133,14 @@
 
 	for _, f := range fields {
 		if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
-			if ret, ok := f.Variables[0].EvalFunction(scope); ok {
+			if ret, ok := f.Variables[0].EvalFunction(file.scope); ok {
 				listValue.Values = append(listValue.Values, stringListToStringValueList(ret)...)
 			} else {
-				// Variable by itself, variable is probably a list
-				if !f.Variables[0].Name.Const() {
-					return nil, fmt.Errorf("unsupported non-const variable name")
+				name, err := extractVariableName(f.Variables[0].Name, file)
+				if err != nil {
+					return nil, err
 				}
-				if f.Variables[0].Name.Value(nil) == "TOP" {
+				if name == "TOP" {
 					listValue.Values = append(listValue.Values, &bpparser.String{
 						Value: ".",
 					})
@@ -151,14 +149,14 @@
 						listOfListValues = append(listOfListValues, listValue)
 					}
 					listOfListValues = append(listOfListValues, &bpparser.Variable{
-						Name:  f.Variables[0].Name.Value(nil),
+						Name:  name,
 						Value: &bpparser.List{},
 					})
 					listValue = &bpparser.List{}
 				}
 			}
 		} else {
-			s, err := makeToStringExpression(f, scope)
+			s, err := makeToStringExpression(f, file)
 			if err != nil {
 				return nil, err
 			}
@@ -208,15 +206,15 @@
 	}, nil
 }
 
-func makeToBoolExpression(ms *mkparser.MakeString) (bpparser.Expression, error) {
+func makeToBoolExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
 	if !ms.Const() {
 		if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
-			name := ms.Variables[0].Name
-			if !name.Const() {
-				return nil, fmt.Errorf("unsupported non-const variable name")
+			name, err := extractVariableName(ms.Variables[0].Name, file)
+			if err != nil {
+				return nil, err
 			}
 			return &bpparser.Variable{
-				Name:  name.Value(nil),
+				Name:  name,
 				Value: &bpparser.Bool{},
 			}, nil
 		} else {
@@ -226,3 +224,17 @@
 
 	return stringToBoolValue(ms.Value(nil))
 }
+
+func extractVariableName(name *mkparser.MakeString, file *bpFile) (string, error) {
+	if !name.Const() {
+		return "", fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+	}
+
+	variableName := name.Value(nil)
+
+	if newName, ok := file.variableRenames[variableName]; ok {
+		variableName = newName
+	}
+
+	return variableName, nil
+}
diff --git a/apex/apex.go b/apex/apex.go
index a4af7aa..e308d48 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -985,9 +985,6 @@
 	// List of providing APEXes' names so that this APEX can depend on provided shared libraries.
 	Uses []string
 
-	// A txt file containing list of files that are allowed to be included in this APEX.
-	Allowed_files *string
-
 	// package format of this apex variant; could be non-flattened, flattened, or zip.
 	// imageApex, zipApex or flattened
 	ApexType apexPackaging `blueprint:"mutated"`
@@ -1063,6 +1060,9 @@
 	// Apex Container Package Name.
 	// Override value for attribute package:name in AndroidManifest.xml
 	Package_name string
+
+	// A txt file containing list of files that are allowed to be included in this APEX.
+	Allowed_files *string `android:"path"`
 }
 
 type apexPackaging int
@@ -1454,6 +1454,9 @@
 }
 
 func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
+	if a.overridableProperties.Allowed_files != nil {
+		android.ExtractSourceDeps(ctx, a.overridableProperties.Allowed_files)
+	}
 	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
 		androidAppTag, a.overridableProperties.Apps...)
 	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
@@ -1553,7 +1556,7 @@
 var _ cc.Coverage = (*apexBundle)(nil)
 
 func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
-	return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+	return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
 }
 
 func (a *apexBundle) PreventInstall() {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index a7a7765..3d5886e 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5396,6 +5396,61 @@
 	ensureNotContains(t, content, "myapex.apex")
 }
 
+func TestAllowedFiles(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			apps: ["app"],
+			allowed_files: "allowed.txt",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		android_app {
+			name: "app",
+			srcs: ["foo/bar/MyClass.java"],
+			package_name: "foo",
+			sdk_version: "none",
+			system_modules: "none",
+			apex_available: [ "myapex" ],
+		}
+	`, withFiles(map[string][]byte{
+		"sub/Android.bp": []byte(`
+			override_apex {
+				name: "override_myapex",
+				base: "myapex",
+				apps: ["override_app"],
+				allowed_files: ":allowed",
+			}
+			// Overridable "path" property should be referenced indirectly
+			filegroup {
+				name: "allowed",
+				srcs: ["allowed.txt"],
+			}
+			override_android_app {
+				name: "override_app",
+				base: "app",
+				package_name: "bar",
+			}
+			`),
+	}))
+
+	rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("diffApexContentRule")
+	if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual {
+		t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
+	}
+
+	rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Rule("diffApexContentRule")
+	if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
+		t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
+	}
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 53c1193..af43417 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -391,7 +391,7 @@
 	emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
 	implicitInputs = append(implicitInputs, a.manifestPbOut)
 
-	if a.properties.Allowed_files != nil {
+	if a.overridableProperties.Allowed_files != nil {
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        emitApexContentRule,
 			Implicits:   implicitInputs,
@@ -402,7 +402,7 @@
 			},
 		})
 		implicitInputs = append(implicitInputs, imageContentFile)
-		allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Allowed_files))
+		allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files))
 
 		phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
 		ctx.Build(pctx, android.BuildParams{
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 05cdfcd..60b6ed5 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -118,6 +118,7 @@
 
 	t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
 		ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
+			config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
 			config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
 		})
 
diff --git a/cc/coverage.go b/cc/coverage.go
index 1a559a9..c823324 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -74,8 +74,8 @@
 }
 
 func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
-	gcovCoverage := ctx.DeviceConfig().NativeCoverageEnabled()
 	clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled()
+	gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled()
 
 	if !gcovCoverage && !clangCoverage {
 		return flags, deps
@@ -161,7 +161,7 @@
 func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
 	useSdk bool, sdkVersion string) CoverageProperties {
 	// Coverage is disabled globally
-	if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
+	if !ctx.DeviceConfig().NativeCoverageEnabled() {
 		return properties
 	}
 
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 7daa624..d471fb7 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -169,3 +169,36 @@
 		t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile)
 	}
 }
+
+func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_sdk_library {
+			name: "foo-shared_library",
+			srcs: ["a.java"],
+		}
+		java_sdk_library {
+			name: "foo-no_shared_library",
+			srcs: ["a.java"],
+			shared_library: false,
+		}
+		`)
+
+	// Verify the existence of internal modules
+	ctx.ModuleForTests("foo-shared_library.xml", "android_common")
+
+	testCases := []struct {
+		moduleName string
+		expected   []string
+	}{
+		{"foo-shared_library", []string{"foo-shared_library.xml"}},
+		{"foo-no_shared_library", nil},
+	}
+	for _, tc := range testCases {
+		mod := ctx.ModuleForTests(tc.moduleName, "android_common").Module()
+		entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+		actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"]
+		if !reflect.DeepEqual(tc.expected, actual) {
+			t.Errorf("Unexpected required modules - expected: %q, actual: %q", tc.expected, actual)
+		}
+	}
+}
diff --git a/java/app.go b/java/app.go
index 4bb292d..c568516 100755
--- a/java/app.go
+++ b/java/app.go
@@ -151,7 +151,7 @@
 				"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
 				"screen-densities":  screenDensities,
 				"sdk-version":       ctx.Config().PlatformSdkVersion(),
-				"stem":              ctx.ModuleName(),
+				"stem":              as.BaseModuleName(),
 			},
 		})
 }
@@ -938,7 +938,7 @@
 }
 
 func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
-	return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+	return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
 }
 
 func (a *AndroidApp) PreventInstall() {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 5cb70e4..a0b7edf 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -121,6 +121,10 @@
 
 	// names of the output files used in args that will be generated
 	Out []string
+
+	// If set, metalava is sandboxed to only read files explicitly specified on the command
+	// line. Defaults to false.
+	Sandbox *bool
 }
 
 type ApiToCheck struct {
@@ -1415,7 +1419,7 @@
 }
 
 func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
-	if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
+	if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() && d.apiFile != nil {
 		if d.apiFile.String() == "" {
 			ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
 		}
@@ -1435,41 +1439,25 @@
 }
 
 func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
-	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicits android.Paths) *android.RuleBuilderCommand {
+	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicitsRsp android.WritablePath, sandbox bool) *android.RuleBuilderCommand {
 	// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
 	rule.HighMem()
 	cmd := rule.Command()
-
-	var implicitsRsp android.WritablePath
-	if len(implicits) > 0 {
-		implicitsRsp = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
-		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
-		if v := ctx.Config().Getenv("RBE_METALAVA_EXEC_STRATEGY"); v != "" {
-			execStrategy = v
-		}
-		pool := "metalava"
-		if v := ctx.Config().Getenv("RBE_METALAVA_POOL"); v != "" {
-			pool = v
+		pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava")
+		execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
+		labels := map[string]string{"type": "compile", "lang": "java", "compiler": "metalava"}
+		if !sandbox {
+			execStrategy = remoteexec.LocalExecStrategy
+			labels["shallow"] = "true"
 		}
 		inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()}
 		if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
 			inputs = append(inputs, strings.Split(v, ",")...)
 		}
 		cmd.Text((&remoteexec.REParams{
-			Labels:          map[string]string{"type": "compile", "lang": "java", "compiler": "metalava", "shallow": "true"},
+			Labels:          labels,
 			ExecStrategy:    execStrategy,
 			Inputs:          inputs,
 			RSPFile:         implicitsRsp.String(),
@@ -1483,8 +1471,17 @@
 		FlagWithArg("-encoding ", "UTF-8").
 		FlagWithArg("-source ", javaVersion.String()).
 		FlagWithRspFileInputList("@", srcs).
-		FlagWithInput("@", srcJarList).
-		FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
+		FlagWithInput("@", srcJarList)
+
+	if javaHome := ctx.Config().Getenv("ANDROID_JAVA_HOME"); javaHome != "" {
+		cmd.Implicit(android.PathForSource(ctx, javaHome))
+	}
+
+	if sandbox {
+		cmd.FlagWithOutput("--strict-input-files ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
+	} else {
+		cmd.FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
+	}
 
 	if implicitsRsp != nil {
 		cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String())
@@ -1534,8 +1531,12 @@
 
 	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
 
+	implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
+
 	cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
-		deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, d.Javadoc.implicits)
+		deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, implicitsRsp,
+		Bool(d.Javadoc.properties.Sandbox))
+	cmd.Implicits(d.Javadoc.implicits)
 
 	d.stubsFlags(ctx, cmd, stubsDir)
 
@@ -1654,6 +1655,16 @@
 		cmd.FlagWithArg("--error-message:compatibility:released ", msg)
 	}
 
+	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("", cmd.GetImplicits()).Output(implicitsRsp)
+	impRule.Build(pctx, ctx, "implicitsGen", "implicits generation")
+	cmd.Implicit(implicitsRsp)
+
 	if generateStubs {
 		rule.Command().
 			BuiltTool(ctx, "soong_zip").
@@ -1836,13 +1847,19 @@
 			Flag("-XDignore.symbol.file").
 			FlagWithArg("-doclet ", "jdiff.JDiff").
 			FlagWithInput("-docletpath ", jdiff).
-			Flag("-quiet").
-			FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
-			FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
-			Implicit(d.apiXmlFile).
-			FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
-			FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
-			Implicit(d.lastReleasedApiXmlFile)
+			Flag("-quiet")
+
+		if d.apiXmlFile != nil {
+			cmd.FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
+				FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
+				Implicit(d.apiXmlFile)
+		}
+
+		if d.lastReleasedApiXmlFile != nil {
+			cmd.FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
+				FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
+				Implicit(d.lastReleasedApiXmlFile)
+		}
 
 		rule.Command().
 			BuiltTool(ctx, "soong_zip").
diff --git a/java/sdk_library.go b/java/sdk_library.go
index cc51e3a..676557e 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1042,8 +1042,10 @@
 		return nil
 	}
 	entriesList := module.Library.AndroidMkEntries()
-	entries := &entriesList[0]
-	entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
+	if module.sharedLibrary() {
+		entries := &entriesList[0]
+		entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
+	}
 	return entriesList
 }
 
@@ -2191,8 +2193,12 @@
 			properties.Jars = jars
 			properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope)
 			properties.StubsSrcJar = paths.stubsSrcJar.Path()
-			properties.CurrentApiFile = paths.currentApiFilePath.Path()
-			properties.RemovedApiFile = paths.removedApiFilePath.Path()
+			if paths.currentApiFilePath.Valid() {
+				properties.CurrentApiFile = paths.currentApiFilePath.Path()
+			}
+			if paths.removedApiFilePath.Valid() {
+				properties.RemovedApiFile = paths.removedApiFilePath.Path()
+			}
 			s.Scopes[apiScope] = properties
 		}
 	}
diff --git a/rust/coverage.go b/rust/coverage.go
index 9be57dc..4e3977b 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -45,7 +45,7 @@
 
 func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
 
-	if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
+	if !ctx.DeviceConfig().NativeCoverageEnabled() {
 		return flags, deps
 	}
 
diff --git a/rust/library.go b/rust/library.go
index 704c77b..3c948ea 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -305,8 +305,8 @@
 
 func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
 
-	// TODO(b/144861059) Remove if C libraries support dylib linkage in the future.
-	if !ctx.Host() && (library.static() || library.shared()) {
+	// TODO(b/155498724) Remove if C static libraries no longer require libstd as an rlib dependency.
+	if !ctx.Host() && library.static() {
 		library.setNoStdlibs()
 		for _, stdlib := range config.Stdlibs {
 			deps.Rlibs = append(deps.Rlibs, stdlib+".static")
diff --git a/rust/library_test.go b/rust/library_test.go
index 37dd541..9d2f6c0 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -17,6 +17,8 @@
 import (
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 // Test that variants are being generated correctly, and that crate-types are correct.
@@ -115,16 +117,24 @@
 
 }
 
-func TestSharedLibraryFlags(t *testing.T) {
+func TestSharedLibrary(t *testing.T) {
 	ctx := testRust(t, `
-		rust_library_host {
+		rust_library {
 			name: "libfoo",
 			srcs: ["foo.rs"],
 			crate_name: "foo",
 		}`)
 
-	libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
-	if !strings.Contains(libfooShared.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
-		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v", libfooShared.Args["linkFlags"])
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
+
+	libfooOutput := libfoo.Output("libfoo.so")
+	if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
+		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
+			libfooOutput.Args["linkFlags"])
+	}
+
+	if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
+		t.Errorf("Non-static libstd dylib expected to be a dependency of Rust shared libraries. Dylib deps are: %#v",
+			libfoo.Module().(*Module).Properties.AndroidMkDylibs)
 	}
 }
diff --git a/rust/rust_test.go b/rust/rust_test.go
index fe21e3a..703aaed 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -88,6 +88,7 @@
 	config := testConfig(bp)
 
 	if coverage {
+		config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
 		config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
 		config.TestProductVariables.NativeCoveragePaths = []string{"*"}
 	}
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 7bb267d..f28b2b6 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -107,6 +107,8 @@
 
 	testProperties TestProperties
 
+	installDir android.InstallPath
+
 	data       android.Paths
 	testConfig android.Path
 }
@@ -176,13 +178,13 @@
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(entries *android.AndroidMkEntries) {
 				s.customAndroidMkEntries(entries)
+				entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
 			},
 		},
 	}}
 }
 
 func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) {
-	entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
 	entries.SetString("LOCAL_MODULE_SUFFIX", "")
 	entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
 	if len(s.properties.Symlinks) > 0 {
@@ -201,8 +203,14 @@
 	} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
 		testDir = filepath.Join(testDir, ctx.Arch().ArchType.String())
 	}
-	installDir := android.PathForModuleInstall(ctx, testDir, proptools.String(s.properties.Sub_dir))
-	s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
+	if s.SubDir() != "" {
+		// Don't add the module name to the installation path if sub_dir is specified for backward
+		// compatibility.
+		s.installDir = android.PathForModuleInstall(ctx, testDir, s.SubDir())
+	} else {
+		s.installDir = android.PathForModuleInstall(ctx, testDir, s.Name())
+	}
+	s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath)
 
 	s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data)
 
@@ -229,7 +237,7 @@
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(entries *android.AndroidMkEntries) {
 				s.customAndroidMkEntries(entries)
-
+				entries.SetPath("LOCAL_MODULE_PATH", s.installDir.ToMakePath())
 				entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
 				if s.testConfig != nil {
 					entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 6c0d96a..3bfe611 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -55,7 +55,27 @@
 	return ctx, config
 }
 
-func TestShTestTestData(t *testing.T) {
+func TestShTestSubDir(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test {
+			name: "foo",
+			src: "test.sh",
+			sub_dir: "foo_test"
+		}
+	`)
+
+	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+
+	entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+
+	expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo_test"
+	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+	if expectedPath != actualPath {
+		t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+	}
+}
+
+func TestShTest(t *testing.T) {
 	ctx, config := testShBinary(t, `
 		sh_test {
 			name: "foo",
@@ -71,10 +91,17 @@
 	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
 
 	entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
-	expected := []string{":testdata/data1", ":testdata/sub/data2"}
-	actual := entries.EntryMap["LOCAL_TEST_DATA"]
-	if !reflect.DeepEqual(expected, actual) {
-		t.Errorf("Unexpected test data expected: %q, actual: %q", expected, actual)
+
+	expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo"
+	actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+	if expectedPath != actualPath {
+		t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+	}
+
+	expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
+	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+	if !reflect.DeepEqual(expectedData, actualData) {
+		t.Errorf("Unexpected test data expected: %q, actual: %q", expectedData, actualData)
 	}
 }