Merge changes from topic "bazel_framework_res" into main

* changes:
  bp2build support for framework-res
  Keep rules_testing BUILD files
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index d823f08..dcad55e 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -75,14 +75,17 @@
 		"build/soong/cc/libbuildversion":     Bp2BuildDefaultTrue, // Skip tests subdir
 		"build/soong/cc/ndkstubgen":          Bp2BuildDefaultTrue,
 		"build/soong/cc/symbolfile":          Bp2BuildDefaultTrue,
+		"build/soong/jar":                    Bp2BuildDefaultTrue,
 		"build/soong/licenses":               Bp2BuildDefaultTrue,
 		"build/soong/linkerconfig":           Bp2BuildDefaultTrueRecursively,
+		"build/soong/response":               Bp2BuildDefaultTrue,
 		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
+		"build/soong/third_party/zip":        Bp2BuildDefaultTrue,
 
 		"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
-		"cts/libs/json":                          Bp2BuildDefaultTrueRecursively,
-		"cts/tests/tests/gesture":                Bp2BuildDefaultTrueRecursively,
-		"platform_testing/libraries/annotations": Bp2BuildDefaultTrueRecursively,
+		"cts/flags/cc_tests":                          Bp2BuildDefaultTrueRecursively,
+		"cts/libs/json":                               Bp2BuildDefaultTrueRecursively,
+		"cts/tests/tests/gesture":                     Bp2BuildDefaultTrueRecursively,
 
 		"dalvik/tools/dexdeps": Bp2BuildDefaultTrueRecursively,
 
@@ -213,6 +216,7 @@
 		"external/tinyalsa":                      Bp2BuildDefaultTrueRecursively,
 		"external/tinyalsa_new":                  Bp2BuildDefaultTrueRecursively,
 		"external/toybox":                        Bp2BuildDefaultTrueRecursively,
+		"external/xz-java":                       Bp2BuildDefaultTrueRecursively,
 		"external/zlib":                          Bp2BuildDefaultTrueRecursively,
 		"external/zopfli":                        Bp2BuildDefaultTrueRecursively,
 		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
@@ -234,6 +238,7 @@
 		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
 		"frameworks/base/libs/services":                      Bp2BuildDefaultTrue,
 		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
+		"frameworks/base/mime":                               Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/proto":                              Bp2BuildDefaultTrue,
 		"frameworks/base/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
 		"frameworks/base/startop/apps/test":                  Bp2BuildDefaultTrue,
@@ -341,7 +346,9 @@
 		"packages/screensavers/Basic":                        Bp2BuildDefaultTrue,
 		"packages/services/Car/tests/SampleRearViewCamera":   Bp2BuildDefaultFalse, // TODO(b/242834321)
 
-		"platform_testing/tests/example": Bp2BuildDefaultTrueRecursively,
+		"platform_testing/libraries/annotations":              Bp2BuildDefaultTrueRecursively,
+		"platform_testing/libraries/flag-helpers/libflagtest": Bp2BuildDefaultTrueRecursively,
+		"platform_testing/tests/example":                      Bp2BuildDefaultTrueRecursively,
 
 		"prebuilts/clang/host/linux-x86":                   Bp2BuildDefaultTrueRecursively,
 		"prebuilts/gradle-plugin":                          Bp2BuildDefaultTrueRecursively,
@@ -566,7 +573,6 @@
 
 		// framework-minus-apex
 		"ImmutabilityAnnotationProcessor",
-		"android.mime.types.minimized",
 		"debian.mime.types.minimized",
 		"framework-javastream-protos",
 		"libview-inspector-annotation-processor",
@@ -952,6 +958,33 @@
 		"GsonBuildConfig.java",
 		"gson_version_generator",
 		"lab-resource-grpc",
