Merge "Increase ram usage estimate in multiproduct_kati"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 87554a2..fb56ee1 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -669,6 +669,10 @@
 		// kotlin srcs in java libs
 		"CtsPkgInstallerConstants",
 		"kotlinx_atomicfu",
+
+		// kotlin srcs in java binary
+		"AnalyzerKt",
+		"trebuchet-core",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -1318,8 +1322,6 @@
 		"libc_musl_sysroot",
 	}
 
-	Bp2buildCcLibraryStaticOnlyList = []string{}
-
 	MixedBuildsDisabledList = []string{
 		"libruy_static", "libtflite_kernel_utils", // TODO(b/237315968); Depend on prebuilt stl, not from source
 
diff --git a/android/bazel.go b/android/bazel.go
index 3731dfe..10e9251 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -66,8 +66,8 @@
 	//
 	// This is a bool pointer to support tristates: true, false, not set.
 	//
-	// To opt-in a module, set bazel_module: { bp2build_available: true }
-	// To opt-out a module, set bazel_module: { bp2build_available: false }
+	// To opt in a module, set bazel_module: { bp2build_available: true }
+	// To opt out a module, set bazel_module: { bp2build_available: false }
 	// To defer the default setting for the directory, do not set the value.
 	Bp2build_available *bool
 
@@ -126,7 +126,7 @@
 	// one with the single member called Soong_config_variables, which itself is
 	// a struct containing fields for each supported feature in that namespace.
 	//
-	// The reason for using an slice of interface{} is to support defaults
+	// The reason for using a slice of interface{} is to support defaults
 	// propagation of the struct pointers.
 	namespacedVariableProps() namespacedVariableProperties
 	setNamespacedVariableProps(props namespacedVariableProperties)
@@ -237,16 +237,6 @@
 
 	// Per-module denylist to always opt modules out of bp2build conversion.
 	moduleDoNotConvert map[string]bool
-
-	// Per-module denylist of cc_library modules to only generate the static
-	// variant if their shared variant isn't ready or buildable by Bazel.
-	ccLibraryStaticOnly map[string]bool
-}
-
-// GenerateCcLibraryStaticOnly returns whether a cc_library module should only
-// generate a static version of itself based on the current global configuration.
-func (a Bp2BuildConversionAllowlist) GenerateCcLibraryStaticOnly(moduleName string) bool {
-	return a.ccLibraryStaticOnly[moduleName]
 }
 
 // NewBp2BuildAllowlist creates a new, empty Bp2BuildConversionAllowlist
@@ -258,7 +248,6 @@
 		map[string]bool{},
 		map[string]bool{},
 		map[string]bool{},
-		map[string]bool{},
 	}
 }
 
@@ -322,18 +311,6 @@
 	return a
 }
 
-// SetCcLibraryStaticOnlyList copies the entries from ccLibraryStaticOnly into the allowlist
-func (a Bp2BuildConversionAllowlist) SetCcLibraryStaticOnlyList(ccLibraryStaticOnly []string) Bp2BuildConversionAllowlist {
-	if a.ccLibraryStaticOnly == nil {
-		a.ccLibraryStaticOnly = map[string]bool{}
-	}
-	for _, m := range ccLibraryStaticOnly {
-		a.ccLibraryStaticOnly[m] = true
-	}
-
-	return a
-}
-
 // ShouldKeepExistingBuildFileForDir returns whether an existing BUILD file should be
 // added to the build symlink forest based on the current global configuration.
 func (a Bp2BuildConversionAllowlist) ShouldKeepExistingBuildFileForDir(dir string) bool {
@@ -365,8 +342,7 @@
 			SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile).
 			SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList).
 			SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList).
-			SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList).
-			SetCcLibraryStaticOnlyList(allowlists.Bp2buildCcLibraryStaticOnlyList)
+			SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList)
 	}).(Bp2BuildConversionAllowlist)
 }
 
@@ -375,30 +351,16 @@
 // method will also log whether this module is mixed build enabled for
 // metrics reporting.
 func MixedBuildsEnabled(ctx BaseModuleContext) bool {
-	mixedBuildEnabled := mixedBuildPossible(ctx)
+	module := ctx.Module()
+	mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
+		ctx.Os() != Windows && // Windows toolchains are not currently supported.
+		module.Enabled() &&
+		convertedToBazel(ctx, module) &&
+		ctx.Config().BazelContext.IsModuleNameAllowed(module.Name())
 	ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
 	return mixedBuildEnabled
 }
 
