Merge "Revert "Re-land test tzdata apex with bazel builds.""
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index d7bcc81..1ece9fa 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -132,6 +132,7 @@
 		"external/f2fs-tools":                    Bp2BuildDefaultTrue,
 		"external/flac":                          Bp2BuildDefaultTrueRecursively,
 		"external/fmtlib":                        Bp2BuildDefaultTrueRecursively,
+		"external/guava":                         Bp2BuildDefaultTrueRecursively,
 		"external/google-benchmark":              Bp2BuildDefaultTrueRecursively,
 		"external/googletest":                    Bp2BuildDefaultTrueRecursively,
 		"external/gwp_asan":                      Bp2BuildDefaultTrueRecursively,
@@ -397,7 +398,6 @@
 		"external/bazelbuild-rules_license":/* recursive = */ true,
 		"external/bazelbuild-kotlin-rules":/* recursive = */ true,
 		"external/bazel-skylib":/* recursive = */ true,
-		"external/guava":/* recursive = */ true,
 		"external/protobuf":/* recursive = */ false,
 		"external/python/absl-py":/* recursive = */ true,
 
@@ -711,6 +711,8 @@
 
 		// allowlisting for kotlinx_coroutines
 		"kotlinx_coroutines",
+		"kotlinx_coroutines-device",
+		"kotlinx_coroutines-host",
 		"annotations",
 		"kotlinx-coroutines-android-annotation-stubs",
 
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 1f01dc6..0ae8073 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -86,7 +86,7 @@
 
 // JavaLibraryName returns the soong module containing the Java APIs of that API surface.
 func (k SdkKind) JavaLibraryName(c Config) string {
-	name := k.defaultJavaLibraryName()
+	name := k.DefaultJavaLibraryName()
 	return JavaApiLibraryName(c, name)
 }
 
@@ -100,7 +100,7 @@
 	return name
 }
 
-func (k SdkKind) defaultJavaLibraryName() string {
+func (k SdkKind) DefaultJavaLibraryName() string {
 	switch k {
 	case SdkPublic:
 		return "android_stubs_current"
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 05c888a..8a02a4a 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7101,7 +7101,7 @@
 			native_shared_libs: ["mylib"],
 			java_libs: ["myjar"],
 			updatable: true,
-			min_sdk_version: "current",
+			min_sdk_version: "33",
 		}
 
 		apex_key {
@@ -7124,7 +7124,7 @@
 				"myapex.updatable",
 				"//apex_available:platform",
 			],
-			min_sdk_version: "current",
+			min_sdk_version: "33",
 		}
 
 		cc_library {
@@ -7137,7 +7137,7 @@
 				"myapex.updatable",
 				"//apex_available:platform",
 			],
-			min_sdk_version: "current",
+			min_sdk_version: "33",
 		}
 
 		cc_library {
@@ -7151,7 +7151,7 @@
 				"myapex.updatable",
 				"//apex_available:platform",
 			],
-			min_sdk_version: "current",
+			min_sdk_version: "33",
 		}
 
 		java_library {
@@ -7165,7 +7165,7 @@
 				"myapex.updatable",
 				"//apex_available:platform",
 			],
-			min_sdk_version: "current",
+			min_sdk_version: "33",
 		}
 
 		java_library {
@@ -7178,7 +7178,7 @@
 				"myapex.updatable",
 				"//apex_available:platform",
 			],
-			min_sdk_version: "current",
+			min_sdk_version: "33",
 		}
 	`
 
diff --git a/apex/builder.go b/apex/builder.go
index e3b6f8e..94aef49 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -71,6 +71,9 @@
 	pctx.HostBinToolVariable("make_erofs", "make_erofs")
 	pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool")
 	pctx.HostBinToolVariable("dexdeps", "dexdeps")
+	pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests")
+	pctx.HostBinToolVariable("deapexer", "deapexer")
+	pctx.HostBinToolVariable("debugfs_static", "debugfs_static")
 	pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
 }
 
@@ -226,7 +229,12 @@
 		Description: "Generate symbol list used by Apex",
 	}, "image_dir", "readelf")
 
-	// Don't add more rules here. Consider using android.NewRuleBuilder instead.
+	apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
+		Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
+			`&& ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
+		CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
+		Description: "run apex_sepolicy_tests",
+	})
 )
 
 // buildManifest creates buile rules to modify the input apex_manifest.json to add information