+		"blueprint-deptools",
+		"protoc-gen-grpc-java-plugin",
+		"perfetto_trace-full",
+		"tf-remote-client",
+		"truth",
+		"tradefed-lite",
+		"tradefed-isolation-protos",
+		"snakeyaml_patched_src_files",
+		"asuite_proto_java",
+		"tradefed-service-grpc-lib",
+		"tradefed-invocation-grpc",
+		"tradefed-external-dependencies",
+		"tradefed-dynamic-sharding-grpc",
+		"tradefed-device-manager-grpc",
+		"statsd_internal_protos",
+		"snakeyaml",
+		"loganalysis",
+		"junit-params",
+		"grpc-java-testing",
+		"grpc-java-netty-shaded",
+		"aoa-helper",
+		"test-services.apk",
+		"test-composers",
+		"py3-stdlib-prebuilt-srcs",
+		"platformprotos",
+		"perfetto_metrics-full",
+		"test-services-normalized.apk",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
diff --git a/android/config.go b/android/config.go
index b3ff86b..769d257 100644
--- a/android/config.go
+++ b/android/config.go
@@ -2084,3 +2084,11 @@
 func (c *deviceConfig) NextReleaseHideFlaggedApi() bool {
 	return Bool(c.config.productVariables.NextReleaseHideFlaggedApi)
 }
