Merge changes from topics "bp2build-tidy-disabled-srcs", "bp2build-tidy-timeout-srcs"

* changes:
  bp2build for tidy_timeout_srcs
  bp2build for tidy_disabled_srcs
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index a1b7dbf..16f144e 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -49,9 +49,9 @@
 		"art/runtime":                           Bp2BuildDefaultTrueRecursively,
 		"art/tools":                             Bp2BuildDefaultTrue,
 		"bionic":                                Bp2BuildDefaultTrueRecursively,
+		"bootable/recovery/applypatch":          Bp2BuildDefaultTrue,
 		"bootable/recovery/minadbd":             Bp2BuildDefaultTrue,
 		"bootable/recovery/minui":               Bp2BuildDefaultTrue,
-		"bootable/recovery/applypatch":          Bp2BuildDefaultTrue,
 		"bootable/recovery/recovery_utils":      Bp2BuildDefaultTrue,
 		"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
 
@@ -69,6 +69,9 @@
 		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
 
 		"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
+
+		"dalvik/tools/dexdeps": Bp2BuildDefaultTrueRecursively,
+
 		"development/apps/DevelopmentSettings":        Bp2BuildDefaultTrue,
 		"development/apps/Fallback":                   Bp2BuildDefaultTrue,
 		"development/apps/WidgetPreview":              Bp2BuildDefaultTrue,
@@ -108,8 +111,8 @@
 
 		"external/aac":                           Bp2BuildDefaultTrueRecursively,
 		"external/arm-optimized-routines":        Bp2BuildDefaultTrueRecursively,
-		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
 		"external/auto":                          Bp2BuildDefaultTrue,
+		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
 		"external/auto/common":                   Bp2BuildDefaultTrueRecursively,
 		"external/auto/service":                  Bp2BuildDefaultTrueRecursively,
 		"external/boringssl":                     Bp2BuildDefaultTrueRecursively,
@@ -176,19 +179,19 @@
 		"external/zopfli":                        Bp2BuildDefaultTrueRecursively,
 		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
 
-		"frameworks/av":                                      Bp2BuildDefaultTrue,
-		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
+		"frameworks/av": Bp2BuildDefaultTrue,
 		"frameworks/av/media/codec2/components/aom":          Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/module/minijail":                Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
 		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
 		"frameworks/base/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
 		"frameworks/base/startop/apps/test":                  Bp2BuildDefaultTrue,
 		"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/tools/streaming_proto":              Bp2BuildDefaultTrueRecursively,
 		"frameworks/base/tools/aapt2":                        Bp2BuildDefaultTrue,
+		"frameworks/base/tools/streaming_proto":              Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/adbd_auth":                   Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/arect":                       Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/gui":                         Bp2BuildDefaultTrue,
@@ -208,10 +211,10 @@
 		"hardware/interfaces/configstore/1.0":          Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/1.1":          Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/utils":        Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/aidl":  Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/2.0":   Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/3.0":   Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/4.0":   Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/aidl":  Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/bufferqueue/1.0": Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/bufferqueue/2.0": Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/common/1.0":      Bp2BuildDefaultTrue,
@@ -249,6 +252,7 @@
 		"packages/apps/Protips":                            Bp2BuildDefaultTrue,
 		"packages/apps/SafetyRegulatoryInfo":               Bp2BuildDefaultTrue,
 		"packages/apps/WallpaperPicker":                    Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/driver/cache":     Bp2BuildDefaultTrueRecursively,
 		"packages/modules/StatsD/lib/libstatssocket":       Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb":                             Bp2BuildDefaultTrue,
 		"packages/modules/adb/apex":                        Bp2BuildDefaultTrue,
@@ -259,7 +263,6 @@
 		"packages/modules/adb/proto":                       Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb/tls":                         Bp2BuildDefaultTrueRecursively,
 		"packages/providers/MediaProvider/tools/dialogs":   Bp2BuildDefaultFalse, // TODO(b/242834374)
-		"packages/modules/NeuralNetworks/driver/cache":     Bp2BuildDefaultTrueRecursively,
 		"packages/screensavers/Basic":                      Bp2BuildDefaultTrue,
 		"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
 
@@ -272,8 +275,8 @@
 		"prebuilts/tools":                          Bp2BuildDefaultTrue,
 		"prebuilts/tools/common/m2":                Bp2BuildDefaultTrue,
 
-		"sdk/eventanalyzer": Bp2BuildDefaultTrue,
 		"sdk/dumpeventlog":  Bp2BuildDefaultTrue,
+		"sdk/eventanalyzer": Bp2BuildDefaultTrue,
 
 		"system/apex":                                            Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
 		"system/apex/apexer":                                     Bp2BuildDefaultTrue,
@@ -1339,9 +1342,12 @@
 		"prebuilt_currysrc_org.eclipse",
 	}
 
+	// Bazel prod-mode allowlist. Modules in this list are built by Bazel
+	// in either prod mode or staging mode.
 	ProdMixedBuildsEnabledList = []string{}
 
-	// Staging builds should be entirely prod, plus some near-ready ones. Add the
-	// new ones to the first argument as needed.
-	StagingMixedBuildsEnabledList = append([]string{}, ProdMixedBuildsEnabledList...)
+	// Staging-mode allowlist. Modules in this list are only built
+	// by Bazel with --bazel-mode-staging. This list should contain modules
+	// which will soon be added to the prod allowlist.
+	StagingMixedBuildsEnabledList = []string{"com.android.tzdata"}
 )
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index c157d39..eec78d2 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -142,7 +142,7 @@
 	GetPythonBinary(label string, cfgKey configKey) (string, error)
 
 	// Returns the results of the GetApexInfo query (including output files)
-	GetApexInfo(label string, cfgkey configKey) (cquery.ApexCqueryInfo, error)
+	GetApexInfo(label string, cfgkey configKey) (cquery.ApexInfo, error)
 
 	// Returns the results of the GetCcUnstrippedInfo query
 	GetCcUnstrippedInfo(label string, cfgkey configKey) (cquery.CcUnstrippedInfo, error)
@@ -226,7 +226,7 @@
 	LabelToOutputFiles  map[string][]string
 	LabelToCcInfo       map[string]cquery.CcInfo
 	LabelToPythonBinary map[string]string
-	LabelToApexInfo     map[string]cquery.ApexCqueryInfo
+	LabelToApexInfo     map[string]cquery.ApexInfo
 	LabelToCcBinary     map[string]cquery.CcUnstrippedInfo
 }
 
@@ -249,8 +249,9 @@
 	return result, nil
 }
 
-func (n MockBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
-	panic("unimplemented")
+func (m MockBazelContext) GetApexInfo(label string, _ configKey) (cquery.ApexInfo, error) {
+	result, _ := m.LabelToApexInfo[label]
+	return result, nil
 }
 
 func (m MockBazelContext) GetCcUnstrippedInfo(label string, _ configKey) (cquery.CcUnstrippedInfo, error) {
@@ -313,18 +314,18 @@
 	return "", fmt.Errorf("no bazel response found for %v", key)
 }
 
-func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) {
+func (bazelCtx *bazelContext) 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)), nil
+		return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString))
 	}
-	return cquery.ApexCqueryInfo{}, fmt.Errorf("no bazel response found for %v", key)
+	return cquery.ApexInfo{}, fmt.Errorf("no bazel response found for %v", key)
 }
 
 func (bazelCtx *bazelContext) 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)), nil
+		return cquery.GetCcUnstrippedInfo.ParseResult(strings.TrimSpace(rawString))
 	}
 	return cquery.CcUnstrippedInfo{}, fmt.Errorf("no bazel response for %s", key)
 }
@@ -345,7 +346,7 @@
 	panic("unimplemented")
 }
 
-func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexInfo, error) {
 	panic("unimplemented")
 }
 
@@ -388,9 +389,12 @@
 		}
 	case BazelStagingMode:
 		modulesDefaultToBazel = false
+		// Staging mode includes all prod modules plus all staging modules.
+		for _, enabledProdModule := range allowlists.ProdMixedBuildsEnabledList {
+			enabledModules[enabledProdModule] = true
+		}
 		for _, enabledStagingMode := range allowlists.StagingMixedBuildsEnabledList {
 			enabledModules[enabledStagingMode] = true
-
 		}
 	case BazelDevMode:
 		modulesDefaultToBazel = true
@@ -567,7 +571,9 @@
 
 		// Suppress noise
 		"--ui_event_filters=-INFO",
-		"--noshow_progress"}
+		"--noshow_progress",
+		"--norun_validations",
+	}
 	cmdFlags = append(cmdFlags, extraFlags...)
 
 	bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
@@ -1082,7 +1088,7 @@
 
 	// Remove old outputs, as some actions might not rerun if the outputs are detected.
 	if len(buildStatement.OutputPaths) > 0 {
-		cmd.Text("rm -f")
+		cmd.Text("rm -rf") // -r because outputs can be Bazel dir/tree artifacts.
 		for _, outputPath := range buildStatement.OutputPaths {
 			cmd.Text(fmt.Sprintf("'%s'", outputPath))
 		}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index c857272..6e3acd5 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -9,8 +9,9 @@
 	"testing"
 
 	"android/soong/bazel/cquery"
-	"google.golang.org/protobuf/proto"
 	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
+	"google.golang.org/protobuf/proto"
 )
 
 var testConfig = TestConfig("out", nil, "", nil)