@@ -872,6 +880,10 @@
 		args["implicits"] = strings.Join(implicits.Strings(), ",")
 		args["outCommaList"] = signedOutputFile.String()
 	}
+	var validations android.Paths
+	if suffix == imageApexSuffix {
+		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "signapk",
@@ -879,6 +891,7 @@
 		Input:       unsignedOutputFile,
 		Implicits:   implicits,
 		Args:        args,
+		Validations: validations,
 	})
 	if suffix == imageApexSuffix {
 		a.outputApexFile = signedOutputFile
@@ -1172,3 +1185,17 @@
 
 	return cannedFsConfig.OutputPath
 }
+
+// Runs apex_sepolicy_tests
+//
+// $ deapexer list -Z {apex_file} > {file_contexts}
+// $ apex_sepolicy_tests -f {file_contexts}
+func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.OutputPath) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "sepolicy_tests.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexSepolicyTestsRule,
+		Input:  apexFile,
+		Output: timestamp,
+	})
+	return timestamp
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 6edd78a..598ca32 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -61,6 +61,7 @@
         "genrule_conversion_test.go",
         "gensrcs_conversion_test.go",
         "java_binary_host_conversion_test.go",
+        "java_host_for_device_conversion_test.go",
         "java_import_conversion_test.go",
         "java_library_conversion_test.go",
         "java_library_host_conversion_test.go",
diff --git a/bp2build/java_host_for_device_conversion_test.go b/bp2build/java_host_for_device_conversion_test.go
new file mode 100644
index 0000000..d908d00
--- /dev/null
+++ b/bp2build/java_host_for_device_conversion_test.go
@@ -0,0 +1,63 @@
+// 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 runJavaHostForDeviceTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "java_host_for_device"
+	(&tc).ModuleTypeUnderTestFactory = java.HostForDeviceFactory
+	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
+}
+
+func runJavaHostForDeviceTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	runJavaHostForDeviceTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("java_library", java.LibraryFactory)
+	})
+}
+
+func TestJavaHostForDevice(t *testing.T) {
+	runJavaHostForDeviceTestCase(t, Bp2buildTestCase{
+		Description: "java_host_for_device test",
+		Blueprint: `java_host_for_device {
+    name: "java-lib-1",
+    libs: ["java-lib-2"],
+    bazel_module: { bp2build_available: true },
+}
+
+java_library {
+    name: "java-lib-2",
+    srcs: ["b.java"],
+    bazel_module: { bp2build_available: true },
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_host_for_device", "java-lib-1", AttrNameToString{
+				"deps": `[":java-lib-2"]`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+			MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{
+				"srcs": `["b.java"]`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
+		},
+	})
+}
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 69d0db9..683ee27 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -740,7 +740,7 @@
 	})
 }
 
-func TestJavaLibraryArchVariantLibs(t *testing.T) {
+func TestJavaLibraryArchVariantDeps(t *testing.T) {
 	runJavaLibraryTestCase(t, Bp2buildTestCase{
 		Description: "java_library with arch variant libs",
 		Blueprint: `java_library {
@@ -750,6 +750,7 @@
     target: {
         android: {
             libs: ["java-lib-3"],
+            static_libs: ["java-lib-4"],
         },
     },
     bazel_module: { bp2build_available: true },
@@ -762,12 +763,23 @@
 	java_library{
 		name: "java-lib-3",
 }
+
+	java_library{
+		name: "java-lib-4",
+}
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"srcs": `["a.java"]`,
+				"exports": `select({
+        "//build/bazel/platforms/os:android": [":java-lib-4"],
+        "//conditions:default": [],
+    })`,
 				"deps": `[":java-lib-2-neverlink"] + select({
-        "//build/bazel/platforms/os:android": [":java-lib-3-neverlink"],
+        "//build/bazel/platforms/os:android": [
+            ":java-lib-3-neverlink",
+            ":java-lib-4",
+        ],
         "//conditions:default": [],
     })`,
 			}),
@@ -776,6 +788,8 @@
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
 			MakeBazelTarget("java_library", "java-lib-3", AttrNameToString{}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-3"),
+			MakeBazelTarget("java_library", "java-lib-4", AttrNameToString{}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-4"),
 		},
 	})
 }
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index aac5e7d..5c33308 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -21,10 +21,13 @@
 	"path/filepath"
 	"regexp"
 	"sort"
