Merge "cc: Make export_include_dirs configurable" into main
diff --git a/android/api_levels.go b/android/api_levels.go
index fab5fc7..dc17238 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -291,6 +291,8 @@
 
 var ApiLevelUpsideDownCake = uncheckedFinalApiLevel(34)
 
+var ApiLevelVanillaIceCream = uncheckedFinalApiLevel(35)
+
 // ReplaceFinalizedCodenames returns the API level number associated with that API level
 // if the `raw` input is the codename of an API level has been finalized.
 // If the input is *not* a finalized codename, the input is returned unmodified.
diff --git a/cc/cc.go b/cc/cc.go
index cb82f86..0db1bd6 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -286,6 +286,11 @@
 	// Deprecated. true is the default, false is invalid.
 	Clang *bool `android:"arch_variant"`
 
+	// Aggresively trade performance for smaller binary size.
+	// This should only be used for on-device binaries that are rarely executed and not
+	// performance critical.
+	Optimize_for_size *bool `android:"arch_variant"`
+
 	// The API level that this module is built against. The APIs of this API level will be
 	// visible at build time, but use of any APIs newer than min_sdk_version will render the
 	// module unloadable on older devices.  In the future it will be possible to weakly-link new
@@ -546,6 +551,7 @@
 	isCfiAssemblySupportEnabled() bool
 	getSharedFlags() *SharedFlags
 	notInPlatform() bool
+	optimizeForSize() bool
 }
 
 type SharedFlags struct {
@@ -985,6 +991,7 @@
 		"WinMsgSrcs":             hasWinMsg,
 		"YaccSrsc":               hasYacc,
 		"OnlyCSrcs":              !(hasAidl || hasLex || hasProto || hasRenderscript || hasSysprop || hasWinMsg || hasYacc),
+		"OptimizeForSize":        c.OptimizeForSize(),
 	}
 }
 
@@ -1070,6 +1077,10 @@
 	return false
 }
 
+func (c *Module) OptimizeForSize() bool {
+	return Bool(c.Properties.Optimize_for_size)
+}
+
 func (c *Module) SdkVersion() string {
 	return String(c.Properties.Sdk_version)
 }
@@ -1613,6 +1624,10 @@
 	return ctx.mod.Object()
 }
 
+func (ctx *moduleContextImpl) optimizeForSize() bool {
+	return ctx.mod.OptimizeForSize()
+}
+
 func (ctx *moduleContextImpl) canUseSdk() bool {
 	return ctx.mod.canUseSdk()
 }
diff --git a/cc/compiler.go b/cc/compiler.go
index 34d98c0..ede6a5d 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -101,7 +101,7 @@
 	Generated_headers []string `android:"arch_variant,variant_prepend"`
 
 	// pass -frtti instead of -fno-rtti
-	Rtti *bool
+	Rtti *bool `android:"arch_variant"`
 
 	// C standard version to use. Can be a specific version (such as "gnu11"),
 	// "experimental" (which will use draft versions like C1x when available),
@@ -693,6 +693,11 @@
 		flags.Local.CFlags = append(flags.Local.CFlags, "-fopenmp")
 	}
 
+	if ctx.optimizeForSize() {
+		flags.Local.CFlags = append(flags.Local.CFlags, "-Oz")
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-enable-ml-inliner=release")
+	}
+
 	// Exclude directories from manual binder interface allowed list.
 	//TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths.
 	if android.HasAnyPrefix(ctx.ModuleDir(), allowedManualInterfacePaths) {
diff --git a/cc/lto.go b/cc/lto.go
index a084db7..60eb4d6 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -144,7 +144,7 @@
 
 		if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
 			// Register allocation MLGO flags for ARM64.
-			if ctx.Arch().ArchType == android.Arm64 {
+			if ctx.Arch().ArchType == android.Arm64 && !ctx.optimizeForSize() {
 				ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
 			}
 			// Flags for training MLGO model.
diff --git a/filesystem/avb_gen_vbmeta_image.go b/filesystem/avb_gen_vbmeta_image.go
index 985f0ea..a7fd782 100644
--- a/filesystem/avb_gen_vbmeta_image.go
+++ b/filesystem/avb_gen_vbmeta_image.go
@@ -81,6 +81,8 @@
 	a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath
 	cmd.FlagWithOutput("--output_vbmeta_image ", a.output)
 	builder.Build("avbGenVbmetaImage", fmt.Sprintf("avbGenVbmetaImage %s", ctx.ModuleName()))
+
+	ctx.SetOutputFiles([]android.Path{a.output}, "")
 }
 
 var _ android.AndroidMkEntriesProvider = (*avbGenVbmetaImage)(nil)
@@ -99,16 +101,6 @@
 	}}
 }
 