@@ -86,7 +87,7 @@
    { "id": 1, "label": "one" },
    { "id": 2, "label": "two" }]
 }`,
-			"cd 'test/exec_root' && rm -f 'one' && touch foo",
+			"cd 'test/exec_root' && rm -rf 'one' && touch foo",
 		}, {`
 {
  "artifacts": [
@@ -105,7 +106,7 @@
    { "id": 20, "label": "one.d", "parent_id": 30 },
    { "id": 30, "label": "parent" }]
 }`,
-			`cd 'test/exec_root' && rm -f 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
+			`cd 'test/exec_root' && rm -rf 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
 		},
 	}
 
diff --git a/android/bazel_test.go b/android/bazel_test.go
index 3164b23..7b38b6a 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -423,3 +423,21 @@
 		}
 	}
 }
+
+func TestShouldKeepExistingBuildFileForDir(t *testing.T) {
+	allowlist := NewBp2BuildAllowlist()
+	// entry "a/b2/c2" is moot because of its parent "a/b2"
+	allowlist.SetKeepExistingBuildFile(map[string]bool{"a": false, "a/b1": false, "a/b2": true, "a/b1/c1": true, "a/b2/c2": false})
+	truths := []string{"a", "a/b1", "a/b2", "a/b1/c1", "a/b2/c", "a/b2/c2", "a/b2/c2/d"}
+	falsities := []string{"a1", "a/b", "a/b1/c"}
+	for _, dir := range truths {
+		if !allowlist.ShouldKeepExistingBuildFileForDir(dir) {
+			t.Errorf("%s expected TRUE but was FALSE", dir)
+		}
+	}
+	for _, dir := range falsities {
+		if allowlist.ShouldKeepExistingBuildFileForDir(dir) {
+			t.Errorf("%s expected FALSE but was TRUE", dir)
+		}
+	}
+}
diff --git a/android/config.go b/android/config.go
index df2c767..0c3e2d1 100644
--- a/android/config.go
+++ b/android/config.go
@@ -536,7 +536,7 @@
 // Returns true if "Bazel builds" is enabled. In this mode, part of build
 // analysis is handled by Bazel.
 func (c *config) IsMixedBuildsEnabled() bool {
-	return c.BuildMode == BazelProdMode || c.BuildMode == BazelDevMode
+	return c.BuildMode == BazelProdMode || c.BuildMode == BazelDevMode || c.BuildMode == BazelStagingMode
 }
 
 func (c *config) SetAllowMissingDependencies() {
@@ -1109,7 +1109,7 @@
 	return c.config.productVariables.WithDexpreopt
 }
 
-func (c *config) FrameworksBaseDirExists(ctx PathContext) bool {
+func (c *config) FrameworksBaseDirExists(ctx PathGlobContext) bool {
 	return ExistentPathForSource(ctx, "frameworks", "base", "Android.bp").Valid()
 }
 
diff --git a/android/licenses.go b/android/licenses.go
index c47b3e6..c6b3243 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -340,4 +340,5 @@
 	ctx.Strict("COMPLIANCENOTICE_SHIPPEDLIBS", ctx.Config().HostToolPath(ctx, "compliancenotice_shippedlibs").String())
 	ctx.Strict("COMPLIANCE_LISTSHARE", ctx.Config().HostToolPath(ctx, "compliance_listshare").String())
 	ctx.Strict("COMPLIANCE_CHECKSHARE", ctx.Config().HostToolPath(ctx, "compliance_checkshare").String())
+	ctx.Strict("COMPLIANCE_SBOM", ctx.Config().HostToolPath(ctx, "compliance_sbom").String())
 }
diff --git a/android/metrics.go b/android/metrics.go
index ecda026..3d41a1d 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -62,7 +62,7 @@
 	})
 }
 
-func collectMetrics(config Config, eventHandler metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
+func collectMetrics(config Config, eventHandler *metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
 	metrics := &soong_metrics_proto.SoongBuildMetrics{}
 
 	soongMetrics, ok := readSoongMetrics(config)
@@ -107,7 +107,7 @@
 	return metrics
 }
 
-func WriteMetrics(config Config, eventHandler metrics.EventHandler, metricsFile string) error {
+func WriteMetrics(config Config, eventHandler *metrics.EventHandler, metricsFile string) error {
 	metrics := collectMetrics(config, eventHandler)
 
 	buf, err := proto.Marshal(metrics)
diff --git a/android/ninja_deps_test.go b/android/ninja_deps_test.go
index 947c257..d6afcc0 100644
--- a/android/ninja_deps_test.go
+++ b/android/ninja_deps_test.go
@@ -18,21 +18,6 @@
 	"testing"
 )
 
-func init() {
-	// This variable uses ExistentPathForSource on a PackageVarContext, which is a PathContext
-	// that is not a PathGlobContext.  That requires the deps to be stored in the Config.
-	pctx.VariableFunc("test_ninja_deps_variable", func(ctx PackageVarContext) string {
-		// Using ExistentPathForSource to look for a file that does not exist in a directory that
-		// does exist (test_ninja_deps) from a PackageVarContext adds a dependency from build.ninja
-		// to the directory.
-		if ExistentPathForSource(ctx, "test_ninja_deps/does_not_exist").Valid() {
-			return "true"
-		} else {
-			return "false"
-		}
-	})
-}
-
 func testNinjaDepsSingletonFactory() Singleton {
 	return testNinjaDepsSingleton{}
 }
@@ -40,33 +25,19 @@
 type testNinjaDepsSingleton struct{}
 
 func (testNinjaDepsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	// Reference the test_ninja_deps_variable in a build statement so Blueprint is forced to
-	// evaluate it.
-	ctx.Build(pctx, BuildParams{
-		Rule:   Cp,
-		Input:  PathForTesting("foo"),
-		Output: PathForOutput(ctx, "test_ninja_deps_out"),
-		Args: map[string]string{
-			"cpFlags": "${test_ninja_deps_variable}",
-		},
-	})
+	ctx.Config().addNinjaFileDeps("foo")
 }
 
 func TestNinjaDeps(t *testing.T) {
-	fs := MockFS{
-		"test_ninja_deps/exists": nil,
-	}
-
 	result := GroupFixturePreparers(
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterSingletonType("test_ninja_deps_singleton", testNinjaDepsSingletonFactory)
 			ctx.RegisterSingletonType("ninja_deps_singleton", ninjaDepsSingletonFactory)
 		}),
-		fs.AddToFixture(),
 	).RunTest(t)
 
 	// Verify that the ninja file has a dependency on the test_ninja_deps directory.
-	if g, w := result.NinjaDeps, "test_ninja_deps"; !InList(w, g) {
+	if g, w := result.NinjaDeps, "foo"; !InList(w, g) {
 		t.Errorf("expected %q in %q", w, g)
 	}
 }
diff --git a/android/package_ctx.go b/android/package_ctx.go
index f354db8..c348c82 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -48,7 +48,7 @@
 
 var _ PathContext = &configErrorWrapper{}
 var _ errorfContext = &configErrorWrapper{}
-var _ PackageVarContext = &configErrorWrapper{}
+var _ PackageVarContext = &variableFuncContextWrapper{}
 var _ PackagePoolContext = &configErrorWrapper{}
 var _ PackageRuleContext = &configErrorWrapper{}
 
@@ -62,21 +62,33 @@
 	e.config.addNinjaFileDeps(deps...)
 }
 
-type PackageVarContext interface {
+type variableFuncContextWrapper struct {
+	configErrorWrapper
+	blueprint.VariableFuncContext
+}
+
+type PackagePoolContext interface {
 	PathContext
 	errorfContext
 }
 
-type PackagePoolContext PackageVarContext
-type PackageRuleContext PackageVarContext
+type PackageRuleContext PackagePoolContext
+
+type PackageVarContext interface {
+	PackagePoolContext
+	PathGlobContext
+}
 
 // VariableFunc wraps blueprint.PackageContext.VariableFunc, converting the interface{} config
 // argument to a PackageVarContext.
 func (p PackageContext) VariableFunc(name string,
 	f func(PackageVarContext) string) blueprint.Variable {
 
-	return p.PackageContext.VariableFunc(name, func(config interface{}) (string, error) {
-		ctx := &configErrorWrapper{p, config.(Config), nil}
+	return p.PackageContext.VariableFunc(name, func(bpctx blueprint.VariableFuncContext, config interface{}) (string, error) {
+		ctx := &variableFuncContextWrapper{
+			configErrorWrapper:  configErrorWrapper{p, config.(Config), nil},
+			VariableFuncContext: bpctx,
+		}
 		ret := f(ctx)
 		if len(ctx.errors) > 0 {
 			return "", ctx.errors[0]
diff --git a/android/paths.go b/android/paths.go
index 375297f..a6a54fa 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -39,6 +39,7 @@
 }
 
 type PathGlobContext interface {
+	PathContext
 	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
 }
 
@@ -56,7 +57,6 @@
 // EarlyModulePathContext is a subset of EarlyModuleContext methods required by the
 // Path methods. These path methods can be called before any mutators have run.
 type EarlyModulePathContext interface {
-	PathContext
 	PathGlobContext
 
 	ModuleDir() string
@@ -375,7 +375,7 @@
 // ExistentPathsForSources returns a list of Paths rooted from SrcDir, *not* rooted from the
 // module's local source directory, that are found in the tree. If any are not found, they are
 // omitted from the list, and dependencies are added so that we're re-run when they are added.
-func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
+func ExistentPathsForSources(ctx PathGlobContext, paths []string) Paths {
 	ret := make(Paths, 0, len(paths))
 	for _, path := range paths {
 		p := ExistentPathForSource(ctx, path)
@@ -1087,21 +1087,12 @@
 
 // existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
 // path does not exist.
-func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err error) {
+func existsWithDependencies(ctx PathGlobContext, path SourcePath) (exists bool, err error) {
 	var files []string
 
-	if gctx, ok := ctx.(PathGlobContext); ok {
-		// Use glob to produce proper dependencies, even though we only want
-		// a single file.
-		files, err = gctx.GlobWithDeps(path.String(), nil)
-	} else {
-		var result pathtools.GlobResult
-		// We cannot add build statements in this context, so we fall back to
-		// AddNinjaFileDeps
-		result, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
-		ctx.AddNinjaFileDeps(result.Deps...)
-		files = result.Matches
-	}
+	// Use glob to produce proper dependencies, even though we only want
+	// a single file.
+	files, err = ctx.GlobWithDeps(path.String(), nil)
 
 	if err != nil {
 		return false, fmt.Errorf("glob: %s", err.Error())
@@ -1124,7 +1115,7 @@
 	}
 
 	if modCtx, ok := ctx.(ModuleMissingDepsPathContext); ok && ctx.Config().AllowMissingDependencies() {
-		exists, err := existsWithDependencies(ctx, path)
+		exists, err := existsWithDependencies(modCtx, path)
 		if err != nil {
 			reportPathError(ctx, err)
 		}
@@ -1158,7 +1149,7 @@
 // rooted from the module's local source directory, if the path exists, or an empty OptionalPath if
 // it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state
 // of the path changes.
-func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
+func ExistentPathForSource(ctx PathGlobContext, pathComponents ...string) OptionalPath {
 	path, err := pathForSource(ctx, pathComponents...)
 	if err != nil {
 		reportPathError(ctx, err)
diff --git a/android/testing.go b/android/testing.go
index f9f9670..2256c96 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -1120,6 +1120,7 @@
 }
 
 func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) []AndroidMkEntries {
+	t.Helper()
 	var p AndroidMkEntriesProvider
 	var ok bool
 	if p, ok = mod.(AndroidMkEntriesProvider); !ok {
@@ -1134,6 +1135,7 @@
 }
 
 func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData {
+	t.Helper()
 	var p AndroidMkDataProvider
 	var ok bool
 	if p, ok = mod.(AndroidMkDataProvider); !ok {
diff --git a/apex/apex.go b/apex/apex.go
index b039d0d..72403f9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -225,7 +225,7 @@
 	// List of JNI libraries that are embedded inside this APEX.
 	Jni_libs []string
 
-	// List of rust dyn libraries
+	// List of rust dyn libraries that are embedded inside this APEX.
 	Rust_dyn_libs []string
 
 	// List of native executables that are embedded inside this APEX.
@@ -236,6 +236,41 @@
 
 	// List of filesystem images that are embedded inside this APEX bundle.
 	Filesystems []string
+
+	// List of native libraries to exclude from this APEX.
+	Exclude_native_shared_libs []string
+
+	// List of JNI libraries to exclude from this APEX.
+	Exclude_jni_libs []string
+
+	// List of rust dyn libraries to exclude from this APEX.
+	Exclude_rust_dyn_libs []string
+
+	// List of native executables to exclude from this APEX.
+	Exclude_binaries []string
+
+	// List of native tests to exclude from this APEX.
+	Exclude_tests []string
+
+	// List of filesystem images to exclude from this APEX bundle.
+	Exclude_filesystems []string
+}
+
+// Merge combines another ApexNativeDependencies into this one
+func (a *ApexNativeDependencies) Merge(b ApexNativeDependencies) {
+	a.Native_shared_libs = append(a.Native_shared_libs, b.Native_shared_libs...)
+	a.Jni_libs = append(a.Jni_libs, b.Jni_libs...)
+	a.Rust_dyn_libs = append(a.Rust_dyn_libs, b.Rust_dyn_libs...)
+	a.Binaries = append(a.Binaries, b.Binaries...)
+	a.Tests = append(a.Tests, b.Tests...)
+	a.Filesystems = append(a.Filesystems, b.Filesystems...)
+
+	a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...)
+	a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...)
+	a.Exclude_rust_dyn_libs = append(a.Exclude_rust_dyn_libs, b.Exclude_rust_dyn_libs...)
+	a.Exclude_binaries = append(a.Exclude_binaries, b.Exclude_binaries...)
+	a.Exclude_tests = append(a.Exclude_tests, b.Exclude_tests...)
+	a.Exclude_filesystems = append(a.Exclude_filesystems, b.Exclude_filesystems...)
 }
 
 type apexMultilibProperties struct {
@@ -675,12 +710,18 @@
 	// Use *FarVariation* to be able to depend on modules having conflicting variations with
 	// this module. This is required since arch variant of an APEX bundle is 'common' but it is
 	// 'arm' or 'arm64' for native shared libs.
-	ctx.AddFarVariationDependencies(binVariations, executableTag, nativeModules.Binaries...)
-	ctx.AddFarVariationDependencies(binVariations, testTag, nativeModules.Tests...)
-	ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
-	ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
-	ctx.AddFarVariationDependencies(rustLibVariations, sharedLibTag, nativeModules.Rust_dyn_libs...)
-	ctx.AddFarVariationDependencies(target.Variations(), fsTag, nativeModules.Filesystems...)
+	ctx.AddFarVariationDependencies(binVariations, executableTag,
+		android.RemoveListFromList(nativeModules.Binaries, nativeModules.Exclude_binaries)...)
+	ctx.AddFarVariationDependencies(binVariations, testTag,
+		android.RemoveListFromList(nativeModules.Tests, nativeModules.Exclude_tests)...)
+	ctx.AddFarVariationDependencies(libVariations, jniLibTag,
+		android.RemoveListFromList(nativeModules.Jni_libs, nativeModules.Exclude_jni_libs)...)
+	ctx.AddFarVariationDependencies(libVariations, sharedLibTag,
+		android.RemoveListFromList(nativeModules.Native_shared_libs, nativeModules.Exclude_native_shared_libs)...)
+	ctx.AddFarVariationDependencies(rustLibVariations, sharedLibTag,
+		android.RemoveListFromList(nativeModules.Rust_dyn_libs, nativeModules.Exclude_rust_dyn_libs)...)
+	ctx.AddFarVariationDependencies(target.Variations(), fsTag,
+		android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -748,12 +789,12 @@
 			continue
 		}
 
-		var depsList []ApexNativeDependencies
+		var deps ApexNativeDependencies
 
 		// Add native modules targeting both ABIs. When multilib.* is omitted for
 		// native_shared_libs/jni_libs/tests, it implies multilib.both
-		depsList = append(depsList, a.properties.Multilib.Both)
-		depsList = append(depsList, ApexNativeDependencies{
+		deps.Merge(a.properties.Multilib.Both)
+		deps.Merge(ApexNativeDependencies{
 			Native_shared_libs: a.properties.Native_shared_libs,
 			Tests:              a.properties.Tests,
 			Jni_libs:           a.properties.Jni_libs,
@@ -764,8 +805,8 @@
 		// binaries, it implies multilib.first
 		isPrimaryAbi := i == 0
 		if isPrimaryAbi {
-			depsList = append(depsList, a.properties.Multilib.First)
-			depsList = append(depsList, ApexNativeDependencies{
+			deps.Merge(a.properties.Multilib.First)
+			deps.Merge(ApexNativeDependencies{
 				Native_shared_libs: nil,
 				Tests:              nil,
 				Jni_libs:           nil,
@@ -776,34 +817,32 @@
 		// Add native modules targeting either 32-bit or 64-bit ABI
 		switch target.Arch.ArchType.Multilib {
 		case "lib32":
-			depsList = append(depsList, a.properties.Multilib.Lib32)
-			depsList = append(depsList, a.properties.Multilib.Prefer32)
+			deps.Merge(a.properties.Multilib.Lib32)
+			deps.Merge(a.properties.Multilib.Prefer32)
 		case "lib64":
-			depsList = append(depsList, a.properties.Multilib.Lib64)
+			deps.Merge(a.properties.Multilib.Lib64)
 			if !has32BitTarget {
-				depsList = append(depsList, a.properties.Multilib.Prefer32)
+				deps.Merge(a.properties.Multilib.Prefer32)
 			}
 		}
 
 		// Add native modules targeting a specific arch variant
 		switch target.Arch.ArchType {
 		case android.Arm:
-			depsList = append(depsList, a.archProperties.Arch.Arm.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.Arm.ApexNativeDependencies)
 		case android.Arm64:
-			depsList = append(depsList, a.archProperties.Arch.Arm64.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.Arm64.ApexNativeDependencies)
 		case android.Riscv64:
-			depsList = append(depsList, a.archProperties.Arch.Riscv64.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.Riscv64.ApexNativeDependencies)
 		case android.X86:
-			depsList = append(depsList, a.archProperties.Arch.X86.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.X86.ApexNativeDependencies)
 		case android.X86_64:
-			depsList = append(depsList, a.archProperties.Arch.X86_64.ApexNativeDependencies)
+			deps.Merge(a.archProperties.Arch.X86_64.ApexNativeDependencies)
 		default:
 			panic(fmt.Errorf("unsupported arch %v\n", ctx.Arch().ArchType))
 		}
 
-		for _, d := range depsList {
-			addDependenciesForNativeModules(ctx, d, target, imageVariation)
-		}
+		addDependenciesForNativeModules(ctx, deps, target, imageVariation)
 		ctx.AddFarVariationDependencies([]blueprint.Variation{
 			{Mutator: "os", Variation: target.OsVariation()},
 			{Mutator: "arch", Variation: target.ArchVariation()},
@@ -1854,24 +1893,24 @@
 	a.outputFile = a.outputApexFile
 	a.setCompression(ctx)
 
+	// TODO(b/257829940): These are used by the apex_keys_text singleton; would probably be a clearer
+	// interface if these were set in a provider rather than the module itself
 	a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[0])
 	a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[1])
 	a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[0])
 	a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[1])
+
 	apexType := a.properties.ApexType
 	switch apexType {
 	case imageApex:
-		// TODO(asmundak): Bazel does not create these files yet.
-		// b/190817312
+
+		// TODO(b/190817312): Generate the notice file from the apex rule.
 		a.htmlGzNotice = android.PathForBazelOut(ctx, "NOTICE.html.gz")
-		// b/239081457
-		a.bundleModuleFile = android.PathForBazelOut(ctx, a.Name()+apexType.suffix()+"-base.zip")
-		// b/239081455
-		a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.txt"))
-		// b/239081456
-		a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_backing.txt"))
-		// b/239084755
-		a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.xml"))
+		a.bundleModuleFile = android.PathForBazelOut(ctx, outputs.BundleFile)
+		a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.SymbolsUsedByApex))
+		a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.BackingLibs))
+		// TODO(b/239084755): Generate the java api using.xml file from Bazel.
+		a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.JavaSymbolsUsedByApex))
 		installSuffix := imageApexSuffix
 		if a.isCompressed {
 			installSuffix = imageCapexSuffix
@@ -2593,6 +2632,7 @@
 	module.AddProperties(
 		&apexBundleProperties{},
 		&apexTargetBundleProperties{},
+		&apexArchBundleProperties{},
 		&overridableProperties{},
 	)
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2e116c7..985ad59 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"os"
 	"path"
 	"path/filepath"
 	"reflect"
@@ -30,6 +29,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel/cquery"
 	"android/soong/bpf"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
@@ -4399,12 +4399,15 @@
 			name: "myapex",
 			key: "myapex.key",
 			updatable: false,
+			native_shared_libs: ["mylib.generic"],
 			arch: {
 				arm64: {
 					native_shared_libs: ["mylib.arm64"],
+					exclude_native_shared_libs: ["mylib.generic"],
 				},
 				x86_64: {
 					native_shared_libs: ["mylib.x64"],
+					exclude_native_shared_libs: ["mylib.generic"],
 				},
 			}
 		}
@@ -4416,6 +4419,18 @@
 		}
 
 		cc_library {
+			name: "mylib.generic",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
+
+		cc_library {
 			name: "mylib.arm64",
 			srcs: ["mylib.cpp"],
 			system_shared_libs: [],
@@ -4445,6 +4460,7 @@
 
 	// Ensure that apex variant is created for the direct dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib.arm64"), "android_arm64_armv8-a_shared_apex10000")
+	ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib.generic"), "android_arm64_armv8-a_shared_apex10000")
 	ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib.x64"), "android_arm64_armv8-a_shared_apex10000")
 
 	// Ensure that both direct and indirect deps are copied into apex
@@ -9730,6 +9746,86 @@
 	android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
 }
 
-func TestMain(m *testing.M) {
-	os.Exit(m.Run())
+func TestApexImageInMixedBuilds(t *testing.T) {
+	bp := `
+apex_key{
+	name: "foo_key",
+}
+apex {
+	name: "foo",
+	key: "foo_key",
+	updatable: true,
+	min_sdk_version: "31",
+	file_contexts: ":myapex-file_contexts",
+	bazel_module: { label: "//:foo" },
+}`
+
+	outputBaseDir := "out/bazel"
+	result := android.GroupFixturePreparers(
+		prepareForApexTest,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: outputBaseDir,
+				LabelToApexInfo: map[string]cquery.ApexInfo{
+					"//:foo": cquery.ApexInfo{
+						SignedOutput:          "signed_out.apex",
+						UnsignedOutput:        "unsigned_out.apex",
+						BundleKeyInfo:         []string{"public_key", "private_key"},
+						ContainerKeyInfo:      []string{"container_cert", "container_private"},
+						SymbolsUsedByApex:     "foo_using.txt",
+						JavaSymbolsUsedByApex: "foo_using.xml",
+						BundleFile:            "apex_bundle.zip",
+
+						// unused
+						PackageName:  "pkg_name",
+						ProvidesLibs: []string{"a", "b"},
+						RequiresLibs: []string{"c", "d"},
+					},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp)
+
+	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
+	ab, ok := m.(*apexBundle)
+	if !ok {
+		t.Fatalf("Expected module to be an apexBundle, was not")
+	}
+
+	if w, g := "out/bazel/execroot/__main__/public_key", ab.publicKeyFile.String(); w != g {
+		t.Errorf("Expected public key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/private_key", ab.privateKeyFile.String(); w != g {
+		t.Errorf("Expected private key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/container_cert", ab.containerCertificateFile.String(); w != g {
+		t.Errorf("Expected public container key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/container_private", ab.containerPrivateKeyFile.String(); w != g {
+		t.Errorf("Expected private container key %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/signed_out.apex", ab.outputFile.String(); w != g {
+		t.Errorf("Expected output file %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
+		t.Errorf("Expected output file %q, got %q", w, g)
+	}
+
+	if w, g := "out/bazel/execroot/__main__/foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
+		t.Errorf("Expected output file %q, got %q", w, g)
+	}
+
+	mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
+	var builder strings.Builder
+	mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
+
+	data := builder.String()
+	if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/apex_bundle.zip"; !strings.Contains(data, w) {
+		t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
+	}
 }
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index febca5d..eb44dd1 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -30,6 +30,7 @@
 	// be a subset of OutputFiles. (or shared libraries, this will be equal to OutputFiles,
 	// but general cc_library will also have dynamic libraries in output files).
 	RootDynamicLibraries []string
+	TidyFiles            []string
 	TocFile              string
 	UnstrippedOutput     string
 }
@@ -165,6 +166,12 @@
   # NOTE: It's OK if there's no ToC, as Soong just uses it for optimization
   pass
 
+tidy_files = []
+p = providers(target)
+clang_tidy_info = p.get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
+if clang_tidy_info:
+  tidy_files = [v.path for v in clang_tidy_info.tidy_files.to_list()]
+
 return json_encode({
 	"OutputFiles": outputFiles,
 	"CcObjectFiles": ccObjectFiles,
@@ -175,6 +182,7 @@
 	"Headers": headers,
 	"RootStaticArchives": rootStaticArchives,
 	"RootDynamicLibraries": rootSharedLibraries,
+	"TidyFiles": tidy_files,
 	"TocFile": toc_file,
 	"UnstrippedOutput": unstripped,
 })`