+
+func (c *deviceConfig) ReleaseExposeFlaggedApi() bool {
+	return Bool(c.config.productVariables.ReleaseExposeFlaggedApi)
+}
+
+func (c *deviceConfig) HideFlaggedApis() bool {
+	return c.NextReleaseHideFlaggedApi() && !c.ReleaseExposeFlaggedApi()
+}
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index aeae20f..17b3230 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -17,7 +17,7 @@
 import "path/filepath"
 
 func init() {
-	RegisterModuleType("prebuilt_build_tool", prebuiltBuildToolFactory)
+	RegisterModuleType("prebuilt_build_tool", NewPrebuiltBuildTool)
 }
 
 type prebuiltBuildToolProperties struct {
@@ -101,10 +101,6 @@
 
 // prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use
 // in genrules with the "tools" property.
-func prebuiltBuildToolFactory() Module {
-	return NewPrebuiltBuildTool()
-}
-
 func NewPrebuiltBuildTool() Module {
 	module := &prebuiltBuildTool{}
 	module.AddProperties(&module.properties)
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 777c1cf..245b759 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -474,13 +474,23 @@
 		Inputs(depFiles.Paths())
 }
 
+// BuildWithNinjaVars adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
+// Outputs. This function will not escape Ninja variables, so it may be used to write sandbox manifests using Ninja variables.
+func (r *RuleBuilder) BuildWithUnescapedNinjaVars(name string, desc string) {
+	r.build(name, desc, false)
+}
+
 // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
 // Outputs.
 func (r *RuleBuilder) Build(name string, desc string) {
+	r.build(name, desc, true)
+}
+
+func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
 	name = ninjaNameEscape(name)
 
 	if len(r.missingDeps) > 0 {
-		r.ctx.Build(pctx, BuildParams{
+		r.ctx.Build(r.pctx, BuildParams{
 			Rule:        ErrorRule,
 			Outputs:     r.Outputs(),
 			Description: desc,
@@ -619,12 +629,35 @@
 				name, r.sboxManifestPath.String(), r.outDir.String())
 		}
 
-		// Create a rule to write the manifest as a the textproto.
+		// Create a rule to write the manifest as textproto.
 		pbText, err := prototext.Marshal(&manifest)
 		if err != nil {
 			ReportPathErrorf(r.ctx, "sbox manifest failed to marshal: %q", err)
 		}
-		WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
+		if ninjaEscapeCommandString {
+			WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
+		} else {
+			// We need  to have a rule to write files that is
+			// defined on the RuleBuilder's pctx in order to
+			// write Ninja variables in the string.
+			// The WriteFileRule function above rule can only write
+			// raw strings because it is defined on the android
+			// package's pctx, and it can't access variables defined
+			// in another context.
+			r.ctx.Build(r.pctx, BuildParams{
+				Rule: r.ctx.Rule(r.pctx, "unescapedWriteFile", blueprint.RuleParams{
+					Command:        `rm -rf ${out} && cat ${out}.rsp > ${out}`,
+					Rspfile:        "${out}.rsp",
+					RspfileContent: "${content}",
+					Description:    "write file",
+				}, "content"),
+				Output:      r.sboxManifestPath,
+				Description: "write sbox manifest " + r.sboxManifestPath.Base(),
+				Args: map[string]string{
+					"content": string(pbText),
+				},
+			})
+		}
 
 		// Generate a new string to use as the command line of the sbox rule.  This uses
 		// a RuleBuilderCommand as a convenience method of building the command line, then
@@ -723,9 +756,13 @@
 		pool = localPool
 	}
 
+	if ninjaEscapeCommandString {
+		commandString = proptools.NinjaEscape(commandString)
+	}
+
 	r.ctx.Build(r.pctx, BuildParams{
-		Rule: r.ctx.Rule(pctx, name, blueprint.RuleParams{
-			Command:        proptools.NinjaEscape(commandString),
+		Rule: r.ctx.Rule(r.pctx, name, blueprint.RuleParams{
+			Command:        commandString,
 			CommandDeps:    proptools.NinjaEscapeList(tools.Strings()),
 			Restat:         r.restat,
 			Rspfile:        proptools.NinjaEscape(rspFile),
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 86647eb..a6b3a27 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -28,6 +28,17 @@
 	"android/soong/shared"
 )
 
+var (
+	pctx_ruleBuilderTest           = NewPackageContext("android/soong/rule_builder")
+	pctx_ruleBuilderTestSubContext = NewPackageContext("android/soong/rule_builder/config")
+)
+
+func init() {
+	pctx_ruleBuilderTest.Import("android/soong/rule_builder/config")
+	pctx_ruleBuilderTest.StaticVariable("cmdFlags", "${config.ConfigFlags}")
+	pctx_ruleBuilderTestSubContext.StaticVariable("ConfigFlags", "--some-clang-flag")
+}
+
 func builderContext() BuilderContext {
 	return BuilderContextForTesting(TestConfig("out", nil, "", map[string][]byte{
 		"ld":      nil,
@@ -496,11 +507,13 @@
 type testRuleBuilderModule struct {
 	ModuleBase
 	properties struct {
-		Srcs []string
+		Srcs  []string
+		Flags []string
 
-		Restat      bool
-		Sbox        bool
-		Sbox_inputs bool
+		Restat              bool
+		Sbox                bool
+		Sbox_inputs         bool
+		Unescape_ninja_vars bool
 	}
 }
 
@@ -518,8 +531,9 @@
 	rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
 	manifestPath := PathForModuleOut(ctx, "sbox.textproto")
 
-	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir,
-		manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs,
+	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags,
+		out, outDep, outDir,
+		manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars,
 		rspFile, rspFileContents, rspFile2, rspFileContents2)
 }
 
@@ -543,17 +557,18 @@
 	rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
 	manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
 
-	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir,
-		manifestPath, true, false, false,
+	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir,
+		manifestPath, true, false, false, false,
 		rspFile, rspFileContents, rspFile2, rspFileContents2)
 }
 
 func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path,
+	flags []string,
 	out, outDep, outDir, manifestPath WritablePath,
-	restat, sbox, sboxInputs bool,
+	restat, sbox, sboxInputs, unescapeNinjaVars bool,
 	rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
 
-	rule := NewRuleBuilder(pctx, ctx)
+	rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx)
 
 	if sbox {
 		rule.Sbox(outDir, manifestPath)
@@ -564,6 +579,7 @@
 
 	rule.Command().
 		Tool(PathForSource(ctx, "cp")).
+		Flags(flags).
 		Inputs(in).
 		Implicit(implicit).
 		OrderOnly(orderOnly).
@@ -577,7 +593,11 @@
 		rule.Restat()
 	}
 
-	rule.Build("rule", "desc")
+	if unescapeNinjaVars {
+		rule.BuildWithUnescapedNinjaVars("rule", "desc")
+	} else {
+		rule.Build("rule", "desc")
+	}
 }
 
 var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -792,3 +812,47 @@
 		})
 	}
 }
+
+func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
+	bp := `
+		rule_builder_test {
+			name: "foo_sbox_escaped_ninja",
+			flags: ["${cmdFlags}"],
+			sbox: true,
+			sbox_inputs: true,
+		}
+		rule_builder_test {
+			name: "foo_sbox",
+			flags: ["${cmdFlags}"],
+			sbox: true,
+			sbox_inputs: true,
+			unescape_ninja_vars: true,
+		}
+	`
+	result := GroupFixturePreparers(
+		prepareForRuleBuilderTest,
+		FixtureWithRootAndroidBp(bp),
+	).RunTest(t)
+
+	escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped_ninja", "").Rule("writeFile")
+	AssertStringDoesContain(
+		t,
+		"",
+		escapedNinjaMod.BuildParams.Args["content"],
+		"$${cmdFlags}",
+	)
+
+	unescapedNinjaMod := result.ModuleForTests("foo_sbox", "").Rule("unescapedWriteFile")
+	AssertStringDoesContain(
+		t,
+		"",
+		unescapedNinjaMod.BuildParams.Args["content"],
+		"${cmdFlags}",
+	)
+	AssertStringDoesNotContain(
+		t,
+		"",
+		unescapedNinjaMod.BuildParams.Args["content"],
+		"$${cmdFlags}",
+	)
+}
diff --git a/android/variable.go b/android/variable.go
index 44a8fd7..516e69c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -490,6 +490,8 @@
 	PartitionVarsForBazelMigrationOnlyDoNotUse PartitionVariables `json:",omitempty"`
 
 	NextReleaseHideFlaggedApi *bool `json:",omitempty"`
+
+	ReleaseExposeFlaggedApi *bool `json:",omitempty"`
 }
 
 type PartitionVariables struct {
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 40356a1..0ca5c4e 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -21,6 +21,17 @@
 	"android/soong/java"
 )
 
