Merge "Bp2build genrule commands as configurable properties" into main
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index d1d1578..4e199dd 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -97,6 +97,15 @@
 	return sb.String()
 }
 
+func optionalVariable(prefix string, value string) string {
+	var sb strings.Builder
+	if value != "" {
+		sb.WriteString(prefix)
+		sb.WriteString(value)
+	}
+	return sb.String()
+}
+
 // Provider published by aconfig_value_set
 type declarationsProviderData struct {
 	Package          string
@@ -124,15 +133,17 @@
 	// Intermediate format
 	inputFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
 	intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb")
+	defaultPermission := ctx.Config().ReleaseAconfigFlagDefaultPermission()
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aconfigRule,
 		Output:      intermediatePath,
 		Description: "aconfig_declarations",
 		Args: map[string]string{
-			"release_version": ctx.Config().ReleaseVersion(),
-			"package":         module.properties.Package,
-			"declarations":    android.JoinPathsWithPrefix(inputFiles, "--declarations "),
-			"values":          joinAndPrefix(" --values ", module.properties.Values),
+			"release_version":    ctx.Config().ReleaseVersion(),
+			"package":            module.properties.Package,
+			"declarations":       android.JoinPathsWithPrefix(inputFiles, "--declarations "),
+			"values":             joinAndPrefix(" --values ", module.properties.Values),
+			"default-permission": optionalVariable(" --default-permission ", defaultPermission),
 		},
 	})
 
diff --git a/aconfig/init.go b/aconfig/init.go
index cfbd79d..797388d 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -30,6 +30,7 @@
 				` --package ${package}` +
 				` ${declarations}` +
 				` ${values}` +