@@ -186,7 +194,9 @@
 // Starlark given in StarlarkFunctionBody.
 func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
 	var ccInfo CcInfo
-	parseJson(rawString, &ccInfo)
+	if err := parseJson(rawString, &ccInfo); err != nil {
+		return ccInfo, err
+	}
 	return ccInfo, nil
 }
 
@@ -218,26 +228,34 @@
     "bundle_key_info": [bundle_key_info.public_key.path, bundle_key_info.private_key.path],
     "container_key_info": [container_key_info.pem.path, container_key_info.pk8.path, container_key_info.key_name],
     "package_name": info.package_name,
+    "symbols_used_by_apex": info.symbols_used_by_apex.path,
+    "java_symbols_used_by_apex": info.java_symbols_used_by_apex.path,
+    "backing_libs": info.backing_libs.path,
+    "bundle_file": info.base_with_config_zip.path,
 })`
 }
 
-type ApexCqueryInfo struct {
-	SignedOutput     string   `json:"signed_output"`
-	UnsignedOutput   string   `json:"unsigned_output"`
-	ProvidesLibs     []string `json:"provides_native_libs"`
-	RequiresLibs     []string `json:"requires_native_libs"`
-	BundleKeyInfo    []string `json:"bundle_key_info"`
-	ContainerKeyInfo []string `json:"container_key_info"`
-	PackageName      string   `json:"package_name"`
+type ApexInfo struct {
+	SignedOutput          string   `json:"signed_output"`
+	UnsignedOutput        string   `json:"unsigned_output"`
+	ProvidesLibs          []string `json:"provides_native_libs"`
+	RequiresLibs          []string `json:"requires_native_libs"`
+	BundleKeyInfo         []string `json:"bundle_key_info"`
+	ContainerKeyInfo      []string `json:"container_key_info"`
+	PackageName           string   `json:"package_name"`
+	SymbolsUsedByApex     string   `json:"symbols_used_by_apex"`
+	JavaSymbolsUsedByApex string   `json:"java_symbols_used_by_apex"`
+	BackingLibs           string   `json:"backing_libs"`
+	BundleFile            string   `json:"bundle_file"`
 }
 
 // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
 // The given rawString must correspond to the string output which was created by evaluating the
 // Starlark given in StarlarkFunctionBody.
-func (g getApexInfoType) ParseResult(rawString string) ApexCqueryInfo {
-	var info ApexCqueryInfo
-	parseJson(rawString, &info)
-	return info
+func (g getApexInfoType) ParseResult(rawString string) (ApexInfo, error) {
+	var info ApexInfo
+	err := parseJson(rawString, &info)
+	return info, err
 }
 
 // getCcUnstrippedInfoType implements cqueryRequest interface. It handles the
@@ -266,10 +284,10 @@
 // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
 // The given rawString must correspond to the string output which was created by evaluating the
 // Starlark given in StarlarkFunctionBody.
-func (g getCcUnstippedInfoType) ParseResult(rawString string) CcUnstrippedInfo {
+func (g getCcUnstippedInfoType) ParseResult(rawString string) (CcUnstrippedInfo, error) {
 	var info CcUnstrippedInfo
-	parseJson(rawString, &info)
-	return info
+	err := parseJson(rawString, &info)
+	return info, err
 }
 
 type CcUnstrippedInfo struct {
@@ -289,10 +307,12 @@
 
 // parseJson decodes json string into the fields of the receiver.
 // Unknown attribute name causes panic.
-func parseJson(jsonString string, info interface{}) {
+func parseJson(jsonString string, info interface{}) error {
 	decoder := json.NewDecoder(strings.NewReader(jsonString))
 	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
-	if err := decoder.Decode(info); err != nil {
-		panic(fmt.Errorf("cannot parse cquery result '%s': %s", jsonString, err))
+	err := decoder.Decode(info)
+	if err != nil {
+		return fmt.Errorf("cannot parse cquery result '%s': %s", jsonString, err)
 	}
+	return nil
 }
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 42b42e1..a0a993f 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -3,10 +3,12 @@
 import (
 	"encoding/json"
 	"reflect"
+	"strings"
 	"testing"
 )
 
 func TestGetOutputFilesParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		input          string
@@ -29,14 +31,17 @@
 		},
 	}
 	for _, tc := range testCases {
-		actualOutput := GetOutputFiles.ParseResult(tc.input)
-		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput := GetOutputFiles.ParseResult(tc.input)
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
 	}
 }
 
 func TestGetPythonBinaryParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		input          string
@@ -54,14 +59,17 @@
 		},
 	}
 	for _, tc := range testCases {
-		actualOutput := GetPythonBinary.ParseResult(tc.input)
-		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput := GetPythonBinary.ParseResult(tc.input)
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
 	}
 }
 
 func TestGetCcInfoParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		inputCcInfo    CcInfo
@@ -73,24 +81,6 @@
 			expectedOutput: CcInfo{},
 		},
 		{
-			description: "only output",
-			inputCcInfo: CcInfo{
-				OutputFiles: []string{"test", "test3"},
-			},
-			expectedOutput: CcInfo{
-				OutputFiles: []string{"test", "test3"},
-			},
-		},
-		{
-			description: "only ToC",
-			inputCcInfo: CcInfo{
-				TocFile: "test",
-			},
-			expectedOutput: CcInfo{
-				TocFile: "test",
-			},
-		},
-		{
 			description: "all items set",
 			inputCcInfo: CcInfo{
 				OutputFiles:          []string{"out1", "out2"},
@@ -119,56 +109,135 @@
 		},
 	}
 	for _, tc := range testCases {
-		jsonInput, _ := json.Marshal(tc.inputCcInfo)
-		actualOutput, err := GetCcInfo.ParseResult(string(jsonInput))
-		if err != nil {
-			t.Errorf("%q:\n test case get error: %q", tc.description, err)
-		} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q:\n expected %#v\n!= actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			jsonInput, _ := json.Marshal(tc.inputCcInfo)
+			actualOutput, err := GetCcInfo.ParseResult(string(jsonInput))
+			if err != nil {
+				t.Errorf("error parsing result: %q", err)
+			} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v\n!= actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
+	}
+}
+
+func TestGetCcInfoParseResultsError(t *testing.T) {
+	t.Parallel()
+	testCases := []struct {
+		description   string
+		input         string
+		expectedError string
+	}{
+		{
+			description:   "not json",
+			input:         ``,
+			expectedError: `cannot parse cquery result '': EOF`,
+		},
+		{
+			description: "invalid field",
+			input: `{
+	"toc_file": "dir/file.so.toc"
+}`,
+			expectedError: `json: unknown field "toc_file"`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			_, err := GetCcInfo.ParseResult(tc.input)
+			if !strings.Contains(err.Error(), tc.expectedError) {
+				t.Errorf("expected string %q in error message, got %q", tc.expectedError, err)
+			}
+		})
 	}
 }
 
 func TestGetApexInfoParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		input          string
-		expectedOutput ApexCqueryInfo
+		expectedOutput ApexInfo
 	}{
 		{
 			description:    "no result",
 			input:          "{}",
-			expectedOutput: ApexCqueryInfo{},
+			expectedOutput: ApexInfo{},
 		},
 		{
 			description: "one result",
-			input: `{"signed_output":"my.apex",` +
-				`"unsigned_output":"my.apex.unsigned",` +
-				`"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],` +
-				`"bundle_key_info":["foo.pem", "foo.privkey"],` +
-				`"container_key_info":["foo.x509.pem", "foo.pk8", "foo"],` +
-				`"package_name":"package.name",` +
-				`"provides_native_libs":[]}`,
-			expectedOutput: ApexCqueryInfo{
-				SignedOutput:     "my.apex",
-				UnsignedOutput:   "my.apex.unsigned",
-				RequiresLibs:     []string{"//bionic/libc:libc", "//bionic/libdl:libdl"},
-				ProvidesLibs:     []string{},
-				BundleKeyInfo:    []string{"foo.pem", "foo.privkey"},
-				ContainerKeyInfo: []string{"foo.x509.pem", "foo.pk8", "foo"},
-				PackageName:      "package.name",
+			input: `{
+	"signed_output":"my.apex",
+	"unsigned_output":"my.apex.unsigned",
+	"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],
+	"bundle_key_info":["foo.pem", "foo.privkey"],
+	"container_key_info":["foo.x509.pem", "foo.pk8", "foo"],
+	"package_name":"package.name",
+	"symbols_used_by_apex": "path/to/my.apex_using.txt",
+	"backing_libs":"path/to/backing.txt",
+	"bundle_file": "dir/bundlefile.zip",
+	"provides_native_libs":[]
+}`,
+			expectedOutput: ApexInfo{
+				SignedOutput:      "my.apex",
+				UnsignedOutput:    "my.apex.unsigned",
+				RequiresLibs:      []string{"//bionic/libc:libc", "//bionic/libdl:libdl"},
+				ProvidesLibs:      []string{},
+				BundleKeyInfo:     []string{"foo.pem", "foo.privkey"},
+				ContainerKeyInfo:  []string{"foo.x509.pem", "foo.pk8", "foo"},
+				PackageName:       "package.name",
+				SymbolsUsedByApex: "path/to/my.apex_using.txt",
+				BackingLibs:       "path/to/backing.txt",
+				BundleFile:        "dir/bundlefile.zip",
 			},
 		},
 	}
 	for _, tc := range testCases {
-		actualOutput := GetApexInfo.ParseResult(tc.input)
-		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput, err := GetApexInfo.ParseResult(tc.input)
+			if err != nil {
+				t.Errorf("Unexpected error %q", err)
+			}
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
+	}
+}
+
+func TestGetApexInfoParseResultsError(t *testing.T) {
+	t.Parallel()
+	testCases := []struct {
+		description   string
+		input         string
+		expectedError string
+	}{
+		{
+			description:   "not json",
+			input:         ``,
+			expectedError: `cannot parse cquery result '': EOF`,
+		},
+		{
+			description: "invalid field",
+			input: `{
+	"fake_field": "path/to/file"
+}`,
+			expectedError: `json: unknown field "fake_field"`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			_, err := GetApexInfo.ParseResult(tc.input)
+			if !strings.Contains(err.Error(), tc.expectedError) {
+				t.Errorf("expected string %q in error message, got %q", tc.expectedError, err)
+			}
+		})
 	}
 }
 
 func TestGetCcUnstrippedParseResults(t *testing.T) {
+	t.Parallel()
 	testCases := []struct {
 		description    string
 		input          string
@@ -189,9 +258,45 @@
 		},
 	}
 	for _, tc := range testCases {
-		actualOutput := GetCcUnstrippedInfo.ParseResult(tc.input)
-		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
-		}
+		t.Run(tc.description, func(t *testing.T) {
+			actualOutput, err := GetCcUnstrippedInfo.ParseResult(tc.input)
+			if err != nil {
+				t.Errorf("Unexpected error %q", err)
+			}
+			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
+			}
+		})
+	}
+}
+
+func TestGetCcUnstrippedParseResultsErrors(t *testing.T) {
+	t.Parallel()
+	testCases := []struct {
+		description   string
+		input         string
+		expectedError string
+	}{
+		{
+			description:   "not json",
+			input:         ``,
+			expectedError: `cannot parse cquery result '': EOF`,
+		},
+		{
+			description: "invalid field",
+			input: `{
+	"fake_field": "path/to/file"
+}`,
+			expectedError: `json: unknown field "fake_field"`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			_, err := GetCcUnstrippedInfo.ParseResult(tc.input)
+			if !strings.Contains(err.Error(), tc.expectedError) {
+				t.Errorf("expected string %q in error message, got %q", tc.expectedError, err)
+			}
+		})
 	}
 }
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index a06b89e..5ab54e3 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -136,7 +136,7 @@
 
 type CodegenContext struct {
 	config             android.Config
-	context            android.Context
+	context            *android.Context
 	mode               CodegenMode
 	additionalDeps     []string
 	unconvertedDepMode unconvertedDepsMode
@@ -203,12 +203,12 @@
 	return ctx.additionalDeps
 }
 