-var _ android.OutputFileProducer = (*avbGenVbmetaImage)(nil)
-
-// Implements android.OutputFileProducer
-func (a *avbGenVbmetaImage) OutputFiles(tag string) (android.Paths, error) {
-	if tag == "" {
-		return []android.Path{a.output}, nil
-	}
-	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-}
-
 type avbGenVbmetaImageDefaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 352b451..e796ab9 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -123,6 +123,8 @@
 
 	b.installDir = android.PathForModuleInstall(ctx, "etc")
 	ctx.InstallFile(b.installDir, b.installFileName(), b.output)
+
+	ctx.SetOutputFiles([]android.Path{b.output}, "")
 }
 
 func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android.OutputPath {
@@ -292,13 +294,3 @@
 	}
 	return nil
 }
-
-var _ android.OutputFileProducer = (*bootimg)(nil)
-
-// Implements android.OutputFileProducer
-func (b *bootimg) OutputFiles(tag string) (android.Paths, error) {
-	if tag == "" {
-		return []android.Path{b.output}, nil
-	}
-	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index d2572c2..c889dd6 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -221,6 +221,8 @@
 
 	f.installDir = android.PathForModuleInstall(ctx, "etc")
 	ctx.InstallFile(f.installDir, f.installFileName(), f.output)
+
+	ctx.SetOutputFiles([]android.Path{f.output}, "")
 }
 
 func validatePartitionType(ctx android.ModuleContext, p partition) {
@@ -561,16 +563,6 @@
 	}}
 }
 
-var _ android.OutputFileProducer = (*filesystem)(nil)
-
-// Implements android.OutputFileProducer
-func (f *filesystem) OutputFiles(tag string) (android.Paths, error) {
-	if tag == "" {
-		return []android.Path{f.output}, nil
-	}
-	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-}
-
 // Filesystem is the public interface for the filesystem struct. Currently, it's only for the apex
 // package to have access to the output file.
 type Filesystem interface {
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index e2f7d7b..e483fe4 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -185,6 +185,8 @@
 
 	l.installDir = android.PathForModuleInstall(ctx, "etc")
 	ctx.InstallFile(l.installDir, l.installFileName(), l.output)
+
+	ctx.SetOutputFiles([]android.Path{l.output}, "")
 }
 
 // Add a rule that converts the filesystem for the given partition to the given rule builder. The
@@ -231,13 +233,3 @@
 func (l *logicalPartition) SignedOutputPath() android.Path {
 	return nil // logical partition is not signed by itself
 }
-
-var _ android.OutputFileProducer = (*logicalPartition)(nil)
-
-// Implements android.OutputFileProducer
-func (l *logicalPartition) OutputFiles(tag string) (android.Paths, error) {
-	if tag == "" {
-		return []android.Path{l.output}, nil
-	}
-	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-}
diff --git a/filesystem/raw_binary.go b/filesystem/raw_binary.go
index 1544ea7..ad36c29 100644
--- a/filesystem/raw_binary.go
+++ b/filesystem/raw_binary.go
@@ -15,8 +15,6 @@
 package filesystem
 
 import (
-	"fmt"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -88,6 +86,8 @@
 	r.output = outputFile
 	r.installDir = android.PathForModuleInstall(ctx, "etc")
 	ctx.InstallFile(r.installDir, r.installFileName(), r.output)
+
+	ctx.SetOutputFiles([]android.Path{r.output}, "")
 }
 
 var _ android.AndroidMkEntriesProvider = (*rawBinary)(nil)
@@ -109,13 +109,3 @@
 func (r *rawBinary) SignedOutputPath() android.Path {
 	return nil
 }
-
-var _ android.OutputFileProducer = (*rawBinary)(nil)
-
-// Implements android.OutputFileProducer
-func (r *rawBinary) OutputFiles(tag string) (android.Paths, error) {
-	if tag == "" {
-		return []android.Path{r.output}, nil
-	}
-	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-}
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 43a2f37..0c6e7f4 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -211,6 +211,8 @@
 
 	v.installDir = android.PathForModuleInstall(ctx, "etc")
 	ctx.InstallFile(v.installDir, v.installFileName(), v.output)
+
+	ctx.SetOutputFiles([]android.Path{v.output}, "")
 }
 
 // Returns the embedded shell command that prints the rollback index