+func runAndroidLibraryImportTestWithRegistrationCtxFunc(t *testing.T, registrationCtxFunc func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "android_library_import"
+	(&tc).ModuleTypeUnderTestFactory = java.AARImportFactory
+	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
+}
+
+func runAndroidLibraryImportTest(t *testing.T, tc Bp2buildTestCase) {
+	runAndroidLibraryImportTestWithRegistrationCtxFunc(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
 func TestConvertAndroidLibrary(t *testing.T) {
 	t.Helper()
 	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
@@ -96,20 +107,12 @@
 }
 
 func TestConvertAndroidLibraryImport(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(
-		t,
+	runAndroidLibraryImportTestWithRegistrationCtxFunc(t,
 		func(ctx android.RegistrationContext) {
 			ctx.RegisterModuleType("android_library", java.AndroidLibraryFactory)
 		},
 		Bp2buildTestCase{
-			Description:                "Android Library Import",
-			ModuleTypeUnderTest:        "android_library_import",
-			ModuleTypeUnderTestFactory: java.AARImportFactory,
-			Filesystem: map[string]string{
-				"import.aar": "",
-				"dep.aar":    "",
-			},
+			Description:             "Android Library Import",
 			StubbedBuildDefinitions: []string{"static_lib_dep", "static_import_dep", "static_import_dep-neverlink"},
 			// Bazel's aar_import can only export *_import targets, so we expect
 			// only "static_import_dep" in exports, but both "static_lib_dep" and
@@ -122,7 +125,6 @@
     sdk_version: "current",
 }
 
-// TODO: b/301007952 - This dep is needed because android_library_import must have aars set.
 android_library_import {
         name: "static_import_dep",
         aars: ["import.aar"],
@@ -220,3 +222,16 @@
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
 }
+
+func TestAarImportFailsToConvertNoAars(t *testing.T) {
+	runAndroidLibraryImportTest(t,
+		Bp2buildTestCase{
+			Description: "Android Library Import with no aars does not convert.",
+			Blueprint: `
+android_library_import {
+        name: "no_aar_import",
+}
+`,
+			ExpectedBazelTargets: []string{},
+		})
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index ce2a955..f53588d 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -783,13 +783,13 @@
 			} else if glib, ok := m.(*bootstrap.GoPackage); ok {
 				targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_library")
-				metrics.AddConvertedModule(glib, "go_library", dir)
+				metrics.IncrementRuleClassCount("bootstrap_go_package")
+				metrics.AddConvertedModule(glib, "bootstrap_go_package", dir)
 			} else if gbin, ok := m.(*bootstrap.GoBinary); ok {
 				targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_binary")
-				metrics.AddConvertedModule(gbin, "go_binary", dir)
+				metrics.IncrementRuleClassCount("blueprint_go_binary")
+				metrics.AddConvertedModule(gbin, "blueprint_go_binary", dir)
 			} else {
 				metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
 					ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index b3bb2da..56c57b9 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -386,9 +386,11 @@
 	// level.
 	abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp")
 	prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel)
+	missingPrebuiltErrorTemplate :=
+		"Did not find prebuilt ABI dump for %q (%q). Generate with " +
+			"//development/tools/ndk/update_ndk_abi.sh."
 	missingPrebuiltError := fmt.Sprintf(
-		"Did not find prebuilt ABI dump for %q (%q). Generate with "+
-			"//development/tools/ndk/update_ndk_abi.sh.", this.libraryName(ctx),
+		missingPrebuiltErrorTemplate, this.libraryName(ctx),
 		prebuiltAbiDump.InvalidReason())
 	if !prebuiltAbiDump.Valid() {
 		ctx.Build(pctx, android.BuildParams{
@@ -424,12 +426,15 @@
 		nextAbiDiffPath := android.PathForModuleOut(ctx,
 			"abidiff_next.timestamp")
 		nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel)
+		missingNextPrebuiltError := fmt.Sprintf(
+			missingPrebuiltErrorTemplate, this.libraryName(ctx),
+			nextAbiDump.InvalidReason())
 		if !nextAbiDump.Valid() {
 			ctx.Build(pctx, android.BuildParams{
 				Rule:   android.ErrorRule,
 				Output: nextAbiDiffPath,
 				Args: map[string]string{
-					"error": missingPrebuiltError,
+					"error": missingNextPrebuiltError,
 				},
 			})
 		} else {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 9ceb1c8..6329e97 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1113,12 +1113,15 @@
 // indirectly (via a mutator) sets the bool ptr to true, and you can't
 // distinguish between the cases. It isn't needed though - both cases can be
 // treated identically.
-func (sanitize *sanitize) isSanitizerEnabled(t SanitizerType) bool {
-	if sanitize == nil {
+func (s *sanitize) isSanitizerEnabled(t SanitizerType) bool {
+	if s == nil {
+		return false
+	}
+	if proptools.Bool(s.Properties.SanitizeMutated.Never) {
 		return false
 	}
 
-	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
+	sanitizerVal := s.getSanitizerBoolPtr(t)
 	return sanitizerVal != nil && *sanitizerVal == true
 }
 
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 49117a0..31e668e 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"runtime"
 	"strings"
 	"testing"
@@ -1273,3 +1274,122 @@
 		t.Errorf("non-CFI variant of baz not expected to contain CFI flags ")
 	}
 }
+
+func TestHwasan(t *testing.T) {
+	t.Parallel()
+
+	bp := `
+	cc_library_shared {
+		name: "shared_with_hwaddress",
+		static_libs: [
+			"static_dep_with_hwaddress",
+			"static_dep_no_hwaddress",
+		],
+		sanitize: {
+			hwaddress: true,
+		},
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+
+	cc_library_static {
+		name: "static_dep_with_hwaddress",
+		sanitize: {
+			hwaddress: true,
+		},
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+
+	cc_library_static {
+		name: "static_dep_no_hwaddress",
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+`
+
+	androidArm := "android_arm_armv7-a-neon"
+	androidArm64 := "android_arm64_armv8-a"
+	androidX86 := "android_x86_silvermont"
+	sharedSuffix := "_shared"
+	hwasanSuffix := "_hwasan"
+	staticSuffix := "_static"
+	sdkSuffix := "_sdk"
+
+	sharedWithHwasanVariant := sharedSuffix + hwasanSuffix
+	sharedWithSdkVariant := sdkSuffix + sharedSuffix
+	staticWithHwasanVariant := staticSuffix + hwasanSuffix
+	staticWithSdkVariant := sdkSuffix + staticSuffix
+
+	testCases := []struct {
+		buildOs          string
+		extraPreparer    android.FixturePreparer
+		expectedVariants map[string][]string
+	}{
+		{
+			buildOs: androidArm64,
+			expectedVariants: map[string][]string{
+				"shared_with_hwaddress": []string{
+					androidArm64 + sharedWithHwasanVariant,
+					androidArm64 + sharedWithSdkVariant,
+					androidArm + sharedSuffix,
+					androidArm + sharedWithSdkVariant,
+				},
+				"static_dep_with_hwaddress": []string{
+					androidArm64 + staticSuffix,
+					androidArm64 + staticWithHwasanVariant,
+					androidArm64 + staticWithSdkVariant,
+					androidArm + staticSuffix,
+					androidArm + staticWithSdkVariant,
+				},
+				"static_dep_no_hwaddress": []string{
+					androidArm64 + staticSuffix,
+					androidArm64 + staticWithHwasanVariant,
+					androidArm64 + staticWithSdkVariant,
+					androidArm + staticSuffix,
+					androidArm + staticWithSdkVariant,
+				},
+			},
+		},
+		{
+			buildOs: androidX86,
+			extraPreparer: android.FixtureModifyConfig(func(config android.Config) {
+				config.Targets[android.Android] = []android.Target{
+					{
+						android.Android,
+						android.Arch{
+							ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, android.NativeBridgeDisabled, "", "", false},
+				}
+			}),
+			expectedVariants: map[string][]string{
+				"shared_with_hwaddress": []string{
+					androidX86 + sharedSuffix,
+					androidX86 + sharedWithSdkVariant,
+				},
+				"static_dep_with_hwaddress": []string{
+					androidX86 + staticSuffix,
+					androidX86 + staticWithSdkVariant,
+				},
+				"static_dep_no_hwaddress": []string{
+					androidX86 + staticSuffix,
+					androidX86 + staticWithSdkVariant,
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			prepareForCcTest,
+			android.OptionalFixturePreparer(tc.extraPreparer),
+		)
+		result := preparer.RunTestWithBp(t, bp)
+
+		for m, v := range tc.expectedVariants {
+			variants := result.ModuleVariantsForTests(m)
+			if !reflect.DeepEqual(variants, v) {
+				t.Errorf("Expected variants of %q to be %q, but got %q", m, v, variants)
+			}
+		}
+	}
+}
diff --git a/cc/testing.go b/cc/testing.go
index 7531f6d..71d986b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -35,6 +35,7 @@
 
 	multitree.RegisterApiImportsModule(ctx)
 
+	ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool)
 	ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
 	ctx.RegisterModuleType("cc_object", ObjectFactory)
 	ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index fc56dd5..3364f50 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -119,6 +119,9 @@
 	}
 
 	manifest, err := readManifest(manifestFile)
+	if err != nil {
+		return err
+	}
 
 	if len(manifest.Commands) == 0 {
 		return fmt.Errorf("at least one commands entry is required in %q", manifestFile)
diff --git a/java/aar.go b/java/aar.go
index ad45eed..c0535a4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -1288,6 +1288,10 @@
 }
 
 func (a *AARImport) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	if len(a.properties.Aars) == 0 {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "aars can't be empty")
+		return
+	}
 	aars := android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Aars, []string{})
 	exportableStaticLibs := []string{}
 	// TODO(b/240716882): investigate and handle static_libs deps that are not imports. They are not supported for export by Bazel.
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 67a55bd..b059c0a 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -540,6 +540,10 @@
 	// See b/285312164 for more information.
 	cmd.FlagWithArg("--format-defaults ", "overloaded-method-order=source")
 
+	if ctx.DeviceConfig().HideFlaggedApis() {
+		cmd.FlagWithArg("--hide-annotation ", "android.annotation.FlaggedApi")
+	}
+
 	return cmd
 }
 
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 7a04d73..3c25801 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -22,6 +22,8 @@
 	"testing"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func TestDroidstubs(t *testing.T) {
@@ -403,3 +405,35 @@
 
 	ctx.ModuleForTests("bar", "android_common")
 }
+
+func TestDroidstubsHideFlaggedApi(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.NextReleaseHideFlaggedApi = proptools.BoolPtr(true)
+			variables.ReleaseExposeFlaggedApi = proptools.BoolPtr(false)
+		}),
+		android.FixtureMergeMockFs(map[string][]byte{
+			"a/A.java":      nil,
+			"a/current.txt": nil,
+			"a/removed.txt": nil,
+		}),
+	).RunTestWithBp(t, `
+	droidstubs {
+		name: "foo",
+		srcs: ["a/A.java"],
+		api_surface: "public",
+		check_api: {
+			current: {
+				api_file: "a/current.txt",
+				removed_api_file: "a/removed.txt",
+			}
+		},
+	}
+	`)
+
+	m := result.ModuleForTests("foo", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	cmdline := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command)
+	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "--hide-annotation android.annotation.FlaggedApi")
+}
diff --git a/rust/binary.go b/rust/binary.go
index 1408ff1..aee4da6 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -138,9 +138,14 @@
 
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
-	srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	ret := buildOutput{outputFile: outputFile}
+	var crateRootPath android.Path
+	if binary.baseCompiler.Properties.Crate_root == nil {
+		crateRootPath, _ = srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
+	} else {
+		crateRootPath = android.PathForModuleSrc(ctx, *binary.baseCompiler.Properties.Crate_root)
+	}
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
@@ -155,7 +160,7 @@
 	}
 	binary.baseCompiler.unstrippedOutputFile = outputFile
 
-	ret.kytheFile = TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile).kytheFile
+	ret.kytheFile = TransformSrcToBinary(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	return ret
 }
 