+	"strconv"
+	"strings"
 	"sync"
 	"sync/atomic"
 
 	"android/soong/shared"
+
 	"github.com/google/blueprint/pathtools"
 )
 
@@ -35,6 +38,13 @@
 // excluded from symlinking. Otherwise, the node is not excluded, but one of its
 // descendants is (otherwise the node in question would not exist)
 
+// This is a version int written to a file called symlink_forest_version at the root of the
+// symlink forest. If the version here does not match the version in the file, then we'll
+// clean the whole symlink forest and recreate it. This number can be bumped whenever there's
+// an incompatible change to the forest layout or a bug in incrementality that needs to be fixed
+// on machines that may still have the bug present in their forest.
+const symlinkForestVersion = 1
+
 type instructionsNode struct {
 	name     string
 	excluded bool // If false, this is just an intermediate node
@@ -123,6 +133,34 @@
 	}
 	newContents = append(newContents, srcBuildFileContent...)
 
+	// Say you run bp2build 4 times:
+	// - The first time there's only an Android.bp file. bp2build will convert it to a build file
+	//   under out/soong/bp2build, then symlink from the forest to that generated file
+	// - Then you add a handcrafted BUILD file in the same directory. bp2build will merge this with
+	//   the generated one, and write the result to the output file in the forest. But the output
+	//   file was a symlink to out/soong/bp2build from the previous step! So we erroneously update
+	//   the file in out/soong/bp2build instead. So far this doesn't cause any problems...
+	// - You run a 3rd bp2build with no relevant changes. Everything continues to work.
+	// - You then add a comment to the handcrafted BUILD file. This causes a merge with the
+	//   generated file again. But since we wrote to the generated file in step 2, the generated
+	//   file has an old copy of the handcrafted file in it! This probably causes duplicate bazel
+	//   targets.
+	// To solve this, if we see that the output file is a symlink from a previous build, remove it.
+	stat, err := os.Lstat(output)
+	if err != nil && !os.IsNotExist(err) {
+		return err
+	} else if err == nil {
+		if stat.Mode()&os.ModeSymlink == os.ModeSymlink {
+			if verbose {
+				fmt.Fprintf(os.Stderr, "Removing symlink so that we can replace it with a merged file: %s\n", output)
+			}
+			err = os.Remove(output)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
 	return pathtools.WriteFileIfChanged(output, newContents, 0666)
 }
 
@@ -202,6 +240,46 @@
 	return false
 }
 