@@ -288,13 +290,3 @@
 func (v *vbmeta) SignedOutputPath() android.Path {
 	return v.OutputPath() // vbmeta is always signed
 }
-
-var _ android.OutputFileProducer = (*vbmeta)(nil)
-
-// Implements android.OutputFileProducer
-func (v *vbmeta) OutputFiles(tag string) (android.Paths, error) {
-	if tag == "" {
-		return []android.Path{v.output}, nil
-	}
-	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 5ca6c25..b32b754 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -1054,8 +1054,7 @@
 	}
 
 	if !treatDocumentationIssuesAsErrors {
-		// Treat documentation issues as warnings, but error when new.
-		cmd.Flag("--error-when-new-category").Flag("Documentation")
+		treatDocumentationIssuesAsWarningErrorWhenNew(cmd)
 	}
 
 	// Add "check released" options. (Detect incompatible API changes from the last public release)
@@ -1083,6 +1082,22 @@
 	}
 }
 
+// HIDDEN_DOCUMENTATION_ISSUES is the set of documentation related issues that should always be
+// hidden as they are very noisy and provide little value.
+var HIDDEN_DOCUMENTATION_ISSUES = []string{
+	"Deprecated",
+	"IntDef",
+	"Nullable",
+}
+
+func treatDocumentationIssuesAsWarningErrorWhenNew(cmd *android.RuleBuilderCommand) {
+	// Treat documentation issues as warnings, but error when new.
+	cmd.Flag("--error-when-new-category").Flag("Documentation")
+
+	// Hide some documentation issues that generated a lot of noise for little benefit.
+	cmd.FlagForEachArg("--hide ", HIDDEN_DOCUMENTATION_ISSUES)
+}
+
 // Sandbox rule for generating exportable stubs and other artifacts
 func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) {
 	optionalCmdParams := stubsCommandParams{
@@ -1154,7 +1169,7 @@
 	}
 
 	// Treat documentation issues as warnings, but error when new.
-	cmd.Flag("--error-when-new-category").Flag("Documentation")
+	treatDocumentationIssuesAsWarningErrorWhenNew(cmd)
 
 	if params.stubConfig.generateStubs {
 		rule.Command().
diff --git a/java/java.go b/java/java.go
index ccccbac..08fb678 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2180,7 +2180,7 @@
 
 // Map where key is the api scope name and value is the int value
 // representing the order of the api scope, narrowest to the widest
-var scopeOrderMap = allApiScopes.MapToIndex(
+var scopeOrderMap = AllApiScopes.MapToIndex(
 	func(s *apiScope) string { return s.name })
 
 func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 72eb6e3..6c1a38d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -324,6 +324,16 @@
 	return ret
 }
 
+func (scopes apiScopes) ConvertStubsLibraryExportableToEverything(name string) string {
+	for _, scope := range scopes {
+		if strings.HasSuffix(name, scope.exportableStubsLibraryModuleNameSuffix()) {
+			return strings.TrimSuffix(name, scope.exportableStubsLibraryModuleNameSuffix()) +
+				scope.stubsLibraryModuleNameSuffix()
+		}
+	}
+	return name
+}
+
 var (
 	scopeByName    = make(map[string]*apiScope)
 	allScopeNames  []string
@@ -418,7 +428,7 @@
 		},
 		kind: android.SdkSystemServer,
 	})