diff --git a/rust/compiler.go b/rust/compiler.go
index e6a7a93..d6c52e8 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -73,6 +73,15 @@
 	// If no source file is defined, a single generated source module can be defined to be used as the main source.
 	Srcs []string `android:"path,arch_variant"`
 
+	// Entry point that is passed to rustc to begin the compilation. E.g. main.rs or lib.rs.
+	// When this property is set,
+	//    * sandboxing is enabled for this module, and
+	//    * the srcs attribute is interpreted as a list of all source files potentially
+	//          used in compilation, including the entrypoint, and
+	//    * compile_data can be used to add additional files used in compilation that
+	//          not directly used as source files.
+	Crate_root *string `android:"path,arch_variant"`
+
 	// name of the lint set that should be used to validate this module.
 	//
 	// Possible values are "default" (for using a sensible set of lints
@@ -511,6 +520,8 @@
 		ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.")
 	}
 
+	// TODO: b/297264540 - once all modules are sandboxed, we need to select the proper
+	// entry point file from Srcs rather than taking the first one
 	paths := android.PathsForModuleSrc(ctx, srcs)
 	return paths[srcIndex], paths[1:]
 }
diff --git a/rust/config/global.go b/rust/config/global.go
index c976617..f397ce9 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -81,13 +81,7 @@
 
 func init() {
 	pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
-	pctx.VariableConfigMethod("HostPrebuiltTag", func(config android.Config) string {
-		if config.UseHostMusl() {
-			return "linux-musl-x86"
-		} else {
-			return config.PrebuiltOS()
-		}
-	})
+	pctx.VariableConfigMethod("HostPrebuiltTag", HostPrebuiltTag)
 
 	pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
@@ -109,6 +103,14 @@
 	exportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
 }
 