+// maybeCleanSymlinkForest will remove the whole symlink forest directory if the version recorded
+// in the symlink_forest_version file is not equal to symlinkForestVersion.
+func maybeCleanSymlinkForest(topdir, forest string, verbose bool) error {
+	versionFilePath := shared.JoinPath(topdir, forest, "symlink_forest_version")
+	versionFileContents, err := os.ReadFile(versionFilePath)
+	if err != nil && !os.IsNotExist(err) {
+		return err
+	}
+	versionFileString := strings.TrimSpace(string(versionFileContents))
+	symlinkForestVersionString := strconv.Itoa(symlinkForestVersion)
+	if err != nil || versionFileString != symlinkForestVersionString {
+		if verbose {
+			fmt.Fprintf(os.Stderr, "Old symlink_forest_version was %q, current is %q. Cleaning symlink forest before recreating...\n", versionFileString, symlinkForestVersionString)
+		}
+		err = os.RemoveAll(shared.JoinPath(topdir, forest))
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// maybeWriteVersionFile will write the symlink_forest_version file containing symlinkForestVersion
+// if it doesn't exist already. If it exists we know it must contain symlinkForestVersion because
+// we checked for that already in maybeCleanSymlinkForest
+func maybeWriteVersionFile(topdir, forest string) error {
+	versionFilePath := shared.JoinPath(topdir, forest, "symlink_forest_version")
+	_, err := os.Stat(versionFilePath)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			return err
+		}
+		err = os.WriteFile(versionFilePath, []byte(strconv.Itoa(symlinkForestVersion)+"\n"), 0666)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // Recursively plants a symlink forest at forestDir. The symlink tree will
 // contain every file in buildFilesDir and srcDir excluding the files in
 // instructions. Collects every directory encountered during the traversal of
@@ -395,6 +473,12 @@
 		symlinkCount: atomic.Uint64{},
 	}
 
+	err := maybeCleanSymlinkForest(topdir, forest, verbose)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+
 	instructions := instructionsFromExcludePathList(exclude)
 	go func() {
 		context.wg.Add(1)
@@ -407,5 +491,11 @@
 		deps = append(deps, dep)
 	}
 
+	err = maybeWriteVersionFile(topdir, forest)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+
 	return deps, context.mkdirCount.Load(), context.symlinkCount.Load()
 }
diff --git a/cc/afdo.go b/cc/afdo.go
index 4a8498b..be4f50a 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -71,10 +71,10 @@
 
 func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
 	if path := afdo.Properties.FdoProfilePath; path != nil {
+		// The flags are prepended to allow overriding.
 		profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
-		flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
+		flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...)
+		flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...)
 
 		// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
 		// if profileFile gets updated
diff --git a/cc/config/global.go b/cc/config/global.go
index 5b2191a..4277bcf 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -111,6 +111,9 @@
 
 		// Turn off FMA which got enabled by default in clang-r445002 (http://b/218805949)
 		"-ffp-contract=off",
+
+		// Turn off stack protector check for noreturn calls. (http://b/264965700)
+		"-mllvm -disable-check-noreturn-call",
 	}
 
 	commonGlobalConlyflags = []string{}
