Merge "Fix OUT_DIR lookup in mixed builds."
diff --git a/android/bazel.go b/android/bazel.go
index ef770bf..4967b12 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -220,15 +220,8 @@
 	// Per-module denylist to opt modules out of mixed builds. Such modules will
 	// still be generated via bp2build.
 	mixedBuildsDisabledList = []string{
-		"libc_common",                      // cparsons@ cc_library_static, depends on //bionic/libc:libc_nopthread
-		"libc_common_static",               // cparsons@ cc_library_static, depends on //bionic/libc:libc_common
-		"libc_common_shared",               // cparsons@ cc_library_static, depends on //bionic/libc:libc_common
-		"libc_netbsd",                      // lberki@, cc_library_static, version script assignment of 'LIBC_PRIVATE' to symbol 'SHA1Final' failed: symbol not defined
-		"libc_nopthread",                   // cparsons@ cc_library_static, version script assignment of 'LIBC' to symbol 'memcmp' failed: symbol not defined
-		"libc_openbsd",                     // ruperts@, cc_library_static, OK for bp2build but error: duplicate symbol: strcpy for mixed builds
-		"libarm-optimized-routines-string", // jingwen@, cc_library_static, OK for bp2build but b/186615213 (asflags not handled in  bp2build), version script assignment of 'LIBC' to symbol 'memcmp' failed: symbol not defined (also for memrchr, strnlen)
-		"fmtlib_ndk",                       // http://b/187040371, cc_library_static, OK for bp2build but format-inl.h:11:10: fatal error: 'cassert' file not found for mixed builds
-		"libc_nomalloc",                    // cc_library_static, OK for bp2build but ld.lld: error: undefined symbol: pthread_mutex_lock (and others)
+		"libc_common_shared", // cparsons@ cc_library_static, breaks module `libc`.
+		"libc_nomalloc",      // cparsons@ cc_library_static, breaks module `linker`
 	}
 
 	// Used for quicker lookups
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 4d00944..6a7c35c 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -709,6 +709,79 @@
 	}
 }
 
+func TestApexManifestMinSdkVersion(t *testing.T) {
+	ctx := testApex(t, `
+		apex_defaults {
+			name: "my_defaults",
+			key: "myapex.key",
+			product_specific: true,
+			file_contexts: ":my-file-contexts",
+			updatable: false,
+		}
+		apex {
+			name: "myapex_30",
+			min_sdk_version: "30",
+			defaults: ["my_defaults"],
+		}
+
+		apex {
+			name: "myapex_current",
+			min_sdk_version: "current",
+			defaults: ["my_defaults"],
+		}
+
+		apex {
+			name: "myapex_none",
+			defaults: ["my_defaults"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		filegroup {
+			name: "my-file-contexts",
+			srcs: ["product_specific_file_contexts"],
+		}
+	`, withFiles(map[string][]byte{
+		"product_specific_file_contexts": nil,
+	}), android.FixtureModifyProductVariables(
+		func(variables android.FixtureProductVariables) {
+			variables.Unbundled_build = proptools.BoolPtr(true)
+			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(false)
+		}), android.FixtureMergeEnv(map[string]string{
+		"UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT": "true",
+	}))
+
+	testCases := []struct {
+		module        string
+		minSdkVersion string
+	}{
+		{
+			module:        "myapex_30",
+			minSdkVersion: "30",
+		},
+		{
+			module:        "myapex_current",
+			minSdkVersion: "Q.$$(cat out/soong/api_fingerprint.txt)",
+		},
+		{
+			module:        "myapex_none",
+			minSdkVersion: "Q.$$(cat out/soong/api_fingerprint.txt)",
+		},
+	}
+	for _, tc := range testCases {
+		module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module+"_image")
+		args := module.Rule("apexRule").Args
+		optFlags := args["opt_flags"]
+		if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) {
+			t.Errorf("%s: Expected min_sdk_version=%s, got: %s", tc.module, tc.minSdkVersion, optFlags)
+		}
+	}
+}
+
 func TestBasicZipApex(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
diff --git a/apex/builder.go b/apex/builder.go
index da8841c..021e499 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -602,6 +602,11 @@
 		// codename
 		if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
 			minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
+
+			if java.UseApiFingerprint(ctx) {
+				minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+				implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
+			}
 		}
 		// apex module doesn't have a concept of target_sdk_version, hence for the time
 		// being targetSdkVersion == default targetSdkVersion of the branch.