-func (ctx *CodegenContext) Config() android.Config   { return ctx.config }
-func (ctx *CodegenContext) Context() android.Context { return ctx.context }
+func (ctx *CodegenContext) Config() android.Config    { return ctx.config }
+func (ctx *CodegenContext) Context() *android.Context { return ctx.context }
 
 // NewCodegenContext creates a wrapper context that conforms to PathContext for
 // writing BUILD files in the output directory.
-func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) *CodegenContext {
+func NewCodegenContext(config android.Config, context *android.Context, mode CodegenMode) *CodegenContext {
 	var unconvertedDeps unconvertedDepsMode
 	if config.IsEnvTrue("BP2BUILD_ERROR_UNCONVERTED") {
 		unconvertedDeps = errorModulesUnconvertedDeps
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 7c24a94..c40c45a 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -209,7 +209,7 @@
 			_, errs = ctx.PrepareBuildActions(config)
 			android.FailIfErrored(t, errs)
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, QueryView)
+			codegenCtx := NewCodegenContext(config, ctx.Context, QueryView)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 			if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
@@ -530,7 +530,7 @@
 				return
 			}
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 
@@ -903,7 +903,7 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 		bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 		android.FailIfErrored(t, err)
 		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
@@ -1156,7 +1156,7 @@
 			_, errs = ctx.ResolveDependencies(config)
 			android.FailIfErrored(t, errs)
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 			if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
@@ -1263,7 +1263,7 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 
 		// For each directory, test that the expected number of generated targets is correct.
 		for dir, expectedCount := range testCase.expectedCount {
@@ -1398,7 +1398,7 @@
 			if testCase.Dir != "" {
 				checkDir = testCase.Dir
 			}
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
 			android.FailIfErrored(t, err)
 			bazelTargets.sort()
diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go
index c4bbae2..272ebf5 100644
--- a/bp2build/performance_test.go
+++ b/bp2build/performance_test.go
@@ -22,11 +22,12 @@
 // run for longer, set -benchtime to a larger value.
 
 import (
-	"android/soong/android"
 	"fmt"
 	"math"
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 const (
@@ -105,7 +106,7 @@
 	ctx := android.NewTestContext(config)
 
 	registerCustomModuleForBp2buildConversion(ctx)
-	codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 	return testConfig{
 		config,
 		ctx,
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 31aa830..3750804 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -155,7 +155,7 @@
 	if tc.Dir != "" {
 		checkDir = tc.Dir
 	}
-	codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 	codegenCtx.unconvertedDepMode = tc.UnconvertedDepsMode
 	bazelTargets, errs := generateBazelTargetsForDir(codegenCtx, checkDir)
 	if tc.ExpectedErr != nil {
diff --git a/cc/cc.go b/cc/cc.go
index a8011b8..306e483 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1853,6 +1853,11 @@
 func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
 	bazelModuleLabel := c.getBazelModuleLabel(ctx)
 
+	bazelCtx := ctx.Config().BazelContext
+	if ccInfo, err := bazelCtx.GetCcInfo(bazelModuleLabel, android.GetConfigKey(ctx)); err == nil {
+		c.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+	}
+
 	c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel)
 
 	c.Properties.SubName = GetSubnameProperty(ctx, c)
@@ -2540,6 +2545,8 @@
 			}, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
 		}
 	}
+
+	updateImportedLibraryDependency(ctx)
 }
 
 func BeginMutator(ctx android.BottomUpMutatorContext) {
diff --git a/cc/config/global.go b/cc/config/global.go
index cf60414..9f18784 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -76,9 +76,6 @@
 		// Help catch common 32/64-bit errors.
 		"-Werror=int-conversion",
 
-		// Enable the new pass manager.
-		"-fexperimental-new-pass-manager",
-
 		// Disable overly aggressive warning for macros defined with a leading underscore
 		// This happens in AndroidConfig.h, which is included nearly everywhere.
 		// TODO: can we remove this now?
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index eb71aa1..052832d 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -244,4 +244,8 @@
 	return LibclangRuntimeLibrary(t, "fuzzer")
 }
 
+func LibFuzzerRuntimeInterceptors(t Toolchain) string {
+	return LibclangRuntimeLibrary(t, "fuzzer_interceptors")
+}
+
 var inList = android.InList
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 0fbe45c..64bb7dd 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -126,6 +126,14 @@
 		deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers")
 	} else {
 		deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
+		// Fuzzers built with HWASAN should use the interceptors for better
+		// mutation based on signals in strcmp, memcpy, etc. This is only needed for
+		// fuzz targets, not generic HWASAN-ified binaries or libraries.
+		if module, ok := ctx.Module().(*Module); ok {
+			if module.IsSanitizerEnabled(Hwasan) {
+				deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeInterceptors(ctx.toolchain()))
+			}
+		}
 	}
 
 	deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