@@ -147,6 +150,9 @@
 	commonGlobalLldflags = []string{
 		"-fuse-ld=lld",
 		"-Wl,--icf=safe",
+
+		// Turn off stack protector check for noreturn calls. (http://b/264965700)
+		"-Wl,-mllvm,-disable-check-noreturn-call",
 	}
 
 	deviceGlobalCppflags = []string{
diff --git a/cc/library.go b/cc/library.go
index a9ada97..7504302 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -26,7 +26,6 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
-	"android/soong/cc/config"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
@@ -2261,8 +2260,7 @@
 		!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() &&
 		library.baseLinker.sanitize.isUnsanitizedVariant() &&
 		ctx.isForPlatform() && !ctx.isPreventInstall() {
-		installPath := getNdkSysrootBase(ctx).Join(
-			ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
+		installPath := getUnversionedLibraryInstallPath(ctx).Join(ctx, file.Base())
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 			Rule:        android.Cp,
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 2473ba2..a824361 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -528,17 +528,20 @@
 	return false
 }
 
-func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
-	arch := ctx.Target().Arch.ArchType.Name
-	// arm64 isn't actually a multilib toolchain, so unlike the other LP64
-	// architectures it's just installed to lib.
-	libDir := "lib"
-	if ctx.toolchain().Is64Bit() && arch != "arm64" {
-		libDir = "lib64"
-	}
+// Returns the install path for unversioned NDK libraries (currently only static
+// libraries).
+func getUnversionedLibraryInstallPath(ctx ModuleContext) android.InstallPath {
+	return getNdkSysrootBase(ctx).Join(ctx, "usr/lib", config.NDKTriple(ctx.toolchain()))
+}
 
-	installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
-		"platforms/android-%s/arch-%s/usr/%s", stub.apiLevel, arch, libDir))
+// Returns the install path for versioned NDK libraries. These are most often
+// stubs, but the same paths are used for CRT objects.
+func getVersionedLibraryInstallPath(ctx ModuleContext, apiLevel android.ApiLevel) android.InstallPath {
+	return getUnversionedLibraryInstallPath(ctx).Join(ctx, apiLevel.String())
+}
+
+func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
+	installDir := getVersionedLibraryInstallPath(ctx, stub.apiLevel)
 	stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
 }
 
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 622558e..dffc6c6 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -142,6 +142,13 @@
 						staticLibInstallPaths, library.ndkSysrootPath)
 				}
 			}
+
+			if object, ok := m.linker.(*objectLinker); ok {
+				if object.ndkSysrootPath != nil {
+					staticLibInstallPaths = append(
+						staticLibInstallPaths, object.ndkSysrootPath)
+				}
+			}
 		}
 	})
 
diff --git a/cc/object.go b/cc/object.go
index ef44467..d65cdea 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -44,6 +44,10 @@
 type objectLinker struct {
 	*baseLinker
 	Properties ObjectLinkerProperties
+
+	// Location of the object in the sysroot. Empty if the object is not
+	// included in the NDK.
+	ndkSysrootPath android.Path
 }
 
 type objectBazelHandler struct {
@@ -99,6 +103,10 @@
 	// Indicates that this module is a CRT object. CRT objects will be split
 	// into a variant per-API level between min_sdk_version and current.
 	Crt *bool
+
+	// Indicates that this module should not be included in the NDK sysroot.
+	// Only applies to CRT objects. Defaults to false.
+	Exclude_from_ndk_sysroot *bool
 }
 
 func newObject(hod android.HostOrDeviceSupported) *Module {
@@ -268,17 +276,28 @@
 
 	objs = objs.Append(deps.Objs)
 
-	var outputFile android.Path
+	var output android.WritablePath
 	builderFlags := flagsToBuilderFlags(flags)
 	outputName := ctx.ModuleName()
 	if !strings.HasSuffix(outputName, objectExtension) {
 		outputName += objectExtension
 	}
 
-	if len(objs.objFiles) == 1 && String(object.Properties.Linker_script) == "" {
-		output := android.PathForModuleOut(ctx, outputName)
-		outputFile = output
+	// isForPlatform is terribly named and actually means isNotApex.
+	if Bool(object.Properties.Crt) &&
+		!Bool(object.Properties.Exclude_from_ndk_sysroot) && ctx.useSdk() &&
+		ctx.isSdkVariant() && ctx.isForPlatform() {
 
+		output = getVersionedLibraryInstallPath(ctx,
+			nativeApiLevelOrPanic(ctx, ctx.sdkVersion())).Join(ctx, outputName)
+		object.ndkSysrootPath = output
+	} else {
+		output = android.PathForModuleOut(ctx, outputName)
+	}
+
+	outputFile := output
+
+	if len(objs.objFiles) == 1 && String(object.Properties.Linker_script) == "" {
 		if String(object.Properties.Prefix_symbols) != "" {
 			transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), objs.objFiles[0],
 				builderFlags, output)
@@ -290,9 +309,6 @@
 			})
 		}
 	} else {
-		output := android.PathForModuleOut(ctx, outputName)
-		outputFile = output
-
 		if String(object.Properties.Prefix_symbols) != "" {
 			input := android.PathForModuleOut(ctx, "unprefixed", outputName)
 			transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), input,
diff --git a/cc/object_test.go b/cc/object_test.go
index 5359a35..b1e2a0f 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -65,7 +65,7 @@
 	variant := "android_arm64_armv8-a_sdk"
 	crt := ctx.ModuleForTests("bin", variant).Rule("ld").Args["crtBegin"]
 	android.AssertStringDoesContain(t, "crt dep of sdk variant", crt,
-		variant+"_29/crtbegin_dynamic.o")
+		"29/crtbegin_dynamic.o")
 
 	// platform variant uses the crt object built for platform
 	variant = "android_arm64_armv8-a"
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
index b63ce42..813187e 100644
--- a/java/core-libraries/TxtStubLibraries.bp
+++ b/java/core-libraries/TxtStubLibraries.bp
@@ -33,8 +33,8 @@
         "system-modules-no-annotations",
     ],
     static_libs: [
-        "core.current.stubs.from-txt",
-        "core-lambda-stubs-for-system-modules",
+        "core.current.stubs.from-text",
+        "core-lambda-stubs.from-text",
     ],
     // TODO: Enable after stub generation from .txt file is available
     enabled: false,