+func HostPrebuiltTag(config android.Config) string {
+	if config.UseHostMusl() {
+		return "linux-musl-x86"
+	} else {
+		return config.PrebuiltOS()
+	}
+}
+
 func getRustVersionPctx(ctx android.PackageVarContext) string {
 	return GetRustVersion(ctx)
 }
diff --git a/rust/library.go b/rust/library.go
index 0357086..f4a2b54 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -489,7 +489,7 @@
 	var outputFile android.ModuleOutPath
 	var ret buildOutput
 	var fileName string
-	srcPath := library.srcPath(ctx, deps)
+	crateRootPath := library.crateRootPath(ctx, deps)
 
 	if library.sourceProvider != nil {
 		deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
@@ -536,13 +536,13 @@
 
 	// Call the appropriate builder for this library type
 	if library.rlib() {
-		ret.kytheFile = TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.dylib() {
-		ret.kytheFile = TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.static() {
-		ret.kytheFile = TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.shared() {
-		ret.kytheFile = TransformSrctoShared(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	}
 
 	if library.rlib() || library.dylib() {
@@ -585,13 +585,15 @@
 	return ret
 }
 
-func (library *libraryDecorator) srcPath(ctx ModuleContext, _ PathDeps) android.Path {
+func (library *libraryDecorator) crateRootPath(ctx ModuleContext, _ PathDeps) android.Path {
 	if library.sourceProvider != nil {
 		// Assume the first source from the source provider is the library entry point.
 		return library.sourceProvider.Srcs()[0]
-	} else {
+	} else if library.baseCompiler.Properties.Crate_root == nil {
 		path, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
 		return path
+	} else {
+		return android.PathForModuleSrc(ctx, *library.baseCompiler.Properties.Crate_root)
 	}
 }
 
@@ -606,7 +608,7 @@
 		return android.OptionalPath{}
 	}
 
-	return android.OptionalPathForPath(Rustdoc(ctx, library.srcPath(ctx, deps),
+	return android.OptionalPathForPath(Rustdoc(ctx, library.crateRootPath(ctx, deps),
 		deps, flags))
 }
 
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
index 326d529..cb345a4 100644
--- a/rust/toolchain_library.go
+++ b/rust/toolchain_library.go
@@ -18,9 +18,12 @@
 
 import (
 	"path"
+	"path/filepath"
 
 	"android/soong/android"
 	"android/soong/rust/config"
+
+	"github.com/google/blueprint/proptools"
 )
 
 // This module is used to compile the rust toolchain libraries
@@ -33,11 +36,15 @@
 		rustToolchainLibraryRlibFactory)
 	android.RegisterModuleType("rust_toolchain_library_dylib",
 		rustToolchainLibraryDylibFactory)
+	android.RegisterModuleType("rust_toolchain_rustc_prebuilt",
+		rustToolchainRustcPrebuiltFactory)
 }
 
 type toolchainLibraryProperties struct {
-	// path to the toolchain source, relative to the top of the toolchain source
-	Toolchain_src *string `android:"arch_variant"`
+	// path to the toolchain crate root, relative to the top of the toolchain source
+	Toolchain_crate_root *string `android:"arch_variant"`
+	// path to the rest of the toolchain srcs, relative to the top of the toolchain source
+	Toolchain_srcs []string `android:"arch_variant"`
 }
 
 type toolchainLibraryDecorator struct {
@@ -82,16 +89,21 @@
 
 func rustSetToolchainSource(ctx android.LoadHookContext) {
 	if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
-		prefix := "linux-x86/" + GetRustPrebuiltVersion(ctx)
-		newSrcs := []string{path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_src))}
+		prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx))
+		versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_crate_root))
+		versionedSrcs := make([]string, len(toolchainLib.Properties.Toolchain_srcs))
+		for i, src := range toolchainLib.Properties.Toolchain_srcs {
+			versionedSrcs[i] = path.Join(prefix, src)
+		}
 
 		type props struct {
-			Srcs []string
+			Crate_root *string
+			Srcs       []string
 		}
 		p := &props{}