@@ -137,9 +145,18 @@
 	// RunPaths on devices isn't instantiated by the base linker. `../lib` for
 	// installed fuzz targets (both host and device), and `./lib` for fuzz
 	// target packages.
-	flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
 	flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
 
+	// When running on device, fuzz targets with vendor: true set will be in
+	// fuzzer_name/vendor/fuzzer_name (note the extra 'vendor' and thus need to
+	// link with libraries in ../../lib/. Non-vendor binaries only need to look
+	// one level up, in ../lib/.
+	if ctx.inVendor() {
+		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../lib`)
+	} else {
+		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
+	}
+
 	return flags
 }
 
diff --git a/cc/library.go b/cc/library.go
index 79a22d6..03a5575 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -956,7 +956,7 @@
 	for _, path := range paths {
 		dir := path.String()
 		// Skip if dir is for generated headers
-		if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
+		if strings.HasPrefix(dir, ctx.Config().OutDir()) {
 			continue
 		}
 
@@ -2597,11 +2597,12 @@
 	m := mctx.Module().(*Module)
 	isLLNDK := m.IsLlndk()
 	isVendorPublicLibrary := m.IsVendorPublicLibrary()
+	isImportedApiLibrary := m.isImportedApiLibrary()
 
 	modules := mctx.CreateLocalVariations(variants...)
 	for i, m := range modules {
 
-		if variants[i] != "" || isLLNDK || isVendorPublicLibrary {
+		if variants[i] != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary {
 			// A stubs or LLNDK stubs variant.
 			c := m.(*Module)
 			c.sanitize = nil
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 760d36a..2fb21a3 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -15,6 +15,10 @@
 package cc
 
 import (
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/multitree"
 )
@@ -26,6 +30,30 @@
 func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
 	ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory)
+	ctx.RegisterModuleType("cc_api_variant", CcApiVariantFactory)
+}
+
+func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) {
+	m, ok := ctx.Module().(*Module)
+	if !ok {
+		return
+	}
+
+	apiLibrary, ok := m.linker.(*apiLibraryDecorator)
+	if !ok {
+		return
+	}
+
+	if m.UseVndk() && apiLibrary.hasLLNDKStubs() {
+		// Add LLNDK dependencies
+		for _, variant := range apiLibrary.properties.Variants {
+			if variant == "llndk" {
+				variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+				ctx.AddDependency(m, nil, variantName)
+				break
+			}
+		}
+	}
 }
 
 // 'cc_api_library' is a module type which is from the exported API surface
@@ -33,7 +61,8 @@
 // offer a link to the module that generates shared library object from the
 // map file.
 type apiLibraryProperties struct {
-	Src *string `android:"arch_variant"`
+	Src      *string `android:"arch_variant"`
+	Variants []string
 }
 
 type apiLibraryDecorator struct {
@@ -55,11 +84,9 @@
 	module.compiler = nil
 	module.linker = apiLibraryDecorator
 	module.installer = nil
+	module.library = apiLibraryDecorator
 	module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
 
-	// Mark module as stub, so APEX would not include this stub in the package.
-	module.library.setBuildStubs(true)
-
 	// Prevent default system libs (libc, libm, and libdl) from being linked
 	if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
 		apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
@@ -91,12 +118,45 @@
 }
 
 func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
-	// Export headers as system include dirs if specified. Mostly for libc
-	if Bool(d.libraryDecorator.Properties.Llndk.Export_headers_as_system) {
-		d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
-			d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
-			d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
-		d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
+	m, _ := ctx.Module().(*Module)
+
+	var in android.Path
+
+	if src := proptools.String(d.properties.Src); src != "" {
+		in = android.PathForModuleSrc(ctx, src)
+	}
+
+	// LLNDK variant
+	if m.UseVndk() && d.hasLLNDKStubs() {
+		apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+
+		var mod android.Module
+
+		ctx.VisitDirectDeps(func(depMod android.Module) {
+			if depMod.Name() == apiVariantModule {
+				mod = depMod
+			}
+		})
+
+		if mod != nil {
+			variantMod, ok := mod.(*CcApiVariant)
+			if ok {
+				in = variantMod.Src()
+
+				// Copy LLDNK properties to cc_api_library module
+				d.libraryDecorator.flagExporter.Properties.Export_include_dirs = append(
+					d.libraryDecorator.flagExporter.Properties.Export_include_dirs,
+					variantMod.exportProperties.Export_headers...)
+
+				// Export headers as system include dirs if specified. Mostly for libc
+				if proptools.Bool(variantMod.exportProperties.Export_headers_as_system) {
+					d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
+						d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
+						d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
+					d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
+				}
+			}
+		}
 	}
 
 	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
@@ -107,13 +167,10 @@
 	d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
 	d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
 
-	if d.properties.Src == nil {
-		ctx.PropertyErrorf("src", "src is a required property")
+	if in == nil {
+		ctx.PropertyErrorf("src", "Unable to locate source property")
+		return nil
 	}
-	// Skip the existence check of the stub prebuilt file.
-	// The file is not guaranteed to exist during Soong analysis.
-	// Build orchestrator will be responsible for creating a connected ninja graph.
-	in := android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), *d.properties.Src)
 
 	// Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file)
 	// The .so file itself has an order-only dependency on the headers contributed by this library.
@@ -143,6 +200,43 @@
 	return true
 }
 
+func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+	m, ok := ctx.Module().(*Module)
+
+	if !ok {
+		return nil
+	}
+
+	if d.hasLLNDKStubs() && m.UseVndk() {
+		// LLNDK libraries only need a single stubs variant.
+		return []string{android.FutureApiLevel.String()}
+	}
+
+	// TODO(b/244244438) Create more version information for NDK and APEX variations
+	// NDK variants
+	if m.MinSdkVersion() == "" {
+		return nil
+	}
+
+	firstVersion, err := nativeApiLevelFromUser(ctx,
+		m.MinSdkVersion())
+
+	if err != nil {
+		return nil
+	}
+
+	return ndkLibraryVersions(ctx, firstVersion)
+}
+
+func (d *apiLibraryDecorator) hasLLNDKStubs() bool {
+	for _, variant := range d.properties.Variants {
+		if strings.Contains(variant, "llndk") {
+			return true
+		}
+	}
+	return false
+}
+
 // 'cc_api_headers' is similar with 'cc_api_library', but which replaces
 // header libraries. The module will replace any dependencies to existing
 // original header libraries.
@@ -165,9 +259,6 @@
 	module.linker = apiHeadersDecorator
 	module.installer = nil
 
-	// Mark module as stub, so APEX would not include this stub in the package.
-	module.library.setBuildStubs(true)
-
 	// Prevent default system libs (libc, libm, and libdl) from being linked
 	if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil {
 		apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{}
@@ -189,3 +280,91 @@
 	// Stub from API surface should be available for any APEX.
 	return true
 }
+
+type ccApiexportProperties struct {
+	Src     *string `android:"arch_variant"`
+	Variant *string
+	Version *string
+}
+
+type variantExporterProperties struct {
+	// Header directory or library to export
+	Export_headers []string
+
+	// Export all headers as system include
+	Export_headers_as_system *bool
+}
+
+type CcApiVariant struct {
+	android.ModuleBase
+
+	properties       ccApiexportProperties
+	exportProperties variantExporterProperties
+
+	src android.Path
+}
+
+var _ android.Module = (*CcApiVariant)(nil)
+var _ android.ImageInterface = (*CcApiVariant)(nil)
+
+func CcApiVariantFactory() android.Module {
+	module := &CcApiVariant{}
+
+	module.AddProperties(&module.properties)
+	module.AddProperties(&module.exportProperties)
+
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+	return module
+}
+
+func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// No need to build
+
+	if proptools.String(v.properties.Src) == "" {
+		ctx.PropertyErrorf("src", "src is a required property")
+	}
+
+	// Skip the existence check of the stub prebuilt file.
+	// The file is not guaranteed to exist during Soong analysis.
+	// Build orchestrator will be responsible for creating a connected ninja graph.
+	v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), proptools.String(v.properties.Src))
+}
+
+func (v *CcApiVariant) Name() string {
+	version := proptools.String(v.properties.Version)
+	return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version)
+}
+
+func (v *CcApiVariant) Src() android.Path {
+	return v.src
+}
+
+func BuildApiVariantName(baseName string, variant string, version string) string {
+	names := []string{baseName, variant}
+	if version != "" {
+		names = append(names, version)
+	}
+
+	return strings.Join(names[:], ".") + multitree.GetApiImportSuffix()
+}
+
+// Implement ImageInterface to generate image variants
+func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext)               {}
+func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool          { return false }
+func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool       { return false }
+func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
+func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool  { return false }
+func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool      { return false }
+func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+	var variations []string
+	platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
+
+	if proptools.String(v.properties.Variant) == "llndk" {
+		variations = append(variations, VendorVariationPrefix+platformVndkVersion)
+		variations = append(variations, ProductVariationPrefix+platformVndkVersion)
+	}
+
+	return variations
+}
+func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 54b0ba6..8ce74c4 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -284,3 +284,54 @@
 	// These header files are required for compiling the other API domain (vendor in this case)
 	android.AssertStringListContains(t, "Vendor binary compilation should have an implicit dep on the stub .so file", vendorImplicits, "libfoo.so")
 }
+
+func TestApiLibraryWithLlndkVariant(t *testing.T) {
+	bp := `
+		cc_binary {
+			name: "binfoo",
+			vendor: true,
+			srcs: ["binfoo.cc"],
+			shared_libs: ["libbar"],
+		}
+
+		cc_api_library {
+			name: "libbar",
+			// TODO(b/244244438) Remove src property once all variants are implemented.
+			src: "libbar.so",
+			vendor_available: true,
+			variants: [
+				"llndk",
+			],
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "llndk",
+			src: "libbar_llndk.so",
+			export_headers: ["libbar_llndk_include"]
+		}
+
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libbar",
+			],
+			header_libs: [],
+		}
+	`
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	libfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module()
+	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
+	libbarApiVariant := ctx.ModuleForTests("libbar.llndk.apiimport", "android_vendor.29_arm64_armv8-a").Module()
+
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+	android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant))
+
+	libFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"]
+	android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", libFooLibFlags, "libbar_llndk.so")
+
+	libFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
+	android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", libFooCFlags, "-Ilibbar_llndk_include")
+}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 49a919e..d704e32 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -307,6 +307,7 @@
 	impl, ok := dep.(*Module)
 	if !ok {
 		ctx.ModuleErrorf("Implementation for stub is not correct module type")
+		return nil
 	}
 	output := impl.UnstrippedOutputFile()
 	if output == nil {
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 48ac650..2393f3e 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -41,6 +41,7 @@
 			static_libs: [
 				"libstatic",
 				"libnoasan",
+				"libstatic_asan",
 			],
 			sanitize: {
 				address: true,
@@ -57,6 +58,7 @@
 			static_libs: [
 				"libstatic",
 				"libnoasan",
+				"libstatic_asan",
 			],
 		}
 
@@ -92,6 +94,15 @@
 				address: false,
 			}
 		}
+
+		cc_library_static {
+			name: "libstatic_asan",
+			host_supported: true,
+			sanitize: {
+				address: true,
+			}
+		}
+
 	`
 
 	result := android.GroupFixturePreparers(
@@ -125,6 +136,10 @@
 		// Static library that never uses asan.
 		libNoAsan := result.ModuleForTests("libnoasan", staticVariant)
 
+		// Static library that specifies asan
+		libStaticAsan := result.ModuleForTests("libstatic_asan", staticAsanVariant)
+		libStaticAsanNoAsanVariant := result.ModuleForTests("libstatic_asan", staticVariant)
+
 		// expectSharedLinkDep verifies that the from module links against the to module as a
 		// shared library.
 		expectSharedLinkDep := func(from, to android.TestingModule) {
@@ -176,6 +191,7 @@
 
 		expectStaticLinkDep(binWithAsan, libStaticAsanVariant)
 		expectStaticLinkDep(binWithAsan, libNoAsan)
+		expectStaticLinkDep(binWithAsan, libStaticAsan)
 
 		expectInstallDep(binWithAsan, libShared)
 		expectInstallDep(binWithAsan, libAsan)
@@ -190,6 +206,7 @@
 
 		expectStaticLinkDep(binNoAsan, libStaticNoAsanVariant)
 		expectStaticLinkDep(binNoAsan, libNoAsan)
+		expectStaticLinkDep(binNoAsan, libStaticAsanNoAsanVariant)
 
 		expectInstallDep(binNoAsan, libShared)
 		expectInstallDep(binNoAsan, libAsan)
diff --git a/cc/sdk.go b/cc/sdk.go
index a83e5ad..a0d196b 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -78,5 +78,7 @@
 		}
 	case *snapshotModule:
 		ctx.CreateVariations("")
+	case *CcApiVariant:
+		ctx.CreateVariations("")
 	}
 }
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 0669f65..3fed1a1 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -187,14 +187,14 @@
 	globListFiles := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
 	ninjaDeps = append(ninjaDeps, globListFiles...)
 