+				` ${default-permission}` +
 				` --cache ${out}.tmp` +
 				` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
 			//				` --build-id ${release_version}` +
@@ -37,7 +38,7 @@
 				"${aconfig}",
 			},
 			Restat: true,
-		}, "release_version", "package", "declarations", "values")
+		}, "release_version", "package", "declarations", "values", "default-permission")
 
 	// For java_aconfig_library: Generate java file
 	javaRule = pctx.AndroidStaticRule("java_aconfig_library",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index b921e41..8a22886 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -440,6 +440,7 @@
 		"external/bazelbuild-rules_license":/* recursive = */ true,
 		"external/bazelbuild-rules_go":/* recursive = */ true,
 		"external/bazelbuild-rules_python":/* recursive = */ true,
+		"external/bazelbuild-rules_rust":/* recursive = */ true,
 		"external/bazelbuild-kotlin-rules":/* recursive = */ true,
 		"external/bazel-skylib":/* recursive = */ true,
 		"external/protobuf":/* recursive = */ false,
@@ -467,6 +468,7 @@
 		"prebuilts/sdk/tools":/* recursive = */ false,
 		"prebuilts/r8":/* recursive = */ false,
 		"prebuilts/runtime":/* recursive = */ false,
+		"prebuilts/rust":/* recursive = */ true,
 
 		// not recursive due to conflicting workspace paths in tools/atest/bazel/rules
 		"tools/asuite/atest":/* recursive = */ false,
diff --git a/android/config.go b/android/config.go
index 5c8b20b..3e7bb14 100644
--- a/android/config.go
+++ b/android/config.go
@@ -206,6 +206,12 @@
 	return c.config.productVariables.ReleaseAconfigValueSets
 }
 
+// The flag default permission value passed to aconfig
+// derived from RELEASE_ACONFIG_FLAG_DEFAULT_PERMISSION
+func (c Config) ReleaseAconfigFlagDefaultPermission() string {
+	return c.config.productVariables.ReleaseAconfigFlagDefaultPermission
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
diff --git a/android/proto.go b/android/proto.go
index 49b3733..b21efd6 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -283,6 +283,15 @@
 				}
 			}
 
+			// TODO - b/246997908: Handle potential orphaned proto_library targets
+			// To create proto_library targets in the same package, we split the .proto files
+			// This means that if a proto_library in a subpackage imports another proto_library from the parent package
+			// (or a different subpackage), it will not find it.
+			// The CcProtoGen action itself runs fine because we construct the correct ProtoInfo,
+			// but the FileDescriptorSet of each proto_library might not be compile-able
+			if pkg != ctx.ModuleDir() {
+				tags.Append(bazel.MakeStringListAttribute([]string{"manual"}))
+			}
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
 				CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags},
diff --git a/android/variable.go b/android/variable.go
index 664ead7..bae2adc 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -482,6 +482,8 @@
 	ReleaseVersion          string   `json:",omitempty"`
 	ReleaseAconfigValueSets []string `json:",omitempty"`
 
+	ReleaseAconfigFlagDefaultPermission string `json:",omitempty"`
+
 	KeepVndk *bool `json:",omitempty"`
 }
 
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index e5ae73e..622ec4a 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -4967,6 +4967,7 @@
 	tc.ExpectedBazelTargets = []string{
 		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 			"srcs": `["//bar:bar.proto"]`,
+			"tags": `["manual"]`,
 		}),
 	}
 	runCcLibraryTestCase(t, tc)
@@ -4976,6 +4977,7 @@
 	tc.ExpectedBazelTargets = []string{
 		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 			"srcs": `["//baz/subbaz:baz.proto"]`,
+			"tags": `["manual"]`,
 		}),
 	}
 	runCcLibraryTestCase(t, tc)
@@ -5035,6 +5037,7 @@
 			"srcs":                `["//bar:bar.proto"]`,
 			"strip_import_prefix": `""`,
 			"import_prefix":       `"bar"`,
+			"tags":                `["manual"]`,
 		}),
 	}
 	runCcLibraryTestCase(t, tc)
@@ -5046,6 +5049,7 @@
 			"srcs":                `["//baz/subbaz:baz.proto"]`,
 			"strip_import_prefix": `""`,
 			"import_prefix":       `"baz/subbaz"`,
+			"tags":                `["manual"]`,
 		}),
 	}
 	runCcLibraryTestCase(t, tc)
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 3397e3d..3d6890c 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -183,12 +183,7 @@
 	exportedVars.ExportString("ArmClangTriple", clangTriple)
 
 	exportedVars.ExportStringListStaticVariable("ArmLdflags", armLdflags)
-	exportedVars.ExportStringList("ArmLldflags", armLldflags)
-	pctx.VariableFunc("ArmLldflags", func(ctx android.PackageVarContext) string {
-		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
-		flags := append(armLldflags, maxPageSizeFlag)
-		return strings.Join(flags, " ")
-	})
+	exportedVars.ExportStringListStaticVariable("ArmLldflags", armLldflags)
 
 	exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags)
 	exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags)
diff --git a/cc/orderfile.go b/cc/orderfile.go
index cc1ab29..b64c1c7 100644
--- a/cc/orderfile.go
+++ b/cc/orderfile.go
@@ -121,9 +121,9 @@
 }
 
 func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
-	flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
 	flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag)
 	flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation")
+	flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
 	flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag)
 	return flags
 }
@@ -140,7 +140,6 @@
 	orderFilePath := orderFile.Path()
 	loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
 
-	flags.Local.CFlags = append(flags.Local.CFlags, loadFlags...)
 	flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
 
 	// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go
index 9e30bd2..f68457d 100644
--- a/cc/orderfile_test.go
+++ b/cc/orderfile_test.go
@@ -79,12 +79,6 @@
 
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
 
-	// Check cFlags of orderfile-enabled module
-	cFlags := libTest.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
-	}
-
 	// Check ldFlags of orderfile-enabled module
 	ldFlags := libTest.Rule("ld").Args["ldFlags"]
 	if !strings.Contains(ldFlags, expectedCFlag) {
@@ -150,12 +144,6 @@
 
 	test := result.ModuleForTests("test", "android_arm64_armv8-a")
 
-	// Check cFlags of orderfile-enabled module
-	cFlags := test.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'test' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
-	}
-
 	// Check ldFlags of orderfile-enabled module
 	ldFlags := test.Rule("ld").Args["ldFlags"]
 	if !strings.Contains(ldFlags, expectedCFlag) {
@@ -285,28 +273,17 @@
 
 	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
 
-	// Check cFlags of orderfile-enabled module
+	// Check ldFlags of orderfile-enabled module
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
 
-	cFlags := libTest.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	ldFlags := libTest.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldFlags %q", expectedCFlag, ldFlags)
 	}
 
-	// Check cFlags of the non-orderfile variant static libraries
 	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
 	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
-	cFlags = libFoo.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libFoo' not load orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
-	}
-
-	cFlags = libBar.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libBar' not load orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
-	}
-
 	// Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries
 	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
 		t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 51d36e4..f05ef1f 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -694,6 +694,13 @@
 		cmd.FlagWithArg("--error-message:compatibility:released ", msg)
 	}
 
+	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
+		// Pass the current API file into metalava so it can use it as the basis for determining how to
+		// generate the output signature files (both api and removed).
+		currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+		cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
+	}
+
 	if generateStubs {
 		rule.Command().
 			BuiltTool("soong_zip").
diff --git a/java/java.go b/java/java.go
index 0d39a6a..70aba8e 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1683,6 +1683,9 @@
 	// extracting the compiled class files provided by the
 	// full_api_surface_stub module.
 	Full_api_surface_stub *string
+
+	// Version of previously released API file for compatibility check.
+	Previous_api *string `android:"path"`
 }
 
 func ApiLibraryFactory() android.Module {
@@ -1812,6 +1815,28 @@
 	}
 }
 
+// API signature file names sorted from
+// the narrowest api scope to the widest api scope
+var scopeOrderedSourceFileNames = allApiScopes.Strings(
+	func(s *apiScope) string { return s.apiFilePrefix + "current.txt" })
+
+func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFiles android.Paths) android.Paths {
+	sortedSrcFiles := android.Paths{}
+
+	for _, scopeSourceFileName := range scopeOrderedSourceFileNames {
+		for _, sourceFileName := range srcFiles {
+			if sourceFileName.Base() == scopeSourceFileName {
+				sortedSrcFiles = append(sortedSrcFiles, sourceFileName)
+			}
+		}
+	}
+	if len(srcFiles) != len(sortedSrcFiles) {
+		ctx.ModuleErrorf("Unrecognizable source file found within %s", srcFiles)
+	}
+
+	return sortedSrcFiles
+}
+
 func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 
 	rule := android.NewRuleBuilder(pctx, ctx)
@@ -1862,10 +1887,18 @@
 		ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
 	}
 
+	srcFiles = al.sortApiFilesByApiScope(ctx, srcFiles)
+
 	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir)
 
 	al.stubsFlags(ctx, cmd, stubsDir)
 
+	migratingNullability := String(al.properties.Previous_api) != ""
+	if migratingNullability {
+		previousApi := android.PathForModuleSrc(ctx, String(al.properties.Previous_api))
+		cmd.FlagWithInput("--migrate-nullness ", previousApi)
+	}
+
 	al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
 	al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, "metalava", "stubs.jar")
 	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
diff --git a/java/java_test.go b/java/java_test.go
index dd98677..6110e21 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1864,12 +1864,12 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	ctx, _ := testJavaWithFS(t, `
@@ -1897,11 +1897,11 @@
 	}{
 		{
 			moduleName:         "bar1",
-			sourceTextFileDirs: []string{"a/foo1.txt"},
+			sourceTextFileDirs: []string{"a/current.txt"},
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.txt", "api1/current.txt", "api2/current.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -1918,25 +1918,25 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_c := `
 	java_api_contribution {
 		name: "foo3",
-		api_file: "foo3.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_d := `
 	java_api_contribution {
 		name: "foo4",
-		api_file: "foo4.txt",
+		api_file: "current.txt",
 	}
 	`
 	ctx, _ := testJavaWithFS(t, `
@@ -1985,15 +1985,15 @@
 	}{
 		{
 			moduleName:         "bar1",
-			sourceTextFileDirs: []string{"a/foo1.txt"},
+			sourceTextFileDirs: []string{"a/current.txt"},
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"},
 		},
 		{
 			moduleName:         "bar3",
-			sourceTextFileDirs: []string{"c/foo3.txt", "a/foo1.txt", "b/foo2.txt", "d/foo4.txt", "api1/current.txt", "api2/current.txt"},
+			sourceTextFileDirs: []string{"c/current.txt", "a/current.txt", "b/current.txt", "d/current.txt", "api1/current.txt", "api2/current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -2010,13 +2010,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	ctx, _ := testJavaWithFS(t, `
@@ -2063,13 +2063,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	lib_bp_a := `
@@ -2138,13 +2138,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	lib_bp_a := `
@@ -2212,13 +2212,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	lib_bp_a := `
diff --git a/java/sdk_library.go b/java/sdk_library.go
index dbb2f02..a38262b 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -387,6 +387,23 @@
 		apiScopeModuleLib,
 		apiScopeSystemServer,
 	}
+	apiLibraryAdditionalProperties = map[string]struct {
+		FullApiSurfaceStubLib     string
+		AdditionalApiContribution string
+	}{
+		"legacy.i18n.module.platform.api": {
+			FullApiSurfaceStubLib:     "legacy.core.platform.api.stubs",
+			AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution",
+		},
+		"stable.i18n.module.platform.api": {
+			FullApiSurfaceStubLib:     "stable.core.platform.api.stubs",
+			AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution",
+		},
+		"conscrypt.module.platform.api": {
+			FullApiSurfaceStubLib:     "stable.core.platform.api.stubs",
+			AdditionalApiContribution: "conscrypt.module.public.api.stubs.source.api.contribution",
+		},
+	}
 )
 
 var (
@@ -1513,6 +1530,29 @@
 	return exists
 }
 
+// The listed modules are the special java_sdk_libraries where apiScope.kind do not match the
+// api surface that the module contribute to. For example, the public droidstubs and java_library
+// do not contribute to the public api surface, but contributes to the core platform api surface.
+// This method returns the full api surface stub lib that
+// the generated java_api_library should depend on.
+func (module *SdkLibrary) alternativeFullApiSurfaceStubLib() string {
+	if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok {
+		return val.FullApiSurfaceStubLib
+	}
+	return ""
+}
+
+// The listed modules' stubs contents do not match the corresponding txt files,
+// but require additional api contributions to generate the full stubs.
+// This method returns the name of the additional api contribution module
+// for corresponding sdk_library modules.
+func (module *SdkLibrary) apiLibraryAdditionalApiContribution() string {
+	if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok {
+		return val.AdditionalApiContribution
+	}
+	return ""
+}
+
 func childModuleVisibility(childVisibility []string) []string {
 	if childVisibility == nil {
 		// No child visibility set. The child will use the visibility of the sdk_library.
@@ -1778,7 +1818,7 @@
 	mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
 }
 
-func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope, alternativeFullApiSurfaceStub string) {
 	props := struct {
 		Name                  *string
 		Visibility            []string
@@ -1801,6 +1841,12 @@
 		apiContributions = append(apiContributions, module.stubsSourceModuleName(scope)+".api.contribution")
 		scope = scope.extends
 	}
+	if apiScope == apiScopePublic {
+		additionalApiContribution := module.apiLibraryAdditionalApiContribution()
+		if additionalApiContribution != "" {
+			apiContributions = append(apiContributions, additionalApiContribution)
+		}
+	}
 
 	props.Api_contributions = apiContributions
 	props.Libs = module.properties.Libs
@@ -1808,6 +1854,9 @@
 	props.Libs = append(props.Libs, "stub-annotations")
 	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
 	props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + ".from-text")
+	if alternativeFullApiSurfaceStub != "" {
+		props.Full_api_surface_stub = proptools.StringPtr(alternativeFullApiSurfaceStub)
+	}
 
 	// android_module_lib_stubs_current.from-text only comprises api contributions from art, conscrypt and i18n.
 	// Thus, replace with android_module_lib_stubs_current_full.from-text, which comprises every api domains.
@@ -2062,9 +2111,13 @@
 
 		module.createStubsLibrary(mctx, scope)
 
-		contributesToApiSurface := module.contributesToApiSurface(mctx.Config())
+		alternativeFullApiSurfaceStubLib := ""
+		if scope == apiScopePublic {
+			alternativeFullApiSurfaceStubLib = module.alternativeFullApiSurfaceStubLib()
+		}
+		contributesToApiSurface := module.contributesToApiSurface(mctx.Config()) || alternativeFullApiSurfaceStubLib != ""
 		if contributesToApiSurface {
-			module.createApiLibrary(mctx, scope)
+			module.createApiLibrary(mctx, scope, alternativeFullApiSurfaceStubLib)
 		}
 
 		module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface)
diff --git a/rust/binary_test.go b/rust/binary_test.go
index dd4f993..fc4c560 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -21,6 +21,27 @@
 	"android/soong/android"
 )
 
+// Test that rustlibs default linkage is always rlib for host binaries.
+func TestBinaryHostLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary_host {
+			name: "fizz-buzz",
+			srcs: ["foo.rs"],
+			rustlibs: ["libfoo"],
+		}
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			host_supported: true,
+		}
+	`)
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+	if !android.InList("libfoo.rlib-std", fizzBuzz.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs dependency libfoo should be an rlib dep for host binaries")
+	}
+}
+
 // Test that rustlibs default linkage is correct for binaries.
 func TestBinaryLinkage(t *testing.T) {
 	ctx := testRust(t, `
@@ -54,6 +75,12 @@
 	if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) {
 		t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules")
 	}
+
+	rlibLinkDevice := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module)
+
+	if !android.InList("libfoo.rlib-std", rlibLinkDevice.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs dependency libfoo should be an rlib dep for device modules when prefer_rlib is set")
+	}
 }
 
 // Test that prefer_rlib links in libstd statically as well as rustlibs.