Merge "Drop INTERNAL_PLATFORM_MISSING_USES_LIBRARIES."
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 0dd7dae..bd2d973 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -1470,6 +1470,13 @@
 
 		// python_test_host with test data
 		"sbom_writers_test",
+
+		// TODO(B/283193845): tradefed and its java_test_host dependents
+		"tradefed",
+		"permissive_mte_test",
+		"ICU4CTestRunner",
+
+		"HelloWorldHostTest",  // TODO(b/280452825): Convert HelloWorldHostTest to b test
 	}
 
 	MixedBuildsDisabledList = []string{
diff --git a/bazel/bazel_proxy.go b/bazel/bazel_proxy.go
index 2940b99..229818d 100644
--- a/bazel/bazel_proxy.go
+++ b/bazel/bazel_proxy.go
@@ -26,10 +26,11 @@
 	"time"
 )
 
-// Logs fatal events of ProxyServer.
+// Logs events of ProxyServer.
 type ServerLogger interface {
 	Fatal(v ...interface{})
 	Fatalf(format string, v ...interface{})
+	Println(v ...interface{})
 }
 
 // CmdRequest is a request to the Bazel Proxy server.
@@ -71,9 +72,10 @@
 // The ProxyServer will only live as long as soong_ui does; the
 // underlying Bazel server will live past the duration of the build.
 type ProxyServer struct {
-	logger       ServerLogger
-	outDir       string
-	workspaceDir string
+	logger          ServerLogger
+	outDir          string
+	workspaceDir    string
+	bazeliskVersion string
 	// The server goroutine will listen on this channel and stop handling requests
 	// once it is written to.
 	done chan struct{}
@@ -119,12 +121,17 @@
 }
 
 // NewProxyServer is a constructor for a ProxyServer.
-func NewProxyServer(logger ServerLogger, outDir string, workspaceDir string) *ProxyServer {
+func NewProxyServer(logger ServerLogger, outDir string, workspaceDir string, bazeliskVersion string) *ProxyServer {
+	if len(bazeliskVersion) > 0 {
+		logger.Println("** Using Bazelisk for this build, due to env var USE_BAZEL_VERSION=" + bazeliskVersion + " **")
+	}
+
 	return &ProxyServer{
-		logger:       logger,
-		outDir:       outDir,
-		workspaceDir: workspaceDir,
-		done:         make(chan struct{}),
+		logger:          logger,
+		outDir:          outDir,
+		workspaceDir:    workspaceDir,
+		done:            make(chan struct{}),
+		bazeliskVersion: bazeliskVersion,
 	}
 }
 
@@ -155,6 +162,9 @@
 		return fmt.Errorf("Error decoding request: %s", err)
 	}
 