@@ -58,8 +58,8 @@
         "system-modules-no-annotations",
     ],
     static_libs: [
-        "core.module_lib.stubs.txt",
-        "core-lambda-stubs-for-system-modules",
+        "core.module_lib.stubs.from-text",
+        "core-lambda-stubs.from-text",
     ],
     // TODO: Enable after stub generation from .txt file is available
     enabled: false,
@@ -89,7 +89,7 @@
     visibility: core_platform_visibility,
     libs: [
         "legacy.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs-for-system-modules",
+        "core-lambda-stubs.from-text",
     ],
     // TODO: Enable after stub generation from .txt file is available
     enabled: false,
@@ -118,7 +118,7 @@
     visibility: core_platform_visibility,
     libs: [
         "stable.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs-for-system-modules",
+        "core-lambda-stubs.from-text",
     ],
     // TODO: Enable after stub generation from .txt file is available
     enabled: false,
@@ -140,3 +140,17 @@
     // TODO: Enable after stub generation from .txt file is available
     enabled: false,
 }
+
+java_api_library {
+    name: "core-lambda-stubs.from-text",
+    api_surface: "toolchain",
+    api_contributions: [
+        "art.module.toolchain.api.api.contribution",
+    ],
+    libs: [
+        // LambdaMetaFactory depends on CallSite etc. which is part of the Core API surface
+        "core.current.stubs.from-text",
+    ],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 4abdcc6..656c866 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -19,12 +19,14 @@
 	"io"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/dexpreopt"
 )
 
 type DeviceHostConverter struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.BazelModuleBase
 
 	properties DeviceHostConverterProperties
 
@@ -76,6 +78,7 @@
 	module.AddProperties(&module.properties)
 
 	InitJavaModule(module, android.DeviceSupported)
+	android.InitBazelModule(module)
 	return module
 }
 
@@ -186,3 +189,30 @@
 		},
 	}
 }
+
+type bazelDeviceHostConverterAttributes struct {
+	Deps bazel.LabelListAttribute
+}
+
+func (d *DeviceHostConverter) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "java_host_for_device",
+			Bzl_load_location: "//build/bazel/rules/java:host_for_device.bzl",
+		},
+		android.CommonAttributes{Name: d.Name()},
+		&bazelDeviceHostConverterAttributes{
+			Deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, d.properties.Libs)),
+		},
+	)
+	neverlinkProp := true
+	neverLinkAttrs := &javaLibraryAttributes{
+		Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + d.Name()}),
+		Neverlink: bazel.BoolAttribute{Value: &neverlinkProp},
+	}
+	ctx.CreateBazelTargetModule(
+		javaLibraryBazelTargetModuleProperties(),
+		android.CommonAttributes{Name: d.Name() + "-neverlink"},
+		neverLinkAttrs)
+
+}
diff --git a/java/java.go b/java/java.go
index 97d5514..d400b0c 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1612,7 +1612,7 @@
 }
 
 type JavaApiLibraryDepsInfo struct {
-	StubsJar    android.Path
+	JavaInfo
 	StubsSrcJar android.Path
 }
 