@@ -611,10 +616,6 @@
 			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
 			implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
 		}
-		if java.UseApiFingerprint(ctx) {
-			minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
-			implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
-		}
 		optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
 		optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
 
diff --git a/cc/builder.go b/cc/builder.go
index 51c8a0b..fae9522 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -534,7 +534,7 @@
 				Implicits:   cFlagsDeps,
 				OrderOnly:   pathDeps,
 				Args: map[string]string{
-					"windresCmd": gccCmd(flags.toolchain, "windres"),
+					"windresCmd": mingwCmd(flags.toolchain, "windres"),
 					"flags":      flags.toolchain.WindresFlags(),
 				},
 			})
@@ -1069,6 +1069,6 @@
 	})
 }
 
-func gccCmd(toolchain config.Toolchain, cmd string) string {
+func mingwCmd(toolchain config.Toolchain, cmd string) string {
 	return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
 }
diff --git a/cc/cc.go b/cc/cc.go
index aa218bf..91c4417 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -726,7 +726,6 @@
 	runtimeDepTag         = installDependencyTag{name: "runtime lib"}
 	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
 	stubImplDepTag        = dependencyTag{name: "stub_impl"}
-	llndkStubDepTag       = dependencyTag{name: "llndk stub"}
 )
 
 func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
@@ -3238,8 +3237,8 @@
 			return false
 		}
 	}
-	if depTag == stubImplDepTag || depTag == llndkStubDepTag {
-		// We don't track beyond LLNDK or from an implementation library to its stubs.
+	if depTag == stubImplDepTag {
+		// We don't track from an implementation library to its stubs.
 		return false
 	}
 	if depTag == staticVariantTag {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 5acafbe..7fc044d 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2799,12 +2799,8 @@
 		}
 	}
 	expected := []string{
-		"android_vendor.29_arm64_armv8-a_shared_1",
-		"android_vendor.29_arm64_armv8-a_shared_2",
 		"android_vendor.29_arm64_armv8-a_shared_current",
 		"android_vendor.29_arm64_armv8-a_shared",
-		"android_vendor.29_arm_armv7-a-neon_shared_1",
-		"android_vendor.29_arm_armv7-a-neon_shared_2",
 		"android_vendor.29_arm_armv7-a-neon_shared_current",
 		"android_vendor.29_arm_armv7-a-neon_shared",
 	}
@@ -2813,9 +2809,6 @@
 	params := result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub")
 	android.AssertSame(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
 
-	params = result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared_1").Description("generate stub")
-	android.AssertSame(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"])
-
 	checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) {
 		t.Helper()
 		m := result.ModuleForTests(module, variant).Module()
diff --git a/cc/gen.go b/cc/gen.go
index b152e02..3a1a0e2 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -204,7 +204,7 @@
 	headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h")
 	rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc")
 
-	windmcCmd := gccCmd(flags.toolchain, "windmc")
+	windmcCmd := mingwCmd(flags.toolchain, "windmc")
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:           windmc,
diff --git a/cc/library.go b/cc/library.go
index 9fb7a24..5e70c51 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1813,6 +1813,11 @@
 		return nil
 	}
 
+	if library.hasLLNDKStubs() && ctx.Module().(*Module).UseVndk() {
+		// LLNDK libraries only need a single stubs variant.
+		return []string{android.FutureApiLevel.String()}
+	}
+
 	// Future API level is implicitly added if there isn't
 	vers := library.Properties.Stubs.Versions
 	if inList(android.FutureApiLevel.String(), vers) {
@@ -2154,8 +2159,7 @@
 	return nil
 }
 
-// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions,
-// and propagates the value from implementation libraries to llndk libraries with the same name.
+// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions.
 func versionSelectorMutator(mctx android.BottomUpMutatorContext) {
 	if library := moduleLibraryInterface(mctx.Module()); library != nil && CanBeVersionVariant(mctx.Module().(*Module)) {
 		if library.buildShared() {
@@ -2169,15 +2173,6 @@
 				// depend on the implementation library and haven't been mutated yet.
 				library.setAllStubsVersions(versions)
 			}
-
-			if mctx.Module().(*Module).UseVndk() && library.hasLLNDKStubs() {
-				// Propagate the version to the llndk stubs module.
-				mctx.VisitDirectDepsWithTag(llndkStubDepTag, func(stubs android.Module) {
-					if stubsLib := moduleLibraryInterface(stubs); stubsLib != nil {
-						stubsLib.setAllStubsVersions(library.allStubsVersions())
-					}
-				})
-			}
 		}
 	}
 }
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index e0f8caa..20f146a 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -433,7 +433,7 @@
 	config := build.NewConfig(ctx, args...)
 	config.Environment().Set("OUT_DIR", outDir)
 	if !*keepArtifacts {
-		config.Environment().Set("EMPTY_NINJA_FILE", "true")
+		config.SetEmptyNinjaFile(true)
 	}
 	build.FindSources(ctx, config, mpctx.Finder)
 	config.Lunch(ctx, product, *buildVariant)