+	if len(b.bazeliskVersion) > 0 {
+		req.Env = append(req.Env, "USE_BAZEL_VERSION="+b.bazeliskVersion)
+	}
 	stdout, stderr, cmdErr := ExecBazel("./build/bazel/bin/bazel", b.workspaceDir, req)
 	errorString := ""
 	if cmdErr != nil {
diff --git a/bp2build/java_test_host_conversion_test.go b/bp2build/java_test_host_conversion_test.go
new file mode 100644
index 0000000..f411ffb
--- /dev/null
+++ b/bp2build/java_test_host_conversion_test.go
@@ -0,0 +1,149 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/java"
+)
+
+func runJavaTestHostTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "java_test_host"
+	(&tc).ModuleTypeUnderTestFactory = java.TestHostFactory
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("java_library", java.LibraryFactory)
+	}, tc)
+}
+
+func TestJavaTestHostGeneral(t *testing.T) {
+	runJavaTestHostTestCase(t, Bp2buildTestCase{
+		Description: "java_test_host general",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+java_test_host {
+    name: "java_test_host-1",
+    srcs: ["a.java", "b.java"],
+    libs: ["lib_a"],
+    static_libs: ["static_libs_a"],
+    exclude_srcs: ["b.java"],
+    javacflags: ["-Xdoclint:all/protected"],
+    java_version: "8",
+}
+
+java_library {
+    name: "lib_a",
+    bazel_module: { bp2build_available: false },
+}
+
+java_library {
+    name: "static_libs_a",
+    bazel_module: { bp2build_available: false },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_library", "java_test_host-1_lib", AttrNameToString{
+				"deps": `[
+        ":lib_a-neverlink",
+        ":static_libs_a",
+    ]`,
+				"java_version": `"8"`,
+				"javacopts":    `["-Xdoclint:all/protected"]`,
+				"srcs":         `["a.java"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
+				"runtime_deps": `[":java_test_host-1_lib"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestJavaTestHostNoSrcs(t *testing.T) {
+	runJavaTestHostTestCase(t, Bp2buildTestCase{
+		Description: "java_test_host without srcs",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+java_test_host {
+    name: "java_test_host-1",
+    libs: ["lib_a"],
+    static_libs: ["static_libs_a"],
+}
+
+java_library {
+    name: "lib_a",
+    bazel_module: { bp2build_available: false },
+}
+
+java_library {
+    name: "static_libs_a",
+    bazel_module: { bp2build_available: false },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
+				"runtime_deps": `[
+        ":lib_a-neverlink",
+        ":static_libs_a",
+    ]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestJavaTestHostKotlinSrcs(t *testing.T) {
+	runJavaTestHostTestCase(t, Bp2buildTestCase{
+		Description: "java_test_host with .kt in srcs",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+java_test_host {
+    name: "java_test_host-1",
+    srcs: ["a.java", "b.kt"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
+				"runtime_deps": `[":java_test_host-1_lib"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("kt_jvm_library", "java_test_host-1_lib", AttrNameToString{
+				"srcs": `[
+        "a.java",
+        "b.kt",
+    ]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
diff --git a/cc/lto.go b/cc/lto.go
index be8fc56..a8bed23 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -43,16 +43,13 @@
 	// referred to in blueprint files as "lto"
 	Lto struct {
 		Never *bool `android:"arch_variant"`
-		Full  *bool `android:"arch_variant"`
 		Thin  *bool `android:"arch_variant"`
 	} `android:"arch_variant"`
 
 	// Dep properties indicate that this module needs to be built with LTO
 	// since it is an object dependency of an LTO module.
-	FullEnabled  bool `blueprint:"mutated"`
 	ThinEnabled  bool `blueprint:"mutated"`
 	NoLtoEnabled bool `blueprint:"mutated"`
-	FullDep      bool `blueprint:"mutated"`
 	ThinDep      bool `blueprint:"mutated"`
 	NoLtoDep     bool `blueprint:"mutated"`
 
@@ -86,8 +83,6 @@
 		var ltoLdFlag string
 		if lto.ThinLTO() {
 			ltoCFlag = "-flto=thin -fsplit-lto-unit"
-		} else if lto.FullLTO() {
-			ltoCFlag = "-flto"
 		} else {
 			ltoCFlag = "-flto=thin -fsplit-lto-unit"
 			ltoLdFlag = "-Wl,--lto-O0"
@@ -126,13 +121,13 @@
 }
 
 func (lto *lto) LTO(ctx BaseModuleContext) bool {
-	return lto.ThinLTO() || lto.FullLTO() || lto.DefaultThinLTO(ctx)
+	return lto.ThinLTO() || lto.DefaultThinLTO(ctx)
 }
 
 func (lto *lto) DefaultThinLTO(ctx BaseModuleContext) bool {
 	// LP32 has many subtle issues and less test coverage.
 	lib32 := ctx.Arch().ArchType.Multilib == "lib32"
-	// CFI enables full LTO.
+	// CFI adds LTO flags by itself.
 	cfi := ctx.isCfi()
 	// Performance and binary size are less important for host binaries and tests.
 	host := ctx.Host()
@@ -143,10 +138,6 @@
 	return GlobalThinLTO(ctx) && !lto.Never() && !lib32 && !cfi && !host && !test && !vndk
 }
 
-func (lto *lto) FullLTO() bool {
-	return lto != nil && (proptools.Bool(lto.Properties.Lto.Full) || lto.Properties.FullEnabled)
-}
-
 func (lto *lto) ThinLTO() bool {
 	return lto != nil && (proptools.Bool(lto.Properties.Lto.Thin) || lto.Properties.ThinEnabled)
 }
@@ -164,12 +155,8 @@
 	globalThinLTO := GlobalThinLTO(mctx)
 
 	if m, ok := mctx.Module().(*Module); ok {
-		full := m.lto.FullLTO()
 		thin := m.lto.ThinLTO()
 		never := m.lto.Never()
-		if full && thin {
-			mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
-		}
 
 		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
 			tag := mctx.OtherModuleDependencyTag(dep)
@@ -187,9 +174,6 @@
 			}
 
 			if dep, ok := dep.(*Module); ok {
-				if full && !dep.lto.FullLTO() {
-					dep.lto.Properties.FullDep = true
-				}
 				if !globalThinLTO && thin && !dep.lto.ThinLTO() {
 					dep.lto.Properties.ThinDep = true
 				}
@@ -212,9 +196,6 @@
 		// Create variations for LTO types required as static
 		// dependencies
 		variationNames := []string{""}
-		if m.lto.Properties.FullDep && !m.lto.FullLTO() {
-			variationNames = append(variationNames, "lto-full")
-		}
 		if !globalThinLTO && m.lto.Properties.ThinDep && !m.lto.ThinLTO() {
 			variationNames = append(variationNames, "lto-thin")
 		}
@@ -224,13 +205,10 @@
 
 		// Use correct dependencies if LTO property is explicitly set
 		// (mutually exclusive)
-		if m.lto.FullLTO() {
-			mctx.SetDependencyVariation("lto-full")
-		}
 		if !globalThinLTO && m.lto.ThinLTO() {
 			mctx.SetDependencyVariation("lto-thin")
 		}
-		// Never must be the last, it overrides Thin or Full.
+		// Never must be the last, it overrides Thin.
 		if globalThinLTO && m.lto.Never() {
 			mctx.SetDependencyVariation("lto-none")
 		}
@@ -247,9 +225,6 @@
 				}
 
 				// LTO properties for dependencies
-				if name == "lto-full" {
-					variation.lto.Properties.FullEnabled = true
-				}
 				if name == "lto-thin" {
 					variation.lto.Properties.ThinEnabled = true
 				}
@@ -258,7 +233,6 @@
 				}
 				variation.Properties.PreventInstall = true
 				variation.Properties.HideFromMake = true
-				variation.lto.Properties.FullDep = false
 				variation.lto.Properties.ThinDep = false
 				variation.lto.Properties.NoLtoDep = false
 			}
diff --git a/cc/test.go b/cc/test.go
index 27de06b..3f5f710 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -70,6 +70,10 @@
 	// Add MinApiLevelModuleController with ro.vndk.version property. If ro.vndk.version has an
 	// integer value and the value is less than the min_vndk_version, skip this module.
 	Min_vndk_version *int64
+
+	// Extra <option> tags to add to the auto generated test xml file under the test runner, e.g., GTest.
+	// The "key" is optional in each of these.
+	Test_runner_options []tradefed.Option
 }
 
 type TestBinaryProperties struct {
@@ -398,6 +402,7 @@
 		TestConfigTemplateProp: test.Properties.Test_config_template,
 		TestSuites:             test.testDecorator.InstallerProperties.Test_suites,
 		Config:                 configs,
+		TestRunnerOptions:      test.Properties.Test_options.Test_runner_options,
 		AutoGenConfig:          test.Properties.Auto_gen_config,
 		TestInstallBase:        testInstallBase,
 		DeviceTemplate:         "${NativeTestConfigTemplate}",
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index e006c9d..d589925 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -552,6 +552,12 @@
 		}
 		writeMetrics(configuration, ctx.EventHandler, metricsDir)
 	}
+
+	// Register this environment variablesas being an implicit dependencies of
+	// soong_build. Changes to this environment variable will result in
+	// retriggering soong_build.
+	configuration.Getenv("USE_BAZEL_VERSION")
+
 	writeUsedEnvironmentFile(configuration)
 
 	// Touch the output file so that it's the newest file created by soong_build.
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 875dbab..2954f8b 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -14,10 +14,6 @@
 
 package genrule
 
-import (
-	"android/soong/android"
-)
-
 var (
 	DepfileAllowList = []string{
 		"depfile_allowed_for_test",
@@ -136,12 +132,3 @@
 		"external/perfetto",
 	}
 )
-var DepfileAllowSet = map[string]bool{}
-var SandboxingDenyModuleSet = map[string]bool{}
-var SandboxingDenyPathSet = map[string]bool{}
-
-func init() {
-	android.AddToStringSet(DepfileAllowSet, DepfileAllowList)
-	android.AddToStringSet(SandboxingDenyModuleSet, append(DepfileAllowList, SandboxingDenyModuleList...))
-	android.AddToStringSet(SandboxingDenyPathSet, SandboxingDenyPathList)
-}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index c830fcc..4992625 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -24,6 +24,7 @@
 	"path/filepath"
 	"strconv"
 	"strings"
+	"sync"
 
 	"android/soong/bazel/cquery"
 
@@ -60,6 +61,12 @@
 	PrepareForTestWithGenRuleBuildComponents,
 )
 
+var DepfileAllowSet map[string]bool
+var SandboxingDenyModuleSet map[string]bool
+var SandboxingDenyPathSet map[string]bool
+var SandboxingDenyModuleSetLock sync.Mutex
+var DepfileAllowSetLock sync.Mutex
+
 func RegisterGenruleBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("genrule_defaults", defaultsFactory)
 
@@ -595,6 +602,12 @@
 	// Allowlist genrule to use depfile until we have a solution to remove it.
 	// TODO(b/235582219): Remove allowlist for genrule
 	if Bool(g.properties.Depfile) {
+		if DepfileAllowSet == nil {
+			DepfileAllowSetLock.Lock()
+			defer DepfileAllowSetLock.Unlock()
+			DepfileAllowSet = map[string]bool{}
+			android.AddToStringSet(DepfileAllowSet, DepfileAllowList)
+		}
 		// TODO(b/283852474): Checking the GenruleSandboxing flag is temporary in
 		// order to pass the presubmit before internal master is updated.
 		if ctx.DeviceConfig().GenruleSandboxing() && !DepfileAllowSet[g.Name()] {
@@ -1024,8 +1037,19 @@
 }
 
 func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
-	if !ctx.DeviceConfig().GenruleSandboxing() || SandboxingDenyPathSet[ctx.ModuleDir()] ||
-		SandboxingDenyModuleSet[ctx.ModuleName()] {
+	if !ctx.DeviceConfig().GenruleSandboxing() {
+		return r.SandboxTools()
+	}
+	if SandboxingDenyModuleSet == nil {
+		SandboxingDenyModuleSetLock.Lock()
+		defer SandboxingDenyModuleSetLock.Unlock()
+		SandboxingDenyModuleSet = map[string]bool{}
+		SandboxingDenyPathSet = map[string]bool{}
+		android.AddToStringSet(SandboxingDenyModuleSet, append(DepfileAllowList, SandboxingDenyModuleList...))
+		android.AddToStringSet(SandboxingDenyPathSet, SandboxingDenyPathList)
+	}
+
+	if SandboxingDenyPathSet[ctx.ModuleDir()] || SandboxingDenyModuleSet[ctx.ModuleName()] {
 		return r.SandboxTools()
 	}
 	return r.SandboxInputs()
diff --git a/java/app.go b/java/app.go
index cdec1e1..58580d4 100755
--- a/java/app.go
+++ b/java/app.go
@@ -796,8 +796,9 @@
 	shouldInstallAppPackage := (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && !a.appProperties.PreventInstall
 	if shouldInstallAppPackage {
 		if a.privAppAllowlist.Valid() {
-			installPath := android.PathForModuleInstall(ctx, "etc", "permissions")
-			ctx.InstallFile(installPath, a.privAppAllowlist.Path().Base(), a.privAppAllowlist.Path())
+			allowlistInstallPath := android.PathForModuleInstall(ctx, "etc", "permissions")
+			allowlistInstallFilename := a.installApkName + ".xml"
+			ctx.InstallFile(allowlistInstallPath, allowlistInstallFilename, a.privAppAllowlist.Path())
 		}
 
 		var extraInstalledPaths android.Paths
diff --git a/java/app_test.go b/java/app_test.go
index 592859c..5aed178 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3542,8 +3542,8 @@
 	}
 
 	// verify that permissions are copied to device
-	app.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.android.foo.xml")
-	overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.google.android.foo.xml")
+	app.Output("out/soong/target/product/test_device/system/etc/permissions/foo.xml")
+	overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/bar.xml")
 }
 
 func TestPrivappAllowlistAndroidMk(t *testing.T) {
@@ -3594,7 +3594,7 @@
 		t,
 		"androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist",
 		baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
-		"privapp_allowlist_com.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/privapp_allowlist_com.android.foo.xml",
+		"privapp_allowlist_com.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/foo.xml",
 	)
 
 	overrideAndroidApp := overrideApp.Module().(*AndroidApp)
@@ -3621,6 +3621,6 @@
 		t,
 		"androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist",
 		overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
-		"\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/privapp_allowlist_com.google.android.foo.xml",
+		"\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/bar.xml",
 	)
 }
diff --git a/java/base.go b/java/base.go
index 374138c..dd02ef8 100644
--- a/java/base.go
+++ b/java/base.go
@@ -2188,5 +2188,9 @@
 		if binary, ok := ctx.Module().(*Binary); ok {
 			javaBinaryHostBp2Build(ctx, binary)
 		}
+	case "java_test_host":
+		if testHost, ok := ctx.Module().(*TestHost); ok {
+			javaTestHostBp2Build(ctx, testHost)
+		}
 	}
 }
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 116c833..35f6097 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -816,7 +816,7 @@
 		cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
 	}
 
-	if global.EnableUffdGc {
+	if global.EnableUffdGc && image.target.Os == android.Android {
 		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
 	}
 
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 8a521aa..151c94a 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -535,6 +535,14 @@
 		// b/223382732
 		FlagWithArg("--hide ", "ChangedDefault")
 
+	// Force metalava to ignore classes on the classpath when an API file contains missing classes.
+	// See b/285140653 for more information.
+	cmd.FlagWithArg("--api-class-resolution ", "api")
+
+	// Force metalava to sort overloaded methods by their order in the source code.
+	// See b/285312164 for more information.
+	cmd.FlagWithArg("--api-overloaded-method-order ", "source")
+
 	return cmd
 }
 
diff --git a/java/java.go b/java/java.go
index aa9f936..4f7b401 100644
--- a/java/java.go
+++ b/java/java.go
@@ -936,6 +936,10 @@
 	// Extra <option> tags to add to the auto generated test xml file. The "key"
 	// is optional in each of these.
 	Tradefed_options []tradefed.Option
+
+	// Extra <option> tags to add to the auto generated test xml file under the test runner, e.g., AndroidJunitTest.
+	// The "key" is optional in each of these.
+	Test_runner_options []tradefed.Option
 }
 
 type testProperties struct {
@@ -1218,6 +1222,7 @@
 		TestSuites:              j.testProperties.Test_suites,
 		Config:                  configs,
 		OptionsForAutogenerated: j.testProperties.Test_options.Tradefed_options,
+		TestRunnerOptions:       j.testProperties.Test_options.Test_runner_options,
 		AutoGenConfig:           j.testProperties.Auto_gen_config,
 		UnitTest:                j.testProperties.Test_options.Unit_test,
 		DeviceTemplate:          "${JavaTestConfigTemplate}",
@@ -1416,6 +1421,8 @@
 		nil,
 		nil)
 
+	android.InitBazelModule(module)
+
 	InitJavaModuleMultiTargets(module, android.HostSupported)
 
 	return module
@@ -1728,6 +1735,14 @@
 		FlagWithArg("--hide ", "InvalidNullabilityOverride").
 		FlagWithArg("--hide ", "ChangedDefault")
 
+	// Force metalava to ignore classes on the classpath when an API file contains missing classes.
+	// See b/285140653 for more information.
+	cmd.FlagWithArg("--api-class-resolution ", "api")
+
+	// Force metalava to sort overloaded methods by their order in the source code.
+	// See b/285312164 for more information.
+	cmd.FlagWithArg("--api-overloaded-method-order ", "source")
+
 	return cmd
 }
 
@@ -3114,23 +3129,89 @@
 		return
 	}
 
-	libName := m.Name() + "_lib"
+	libInfo := libraryCreationInfo{
+		deps: deps,
+		attrs: commonAttrs,
+		baseName: m.Name(),
+		hasKotlin: bp2BuildInfo.hasKotlin,
+	}
+	libName := createLibraryTarget(ctx, libInfo)
+	binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
+
+	// Create the BazelTargetModule.
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
+}
+
+type javaTestHostAttributes struct {
+	*javaCommonAttributes
+	Deps         bazel.LabelListAttribute
+	Runtime_deps bazel.LabelListAttribute
+}
+
+// javaTestHostBp2Build is for java_test_host bp2build.
+func javaTestHostBp2Build(ctx android.TopDownMutatorContext, m *TestHost) {
+	commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
+	depLabels := bp2BuildInfo.DepLabels
+
+	deps := depLabels.Deps
+	deps.Append(depLabels.StaticDeps)
+
+	var runtimeDeps bazel.LabelListAttribute
+	attrs := &javaTestHostAttributes{
+		Runtime_deps: runtimeDeps,
+	}
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "java_test",
+		Bzl_load_location: "//build/bazel/rules/java:test.bzl",
+	}
+
+	if commonAttrs.Srcs.IsEmpty() {
+		// if there are no sources, then the dependencies can only be used at runtime
+		attrs.Runtime_deps = deps
+		attrs.javaCommonAttributes = commonAttrs
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+		return
+	}
+
+	libInfo := libraryCreationInfo{
+		deps: deps,
+		attrs: commonAttrs,
+		baseName: m.Name(),
+		hasKotlin: bp2BuildInfo.hasKotlin,
+	}
+	libName := createLibraryTarget(ctx, libInfo)
+	attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
+
+	// Create the BazelTargetModule.
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+}
+
+// libraryCreationInfo encapsulates the info needed to create java_library target from
+// java_binary_host or java_test_host.
+type libraryCreationInfo struct {
+	deps bazel.LabelListAttribute
+	attrs *javaCommonAttributes
+	baseName string
+	hasKotlin bool
+}
+
+// helper function that creates java_library target from java_binary_host or java_test_host,
+// and returns the library target name,
+func createLibraryTarget(ctx android.TopDownMutatorContext, libInfo libraryCreationInfo) string {
+	libName := libInfo.baseName + "_lib"
 	var libProps bazel.BazelTargetModuleProperties
-	if bp2BuildInfo.hasKotlin {
+	if libInfo.hasKotlin {
 		libProps = ktJvmLibraryBazelTargetModuleProperties()
 	} else {
 		libProps = javaLibraryBazelTargetModuleProperties()
 	}
 	libAttrs := &javaLibraryAttributes{
-		Deps:                 deps,
-		javaCommonAttributes: commonAttrs,
+		Deps:                 libInfo.deps,
+		javaCommonAttributes: libInfo.attrs,
 	}
 
 	ctx.CreateBazelTargetModule(libProps, android.CommonAttributes{Name: libName}, libAttrs)
-	binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
-
-	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
+	return libName
 }
 
 type bazelJavaImportAttributes struct {
diff --git a/java/java_test.go b/java/java_test.go
index ea89e6e..cd5c343 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2298,3 +2298,27 @@
 		t.Errorf("Expected args[\"extraConfigs\"] to equal %q, was %q", expected, args["extraConfigs"])
 	}
 }
+
+func TestTestRunnerOptions(t *testing.T) {
+	result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
+java_test_host {
+	name: "foo",
+	test_options: {
+		test_runner_options: [
+			{
+				name: "test-timeout",
+				value: "10m"
+			}
+		]
+	}
+}
+`)
+
+	buildOS := result.Config.BuildOS.String()
+	args := result.ModuleForTests("foo", buildOS+"_common").
+		Output("out/soong/.intermediates/foo/" + buildOS + "_common/foo.config").Args
+	expected := proptools.NinjaAndShellEscape("<option name=\"test-timeout\" value=\"10m\" />\\n        ")
+	if args["extraTestRunnerConfigs"] != expected {
+		t.Errorf("Expected args[\"extraTestRunnerConfigs\"] to equal %q, was %q", expected, args["extraTestRunnerConfigs"])
+	}
+}
diff --git a/rust/builder.go b/rust/builder.go
index 0aa2225..0dfaef4 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -261,7 +261,7 @@
 	// Disallow experimental features
 	modulePath := android.PathForModuleSrc(ctx).String()
 	if !(android.IsThirdPartyPath(modulePath) || strings.HasPrefix(modulePath, "prebuilts")) {
-		rustcFlags = append(rustcFlags, "-Zallow-features=\"custom_inner_attributes,mixed_integer_ops\"")
+		rustcFlags = append(rustcFlags, "-Zallow-features=\"\"")
 	}
 
 	// Collect linker flags
diff --git a/rust/config/global.go b/rust/config/global.go
index 748bb3d..60acc6e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -51,9 +51,6 @@
 		// Use v0 mangling to distinguish from C++ symbols
 		"-C symbol-mangling-version=v0",
 		"--color always",
-		// TODO (b/267698452): Temporary workaround until the "no unstable
-		// features" policy is enforced.
-		"-A stable-features",
 		"-Zdylib-lto",
 	}
 
diff --git a/tests/genrule_sandbox_test.sh b/tests/genrule_sandbox_test.sh
new file mode 100755
index 0000000..21b476b
--- /dev/null
+++ b/tests/genrule_sandbox_test.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+# Build the given genrule modules with GENRULE_SANDBOXING enabled and disabled,
+# then compare the output of the modules and report result.
+
+function die() { format=$1; shift; printf >&2 "$format\n" $@; exit 1; }
+
+function usage() {
+  die "usage: ${0##*/} <-t lunch_target> [module]..."
+}
+
+if [ ! -e "build/make/core/Makefile" ]; then
+  die "$0 must be run from the top of the Android source tree."
+fi
+
+declare TARGET=
+while getopts "t:" opt; do
+  case $opt in
+    t)
+      TARGET=$OPTARG ;;
+    *) usage ;;
+  esac
+done
+
+shift $((OPTIND-1))
+MODULES="$@"
+
+source build/envsetup.sh
+
+if [[ -n $TARGET ]]; then
+  lunch $TARGET
+fi
+
+if [[ -z ${OUT_DIR+x} ]]; then
+  OUT_DIR="out"
+fi
+
+OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+PASS=true
+
+function cleanup {
+  if [ $PASS = true ]; then
+    rm -rf "${OUTPUT_DIR}"
+  fi
+}
+trap cleanup EXIT
+
+declare -A GEN_PATH_MAP
+
+function find_gen_paths() {
+  for module in $MODULES; do
+    module_path=$(pathmod "$module")
+    package_path=${module_path#$ANDROID_BUILD_TOP}
+    gen_path=$OUT_DIR/soong/.intermediates$package_path/$module
+    GEN_PATH_MAP[$module]=$gen_path
+  done
+}
+
+function store_outputs() {
+  local dir=$1; shift
+
+  for module in $MODULES; do
+    dest_dir=$dir/${module}
+    mkdir -p $dest_dir
+    gen_path=${GEN_PATH_MAP[$module]}
+    cp -r $gen_path $dest_dir
+  done
+}
+
+function cmp_outputs() {
+  local dir1=$1; shift
+  local dir2=$1; shift
+
+  for module in $MODULES; do
+    if ! diff -rq --exclude=genrule.sbox.textproto $dir1/$module $dir2/$module; then
+      PASS=false
+      echo "$module differ"
+    fi
+  done
+  if [ $PASS = true ]; then
+    echo "Test passed"
+  fi
+}
+
+if [ ! -f "$ANDROID_PRODUCT_OUT/module-info.json" ]; then
+  refreshmod
+fi
+
+find_gen_paths
+m --skip-soong-tests GENRULE_SANDBOXING=true "${MODULES[@]}"
+store_outputs "$OUTPUT_DIR/sandbox"
+m --skip-soong-tests GENRULE_SANDBOXING=false "${MODULES[@]}"
+store_outputs "$OUTPUT_DIR/non_sandbox"
+
+cmp_outputs "$OUTPUT_DIR/non_sandbox" "$OUTPUT_DIR/sandbox"
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 49b09af..3c55c51 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -40,9 +40,9 @@
 }
 
 var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
-	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out",
+	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{EXTRA_TEST_RUNNER_CONFIGS}&'${extraTestRunnerConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out",
 	CommandDeps: []string{"$template"},
-}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase")
+}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase", "extraTestRunnerConfigs")
 
 func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
 	p := getTestConfig(ctx, prop)
@@ -107,7 +107,7 @@
 
 }
 
-func autogenTemplate(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) {
+func autogenTemplate(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, testRunnerConfigs []Option, outputFileName string, testInstallBase string) {
 	if template == "" {
 		ctx.ModuleErrorf("Empty template")
 	}
@@ -118,16 +118,27 @@
 	extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
 	extraConfigs = proptools.NinjaAndShellEscape(extraConfigs)
 
+	var testRunnerConfigStrings []string
+	for _, config := range testRunnerConfigs {
+		testRunnerConfigStrings = append(testRunnerConfigStrings, config.Config())
+	}
+	extraTestRunnerConfigs := strings.Join(testRunnerConfigStrings, fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent))
+	if len(extraTestRunnerConfigs) > 0 {
+		extraTestRunnerConfigs += fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent)
+	}
+	extraTestRunnerConfigs = proptools.NinjaAndShellEscape(extraTestRunnerConfigs)
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        autogenTestConfig,
 		Description: "test config",
 		Output:      output,
 		Args: map[string]string{
-			"name":            name,
-			"template":        template,
-			"extraConfigs":    extraConfigs,
-			"outputFileName":  outputFileName,
-			"testInstallBase": testInstallBase,
+			"name":                   name,
+			"template":               template,
+			"extraConfigs":           extraConfigs,
+			"outputFileName":         outputFileName,
+			"testInstallBase":        testInstallBase,
+			"extraTestRunnerConfigs": extraTestRunnerConfigs,
 		},
 	})
 }
@@ -142,6 +153,7 @@
 	TestSuites              []string
 	Config                  []Config
 	OptionsForAutogenerated []Option
+	TestRunnerOptions       []Option
 	AutoGenConfig           *bool
 	UnitTest                *bool
 	TestInstallBase         string
@@ -155,6 +167,7 @@
 	for _, c := range options.OptionsForAutogenerated {
 		configs = append(configs, c)
 	}
+	testRunnerConfigs := append([]Option{}, options.TestRunnerOptions...)
 	name := options.Name
 	if name == "" {
 		name = ctx.ModuleName()
@@ -163,15 +176,15 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, options.TestConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, options.OutputFileName, options.TestInstallBase)
+			autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, options.OutputFileName, options.TestInstallBase)
+				autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
 			} else {
 				if Bool(options.UnitTest) {
-					autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, options.OutputFileName, options.TestInstallBase)
+					autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
 				} else {
-					autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, options.OutputFileName, options.TestInstallBase)
+					autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
 				}
 			}
 		}