-	writeDepFile(cmdlineArgs.OutFile, *ctx.EventHandler, ninjaDeps)
+	writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
 }
 
 // Run the code-generation phase to convert BazelTargetModules to BUILD files.
 func runQueryView(queryviewDir, queryviewMarker string, configuration android.Config, ctx *android.Context) {
 	ctx.EventHandler.Begin("queryview")
 	defer ctx.EventHandler.End("queryview")
-	codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
+	codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.QueryView)
 	absoluteQueryViewDir := shared.JoinPath(topDir, queryviewDir)
 	if err := createBazelWorkspace(codegenContext, absoluteQueryViewDir); err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
@@ -235,7 +235,7 @@
 	ninjaDeps = append(ninjaDeps, globs...)
 
 	// Run codegen to generate BUILD files
-	codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.ApiBp2build)
+	codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.ApiBp2build)
 	absoluteApiBp2buildDir := shared.JoinPath(topDir, bazelApiBp2buildDir)
 	if err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir); err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
@@ -266,7 +266,7 @@
 	ninjaDeps = append(ninjaDeps, symlinkDeps...)
 
 	workspaceMarkerFile := workspace + ".marker"
-	writeDepFile(workspaceMarkerFile, *ctx.EventHandler, ninjaDeps)
+	writeDepFile(workspaceMarkerFile, ctx.EventHandler, ninjaDeps)
 	touch(shared.JoinPath(topDir, workspaceMarkerFile))
 	return workspaceMarkerFile
 }