diff --git a/java/androidmk.go b/java/androidmk.go
index 0154544..04357e0 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -460,6 +460,8 @@
 	entries := &entriesList[0]
 	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 		testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites)
+		// introduce a flag variable to control the generation of the .config file
+		entries.SetString("LOCAL_DISABLE_TEST_CONFIG", "true")
 	})
 
 	return entriesList
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 5eaa77b..246c0eb 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -188,3 +188,21 @@
 
 	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_SOONG_DEX_JAR", result.Config, []string{expectedSoongDexJar}, actualSoongDexJar)
 }
+
+func TestAndroidTestHelperApp_LocalDisableTestConfig(t *testing.T) {
+	ctx, _ := testJava(t, `
+		android_test_helper_app {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("foo", "android_common").Module()
+	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+
+	expected := []string{"true"}
+	actual := entries.EntryMap["LOCAL_DISABLE_TEST_CONFIG"]
+	if !reflect.DeepEqual(expected, actual) {
+		t.Errorf("Unexpected flag value - expected: %q, actual: %q", expected, actual)
+	}
+}
diff --git a/ui/build/config.go b/ui/build/config.go
index 1d1f71f..3ebde0d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -72,6 +72,9 @@
 	// During Bazel execution, Bazel cannot write outside OUT_DIR.
 	// So if DIST_DIR is set to an external dir (outside of OUT_DIR), we need to rig it temporarily and then migrate files at the end of the build.
 	riggedDistDirForBazel string
+
+	// Set by multiproduct_kati
+	emptyNinjaFile bool
 }
 
 const srcDirFileCheck = "build/soong/root.bp"
@@ -203,9 +206,6 @@
 		"ANDROID_DEV_SCRIPTS",
 		"ANDROID_EMULATOR_PREBUILTS",
 		"ANDROID_PRE_BUILD_PATHS",
-
-		// Only set in multiproduct_kati after config generation
-		"EMPTY_NINJA_FILE",
 	)
 
 	if ret.UseGoma() || ret.ForceUseGoma() {
@@ -1189,3 +1189,11 @@
 func (c *configImpl) BazelMetricsDir() string {
 	return filepath.Join(c.LogsDir(), "bazel_metrics")
 }
+
+func (c *configImpl) SetEmptyNinjaFile(v bool) {
+	c.emptyNinjaFile = v
+}
+
+func (c *configImpl) EmptyNinjaFile() bool {
+	return c.emptyNinjaFile
+}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 06ec646..dad68fa 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -136,7 +136,7 @@
 	// information out with --empty_ninja_file.
 	//
 	// From https://github.com/google/kati/commit/87b8da7af2c8bea28b1d8ab17679453d859f96e5
-	if config.Environment().IsEnvTrue("EMPTY_NINJA_FILE") {
+	if config.EmptyNinjaFile() {
 		args = append(args, "--empty_ninja_file")
 	}
 
diff --git a/ui/build/soong.go b/ui/build/soong.go
index cd645eb..7128414 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -119,6 +119,7 @@
 	args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
 	args.GlobFile = globFile
 	args.GeneratingPrimaryBuilder = true
+	args.EmptyNinjaFile = config.EmptyNinjaFile()
 
 	args.DelveListen = os.Getenv("SOONG_DELVE")
 	if args.DelveListen != "" {