diff --git a/ui/build/config.go b/ui/build/config.go
index bfbf85d..711774a 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -231,8 +231,9 @@
 
 func NewConfig(ctx Context, args ...string) Config {
 	ret := &configImpl{
-		environ:       OsEnvironment(),
-		sandboxConfig: &SandboxConfig{},
+		environ:               OsEnvironment(),
+		sandboxConfig:         &SandboxConfig{},
+		ninjaWeightListSource: NINJA_LOG,
 	}
 
 	// Default matching ninja
@@ -1641,6 +1642,16 @@
 	return c.Environment().IsEnvTrue("USE_PERSISTENT_BAZEL")
 }
 
+// GetBazeliskBazelVersion returns the Bazel version to use for this build,
+// or the empty string if the current canonical prod Bazel should be used.
+// This environment variable should only be set to debug the build system.
+// The Bazel version, if set, will be passed to Bazelisk, and Bazelisk will
+// handle downloading and invoking the correct Bazel binary.
+func (c *configImpl) GetBazeliskBazelVersion() string {
+	value, _ := c.Environment().Get("USE_BAZEL_VERSION")
+	return value
+}
+
 func (c *configImpl) BazelModulesForceEnabledByFlag() string {
 	return c.bazelForceEnabledModules
 }
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 5d56531..61aaad8 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -35,48 +35,6 @@
 	ninjaWeightListFileName = ".ninja_weight_list"
 )
 