@@ -293,7 +293,7 @@
 	return ret
 }
 
-func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
+func writeMetrics(configuration android.Config, eventHandler *metrics.EventHandler, metricsDir string) {
 	if len(metricsDir) < 1 {
 		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
 		os.Exit(1)
@@ -333,7 +333,7 @@
 	return bootstrap.GlobFileListFiles(globDir)
 }
 
-func writeDepFile(outputFile string, eventHandler metrics.EventHandler, ninjaDeps []string) {
+func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
 	eventHandler.Begin("ninja_deps")
 	defer eventHandler.End("ninja_deps")
 	depFile := shared.JoinPath(topDir, outputFile+".d")
@@ -347,14 +347,14 @@
 // doChosenActivity runs Soong for a specific activity, like bp2build, queryview
 // or the actual Soong build for the build.ninja file. Returns the top level
 // output file of the specific activity.
-func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string) string {
+func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string, metricsDir string) string {
 	if configuration.BuildMode == android.SymlinkForest {
-		runSymlinkForestCreation(configuration, extraNinjaDeps)
+		runSymlinkForestCreation(configuration, extraNinjaDeps, metricsDir)
 		return symlinkForestMarker
 	} else if configuration.BuildMode == android.Bp2build {
 		// Run the alternate pipeline of bp2build mutators and singleton to convert
 		// Blueprint to BUILD files before everything else.
-		runBp2Build(configuration, extraNinjaDeps)
+		runBp2Build(configuration, extraNinjaDeps, metricsDir)
 		return bp2buildMarker
 	} else if configuration.IsMixedBuildsEnabled() {
 		runMixedModeBuild(configuration, ctx, extraNinjaDeps)
@@ -380,11 +380,11 @@
 		if configuration.BuildMode == android.GenerateQueryView {
 			queryviewMarkerFile := bazelQueryViewDir + ".marker"
 			runQueryView(bazelQueryViewDir, queryviewMarkerFile, configuration, ctx)
-			writeDepFile(queryviewMarkerFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(queryviewMarkerFile, ctx.EventHandler, ninjaDeps)
 			return queryviewMarkerFile
 		} else if configuration.BuildMode == android.GenerateModuleGraph {
 			writeJsonModuleGraphAndActions(ctx, moduleGraphFile, moduleActionsFile)
-			writeDepFile(moduleGraphFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(moduleGraphFile, ctx.EventHandler, ninjaDeps)
 			return moduleGraphFile
 		} else if configuration.BuildMode == android.GenerateDocFile {
 			// TODO: we could make writeDocs() return the list of documentation files
@@ -394,12 +394,12 @@
 				fmt.Fprintf(os.Stderr, "error building Soong documentation: %s\n", err)
 				os.Exit(1)
 			}
-			writeDepFile(docFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(docFile, ctx.EventHandler, ninjaDeps)
 			return docFile
 		} else {
 			// The actual output (build.ninja) was written in the RunBlueprint() call
 			// above
-			writeDepFile(cmdlineArgs.OutFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
 		}
 	}
 
@@ -465,10 +465,10 @@
 	ctx := newContext(configuration)
 	ctx.EventHandler.Begin("soong_build")
 
-	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps)
+	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps, logDir)
 
 	ctx.EventHandler.End("soong_build")
-	writeMetrics(configuration, *ctx.EventHandler, logDir)
+	writeMetrics(configuration, ctx.EventHandler, logDir)
 
 	writeUsedEnvironmentFile(configuration, finalOutputFile)
 }
@@ -614,8 +614,8 @@
 // Ideally, bp2build would write a file that contains instructions to the
 // symlink tree creation binary. Then the latter would not need to depend on
 // the very heavy-weight machinery of soong_build .
-func runSymlinkForestCreation(configuration android.Config, extraNinjaDeps []string) {
-	eventHandler := metrics.EventHandler{}
+func runSymlinkForestCreation(configuration android.Config, extraNinjaDeps []string, metricsDir string) {
+	eventHandler := &metrics.EventHandler{}
 
 	var ninjaDeps []string
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
@@ -651,7 +651,6 @@
 
 	writeDepFile(symlinkForestMarker, eventHandler, ninjaDeps)
 	touch(shared.JoinPath(topDir, symlinkForestMarker))
-	metricsDir := configuration.Getenv("LOG_DIR")
 	codegenMetrics := bp2build.ReadCodegenMetrics(metricsDir)
 	if codegenMetrics == nil {
 		m := bp2build.CreateCodegenMetrics()
@@ -660,15 +659,15 @@
 		//TODO (usta) we cannot determine if we loaded a stale file, i.e. from an unrelated prior
 		//invocation of codegen. We should simply use a separate .pb file
 	}
-	writeBp2BuildMetrics(codegenMetrics, configuration, eventHandler)
+	writeBp2BuildMetrics(codegenMetrics, eventHandler, metricsDir)
 }
 
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
-func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
+func runBp2Build(configuration android.Config, extraNinjaDeps []string, metricsDir string) {
 	var codegenMetrics *bp2build.CodegenMetrics
-	eventHandler := metrics.EventHandler{}
+	eventHandler := &metrics.EventHandler{}
 	eventHandler.Do("bp2build", func() {
 
 		// Register an alternate set of singletons and mutators for bazel
@@ -699,7 +698,7 @@
 
 		// Run the code-generation phase to convert BazelTargetModules to BUILD files
 		// and print conversion codegenMetrics to the user.
-		codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
+		codegenContext := bp2build.NewCodegenContext(configuration, bp2buildCtx, bp2build.Bp2Build)
 		eventHandler.Do("codegen", func() {
 			codegenMetrics = bp2build.Codegen(codegenContext)
 		})
@@ -716,12 +715,11 @@
 	if configuration.IsEnvTrue("BP2BUILD_VERBOSE") {
 		codegenMetrics.Print()
 	}
-	writeBp2BuildMetrics(codegenMetrics, configuration, eventHandler)
+	writeBp2BuildMetrics(codegenMetrics, eventHandler, metricsDir)
 }
 
 // Write Bp2Build metrics into $LOG_DIR
-func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics,
-	configuration android.Config, eventHandler metrics.EventHandler) {
+func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics, eventHandler *metrics.EventHandler, metricsDir string) {
 	for _, event := range eventHandler.CompletedEvents() {
 		codegenMetrics.AddEvent(&bp2build_metrics_proto.Event{
 			Name:      event.Id,
@@ -729,7 +727,6 @@
 			RealTime:  event.RuntimeNanoseconds(),
 		})
 	}
-	metricsDir := configuration.Getenv("LOG_DIR")
 	if len(metricsDir) < 1 {
 		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating bp2build metrics: LOG_DIR\n")
 		os.Exit(1)
diff --git a/java/config/config.go b/java/config/config.go
index 45b668b..49d88c4 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -43,6 +43,7 @@
 	InstrumentFrameworkModules = []string{
 		"framework",
 		"framework-minus-apex",
+		"ims-common",
 		"telephony-common",
 		"services",
 		"android.car",
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 2e5c361..54981e1 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -1152,7 +1152,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-WTFPL",
-    conditions: ["notice"],
+    conditions: ["permissive"],
     url: "https://spdx.org/licenses/WTFPL.html",
 }
 
diff --git a/scripts/gen_ndk_usedby_apex.sh b/scripts/gen_ndk_usedby_apex.sh
index 0d3ed5a..93d1370 100755
--- a/scripts/gen_ndk_usedby_apex.sh
+++ b/scripts/gen_ndk_usedby_apex.sh
@@ -19,6 +19,7 @@
 # For example, current line llvm-readelf output is:
 # 1: 00000000     0     FUNC      GLOBAL  DEFAULT   UND   dlopen@LIBC
 # After the parse function below "dlopen" would be write to the output file.
+
 printHelp() {
     echo "**************************** Usage Instructions ****************************"
     echo "This script is used to generate the Mainline modules used-by NDK symbols."
@@ -29,30 +30,33 @@
 }
 
 parseReadelfOutput() {
+  local readelfOutput=$1; shift
+  local ndkApisOutput=$1; shift
   while IFS= read -r line
   do
       if [[ $line = *FUNC*GLOBAL*UND*@* ]] ;
       then
-          echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "$2"
+          echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "${ndkApisOutput}"
       fi
-  done < "$1"
-  echo "" >> "$2"
+  done < "${readelfOutput}"
+  echo "" >> "${ndkApisOutput}"
 }
 
 unzipJarAndApk() {
-  tmpUnzippedDir="$1"/tmpUnzipped
-  [[ -e "$tmpUnzippedDir" ]] && rm -rf "$tmpUnzippedDir"
-  mkdir -p "$tmpUnzippedDir"
-  find "$1" -name "*.jar" -exec unzip -o {} -d "$tmpUnzippedDir" \;
-  find "$1" -name "*.apk" -exec unzip -o {} -d "$tmpUnzippedDir" \;
-  find "$tmpUnzippedDir" -name "*.MF" -exec rm {} \;
+  local dir="$1"; shift
+  local tmpUnzippedDir="$1"; shift
+  mkdir -p "${tmpUnzippedDir}"
+  find "$dir" -name "*.jar" -exec unzip -o {} -d "${tmpUnzippedDir}" \;
+  find "$dir" -name "*.apk" -exec unzip -o {} -d "${tmpUnzippedDir}" \;
+  find "${tmpUnzippedDir}" -name "*.MF" -exec rm {} \;
 }
 
 lookForExecFile() {
-  dir="$1"
-  readelf="$2"
-  find "$dir" -type f -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
-  find "$dir" -type f -perm /111 ! -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
+  local dir="$1"; shift
+  local readelf="$1"; shift
+  local tmpOutput="$1"; shift
+  find -L "$dir" -type f -name "*.so"  -exec "${readelf}" --dyn-symbols {} >> "${tmpOutput}" \;
+  find -L "$dir" -type f -perm /111 ! -name "*.so" -exec "${readelf}" --dyn-symbols {} >> "${tmpOutput}" \;
 }
 
 if [[ "$1" == "help" ]]
@@ -62,11 +66,22 @@
 then
   echo "Wrong argument length. Expecting 3 argument representing image file directory, llvm-readelf tool path, output path."
 else
-  unzipJarAndApk "$1"
-  lookForExecFile "$1" "$2"
-  tmpReadelfOutput="$1/../tmpReadelf.txt"
-  [[ -e "$3" ]] && rm "$3"
-  parseReadelfOutput "$tmpReadelfOutput" "$3"
-  [[ -e "$tmpReadelfOutput" ]] && rm "$tmpReadelfOutput"
-  rm -rf "$1/tmpUnzipped"
-fi
\ No newline at end of file
+  imageDir="$1"; shift
+  readelf="$1"; shift
+  outputFile="$1"; shift
+
+  tmpReadelfOutput=$(mktemp /tmp/temporary-file.XXXXXXXX)
+  tmpUnzippedDir=$(mktemp -d /tmp/temporary-dir.XXXXXXXX)
+  trap 'rm -rf -- "${tmpReadelfOutput}" "${tmpUnzippedDir}"' EXIT
+
+  # If there are any jars or apks, unzip them to surface native files.
+  unzipJarAndApk "${imageDir}" "${tmpUnzippedDir}"
+  # Analyze the unzipped files.
+  lookForExecFile "${tmpUnzippedDir}" "${readelf}" "${tmpReadelfOutput}"
+
+  # Analyze the apex image staging dir itself.
+  lookForExecFile "${imageDir}" "${readelf}" "${tmpReadelfOutput}"
+
+  [[ -e "${outputFile}" ]] && rm "${outputFile}"
+  parseReadelfOutput "${tmpReadelfOutput}" "${outputFile}"
+fi
diff --git a/symbol_inject/macho.go b/symbol_inject/macho.go
index 9946d34..ca3d50e 100644
--- a/symbol_inject/macho.go
+++ b/symbol_inject/macho.go
@@ -16,9 +16,12 @@
 
 import (
 	"debug/macho"
+	"encoding/binary"
 	"fmt"
 	"io"
+	"os"
 	"os/exec"
+	"path/filepath"
 	"sort"
 	"strings"
 )
@@ -98,6 +101,80 @@
 }
 
 func CodeSignMachoFile(path string) error {
-	cmd := exec.Command("/usr/bin/codesign", "--force", "-s", "-", path)
-	return cmd.Run()
+	filename := filepath.Base(path)
+	cmd := exec.Command("/usr/bin/codesign", "--force", "-s", "-", "-i", filename, path)
+	if err := cmd.Run(); err != nil {
+		return err
+	}
+	return modifyCodeSignFlags(path)
+}
+
+const LC_CODE_SIGNATURE = 0x1d
+const CSSLOT_CODEDIRECTORY = 0
+
+// To make codesign not invalidated by stripping, modify codesign flags to 0x20002
+// (adhoc | linkerSigned).
+func modifyCodeSignFlags(path string) error {
+	f, err := os.OpenFile(path, os.O_RDWR, 0)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	// Step 1: find code signature section.
+	machoFile, err := macho.NewFile(f)
+	if err != nil {
+		return err
+	}
+	var codeSignSectionOffset uint32 = 0
+	var codeSignSectionSize uint32 = 0
+	for _, l := range machoFile.Loads {
+		data := l.Raw()
+		cmd := machoFile.ByteOrder.Uint32(data)
+		if cmd == LC_CODE_SIGNATURE {
+			codeSignSectionOffset = machoFile.ByteOrder.Uint32(data[8:])
+			codeSignSectionSize = machoFile.ByteOrder.Uint32(data[12:])
+		}
+	}
+	if codeSignSectionOffset == 0 {
+		return fmt.Errorf("code signature section not found")
+	}
+
+	data := make([]byte, codeSignSectionSize)
+	_, err = f.ReadAt(data, int64(codeSignSectionOffset))
+	if err != nil {
+		return err
+	}
+
+	// Step 2: get flags offset.
+	blobCount := binary.BigEndian.Uint32(data[8:])
+	off := 12
+	var codeDirectoryOff uint32 = 0
+	for blobCount > 0 {
+		blobType := binary.BigEndian.Uint32(data[off:])
+		if blobType == CSSLOT_CODEDIRECTORY {
+			codeDirectoryOff = binary.BigEndian.Uint32(data[off+4:])
+			break
+		}
+		blobCount--
+		off += 8
+	}
+	if codeDirectoryOff == 0 {
+		return fmt.Errorf("no code directory in code signature section")
+	}
+	flagsOff := codeSignSectionOffset + codeDirectoryOff + 12
+
+	// Step 3: modify flags.
+	flagsData := make([]byte, 4)
+	_, err = f.ReadAt(flagsData, int64(flagsOff))
+	if err != nil {
+		return err
+	}
+	oldFlags := binary.BigEndian.Uint32(flagsData)
+	if oldFlags != 0x2 {
+		return fmt.Errorf("unexpected flags in code signature section: 0x%x", oldFlags)
+	}
+	binary.BigEndian.PutUint32(flagsData, 0x20002)
+	_, err = f.WriteAt(flagsData, int64(flagsOff))
+	return err
 }
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index ba5ba8b..d89e6b7 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -285,6 +285,35 @@
 
 }
 
+function test_create_global_include_directory() {
+  setup
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  # Soong needs to know if top level directories like hardware/ exist for use
+  # as global include directories.  Make sure that doesn't cause regens for
+  # unrelated changes to the top level directory.
+  mkdir -p system/core
+
+  run_soong
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime1" != "$mtime2" ]]; then
+    fail "Output Ninja file changed when top level directory changed"
+  fi
+
+  # Make sure it does regen if a missing directory in the path of a global
+  # include directory is added.
+  mkdir -p system/core/include
+
+  run_soong
+  local mtime3=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime2" = "$mtime3" ]]; then
+    fail "Output Ninja file did not change when global include directory created"
+  fi
+
+}
+
+
 function test_add_file_to_soong_build() {
   setup
   run_soong
@@ -874,6 +903,7 @@
 test_add_file_to_soong_build
 test_glob_during_bootstrapping
 test_soong_build_rerun_iff_environment_changes
+test_create_global_include_directory
 test_multiple_soong_build_modes
 test_dump_json_module_graph
 test_json_module_graph_back_and_forth_null_build