@@ -1821,7 +1821,7 @@
 			staticLibs = append(staticLibs, provider.HeaderJars...)
 		case depApiSrcsTag:
 			provider := ctx.OtherModuleProvider(dep, JavaApiLibraryDepsProvider).(JavaApiLibraryDepsInfo)
-			classPaths = append(classPaths, provider.StubsJar)
+			classPaths = append(classPaths, provider.HeaderJars...)
 			depApiSrcsStubsSrcJar = provider.StubsSrcJar
 		}
 	})
@@ -1900,7 +1900,9 @@
 	})
 
 	ctx.SetProvider(JavaApiLibraryDepsProvider, JavaApiLibraryDepsInfo{
-		StubsJar:    al.stubsJar,
+		JavaInfo: JavaInfo{
+			HeaderJars: android.PathsIfNonNil(al.stubsJar),
+		},
 		StubsSrcJar: al.stubsSrcJar,
 	})
 }
@@ -2905,10 +2907,6 @@
 		}
 	}
 
-	if m.properties.Static_libs != nil {
-		staticDeps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Static_libs))))
-	}
-
 	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
 	// Soong does not differentiate between a java_library and the Bazel equivalent of
 	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
@@ -2920,7 +2918,18 @@
 
 	depLabels := &javaDependencyLabels{}
 	depLabels.Deps = deps