-func useNinjaBuildLog(ctx Context, config Config, cmd *Cmd) {
-	ninjaLogFile := filepath.Join(config.OutDir(), ninjaLogFileName)
-	data, err := os.ReadFile(ninjaLogFile)
-	var outputBuilder strings.Builder
-	if err == nil {
-		lines := strings.Split(strings.TrimSpace(string(data)), "\n")
-		// ninja log: <start>	<end>	<restat>	<name>	<cmdhash>
-		// ninja weight list: <name>,<end-start+1>
-		for _, line := range lines {
-			if strings.HasPrefix(line, "#") {
-				continue
-			}
-			fields := strings.Split(line, "\t")
-			path := fields[3]
-			start, err := strconv.Atoi(fields[0])
-			if err != nil {
-				continue
-			}
-			end, err := strconv.Atoi(fields[1])
-			if err != nil {
-				continue
-			}
-			outputBuilder.WriteString(path)
-			outputBuilder.WriteString(",")
-			outputBuilder.WriteString(strconv.Itoa(end-start+1) + "\n")
-		}
-	} else {
-		// If there is no ninja log file, just pass empty ninja weight list.
-		// Because it is still efficient with critical path calculation logic even without weight.
-		ctx.Verbosef("There is an error during reading ninja log, so ninja will use empty weight list: %s", err)
-	}
-
-	weightListFile := filepath.Join(config.OutDir(), ninjaWeightListFileName)
-
-	err = os.WriteFile(weightListFile, []byte(outputBuilder.String()), 0644)
-	if err == nil {
-		cmd.Args = append(cmd.Args, "-o", "usesweightlist="+weightListFile)
-	} else {
-		ctx.Panicf("Could not write ninja weight list file %s", err)
-	}
-}
-
 // Constructs and runs the Ninja command line with a restricted set of
 // environment variables. It's important to restrict the environment Ninja runs
 // for hermeticity reasons, and to avoid spurious rebuilds.
@@ -131,7 +89,7 @@
 
 	switch config.NinjaWeightListSource() {
 	case NINJA_LOG:
-		useNinjaBuildLog(ctx, config, cmd)
+		cmd.Args = append(cmd.Args, "-o", "usesninjalogasweightlist=yes")
 	case EVENLY_DISTRIBUTED:
 		// pass empty weight list means ninja considers every tasks's weight as 1(default value).
 		cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 6de8d6f..986ec70 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -533,7 +533,7 @@
 		defer ctx.EndTrace()
 
 		if config.IsPersistentBazelEnabled() {
-			bazelProxy := bazel.NewProxyServer(ctx.Logger, config.OutDir(), filepath.Join(config.SoongOutDir(), "workspace"))
+			bazelProxy := bazel.NewProxyServer(ctx.Logger, config.OutDir(), filepath.Join(config.SoongOutDir(), "workspace"), config.GetBazeliskBazelVersion())
 			bazelProxy.Start()
 			defer bazelProxy.Close()
 		}