-		p.Srcs = newSrcs
+		p.Crate_root = &versionedCrateRoot
+		p.Srcs = versionedSrcs
 		ctx.AppendProperties(p)
-
 	} else {
 		ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.")
 	}
@@ -101,3 +113,47 @@
 func GetRustPrebuiltVersion(ctx android.LoadHookContext) string {
 	return ctx.AConfig().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion)
 }
+
+type toolchainRustcPrebuiltProperties struct {
+	// path to rustc prebuilt, relative to the top of the toolchain source
+	Toolchain_prebuilt_src *string
+	// path to deps, relative to the top of the toolchain source
+	Toolchain_deps []string
+	// path to deps, relative to module directory
+	Deps []string
+}
+
+func rustToolchainRustcPrebuiltFactory() android.Module {
+	module := android.NewPrebuiltBuildTool()
+	module.AddProperties(&toolchainRustcPrebuiltProperties{})
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		var toolchainProps *toolchainRustcPrebuiltProperties
+		for _, p := range ctx.Module().GetProperties() {
+			toolchainProperties, ok := p.(*toolchainRustcPrebuiltProperties)
+			if ok {
+				toolchainProps = toolchainProperties
+			}
+		}
+
+		if toolchainProps.Toolchain_prebuilt_src == nil {
+			ctx.PropertyErrorf("toolchain_prebuilt_src", "must set path to rustc prebuilt")
+		}
+
+		prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx))
+		deps := make([]string, 0, len(toolchainProps.Toolchain_deps)+len(toolchainProps.Deps))
+		for _, d := range toolchainProps.Toolchain_deps {
+			deps = append(deps, path.Join(prefix, d))
+		}
+		deps = append(deps, toolchainProps.Deps...)
+
+		props := struct {
+			Src  *string
+			Deps []string
+		}{
+			Src:  proptools.StringPtr(path.Join(prefix, *toolchainProps.Toolchain_prebuilt_src)),
+			Deps: deps,
+		}
+		ctx.AppendProperties(&props)
+	})
+	return module
+}