-	depLabels.StaticDeps = bazel.MakeLabelListAttribute(staticDeps)
+
+	for axis, configToProps := range archVariantProps {
+		for config, _props := range configToProps {
+			if archProps, ok := _props.(*CommonProperties); ok {
+				archStaticLibs := android.BazelLabelForModuleDeps(
+					ctx,
+					android.LastUniqueStrings(android.CopyOf(archProps.Static_libs)))
+				depLabels.StaticDeps.SetSelectValue(axis, config, archStaticLibs)
+			}
+		}
+	}
+	depLabels.StaticDeps.Value.Append(staticDeps)
 
 	hasKotlin := !kotlinSrcs.IsEmpty()
 	commonAttrs.kotlinAttributes = &kotlinAttributes{
diff --git a/java/sdk.go b/java/sdk.go
index 1b18ba4..8b4918a 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -151,7 +151,7 @@
 		systemModules := android.JavaApiLibraryName(ctx.Config(), fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind))
 		return sdkDep{
 			useModule:          true,
-			bootclasspath:      []string{module, config.DefaultLambdaStubsLibrary},
+			bootclasspath:      []string{module, android.JavaApiLibraryName(ctx.Config(), config.DefaultLambdaStubsLibrary)},
 			systemModules:      systemModules,
 			java9Classpath:     []string{module},
 			frameworkResModule: "framework-res",
@@ -197,7 +197,7 @@
 	case android.SdkCore:
 		return sdkDep{
 			useModule:        true,
-			bootclasspath:    []string{android.SdkCore.JavaLibraryName(ctx.Config()), config.DefaultLambdaStubsLibrary},
+			bootclasspath:    []string{android.SdkCore.JavaLibraryName(ctx.Config()), android.JavaApiLibraryName(ctx.Config(), config.DefaultLambdaStubsLibrary)},
 			systemModules:    android.JavaApiLibraryName(ctx.Config(), "core-public-stubs-system-modules"),
 			noFrameworksLibs: true,
 		}
diff --git a/java/testing.go b/java/testing.go
index 8a0db9c..0764d26 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -368,14 +368,6 @@
 		"core.current.stubs",
 		"legacy.core.platform.api.stubs",
 		"stable.core.platform.api.stubs",
-		"android_stubs_current.from-text",
-		"android_system_stubs_current.from-text",
-		"android_test_stubs_current.from-text",
-		"android_module_lib_stubs_current.from-text",
-		"android_system_server_stubs_current.from-text",
-		"core.current.stubs.from-text",
-		"legacy.core.platform.api.stubs.from-text",
-		"stable.core.platform.api.stubs.from-text",
 
 		"kotlin-stdlib",
 		"kotlin-stdlib-jdk7",
@@ -396,6 +388,27 @@
 		`, extra)
 	}
 
+	extraApiLibraryModules := map[string]string{
+		"android_stubs_current.from-text":               "api/current.txt",
+		"android_system_stubs_current.from-text":        "api/system-current.txt",
+		"android_test_stubs_current.from-text":          "api/test-current.txt",
+		"android_module_lib_stubs_current.from-text":    "api/module-lib-current.txt",
+		"android_system_server_stubs_current.from-text": "api/system-server-current.txt",
+		"core.current.stubs.from-text":                  "api/current.txt",
+		"legacy.core.platform.api.stubs.from-text":      "api/current.txt",
+		"stable.core.platform.api.stubs.from-text":      "api/current.txt",
+		"core-lambda-stubs.from-text":                   "api/current.txt",
+	}
+
+	for libName, apiFile := range extraApiLibraryModules {
+		bp += fmt.Sprintf(`
+            java_api_library {
+                name: "%s",
+                api_files: ["%s"],
+            }
+        `, libName, apiFile)
+	}
+
 	bp += `
 		java_library {
 			name: "framework",
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index a507349..2f154cd 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -98,19 +98,15 @@
  -I /system/lib64/libkm_compat.so \
  -I /system/lib64/vndk-29 \
  -I /system/lib64/vndk-sp-29 \
- -I /system/lib/modules \
  -I /system/lib/vndk-29 \
  -I /system/lib/vndk-sp-29 \
- -I /system/product \
- -I /system/system_ext \
  -I /system/usr/icu \
- -I /system/vendor \
  -I /vendor_dlkm/etc"
 
- function diff_files {
-   file_list_file="$1";
-   files_in_spdx_file="$2"
-   partition_name="$3"
+function diff_files {
+   file_list_file="$1"; shift
+   files_in_spdx_file="$1"; shift
+   partition_name="$1"; shift
    exclude=
    if [ -v 'diff_excludes[$partition_name]' ]; then
      exclude=${diff_excludes[$partition_name]}
@@ -168,9 +164,9 @@
     all_dirs=$(echo "$all_dirs" | cut -d ' ' -f1 --complement -s)
     entries=$($dump_erofs --ls --path "$dir" $f | tail -n +11)
     while read -r entry; do
-      type=$(echo $entry | awk -F ' ' '{print $2}')
+      inode_type=$(echo $entry | awk -F ' ' '{print $2}')
       name=$(echo $entry | awk -F ' ' '{print $3}')
-      case $type in
+      case $inode_type in
         "2")  # directory
           all_dirs=$(echo "$all_dirs $dir/$name" | sed 's/^\s*//')
           ;;
@@ -204,6 +200,11 @@
   partition_name=$(basename $f | cut -d. -f1)
   file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
   files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+  # lz4 decompress $f to stdout
+  # cpio list all entries like ls -l
+  # grep filter normal files and symlinks
+  # awk get entry names
+  # sed remove partition name from entry names
   $lz4 -c -d $f | cpio -tv 2>/dev/null | grep '^[-l]' | awk -F ' ' '{print $9}' | sed "s:^:/$partition_name/:" | sort -n > "$file_list_file"
 
   grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"