-// mixedBuildPossible returns true if a module is ready to be replaced by a
-// converted or handcrafted Bazel target.
-func mixedBuildPossible(ctx BaseModuleContext) bool {
-	if !ctx.Config().IsMixedBuildsEnabled() {
-		return false
-	}
-	if ctx.Os() == Windows {
-		// Windows toolchains are not currently supported.
-		return false
-	}
-	if !ctx.Module().Enabled() {
-		return false
-	}
-	if !convertedToBazel(ctx, ctx.Module()) {
-		return false
-	}
-	return ctx.Config().BazelContext.BazelAllowlisted(ctx.Module().Name())
-}
-
 // ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
 func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool {
 	b, ok := module.(Bazelable)
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 40cc6a2..8d45041 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -152,7 +152,7 @@
 	// Note that this only implies "bazel mixed build" allowlisting. The caller
 	// should independently verify the module is eligible for Bazel handling
 	// (for example, that it is MixedBuildBuildable).
-	BazelAllowlisted(moduleName string) bool
+	IsModuleNameAllowed(moduleName string) bool
 
 	// Returns the bazel output base (the root directory for all bazel intermediate outputs).
 	OutputBase() string
@@ -181,7 +181,7 @@
 
 // A context object which tracks queued requests that need to be made to Bazel,
 // and their results after the requests have been made.
-type bazelContext struct {
+type mixedBuildBazelContext struct {
 	bazelRunner
 	paths        *bazelPaths
 	requests     map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
@@ -210,7 +210,7 @@
 	targetBuildVariant string
 }
 
-var _ BazelContext = &bazelContext{}
+var _ BazelContext = &mixedBuildBazelContext{}
 
 // A bazel context to use when Bazel is disabled.
 type noopBazelContext struct{}
@@ -261,7 +261,7 @@
 	panic("unimplemented")
 }
 
-func (m MockBazelContext) BazelAllowlisted(_ string) bool {
+func (m MockBazelContext) IsModuleNameAllowed(_ string) bool {
 	return true
 }
 
@@ -277,14 +277,14 @@
 
 var _ BazelContext = MockBazelContext{}
 
-func (bazelCtx *bazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
+func (bazelCtx *mixedBuildBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
 	key := makeCqueryKey(label, requestType, cfgKey)
 	bazelCtx.requestMutex.Lock()
 	defer bazelCtx.requestMutex.Unlock()
 	bazelCtx.requests[key] = true
 }
 
-func (bazelCtx *bazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
+func (bazelCtx *mixedBuildBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
 	key := makeCqueryKey(label, cquery.GetOutputFiles, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		bazelOutput := strings.TrimSpace(rawString)
@@ -294,7 +294,7 @@
 	return nil, fmt.Errorf("no bazel response found for %v", key)
 }
 
-func (bazelCtx *bazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
+func (bazelCtx *mixedBuildBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
 	key := makeCqueryKey(label, cquery.GetCcInfo, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		bazelOutput := strings.TrimSpace(rawString)
@@ -303,7 +303,7 @@
 	return cquery.CcInfo{}, fmt.Errorf("no bazel response found for %v", key)
 }
 
-func (bazelCtx *bazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
+func (bazelCtx *mixedBuildBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
 	key := makeCqueryKey(label, cquery.GetPythonBinary, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		bazelOutput := strings.TrimSpace(rawString)
@@ -312,7 +312,7 @@
 	return "", fmt.Errorf("no bazel response found for %v", key)
 }
 
-func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexInfo, error) {
+func (bazelCtx *mixedBuildBazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexInfo, error) {
 	key := makeCqueryKey(label, cquery.GetApexInfo, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString))
@@ -320,7 +320,7 @@
 	return cquery.ApexInfo{}, fmt.Errorf("no bazel response found for %v", key)
 }
 
-func (bazelCtx *bazelContext) GetCcUnstrippedInfo(label string, cfgKey configKey) (cquery.CcUnstrippedInfo, error) {
+func (bazelCtx *mixedBuildBazelContext) GetCcUnstrippedInfo(label string, cfgKey configKey) (cquery.CcUnstrippedInfo, error) {
 	key := makeCqueryKey(label, cquery.GetCcUnstrippedInfo, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		return cquery.GetCcUnstrippedInfo.ParseResult(strings.TrimSpace(rawString))
@@ -361,7 +361,7 @@
 	return ""
 }
 
-func (n noopBazelContext) BazelAllowlisted(_ string) bool {
+func (n noopBazelContext) IsModuleNameAllowed(_ string) bool {
 	return false
 }
 
@@ -396,12 +396,6 @@
 			enabledModules[enabledAdHocModule] = true
 		}
 	case BazelDevMode:
-		// Don't use partially-converted cc_library targets in mixed builds,
-		// since mixed builds would generally rely on both static and shared
-		// variants of a cc_library.
-		for staticOnlyModule := range GetBp2BuildAllowList().ccLibraryStaticOnly {
-			disabledModules[staticOnlyModule] = true
-		}
 		addToStringSet(disabledModules, allowlists.MixedBuildsDisabledList)
 	default:
 		panic("Expected BazelProdMode, BazelStagingMode, or BazelDevMode")
@@ -475,7 +469,7 @@
 		targetProduct = c.DeviceProduct()
 	}
 
-	return &bazelContext{
+	return &mixedBuildBazelContext{
 		bazelRunner:           &builtinBazelRunner{},
 		paths:                 &paths,
 		requests:              make(map[cqueryKey]bool),
@@ -491,7 +485,7 @@
 	return p.metricsDir
 }
 
-func (context *bazelContext) BazelAllowlisted(moduleName string) bool {
+func (context *mixedBuildBazelContext) IsModuleNameAllowed(moduleName string) bool {
 	if context.bazelDisabledModules[moduleName] {
 		return false
 	}
@@ -618,7 +612,7 @@
 
 }
 
-func (context *bazelContext) mainBzlFileContents() []byte {
+func (context *mixedBuildBazelContext) mainBzlFileContents() []byte {
 	// TODO(cparsons): Define configuration transitions programmatically based
 	// on available archs.
 	contents := `
@@ -687,7 +681,7 @@
 	return []byte(productReplacer.Replace(contents))
 }
 
-func (context *bazelContext) mainBuildFileContents() []byte {
+func (context *mixedBuildBazelContext) mainBuildFileContents() []byte {
 	// TODO(cparsons): Map label to attribute programmatically; don't use hard-coded
 	// architecture mapping.
 	formatString := `
@@ -751,10 +745,10 @@
 
 // Returns the file contents of the buildroot.cquery file that should be used for the cquery
 // expression in order to obtain information about buildroot and its dependencies.
-// The contents of this file depend on the bazelContext's requests; requests are enumerated
+// The contents of this file depend on the mixedBuildBazelContext's requests; requests are enumerated
 // and grouped by their request type. The data retrieved for each label depends on its
 // request type.
-func (context *bazelContext) cqueryStarlarkFileContents() []byte {
+func (context *mixedBuildBazelContext) cqueryStarlarkFileContents() []byte {
 	requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
 	for val := range context.requests {
 		cqueryId := getCqueryId(val)
@@ -912,7 +906,7 @@
 
 // Issues commands to Bazel to receive results for all cquery requests
 // queued in the BazelContext.
-func (context *bazelContext) InvokeBazel(config Config, ctx *Context) error {
+func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx *Context) error {
 	if ctx != nil {
 		ctx.EventHandler.Begin("bazel")
 		defer ctx.EventHandler.End("bazel")
@@ -939,7 +933,7 @@
 	return nil
 }
 
-func (context *bazelContext) runCquery(ctx *Context) error {
+func (context *mixedBuildBazelContext) runCquery(ctx *Context) error {
 	if ctx != nil {
 		ctx.EventHandler.Begin("cquery")
 		defer ctx.EventHandler.End("cquery")
@@ -994,7 +988,7 @@
 	return nil
 }
 
-func (context *bazelContext) runAquery(config Config, ctx *Context) error {
+func (context *mixedBuildBazelContext) runAquery(config Config, ctx *Context) error {
 	if ctx != nil {
 		ctx.EventHandler.Begin("aquery")
 		defer ctx.EventHandler.End("aquery")
@@ -1032,7 +1026,7 @@
 	return err
 }
 
-func (context *bazelContext) generateBazelSymlinks(ctx *Context) error {
+func (context *mixedBuildBazelContext) generateBazelSymlinks(ctx *Context) error {
 	if ctx != nil {
 		ctx.EventHandler.Begin("symlinks")
 		defer ctx.EventHandler.End("symlinks")
@@ -1044,15 +1038,15 @@
 	return err
 }
 
-func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+func (context *mixedBuildBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
 	return context.buildStatements
 }
 
-func (context *bazelContext) AqueryDepsets() []bazel.AqueryDepset {
+func (context *mixedBuildBazelContext) AqueryDepsets() []bazel.AqueryDepset {
 	return context.depsets
 }
 
-func (context *bazelContext) OutputBase() string {
+func (context *mixedBuildBazelContext) OutputBase() string {
 	return context.paths.outputBase
 }
 
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index 10bbf31..013e19c 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -189,7 +189,7 @@
 	return actual
 }
 
-func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
+func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
 	t.Helper()
 	p := bazelPaths{
 		soongOutDir:  t.TempDir(),
@@ -201,7 +201,7 @@
 		bazelCommandResults[aqueryCommand] = ""
 	}
 	runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
-	return &bazelContext{
+	return &mixedBuildBazelContext{
 		bazelRunner: runner,
 		paths:       &p,
 		requests:    map[cqueryKey]bool{},
diff --git a/android/bazel_test.go b/android/bazel_test.go
index 7b38b6a..87b2c8f 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -417,11 +417,6 @@
 			t.Errorf("bp2build module do not convert of %s: expected: true, got: %v", k, allowlist.moduleDoNotConvert[k])
 		}
 	}
-	for _, k := range allowlists.Bp2buildCcLibraryStaticOnlyList {
-		if !allowlist.ccLibraryStaticOnly[k] {
-			t.Errorf("bp2build cc library static only of %s: expected: true, got: %v", k, allowlist.ccLibraryStaticOnly[k])
-		}
-	}
 }
 
 func TestShouldKeepExistingBuildFileForDir(t *testing.T) {
diff --git a/android/config.go b/android/config.go
index d5ed883..a8b0a40 100644
--- a/android/config.go
+++ b/android/config.go
@@ -583,32 +583,28 @@
 	c.mockBpList = blueprint.MockModuleListFile
 }
 
+// TODO(b/265062549): Add a field to our collected (and uploaded) metrics which
+// describes a reason that we fell back to non-mixed builds.
 // Returns true if "Bazel builds" is enabled. In this mode, part of build
 // analysis is handled by Bazel.
 func (c *config) IsMixedBuildsEnabled() bool {
 	globalMixedBuildsSupport := c.Once(OnceKey{"globalMixedBuildsSupport"}, func() interface{} {
 		if c.productVariables.DeviceArch != nil && *c.productVariables.DeviceArch == "riscv64" {
-			fmt.Fprintln(os.Stderr, "unsupported device arch 'riscv64' for Bazel: falling back to non-mixed build")
 			return false
 		}
 		if c.IsEnvTrue("GLOBAL_THINLTO") {
-			fmt.Fprintln(os.Stderr, "unsupported env var GLOBAL_THINLTO for Bazel: falling back to non-mixed build")
 			return false
 		}
 		if len(c.productVariables.SanitizeHost) > 0 {
-			fmt.Fprintln(os.Stderr, "unsupported product var SanitizeHost for Bazel: falling back to non-mixed build")
 			return false
 		}
 		if len(c.productVariables.SanitizeDevice) > 0 {
-			fmt.Fprintln(os.Stderr, "unsupported product var SanitizeDevice for Bazel: falling back to non-mixed build")
 			return false
 		}
 		if len(c.productVariables.SanitizeDeviceDiag) > 0 {
-			fmt.Fprintln(os.Stderr, "unsupported product var SanitizeDeviceDiag for Bazel: falling back to non-mixed build")
 			return false
 		}
 		if len(c.productVariables.SanitizeDeviceArch) > 0 {
-			fmt.Fprintln(os.Stderr, "unsupported product var SanitizeDeviceArch for Bazel: falling back to non-mixed build")
 			return false
 		}
 		return true
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 5dc9612..86b9b27 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -45,17 +45,27 @@
 	bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
 	writeFiles(ctx, bp2buildDir, bp2buildFiles)
 
+	soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
+	writeFiles(ctx, soongInjectionDir, CreateSoongInjectionDirFiles(ctx, res.metrics))
+
+	return &res.metrics
+}
+
+// Wrapper function that will be responsible for all files in soong_injection directory
+// This includes
+// 1. config value(s) that are hardcoded in Soong
+// 2. product_config variables
+func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) []BazelFile {
+	var ret []BazelFile
+
 	productConfigFiles, err := CreateProductConfigFiles(ctx)
 	if err != nil {
 		fmt.Printf("ERROR: %s", err.Error())
 		os.Exit(1)
 	}
-
-	soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
-	writeFiles(ctx, soongInjectionDir, productConfigFiles)
-	writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(ctx.Config(), res.metrics))
-
-	return &res.metrics
+	ret = append(ret, productConfigFiles...)
+	ret = append(ret, soongInjectionFiles(ctx.Config(), metrics)...)
+	return ret
 }
 
 // Get the output directory and create it if it doesn't exist.
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index e15dd59..e53f29e 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -20,7 +20,8 @@
 	Contents string
 }
 
-func CreateSoongInjectionFiles(cfg android.Config, metrics CodegenMetrics) []BazelFile {
+// PRIVATE: Use CreateSoongInjectionDirFiles instead
+func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) []BazelFile {
 	var files []BazelFile
 
 	files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index dfc7f0b..43daddc 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -84,7 +84,7 @@
 
 func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
 	testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
-	files := CreateSoongInjectionFiles(testConfig, CreateCodegenMetrics())
+	files := soongInjectionFiles(testConfig, CreateCodegenMetrics())
 
 	expectedFilePaths := []bazelFilepath{
 		{
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index e8551e5..46105c7 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -134,3 +134,153 @@
 		},
 	})
 }
+
+func TestJavaBinaryHostKotlinSrcs(t *testing.T) {
+	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_binary_host with srcs, libs.",
+		Filesystem:  testFs,
+		Blueprint: `java_binary_host {
+    name: "java-binary-host",
+    manifest: "test.mf",
+    srcs: ["a.java", "b.kt"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+				"srcs": `[
+        "a.java",
+        "b.kt",
+    ]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
+				"main_class":   `"com.android.test.MainClass"`,
+				"runtime_deps": `[":java-binary-host_kt"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestJavaBinaryHostKotlinCommonSrcs(t *testing.T) {
+	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_binary_host with common_srcs",
+		Filesystem:  testFs,
+		Blueprint: `java_binary_host {
+    name: "java-binary-host",
+    manifest: "test.mf",
+    srcs: ["a.java"],
+    common_srcs: ["b.kt"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+				"srcs":        `["a.java"]`,
+				"common_srcs": `["b.kt"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
+				"main_class":   `"com.android.test.MainClass"`,
+				"runtime_deps": `[":java-binary-host_kt"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestJavaBinaryHostKotlinWithResourceDir(t *testing.T) {
+	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_binary_host with srcs, libs, resource dir  .",
+		Filesystem: map[string]string{
+			"test.mf":        "Main-Class: com.android.test.MainClass",
+			"res/a.res":      "",
+			"res/dir1/b.res": "",
+		},
+		Blueprint: `java_binary_host {
+    name: "java-binary-host",
+    manifest: "test.mf",
+    srcs: ["a.java", "b.kt"],
+    java_resource_dirs: ["res"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+				"srcs": `[
+        "a.java",
+        "b.kt",
+    ]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
+				"main_class":   `"com.android.test.MainClass"`,
+				"runtime_deps": `[":java-binary-host_kt"]`,
+				"resources": `[
+        "res/a.res",
+        "res/dir1/b.res",
+    ]`,
+				"resource_strip_prefix": `"res"`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestJavaBinaryHostKotlinWithResources(t *testing.T) {
+	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_binary_host with srcs, libs, resources.",
+		Filesystem: map[string]string{
+			"test.mf":   "Main-Class: com.android.test.MainClass",
+			"res/a.res": "",
+			"res/b.res": "",
+		},
+		Blueprint: `java_binary_host {
+    name: "java-binary-host",
+    manifest: "test.mf",
+    srcs: ["a.java", "b.kt"],
+    java_resources: ["res/a.res", "res/b.res"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+				"srcs": `[
+        "a.java",
+        "b.kt",
+    ]`,
+				"resources": `[
+        "res/a.res",
+        "res/b.res",
+    ]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
+				"main_class":   `"com.android.test.MainClass"`,
+				"runtime_deps": `[":java-binary-host_kt"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index d331d89..6f97260 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -91,12 +91,12 @@
 	}
 	archVariantProps := m.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
 	for axis, configToProps := range archVariantProps {
-		for config, _props := range configToProps {
+		for cfg, _props := range configToProps {
 			if archProps, ok := _props.(*BaseCompilerProperties); ok {
 				archDisabledSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_disabled_srcs)
-				moduleAttrs.Tidy_disabled_srcs.SetSelectValue(axis, config, archDisabledSrcs)
+				moduleAttrs.Tidy_disabled_srcs.SetSelectValue(axis, cfg, archDisabledSrcs)
 				archTimeoutSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_timeout_srcs)
-				moduleAttrs.Tidy_timeout_srcs.SetSelectValue(axis, config, archTimeoutSrcs)
+				moduleAttrs.Tidy_timeout_srcs.SetSelectValue(axis, cfg, archTimeoutSrcs)
 			}
 		}
 	}
@@ -205,14 +205,14 @@
 
 func bp2BuildPropParseHelper(ctx android.ArchVariantContext, module *Module, propsType interface{}, parseFunc func(axis bazel.ConfigurationAxis, config string, props interface{})) {
 	for axis, configToProps := range module.GetArchVariantProperties(ctx, propsType) {
-		for config, props := range configToProps {
-			parseFunc(axis, config, props)
+		for cfg, props := range configToProps {
+			parseFunc(axis, cfg, props)
 		}
 	}
 }
 
 // Parses properties common to static and shared libraries. Also used for prebuilt libraries.
-func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
+func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, _ *libraryDecorator, isStatic bool) staticOrSharedAttributes {
 	attrs := staticOrSharedAttributes{}
 
 	setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
@@ -669,8 +669,8 @@
 
 	ret := &bazel.LabelAttribute{}
 	for _, axis := range ca.asmSrcs.SortedConfigurationAxes() {
-		for config := range ca.asmSrcs.ConfigurableValues[axis] {
-			ret.SetSelectValue(axis, config, bazel.Label{Label: ":" + m.Name() + "_yasm"})
+		for cfg := range ca.asmSrcs.ConfigurableValues[axis] {
+			ret.SetSelectValue(axis, cfg, bazel.Label{Label: ":" + m.Name() + "_yasm"})
 		}
 	}
 	return ret
@@ -690,8 +690,8 @@
 			if _, ok := axisToConfigs[axis]; !ok {
 				axisToConfigs[axis] = map[string]bool{}
 			}
-			for config, _ := range configMap {
-				axisToConfigs[axis][config] = true
+			for cfg := range configMap {
+				axisToConfigs[axis][cfg] = true
 			}
 		}
 	}
@@ -703,49 +703,49 @@
 	linkerAttrs := linkerAttributes{}
 
 	for axis, configs := range axisToConfigs {
-		for config, _ := range configs {
+		for cfg := range configs {
 			var allHdrs []string
-			if baseCompilerProps, ok := archVariantCompilerProps[axis][config].(*BaseCompilerProperties); ok {
+			if baseCompilerProps, ok := archVariantCompilerProps[axis][cfg].(*BaseCompilerProperties); ok {
 				allHdrs = baseCompilerProps.Generated_headers
 				if baseCompilerProps.Lex != nil {
-					compilerAttrs.lexopts.SetSelectValue(axis, config, baseCompilerProps.Lex.Flags)
+					compilerAttrs.lexopts.SetSelectValue(axis, cfg, baseCompilerProps.Lex.Flags)
 				}
-				(&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, config, baseCompilerProps)
+				(&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, cfg, baseCompilerProps)
 			}
 
 			var exportHdrs []string
 
-			if baseLinkerProps, ok := archVariantLinkerProps[axis][config].(*BaseLinkerProperties); ok {
+			if baseLinkerProps, ok := archVariantLinkerProps[axis][cfg].(*BaseLinkerProperties); ok {
 				exportHdrs = baseLinkerProps.Export_generated_headers
 
-				(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module.Binary(), axis, config, baseLinkerProps)
+				(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module.Binary(), axis, cfg, baseLinkerProps)
 			}
 			headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps)
-			implementationHdrs.SetSelectValue(axis, config, headers.implementation)
-			compilerAttrs.hdrs.SetSelectValue(axis, config, headers.export)
+			implementationHdrs.SetSelectValue(axis, cfg, headers.implementation)
+			compilerAttrs.hdrs.SetSelectValue(axis, cfg, headers.export)
 
 			exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export)
-			compilerAttrs.includes.Includes.SetSelectValue(axis, config, exportIncludes)
-			compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, config, exportAbsoluteIncludes)
+			compilerAttrs.includes.Includes.SetSelectValue(axis, cfg, exportIncludes)
+			compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, cfg, exportAbsoluteIncludes)
 
 			includes, absoluteIncludes := includesFromLabelList(headers.implementation)
-			currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, config)
+			currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, cfg)
 			currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...))
 
-			compilerAttrs.absoluteIncludes.SetSelectValue(axis, config, currAbsoluteIncludes)
+			compilerAttrs.absoluteIncludes.SetSelectValue(axis, cfg, currAbsoluteIncludes)
 
-			currIncludes := compilerAttrs.localIncludes.SelectValue(axis, config)
+			currIncludes := compilerAttrs.localIncludes.SelectValue(axis, cfg)
 			currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...))
 
-			compilerAttrs.localIncludes.SetSelectValue(axis, config, currIncludes)
+			compilerAttrs.localIncludes.SetSelectValue(axis, cfg, currIncludes)
 
-			if libraryProps, ok := archVariantLibraryProperties[axis][config].(*LibraryProperties); ok {
+			if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok {
 				if axis == bazel.NoConfigAxis {
 					compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
-					compilerAttrs.stubsVersions.SetSelectValue(axis, config, libraryProps.Stubs.Versions)
+					compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, libraryProps.Stubs.Versions)
 				}
 				if suffix := libraryProps.Suffix; suffix != nil {
-					compilerAttrs.suffix.SetSelectValue(axis, config, suffix)
+					compilerAttrs.suffix.SetSelectValue(axis, cfg, suffix)
 				}
 			}
 		}
@@ -1213,7 +1213,7 @@
 	for name, dep := range productVarToDepFields {
 		props, exists := productVariableProps[name]
 		excludeProps, excludesExists := productVariableProps[dep.excludesField]
-		// if neither an include or excludes property exists, then skip it
+		// if neither an include nor excludes property exists, then skip it
 		if !exists && !excludesExists {
 			continue
 		}
@@ -1352,7 +1352,7 @@
 
 func bazelLabelForStaticModule(ctx android.BazelConversionPathContext, m blueprint.Module) string {
 	label := android.BazelModuleLabel(ctx, m)
-	if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary && !android.GetBp2BuildAllowList().GenerateCcLibraryStaticOnly(m.Name()) {
+	if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary {
 		return BazelLabelNameForStaticModule(label)
 	}
 	return label
diff --git a/cc/library.go b/cc/library.go
index 787de44..8fd0019 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -292,14 +292,6 @@
 }
 
 func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
-	// For some cc_library modules, their static variants are ready to be
-	// converted, but not their shared variants. For these modules, delegate to
-	// the cc_library_static bp2build converter temporarily instead.
-	if android.GetBp2BuildAllowList().GenerateCcLibraryStaticOnly(ctx.Module().Name()) {
-		sharedOrStaticLibraryBp2Build(ctx, m, true)
-		return
-	}
-
 	sharedAttrs := bp2BuildParseSharedProps(ctx, m)
 	staticAttrs := bp2BuildParseStaticProps(ctx, m)
 	baseAttributes := bp2BuildParseBaseProps(ctx, m)
@@ -413,12 +405,12 @@
 	sharedTargetAttrs.Suffix = compilerAttrs.suffix
 
 	for axis, configToProps := range m.GetArchVariantProperties(ctx, &LibraryProperties{}) {
-		for config, props := range configToProps {
+		for cfg, props := range configToProps {
 			if props, ok := props.(*LibraryProperties); ok {
 				if props.Inject_bssl_hash != nil {
 					// This is an edge case applies only to libcrypto
 					if m.Name() == "libcrypto" || m.Name() == "libcrypto_for_testing" {
-						sharedTargetAttrs.Inject_bssl_hash.SetSelectValue(axis, config, props.Inject_bssl_hash)
+						sharedTargetAttrs.Inject_bssl_hash.SetSelectValue(axis, cfg, props.Inject_bssl_hash)
 					} else {
 						ctx.PropertyErrorf("inject_bssl_hash", "only applies to libcrypto")
 					}
@@ -1034,7 +1026,7 @@
 	return ret
 }
 
-func GlobGeneratedHeadersForSnapshot(ctx android.ModuleContext, paths android.Paths) android.Paths {
+func GlobGeneratedHeadersForSnapshot(_ android.ModuleContext, paths android.Paths) android.Paths {
 	ret := android.Paths{}
 	for _, header := range paths {
 		// TODO(b/148123511): remove exportedDeps after cleaning up genrule
@@ -1900,7 +1892,7 @@
 	errorMessage := "error: Please follow https://android.googlesource.com/platform/development/+/master/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the ABI difference between your source code and version " + prevVersion + "."
 
 	library.sourceAbiDiff(ctx, referenceDump, baseName, prevVersion,
-		isLlndkOrNdk, /* allowExtensions */ true, sourceVersion, errorMessage)
+		isLlndkOrNdk, true /* allowExtensions */, sourceVersion, errorMessage)
 }
 
 func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
@@ -1909,7 +1901,7 @@
 	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
 	errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName
 
-	library.sourceAbiDiff(ctx, referenceDump, baseName, /* nameExt */ "",
+	library.sourceAbiDiff(ctx, referenceDump, baseName, "",
 		isLlndkOrNdk, allowExtensions, "current", errorMessage)
 }
 
@@ -1920,7 +1912,7 @@
 	errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName + " -ref-dump-dir $$ANDROID_BUILD_TOP/" + refDumpDir
 
 	library.sourceAbiDiff(ctx, referenceDump, baseName, nameExt,
-		isLlndkOrNdk, /* allowExtensions */ false, "current", errorMessage)
+		isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage)
 }
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index baa7380..803ab0d 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -145,8 +145,10 @@
 func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string {
 	ctx.EventHandler.Begin("api_bp2build")
 	defer ctx.EventHandler.End("api_bp2build")
-	// Do not allow missing dependencies.
-	ctx.SetAllowMissingDependencies(false)
+	// api_bp2build does not run the typical pipeline of soong mutators.
+	// Hoevever, it still runs the defaults mutator which can create dependencies.
+	// These dependencies might not always exist (e.g. in tests)
+	ctx.SetAllowMissingDependencies(ctx.Config().AllowMissingDependencies())
 	ctx.RegisterForApiBazelConversion()
 
 	// Register the Android.bp files in the tree
@@ -176,7 +178,7 @@
 	ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
 
 	// Create soong_injection repository
-	soongInjectionFiles := bp2build.CreateSoongInjectionFiles(ctx.Config(), bp2build.CreateCodegenMetrics())
+	soongInjectionFiles := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics())
 	absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName)
 	for _, file := range soongInjectionFiles {
 		// The API targets in api_bp2build workspace do not have any dependency on api_bp2build.
diff --git a/go.mod b/go.mod
index 7239f6d..a5d9dd5 100644
--- a/go.mod
+++ b/go.mod
@@ -1,21 +1,9 @@
 module android/soong
 
+go 1.19
+
 require (
-  google.golang.org/protobuf v0.0.0
-  github.com/google/blueprint v0.0.0
-  prebuilts/bazel/common/proto/analysis_v2 v0.0.0
-  prebuilts/bazel/common/proto/build v0.0.0 // indirect
+	github.com/google/blueprint v0.0.0
+	google.golang.org/protobuf v0.0.0
+	prebuilts/bazel/common/proto/analysis_v2 v0.0.0
 )
-
-replace (
-  google.golang.org/protobuf v0.0.0 => ../../external/golang-protobuf
-  github.com/google/blueprint v0.0.0 => ../blueprint
-  github.com/google/go-cmp v0.5.5 => ../../external/go-cmp
-  prebuilts/bazel/common/proto/analysis_v2 => ../../prebuilts/bazel/common/proto/analysis_v2
-  prebuilts/bazel/common/proto/build => ../../prebuilts/bazel/common/proto/build
-)
-
-// Indirect deps from golang-protobuf
-exclude github.com/golang/protobuf v1.5.0
-
-go 2.0
diff --git a/go.work b/go.work
new file mode 100644
index 0000000..737a9df
--- /dev/null
+++ b/go.work
@@ -0,0 +1,19 @@
+go 1.19
+
+use (
+	.
+	../../external/go-cmp
+	../../external/golang-protobuf
+	../../prebuilts/bazel/common/proto/analysis_v2
+	../../prebuilts/bazel/common/proto/build
+	../blueprint
+)
+
+replace (
+	github.com/golang/protobuf v0.0.0 => ../../external/golang-protobuf
+	github.com/google/blueprint v0.0.0 => ../blueprint
+	github.com/google/go-cmp v0.0.0 => ../../external/go-cmp
+	google.golang.org/protobuf v0.0.0 => ../../external/golang-protobuf
+	prebuilts/bazel/common/proto/analysis_v2 v0.0.0 => ../../prebuilts/bazel/common/proto/analysis_v2
+	prebuilts/bazel/common/proto/build v0.0.0 => ../../prebuilts/bazel/common/proto/build
+)
diff --git a/java/app.go b/java/app.go
index 3c5760b..845f850 100755
--- a/java/app.go
+++ b/java/app.go
@@ -801,6 +801,8 @@
 						unstrippedFile: dep.UnstrippedOutputFile(),
 						partition:      dep.Partition(),
 					})
+				} else if ctx.Config().AllowMissingDependencies() {
+					ctx.AddMissingDependencies([]string{otherName})
 				} else {
 					ctx.ModuleErrorf("dependency %q missing output file", otherName)
 				}
diff --git a/java/app_test.go b/java/app_test.go
index cd88864..3fb67c1 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3163,6 +3163,7 @@
 				variables.Platform_sdk_version = &platform_sdk_version
 				variables.Platform_sdk_codename = &platform_sdk_codename
 				variables.Platform_version_active_codenames = []string{platform_sdk_codename}
+				variables.Unbundled_build = proptools.BoolPtr(true)
 				variables.Unbundled_build_apps = []string{"sampleModule"}
 			}),
 		)
@@ -3241,6 +3242,7 @@
 				variables.Platform_sdk_final = &testCase.platform_sdk_final
 				variables.Platform_sdk_version = &platform_sdk_version
 				variables.Platform_sdk_codename = &platform_sdk_codename
+				variables.Unbundled_build = proptools.BoolPtr(true)
 				variables.Unbundled_build_apps = []string{"sampleModule"}
 			}),
 		)
@@ -3311,6 +3313,7 @@
 				variables.Platform_sdk_final = &testCase.platform_sdk_final
 				variables.Platform_sdk_version = &platform_sdk_version
 				variables.Platform_sdk_codename = &platform_sdk_codename
+				variables.Unbundled_build = proptools.BoolPtr(true)
 				variables.Unbundled_build_apps = []string{"sampleModule"}
 			}),
 		)
diff --git a/java/java.go b/java/java.go
index 3b0ad8d..5c44523 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2526,9 +2526,10 @@
 
 type javaCommonAttributes struct {
 	*javaResourcesAttributes
-	Srcs      bazel.LabelListAttribute
-	Plugins   bazel.LabelListAttribute
-	Javacopts bazel.StringListAttribute
+	Srcs        bazel.LabelListAttribute
+	Plugins     bazel.LabelListAttribute
+	Javacopts   bazel.StringListAttribute
+	Common_srcs bazel.LabelListAttribute
 }
 
 type javaDependencyLabels struct {
@@ -2714,10 +2715,9 @@
 
 type javaLibraryAttributes struct {
 	*javaCommonAttributes
-	Deps        bazel.LabelListAttribute
-	Exports     bazel.LabelListAttribute
-	Neverlink   bazel.BoolAttribute
-	Common_srcs bazel.LabelListAttribute
+	Deps      bazel.LabelListAttribute
+	Exports   bazel.LabelListAttribute
+	Neverlink bazel.BoolAttribute
 }
 
 func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
@@ -2751,7 +2751,7 @@
 			Bzl_load_location: "//build/bazel/rules/java:library.bzl",
 		}
 	} else {
-		attrs.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Common_srcs))
+		attrs.javaCommonAttributes.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Common_srcs))
 
 		props = bazel.BazelTargetModuleProperties{
 			Rule_class:        "kt_jvm_library",
@@ -2807,14 +2807,8 @@
 		mainClass = mainClassInManifest
 	}
 
-	attrs := &javaBinaryHostAttributes{
-		javaCommonAttributes: commonAttrs,
-		Deps:                 deps,
-		Runtime_deps:         runtimeDeps,
-		Main_class:           mainClass,
-	}
-
 	// Attribute jvm_flags
+	var jvmFlags bazel.StringListAttribute
 	if m.binaryProperties.Jni_libs != nil {
 		jniLibPackages := map[string]bool{}
 		for _, jniLibLabel := range android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs).Includes {
@@ -2837,12 +2831,56 @@
 			// See cs/f:.*/third_party/bazel/.*java_stub_template.txt for the use of RUNPATH
 			jniLibPaths = append(jniLibPaths, "$${RUNPATH}"+jniLibPackage)
 		}
-		attrs.Jvm_flags = bazel.MakeStringListAttribute([]string{"-Djava.library.path=" + strings.Join(jniLibPaths, ":")})
+		jvmFlags = bazel.MakeStringListAttribute([]string{"-Djava.library.path=" + strings.Join(jniLibPaths, ":")})
 	}
 
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class: "java_binary",
 	}
+	attrs := &javaBinaryHostAttributes{
+		Runtime_deps: runtimeDeps,
+		Main_class:   mainClass,
+		Jvm_flags:    jvmFlags,
+	}
+
+	if !bp2BuildInfo.hasKotlinSrcs && len(m.properties.Common_srcs) == 0 {
+		attrs.javaCommonAttributes = commonAttrs
+		attrs.Deps = deps
+	} else {
+		ktName := m.Name() + "_kt"
+		ktProps := bazel.BazelTargetModuleProperties{
+			Rule_class:        "kt_jvm_library",
+			Bzl_load_location: "@rules_kotlin//kotlin:jvm_library.bzl",
+		}
+		ktAttrs := &javaLibraryAttributes{
+			Deps: deps,
+			javaCommonAttributes: &javaCommonAttributes{
+				Srcs:      commonAttrs.Srcs,
+				Plugins:   commonAttrs.Plugins,
+				Javacopts: commonAttrs.Javacopts,
+			},
+		}
+
+		if len(m.properties.Common_srcs) != 0 {
+			ktAttrs.javaCommonAttributes.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Common_srcs))
+		}
+
+		// kt_jvm_library does not support resource_strip_prefix, if this attribute
+		// is set, than javaResourcesAttributes needs to be set in the
+		// javaCommonAttributes of the java_binary target
+		if commonAttrs.javaResourcesAttributes != nil {
+			if commonAttrs.javaResourcesAttributes.Resource_strip_prefix != nil {
+				attrs.javaCommonAttributes = &javaCommonAttributes{
+					javaResourcesAttributes: commonAttrs.javaResourcesAttributes,
+				}
+			} else {
+				ktAttrs.javaCommonAttributes.javaResourcesAttributes = commonAttrs.javaResourcesAttributes
+			}
+		}
+
+		ctx.CreateBazelTargetModule(ktProps, android.CommonAttributes{Name: ktName}, ktAttrs)
+		attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + ktName}})
+	}
 
 	// Create the BazelTargetModule.
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index e46efe4..3d7c0fa 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -27,13 +27,15 @@
 
 
 def Proto(args):
-    json_content = ''
-    with open(args.source) as f:
-        for line in f:
-            if not line.lstrip().startswith('//'):
-                json_content += line
-    obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
-    pb = ParseDict(obj, linker_config_pb2.LinkerConfig())
+    pb = linker_config_pb2.LinkerConfig()
+    for input in args.source.split(':'):
+        json_content = ''
+        with open(input) as f:
+            for line in f:
+                if not line.lstrip().startswith('//'):
+                    json_content += line
+        obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
+        ParseDict(obj, pb)
     with open(args.output, 'wb') as f:
         f.write(pb.SerializeToString())
 
@@ -104,7 +106,7 @@
         '--source',
         required=True,
         type=str,
-        help='Source linker configuration file in JSON.')
+        help='Colon-separated list of linker configuration files in JSON.')
     parser_proto.add_argument(
         '-o',
         '--output',
diff --git a/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
index 412f84a..5007078 100755
--- a/tests/apex_comparison_tests.sh
+++ b/tests/apex_comparison_tests.sh
@@ -74,7 +74,7 @@
 # # Build debugfs separately, as it's not a dep of apexer, but needs to be an explicit arg.
 call_bazel build --config=bp2build --config=linux_x86_64 //external/e2fsprogs/debugfs //system/apex/tools:deapexer
 DEBUGFS_PATH="$(realpath $(call_bazel cquery --config=bp2build --config=linux_x86_64 --config=ci --output=files //external/e2fsprogs/debugfs))"
-DEAPEXER="$(realpath $(call_bazel cquery --config=bp2build --config=linux_x86_64 --config=ci --output=files //system/apex/tools:deapexer))"
+DEAPEXER="bazel-bin/system/apex/tools/deapexer"
 DEAPEXER="$DEAPEXER --debugfs_path=$DEBUGFS_PATH"
 
 #######
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 8c2ce48..6477dac 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -231,4 +231,11 @@
   fi
 }
 
+# Smoke test to verify api_bp2build worksapce does not contain any errors
+function test_api_bp2build_empty_build() {
+  setup
+  run_soong api_bp2build
+  run_bazel build --config=android --config=api_bp2build //:empty
+}
+
 scan_and_run_tests