-	allApiScopes = apiScopes{
+	AllApiScopes = apiScopes{
 		apiScopePublic,
 		apiScopeSystem,
 		apiScopeTest,
@@ -1204,7 +1214,7 @@
 	paths := c.findClosestScopePath(apiScope)
 	if paths == nil {
 		var scopes []string
-		for _, s := range allApiScopes {
+		for _, s := range AllApiScopes {
 			if c.findScopePaths(s) != nil {
 				scopes = append(scopes, s.name)
 			}
@@ -1421,7 +1431,7 @@
 	// Check to see if any scopes have been explicitly enabled. If any have then all
 	// must be.
 	anyScopesExplicitlyEnabled := false
-	for _, scope := range allApiScopes {
+	for _, scope := range AllApiScopes {
 		scopeProperties := module.scopeToProperties[scope]
 		if scopeProperties.Enabled != nil {
 			anyScopesExplicitlyEnabled = true
@@ -1431,7 +1441,7 @@
 
 	var generatedScopes apiScopes
 	enabledScopes := make(map[*apiScope]struct{})
-	for _, scope := range allApiScopes {
+	for _, scope := range AllApiScopes {
 		scopeProperties := module.scopeToProperties[scope]
 		// If any scopes are explicitly enabled then ignore the legacy enabled status.
 		// This is to ensure that any new usages of this module type do not rely on legacy
@@ -1451,7 +1461,7 @@
 
 	// Now check to make sure that any scope that is extended by an enabled scope is also
 	// enabled.
-	for _, scope := range allApiScopes {
+	for _, scope := range AllApiScopes {
 		if _, ok := enabledScopes[scope]; ok {
 			extends := scope.extends
 			if extends != nil {
@@ -2580,7 +2590,7 @@
 
 	// Initialize the map from scope to scope specific properties.
 	scopeToProperties := make(map[*apiScope]*ApiScopeProperties)
-	for _, scope := range allApiScopes {
+	for _, scope := range AllApiScopes {
 		scopeToProperties[scope] = scope.scopeSpecificProperties(module)
 	}
 	module.scopeToProperties = scopeToProperties
@@ -2697,7 +2707,7 @@
 // Dynamically create a structure type for each apiscope in allApiScopes.
 func createAllScopePropertiesStructType() reflect.Type {
 	var fields []reflect.StructField
-	for _, apiScope := range allApiScopes {
+	for _, apiScope := range AllApiScopes {
 		field := reflect.StructField{
 			Name: apiScope.fieldName,
 			Type: reflect.TypeOf(sdkLibraryScopeProperties{}),
@@ -2715,7 +2725,7 @@
 	allScopePropertiesStruct := allScopePropertiesPtr.Elem()
 	scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties)
 
-	for _, apiScope := range allApiScopes {
+	for _, apiScope := range AllApiScopes {
 		field := allScopePropertiesStruct.FieldByName(apiScope.fieldName)
 		scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties)
 	}
@@ -3597,7 +3607,7 @@
 	s.Stem = sdk.distStem()
 
 	s.Scopes = make(map[*apiScope]*scopeProperties)
-	for _, apiScope := range allApiScopes {
+	for _, apiScope := range AllApiScopes {
 		paths := sdk.findScopePaths(apiScope)
 		if paths == nil {
 			continue
@@ -3659,7 +3669,7 @@
 
 	stem := s.Stem
 
-	for _, apiScope := range allApiScopes {
+	for _, apiScope := range AllApiScopes {
 		if properties, ok := s.Scopes[apiScope]; ok {
 			scopeSet := propertySet.AddPropertySet(apiScope.propertyName)
 
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index f9d49d9..4894210 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -519,4 +519,140 @@
 		)
 	})
 
+	t.Run("test replacing exportable module", func(t *testing.T) {
+		result := android.GroupFixturePreparers(
+			prepareForSdkTestWithJava,
+			java.PrepareForTestWithJavaDefaultModules,
+			java.PrepareForTestWithJavaSdkLibraryFiles,
+			java.FixtureWithLastReleaseApis("mysdklibrary", "anothersdklibrary"),
+			android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				bootclasspath_fragments: ["mybootclasspathfragment"],
+			}
+
+			bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				apex_available: ["myapex"],
+				contents: ["mysdklibrary"],
+				hidden_api: {
+					split_packages: ["*"],
+				},
+				core_platform_api: {
+					stub_libs: [
+						"anothersdklibrary.stubs.exportable",
+					],
+				},
+				api: {
+					stub_libs: [
+						"anothersdklibrary",
+					],
+				},
+			}
+
+			java_sdk_library {
+				name: "mysdklibrary",
+				srcs: ["Test.java"],
+				compile_dex: true,
+				min_sdk_version: "S",
+				public: {enabled: true},
+				permitted_packages: ["mysdklibrary"],
+			}
+
+			java_sdk_library {
+				name: "anothersdklibrary",
+				srcs: ["Test.java"],
+				compile_dex: true,
+				min_sdk_version: "S",
+				public: {enabled: true},
+				system: {enabled: true},
+				module_lib: {enabled: true},
+			}
+		`),
+			android.FixtureMergeEnv(map[string]string{
+				"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S",
+			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+				}
+				variables.Platform_version_active_codenames = []string{"UpsideDownCake", "Tiramisu", "S-V2"}
+			}),
+		).RunTest(t)
+
+		CheckSnapshot(t, result, "mysdk", "",
+			checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_bootclasspath_fragment {
+    name: "mybootclasspathfragment",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    contents: ["mysdklibrary"],
+    api: {
+        stub_libs: ["anothersdklibrary"],
+    },
+    core_platform_api: {
+        stub_libs: ["anothersdklibrary.stubs"],
+    },
+    hidden_api: {
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        stub_flags: "hiddenapi/stub-flags.csv",
+        all_flags: "hiddenapi/all-flags.csv",
+    },
+}
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    shared_library: true,
+    compile_dex: true,
+    permitted_packages: ["mysdklibrary"],
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+
+java_sdk_library_import {
+    name: "anothersdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    shared_library: true,
+    compile_dex: true,
+    public: {
+        jars: ["sdk_library/public/anothersdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/anothersdklibrary_stub_sources"],
+        current_api: "sdk_library/public/anothersdklibrary.txt",
+        removed_api: "sdk_library/public/anothersdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/anothersdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/system/anothersdklibrary_stub_sources"],
+        current_api: "sdk_library/system/anothersdklibrary.txt",
+        removed_api: "sdk_library/system/anothersdklibrary-removed.txt",
+        sdk_version: "system_current",
+    },
+    module_lib: {
+        jars: ["sdk_library/module-lib/anothersdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/module-lib/anothersdklibrary_stub_sources"],
+        current_api: "sdk_library/module-lib/anothersdklibrary.txt",
+        removed_api: "sdk_library/module-lib/anothersdklibrary-removed.txt",
+        sdk_version: "module_current",
+    },
+}
+`),
+		)
+	})
+
 }
diff --git a/sdk/update.go b/sdk/update.go
index afecf9f..0a97fd9 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -480,6 +480,12 @@
 		// Transform the module module to make it suitable for use in the snapshot.
 		module = transformModule(module, snapshotTransformer)
 		module = transformModule(module, emptyClasspathContentsTransformation{})
+
+		targetApiLevel, err := android.ApiLevelFromUserWithConfig(ctx.Config(), s.targetBuildRelease(ctx).name)
+		if err == nil && targetApiLevel.LessThan(android.ApiLevelVanillaIceCream) {
+			module = transformModule(module, replaceExportablePropertiesTransformer{})
+		}
+
 		if module != nil {
 			bpFile.AddModule(module)
 		}
@@ -804,6 +810,50 @@
 	}
 }
 
+type replaceExportablePropertiesTransformer struct {
+	identityTransformation
+}
+
+var _ bpTransformer = (*replaceExportablePropertiesTransformer)(nil)
+
+func handleExportableProperties[T any](value T) any {
+	switch v := any(value).(type) {
+	case string:
+		return java.AllApiScopes.ConvertStubsLibraryExportableToEverything(v)
+	case *bpPropertySet:
+		v.properties = handleExportableProperties(v.properties).(map[string]interface{})
+		return v
+	case []string:
+		result := make([]string, len(v))
+		for i, elem := range v {
+			result[i] = handleExportableProperties(elem).(string)
+		}
+		return result
+	case []any:
+		result := make([]any, len(v))
+		for i, elem := range v {
+			result[i] = handleExportableProperties(elem)
+		}
+		return result
+	case map[string]any:
+		result := make(map[string]any)
+		for k, val := range v {
+			result[k] = handleExportableProperties(val)
+		}
+		return result
+	default:
+		return value
+	}
+}
+
+func (t replaceExportablePropertiesTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	if name == "name" {
+		return propertySet, tag
+	}
+	propertySet.properties = handleExportableProperties(propertySet.properties).(map[string]interface{})
+	return propertySet, tag
+}
+
 func generateBpContents(bpFile *bpFile) string {
 	contents := &generatedContents{}
 	contents.IndentedPrintf("// This is auto-generated. DO NOT EDIT.\n")
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 3cbbc45..3a4adc6 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -15,7 +15,6 @@
 package sh
 
 import (
-	"fmt"
 	"path/filepath"
 	"strings"
 
@@ -188,15 +187,6 @@
 	return s.outputFilePath
 }
 
-func (s *ShBinary) OutputFiles(tag string) (android.Paths, error) {
-	switch tag {
-	case "":
-		return android.Paths{s.outputFilePath}, nil
-	default:
-		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-	}
-}
-
 func (s *ShBinary) SubDir() string {
 	return proptools.String(s.properties.Sub_dir)
 }
@@ -271,6 +261,8 @@
 		Input:  s.sourceFilePath,
 	})
 	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}})
+
+	ctx.SetOutputFiles(android.Paths{s.outputFilePath}, "")
 }
 
 func (s *ShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {