Merge "Add com.android.tools.r8.emitRecordAnnotationsExInDex flag"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index ff0d33e..d7bcc81 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -385,6 +385,7 @@
 		"build/bazel":/* recursive = */ true,
 		"build/make/core":/* recursive = */ false,
 		"build/bazel_common_rules":/* recursive = */ true,
+		"build/make/target/product/security":/* recursive = */ false,
 		// build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive.
 		"build/make/tools":/* recursive = */ false,
 		"build/pesto":/* recursive = */ true,
diff --git a/android/api_levels.go b/android/api_levels.go
index ea2afdf..7214ccb 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -344,14 +344,17 @@
 		}
 	}
 
-	canonical := ReplaceFinalizedCodenames(config, raw)
-	asInt, err := strconv.Atoi(canonical)
-	if err != nil {
-		return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical)
+	canonical, ok := getApiLevelsMapReleasedVersions()[raw]
+	if !ok {
+		asInt, err := strconv.Atoi(raw)
+		if err != nil {
+			return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw)
+		}
+		return uncheckedFinalApiLevel(asInt), nil
 	}
 
-	apiLevel := uncheckedFinalApiLevel(asInt)
-	return apiLevel, nil
+	return uncheckedFinalApiLevel(canonical), nil
+
 }
 
 // ApiLevelForTest returns an ApiLevel constructed from the supplied raw string.
diff --git a/android/config.go b/android/config.go
index 33deba5..6765f1f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -913,8 +913,16 @@
 		return c.PlatformSdkVersion()
 	}
 	codename := c.PlatformSdkCodename()
+	hostOnlyBuild := c.productVariables.DeviceArch == nil
 	if codename == "" {
-		return NoneApiLevel
+		// There are some host-only builds (those are invoked by build-prebuilts.sh) which
+		// don't set platform sdk codename. Platform sdk codename makes sense only when we
+		// are building the platform. So we don't enforce the below panic for the host-only
+		// builds.
+		if hostOnlyBuild {
+			return NoneApiLevel
+		}
+		panic("Platform_sdk_codename must be set")
 	}
 	if codename == "REL" {
 		panic("Platform_sdk_codename should not be REL when Platform_sdk_final is true")
@@ -1418,6 +1426,21 @@
 	return c.config.productVariables.PgoAdditionalProfileDirs
 }
 
+// AfdoProfile returns fully qualified path associated to the given module name
+func (c *deviceConfig) AfdoProfile(name string) (*string, error) {
+	for _, afdoProfile := range c.config.productVariables.AfdoProfiles {
+		split := strings.Split(afdoProfile, ":")
+		if len(split) != 3 {
+			return nil, fmt.Errorf("AFDO_PROFILES has invalid value: %s. "+
+				"The expected format is <module>:<fully-qualified-path-to-fdo_profile>", afdoProfile)
+		}
+		if split[0] == name {
+			return proptools.StringPtr(strings.Join([]string{split[1], split[2]}, ":")), nil
+		}
+	}
+	return nil, nil
+}
+
 func (c *deviceConfig) VendorSepolicyDirs() []string {
 	return c.config.productVariables.BoardVendorSepolicyDirs
 }
@@ -1894,3 +1917,7 @@
 func (c *config) BuildFromTextStub() bool {
 	return c.buildFromTextStub
 }
+
+func (c *config) SetBuildFromTextStub(b bool) {
+	c.buildFromTextStub = b
+}
diff --git a/android/filegroup.go b/android/filegroup.go
index 38de855..c259f21 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -126,7 +126,7 @@
 
 		props := bazel.BazelTargetModuleProperties{
 			Rule_class:        "aidl_library",
-			Bzl_load_location: "//build/bazel/rules/aidl:library.bzl",
+			Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
 		}
 
 		ctx.CreateBazelTargetModule(
diff --git a/android/namespace.go b/android/namespace.go
index f357ca7..c47a1c5 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -245,6 +245,10 @@
 	return allModules
 }
 
+func (r *NameResolver) SkippedModuleFromName(moduleName string, namespace blueprint.Namespace) (skipInfos []blueprint.SkippedModuleInfo, skipped bool) {
+	return r.rootNamespace.moduleContainer.SkippedModuleFromName(moduleName, namespace)
+}
+
 // parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a
 // module name
 func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) {
@@ -333,11 +337,16 @@
 
 	// determine which namespaces the module can be found in
 	foundInNamespaces := []string{}
+	skippedDepErrors := []error{}
 	for _, namespace := range r.sortedNamespaces.sortedItems() {
 		_, found := namespace.moduleContainer.ModuleFromName(depName, nil)
 		if found {
 			foundInNamespaces = append(foundInNamespaces, namespace.Path)
 		}
+		_, skipped := namespace.moduleContainer.SkippedModuleFromName(depName, nil)
+		if skipped {
+			skippedDepErrors = append(skippedDepErrors, namespace.moduleContainer.MissingDependencyError(depender, dependerNamespace, depName))
+		}
 	}
 	if len(foundInNamespaces) > 0 {
 		// determine which namespaces are visible to dependerNamespace
@@ -350,6 +359,9 @@
 		text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames)
 		text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces)
 	}
+	for _, err := range skippedDepErrors {
+		text += fmt.Sprintf("\n%s", err.Error())
+	}
 
 	return fmt.Errorf(text)
 }
diff --git a/android/packaging.go b/android/packaging.go
index 4a9b591..c764a6d 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -238,11 +238,11 @@
 
 // CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
 // entries into the specified directory.
-func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir ModuleOutPath) (entries []string) {
+func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
 	seenDir := make(map[string]bool)
 	for _, k := range SortedKeys(specs) {
 		ps := specs[k]
-		destPath := dir.Join(ctx, ps.relPathInPackage).String()
+		destPath := filepath.Join(dir.String(), ps.relPathInPackage)
 		destDir := filepath.Dir(destPath)
 		entries = append(entries, ps.relPathInPackage)
 		if _, ok := seenDir[destDir]; !ok {
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 5bb1e5a..1f01dc6 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -87,13 +87,13 @@
 // JavaLibraryName returns the soong module containing the Java APIs of that API surface.
 func (k SdkKind) JavaLibraryName(c Config) string {
 	name := k.defaultJavaLibraryName()
-	return JavaLibraryNameFromText(c, name)
+	return JavaApiLibraryName(c, name)
 }
 
-// JavaLibraryNameFromText returns the name of .txt equivalent of a java_library, but does
+// JavaApiLibraryName returns the name of .txt equivalent of a java_library, but does
 // not check if either module exists.
 // TODO: Return .txt (single-tree or multi-tree equivalents) based on config
-func JavaLibraryNameFromText(c Config, name string) string {
+func JavaApiLibraryName(c Config, name string) string {
 	if c.BuildFromTextStub() {
 		return name + ".from-text"
 	}
diff --git a/android/variable.go b/android/variable.go
index 1da5974..249d53b 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -464,6 +464,8 @@
 
 	IncludeTags    []string `json:",omitempty"`
 	SourceRootDirs []string `json:",omitempty"`
+
+	AfdoProfiles []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/apex.go b/apex/apex.go
index 3678636..5451a04 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1986,9 +1986,9 @@
 	// Set the output file to .apex or .capex depending on the compression configuration.
 	a.setCompression(ctx)
 	if a.isCompressed {
-		a.outputApexFile = android.PathForBazelOut(ctx, outputs.SignedCompressedOutput)
+		a.outputApexFile = android.PathForBazelOutRelative(ctx, ctx.ModuleDir(), outputs.SignedCompressedOutput)
 	} else {
-		a.outputApexFile = android.PathForBazelOut(ctx, outputs.SignedOutput)
+		a.outputApexFile = android.PathForBazelOutRelative(ctx, ctx.ModuleDir(), outputs.SignedOutput)
 	}
 	a.outputFile = a.outputApexFile
 
diff --git a/cc/Android.bp b/cc/Android.bp
index 5fd9afe..be2cc5a 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -21,6 +21,8 @@
     ],
     srcs: [
         "afdo.go",
+        "fdo_profile.go",
+
         "androidmk.go",
         "api_level.go",
         "bp2build.go",
diff --git a/cc/afdo.go b/cc/afdo.go
index d36f4af..4a8498b 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -18,11 +18,13 @@
 	"fmt"
 	"strings"
 
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
+// TODO(b/267229066): Remove globalAfdoProfileProjects after implementing bp2build converter for fdo_profile
 var (
 	globalAfdoProfileProjects = []string{
 		"vendor/google_data/pgo_profile/sampling/",
@@ -34,23 +36,23 @@
 
 const afdoCFlagsFormat = "-funique-internal-linkage-names -fprofile-sample-accurate -fprofile-sample-use=%s"
 
-func getAfdoProfileProjects(config android.DeviceConfig) []string {
-	return config.OnceStringSlice(afdoProfileProjectsConfigKey, func() []string {
-		return globalAfdoProfileProjects
-	})
-}
-
 func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
 	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
 }
 
+type afdoRdep struct {
+	VariationName *string
+	ProfilePath   *string
+}
+
 type AfdoProperties struct {
 	// Afdo allows developers self-service enroll for
 	// automatic feedback-directed optimization using profile data.
 	Afdo bool
 
-	AfdoTarget *string  `blueprint:"mutated"`
-	AfdoDeps   []string `blueprint:"mutated"`
+	FdoProfilePath *string `blueprint:"mutated"`
+
+	AfdoRDeps []afdoRdep `blueprint:"mutated"`
 }
 
 type afdo struct {
@@ -61,116 +63,131 @@
 	return []interface{}{&afdo.Properties}
 }
 
-func (afdo *afdo) AfdoEnabled() bool {
-	return afdo != nil && afdo.Properties.Afdo && afdo.Properties.AfdoTarget != nil
-}
-
-// Get list of profile file names, ordered by level of specialisation. For example:
-//  1. libfoo_arm64.afdo
-//  2. libfoo.afdo
-//
-// Add more specialisation as needed.
-func getProfileFiles(ctx android.BaseModuleContext, moduleName string) []string {
-	var files []string
-	files = append(files, moduleName+"_"+ctx.Arch().ArchType.String()+".afdo")
-	files = append(files, moduleName+".afdo")
-	return files
-}
-
-func (props *AfdoProperties) GetAfdoProfileFile(ctx android.BaseModuleContext, module string) android.OptionalPath {
-	// Test if the profile_file is present in any of the Afdo profile projects
-	for _, profileFile := range getProfileFiles(ctx, module) {
-		for _, profileProject := range getAfdoProfileProjects(ctx.DeviceConfig()) {
-			path := android.ExistentPathForSource(ctx, profileProject, profileFile)
-			if path.Valid() {
-				return path
-			}
-		}
-	}
-
-	// Record that this module's profile file is absent
-	missing := ctx.ModuleDir() + ":" + module
-	recordMissingAfdoProfileFile(ctx, missing)
-
-	return android.OptionalPathForPath(nil)
-}
-
-func (afdo *afdo) begin(ctx BaseModuleContext) {
-	if ctx.Host() {
-		return
-	}
-	if ctx.static() && !ctx.staticBinary() {
-		return
-	}
-	if afdo.Properties.Afdo {
-		module := ctx.ModuleName()
-		if afdo.Properties.GetAfdoProfileFile(ctx, module).Valid() {
-			afdo.Properties.AfdoTarget = proptools.StringPtr(module)
-		}
-	}
+// afdoEnabled returns true for binaries and shared libraries
+// that set afdo prop to True and there is a profile available
+func (afdo *afdo) afdoEnabled() bool {
+	return afdo != nil && afdo.Properties.Afdo && afdo.Properties.FdoProfilePath != nil
 }
 
 func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
-	if profile := afdo.Properties.AfdoTarget; profile != nil {
-		if profileFile := afdo.Properties.GetAfdoProfileFile(ctx, *profile); profileFile.Valid() {
-			profileFilePath := profileFile.Path()
+	if path := afdo.Properties.FdoProfilePath; path != nil {
+		profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
+		flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
 
-			profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, profileFile)
-			flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
-			flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
-			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
-
-			// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
-			// if profileFile gets updated
-			flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
-			flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
-		}
+		// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+		// if profileFile gets updated
+		pathForSrc := android.PathForSource(ctx, *path)
+		flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc)
+		flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc)
 	}
 
 	return flags
 }
 
-// Propagate afdo requirements down from binaries
+func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
+	if ctx.Host() {
+		return
+	}
+
+	if ctx.static() && !ctx.staticBinary() {
+		return
+	}
+
+	if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
+		if fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()); fdoProfileName != nil && err == nil {
+			actx.AddFarVariationDependencies(
+				[]blueprint.Variation{
+					{Mutator: "arch", Variation: actx.Target().ArchVariation()},
+					{Mutator: "os", Variation: "android"},
+				},
+				FdoProfileTag,
+				[]string{*fdoProfileName}...,
+			)
+		}
+	}
+}
+
+// FdoProfileMutator reads the FdoProfileProvider from a direct dep with FdoProfileTag
+// assigns FdoProfileInfo.Path to the FdoProfilePath mutated property
+func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
+	if !c.Enabled() {
+		return
+	}
+
+	ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
+		if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
+			info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
+			c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
+		}
+	})
+}
+
+var _ FdoProfileMutatorInterface = (*Module)(nil)
+
+// Propagate afdo requirements down from binaries and shared libraries
 func afdoDepsMutator(mctx android.TopDownMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && m.afdo.AfdoEnabled() {
-		afdoTarget := *m.afdo.Properties.AfdoTarget
-		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
-			tag := mctx.OtherModuleDependencyTag(dep)
-			libTag, isLibTag := tag.(libraryDependencyTag)
+	if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
+		if path := m.afdo.Properties.FdoProfilePath; path != nil {
+			mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+				tag := mctx.OtherModuleDependencyTag(dep)
+				libTag, isLibTag := tag.(libraryDependencyTag)
 
-			// Do not recurse down non-static dependencies
-			if isLibTag {
-				if !libTag.static() {
-					return false
+				// Do not recurse down non-static dependencies
+				if isLibTag {
+					if !libTag.static() {
+						return false
+					}
+				} else {
+					if tag != objDepTag && tag != reuseObjTag {
+						return false
+					}
 				}
-			} else {
-				if tag != objDepTag && tag != reuseObjTag {
-					return false
+
+				if dep, ok := dep.(*Module); ok {
+					dep.afdo.Properties.AfdoRDeps = append(
+						dep.afdo.Properties.AfdoRDeps,
+						afdoRdep{
+							VariationName: proptools.StringPtr(encodeTarget(m.Name())),
+							ProfilePath:   path,
+						},
+					)
 				}
-			}
 
-			if dep, ok := dep.(*Module); ok {
-				dep.afdo.Properties.AfdoDeps = append(dep.afdo.Properties.AfdoDeps, afdoTarget)
-			}
-
-			return true
-		})
+				return true
+			})
+		}
 	}
 }
 
 // Create afdo variants for modules that need them
 func afdoMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
-		if m.afdo.AfdoEnabled() && !m.static() {
-			afdoTarget := *m.afdo.Properties.AfdoTarget
-			mctx.SetDependencyVariation(encodeTarget(afdoTarget))
+		if !m.static() && m.afdo.Properties.Afdo && m.afdo.Properties.FdoProfilePath != nil {
+			mctx.SetDependencyVariation(encodeTarget(m.Name()))
+			return
 		}
 
 		variationNames := []string{""}
-		afdoDeps := android.FirstUniqueStrings(m.afdo.Properties.AfdoDeps)
-		for _, dep := range afdoDeps {
-			variationNames = append(variationNames, encodeTarget(dep))
+
+		variantNameToProfilePath := make(map[string]*string)
+
+		for _, afdoRDep := range m.afdo.Properties.AfdoRDeps {
+			variantName := *afdoRDep.VariationName
+			// An rdep can be set twice in AfdoRDeps because there can be
+			// more than one path from an afdo-enabled module to
+			// a static dep such as
+			// afdo_enabled_foo -> static_bar ----> static_baz
+			//                   \                      ^
+			//                    ----------------------|
+			// We only need to create one variant per unique rdep
+			if variantNameToProfilePath[variantName] == nil {
+				variationNames = append(variationNames, variantName)
+				variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
+			}
 		}
+
 		if len(variationNames) > 1 {
 			modules := mctx.CreateVariations(variationNames...)
 			for i, name := range variationNames {
@@ -180,7 +197,7 @@
 				variation := modules[i].(*Module)
 				variation.Properties.PreventInstall = true
 				variation.Properties.HideFromMake = true
-				variation.afdo.Properties.AfdoTarget = proptools.StringPtr(decodeTarget(name))
+				variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
 			}
 		}
 	}
diff --git a/cc/afdo_test.go b/cc/afdo_test.go
index 40f705b..1c20bfc 100644
--- a/cc/afdo_test.go
+++ b/cc/afdo_test.go
@@ -58,38 +58,77 @@
 		srcs: ["bar.c"],
 	}
 	`
-	prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libTest.afdo", "TEST")
 
 	result := android.GroupFixturePreparers(
+		PrepareForTestWithFdoProfile,
 		prepareForCcTest,
-		prepareForAfdoTest,
+		android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.AfdoProfiles = []string{
+				"libTest://afdo_profiles_package:libTest_afdo",
+			}
+		}),
+		android.MockFS{
+			"afdo_profiles_package/Android.bp": []byte(`
+				fdo_profile {
+					name: "libTest_afdo",
+					profile: "libTest.afdo",
+				}
+			`),
+		}.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
-	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
-	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
-	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
+	expectedCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
 
-	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+	libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
+	libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
+
+	// Check cFlags of afdo-enabled module and the afdo-variant of its static deps
+	cFlags := libTest.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edge from afdo-enabled module to static deps
+	if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) {
 		t.Errorf("libTest missing dependency on afdo variant of libFoo")
 	}
 
-	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+	if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) {
 		t.Errorf("libTest missing dependency on afdo variant of libBar")
 	}
 
-	cFlags := libTest.Rule("cc").Args["cFlags"]
-	if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) {
-		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", w, cFlags)
-	}
+	// Verify non-afdo variant exists and doesn't contain afdo
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
-	if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) {
-		t.Errorf("Expected 'libFoo' to enable afdo, but did not find %q in cflags %q", w, cFlags)
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+	}
+	cFlags = libBar.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
 	}
 
-	cFlags = libBar.Rule("cc").Args["cFlags"]
-	if w := "-fprofile-sample-accurate"; !strings.Contains(cFlags, w) {
-		t.Errorf("Expected 'libBar' to enable afdo, but did not find %q in cflags %q", w, cFlags)
+	// Check dependency edges of static deps
+	if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest should not depend on non-afdo variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
 	}
 }
 
@@ -113,11 +152,21 @@
 		name: "libBar",
 	}
 	`
-	prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libFoo.afdo", "TEST")
 
 	result := android.GroupFixturePreparers(
 		prepareForCcTest,
-		prepareForAfdoTest,
+		PrepareForTestWithFdoProfile,
+		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libFoo.afdo", ""),
+		android.MockFS{
+			"afdo_profiles_package/Android.bp": []byte(`
+				soong_namespace {
+				}
+				fdo_profile {
+					name: "libFoo_afdo",
+					profile: "libFoo.afdo",
+				}
+			`),
+		}.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared").Module()
@@ -150,7 +199,6 @@
 			t.Errorf("Expected no afdo variant of 'bar', got %q", v)
 		}
 	}
-
 }
 
 func TestAfdoEnabledWithRuntimeDepNoAfdo(t *testing.T) {
@@ -166,11 +214,24 @@
 		name: "libFoo",
 	}
 	`
-	prepareForAfdoTest := android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libTest.afdo", "TEST")
 
 	result := android.GroupFixturePreparers(
 		prepareForCcTest,
-		prepareForAfdoTest,
+		PrepareForTestWithFdoProfile,
+		android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.AfdoProfiles = []string{
+				"libTest://afdo_profiles_package:libTest_afdo",
+			}
+		}),
+		android.MockFS{
+			"afdo_profiles_package/Android.bp": []byte(`
+				fdo_profile {
+					name: "libTest_afdo",
+					profile: "libTest.afdo",
+				}
+			`),
+		}.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
 	libFooVariants := result.ModuleVariantsForTests("libFoo")
@@ -182,7 +243,6 @@
 }
 
 func TestAfdoEnabledWithMultiArchs(t *testing.T) {
-	t.Parallel()
 	bp := `
 	cc_library_shared {
 		name: "foo",
@@ -192,20 +252,43 @@
 	}
 `
 	result := android.GroupFixturePreparers(
+		PrepareForTestWithFdoProfile,
 		prepareForCcTest,
-		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm.afdo", "TEST"),
-		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm64.afdo", "TEST"),
+		android.FixtureAddTextFile("afdo_profiles_package/foo_arm.afdo", ""),
+		android.FixtureAddTextFile("afdo_profiles_package/foo_arm64.afdo", ""),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.AfdoProfiles = []string{
+				"foo://afdo_profiles_package:foo_afdo",
+			}
+		}),
+		android.MockFS{
+			"afdo_profiles_package/Android.bp": []byte(`
+				soong_namespace {
+				}
+				fdo_profile {
+					name: "foo_afdo",
+					arch: {
+						arm: {
+							profile: "foo_arm.afdo",
+						},
+						arm64: {
+							profile: "foo_arm64.afdo",
+						}
+					}
+				}
+			`),
+		}.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
 	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared")
 	fooArmCFlags := fooArm.Rule("cc").Args["cFlags"]
-	if w := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/foo_arm.afdo"; !strings.Contains(fooArmCFlags, w) {
+	if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm.afdo"; !strings.Contains(fooArmCFlags, w) {
 		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArmCFlags)
 	}
 
 	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a_shared")
 	fooArm64CFlags := fooArm64.Rule("cc").Args["cFlags"]
-	if w := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/foo_arm64.afdo"; !strings.Contains(fooArm64CFlags, w) {
+	if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm64.afdo"; !strings.Contains(fooArm64CFlags, w) {
 		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArm64CFlags)
 	}
 }
@@ -234,46 +317,65 @@
 	`
 
 	result := android.GroupFixturePreparers(
+		PrepareForTestWithFdoProfile,
 		prepareForCcTest,
-		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libTest.afdo", "TEST"),
-		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libBar.afdo", "TEST"),
+		android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
+		android.FixtureAddTextFile("afdo_profiles_package/libBar.afdo", ""),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.AfdoProfiles = []string{
+				"libTest://afdo_profiles_package:libTest_afdo",
+				"libBar://afdo_profiles_package:libBar_afdo",
+			}
+		}),
+		android.MockFS{
+			"afdo_profiles_package/Android.bp": []byte(`
+				fdo_profile {
+					name: "libTest_afdo",
+					profile: "libTest.afdo",
+				}
+				fdo_profile {
+					name: "libBar_afdo",
+					profile: "libBar.afdo",
+				}
+			`),
+		}.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
-	expectedCFlagLibTest := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/libTest.afdo"
-	expectedCFlagLibBar := "-fprofile-sample-use=toolchain/pgo-profiles/sampling/libBar.afdo"
+	expectedCFlagLibTest := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
+	expectedCFlagLibBar := "-fprofile-sample-use=afdo_profiles_package/libBar.afdo"
 
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
-	libTestAfdoVariantOfLibFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
+	libFooAfdoVariantWithLibTest := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
 
 	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_shared")
-	libBarAfdoVariantOfLibFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libBar")
+	libFooAfdoVariantWithLibBar := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libBar")
 
-	// Check cFlags of afdo-enabled modules and the afdo-variant of their static deps
+	// Check cFlags of afdo-enabled module and the afdo-variant of its static deps
 	cFlags := libTest.Rule("cc").Args["cFlags"]
 	if !strings.Contains(cFlags, expectedCFlagLibTest) {
 		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
 	}
 	cFlags = libBar.Rule("cc").Args["cFlags"]
 	if !strings.Contains(cFlags, expectedCFlagLibBar) {
-		t.Errorf("Expected 'libBar' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
+		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
 	}
 
-	cFlags = libTestAfdoVariantOfLibFoo.Rule("cc").Args["cFlags"]
+	cFlags = libFooAfdoVariantWithLibTest.Rule("cc").Args["cFlags"]
 	if !strings.Contains(cFlags, expectedCFlagLibTest) {
-		t.Errorf("Expected 'libTestAfdoVariantOfLibFoo' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
+		t.Errorf("Expected 'libFooAfdoVariantWithLibTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
 	}
 
-	cFlags = libBarAfdoVariantOfLibFoo.Rule("cc").Args["cFlags"]
+	cFlags = libFooAfdoVariantWithLibBar.Rule("cc").Args["cFlags"]
 	if !strings.Contains(cFlags, expectedCFlagLibBar) {
-		t.Errorf("Expected 'libBarAfdoVariantOfLibFoo' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
+		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
 	}
 
 	// Check dependency edges of static deps
-	if !hasDirectDep(result, libTest.Module(), libTestAfdoVariantOfLibFoo.Module()) {
+	if !hasDirectDep(result, libTest.Module(), libFooAfdoVariantWithLibTest.Module()) {
 		t.Errorf("libTest missing dependency on afdo variant of libFoo")
 	}
 
-	if !hasDirectDep(result, libBar.Module(), libBarAfdoVariantOfLibFoo.Module()) {
-		t.Errorf("libBar missing dependency on afdo variant of libFoo")
+	if !hasDirectDep(result, libBar.Module(), libFooAfdoVariantWithLibBar.Module()) {
+		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
 	}
 }
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 7c817a2..c8f516c 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -915,7 +915,7 @@
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{
 					Rule_class:        "aidl_library",
-					Bzl_load_location: "//build/bazel/rules/aidl:library.bzl",
+					Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
 				},
 				android.CommonAttributes{Name: aidlLibName},
 				&aidlLibraryAttributes{
diff --git a/cc/cc.go b/cc/cc.go
index b029d71..9c555a1 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -52,6 +52,7 @@
 		ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
 		ctx.BottomUp("version", versionMutator).Parallel()
 		ctx.BottomUp("begin", BeginMutator).Parallel()
+		ctx.BottomUp("fdo_profile", fdoProfileMutator)
 	})
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -763,6 +764,7 @@
 	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
 	stubImplDepTag        = dependencyTag{name: "stub_impl"}
 	JniFuzzLibTag         = dependencyTag{name: "jni_fuzz_lib_tag"}
+	FdoProfileTag         = dependencyTag{name: "fdo_profile"}
 )
 
 func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
@@ -1336,7 +1338,7 @@
 
 func (c *Module) isAfdoCompile() bool {
 	if afdo := c.afdo; afdo != nil {
-		return afdo.Properties.AfdoTarget != nil
+		return afdo.Properties.FdoProfilePath != nil
 	}
 	return false
 }
@@ -2162,9 +2164,6 @@
 	if c.lto != nil {
 		c.lto.begin(ctx)
 	}
-	if c.afdo != nil {
-		c.afdo.begin(ctx)
-	}
 	if c.pgo != nil {
 		c.pgo.begin(ctx)
 	}
@@ -2239,6 +2238,10 @@
 	}
 	ctx.ctx = ctx
 
+	if !actx.Host() || !ctx.static() || ctx.staticBinary() {
+		c.afdo.addDep(ctx, actx)
+	}
+
 	c.begin(ctx)
 }
 
diff --git a/cc/fdo_profile.go b/cc/fdo_profile.go
new file mode 100644
index 0000000..7fbe719
--- /dev/null
+++ b/cc/fdo_profile.go
@@ -0,0 +1,85 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+func init() {
+	RegisterFdoProfileBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterFdoProfileBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("fdo_profile", fdoProfileFactory)
+}
+
+type fdoProfile struct {
+	android.ModuleBase
+
+	properties fdoProfileProperties
+}
+
+type fdoProfileProperties struct {
+	Profile *string `android:"arch_variant"`
+}
+
+// FdoProfileInfo is provided by FdoProfileProvider
+type FdoProfileInfo struct {
+	Path android.Path
+}
+
+// FdoProfileProvider is used to provide path to an fdo profile
+var FdoProfileProvider = blueprint.NewMutatorProvider(FdoProfileInfo{}, "fdo_profile")
+
+// FdoProfileMutatorInterface is the interface implemented by fdo_profile module type
+// module types that can depend on an fdo_profile module
+type FdoProfileMutatorInterface interface {
+	// FdoProfileMutator eithers set or get FdoProfileProvider
+	fdoProfileMutator(ctx android.BottomUpMutatorContext)
+}
+
+var _ FdoProfileMutatorInterface = (*fdoProfile)(nil)
+
+// GenerateAndroidBuildActions of fdo_profile does not have any build actions
+func (fp *fdoProfile) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+// FdoProfileMutator sets FdoProfileProvider to fdo_profile module
+// or sets afdo.Properties.FdoProfilePath to path in FdoProfileProvider of the depended fdo_profile
+func (fp *fdoProfile) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
+	if fp.properties.Profile != nil {
+		path := android.PathForModuleSrc(ctx, *fp.properties.Profile)
+		ctx.SetProvider(FdoProfileProvider, FdoProfileInfo{
+			Path: path,
+		})
+	}
+}
+
+// fdoProfileMutator calls the generic fdoProfileMutator function of fdoProfileMutator
+// which is implemented by cc and cc.FdoProfile
+func fdoProfileMutator(ctx android.BottomUpMutatorContext) {
+	if f, ok := ctx.Module().(FdoProfileMutatorInterface); ok {
+		f.fdoProfileMutator(ctx)
+	}
+}
+
+func fdoProfileFactory() android.Module {
+	m := &fdoProfile{}
+	m.AddProperties(&m.properties)
+	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibBoth)
+	return m
+}
diff --git a/cc/testing.go b/cc/testing.go
index f78ea0f..ced0929 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -670,6 +670,12 @@
 	`),
 )
 
+// PrepareForTestWithFdoProfile registers module types to test with fdo_profile
+var PrepareForTestWithFdoProfile = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("soong_namespace", android.NamespaceFactory)
+	ctx.RegisterModuleType("fdo_profile", fdoProfileFactory)
+})
+
 // TestConfig is the legacy way of creating a test Config for testing cc modules.
 //
 // See testCc for an explanation as to how to stop using this deprecated method.
diff --git a/java/base.go b/java/base.go
index 1bcff2e..9911323 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1923,7 +1923,7 @@
 
 func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
 	switch name {
-	case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
+	case android.SdkCore.JavaLibraryName(ctx.Config()), "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
 		"stub-annotations", "private-stub-annotations-jar",
 		"core-lambda-stubs", "core-generated-annotation-stubs":
 		return javaCore, true
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index c07a94a..f692563 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -499,6 +499,8 @@
 		for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
 			// Add a dependency onto a possibly scope specific stub library.
 			scopeSpecificDependency := apiScope.scopeSpecificStubModule(ctx, additionalStubModule)
+			// Use JavaApiLibraryName function to be redirected to stubs generated from .txt if applicable
+			scopeSpecificDependency = android.JavaApiLibraryName(ctx.Config(), scopeSpecificDependency)
 			tag := hiddenAPIStubsDependencyTag{apiScope: apiScope, fromAdditionalDependency: true}
 			ctx.AddVariationDependencies(nil, tag, scopeSpecificDependency)
 		}
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index b9332dd..958f4ce 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -79,16 +79,25 @@
     ],
 }
 
+// Defaults module to strip out android annotations
+java_defaults {
+    name: "system-modules-no-annotations",
+    sdk_version: "none",
+    system_modules: "none",
+    jarjar_rules: "jarjar-strip-annotations-rules.txt",
+}
+
 // Same as core-current-stubs-for-system-modules, but android annotations are
 // stripped.
 java_library {
     name: "core-current-stubs-for-system-modules-no-annotations",
     visibility: ["//development/sdk"],
+    defaults: [
+        "system-modules-no-annotations",
+    ],
     static_libs: [
         "core-current-stubs-for-system-modules",
     ],
-    sdk_version: "none",
-    system_modules: "none",
     dists: [
         {
             // Legacy dist location for the public file.
@@ -100,7 +109,6 @@
             targets: dist_targets,
         },
     ],
-    jarjar_rules: "jarjar-strip-annotations-rules.txt",
 }
 
 // Used when compiling higher-level code against core.current.stubs.
@@ -158,16 +166,16 @@
 java_library {
     name: "core-module-lib-stubs-for-system-modules-no-annotations",
     visibility: ["//visibility:private"],
+    defaults: [
+        "system-modules-no-annotations",
+    ],
     static_libs: [
         "core-module-lib-stubs-for-system-modules",
     ],
-    sdk_version: "none",
-    system_modules: "none",
     dist: {
         dest: "system-modules/module-lib/core-for-system-modules-no-annotations.jar",
         targets: dist_targets,
     },
-    jarjar_rules: "jarjar-strip-annotations-rules.txt",
 }
 
 // Used when compiling higher-level code with sdk_version "module_current"
@@ -212,16 +220,16 @@
 java_library {
     name: "legacy.core.platform.api.no.annotations.stubs",
     visibility: core_platform_visibility,
+    defaults: [
+        "system-modules-no-annotations",
+    ],
     hostdex: true,
     compile_dex: true,
 
-    sdk_version: "none",
-    system_modules: "none",
     static_libs: [
         "legacy.core.platform.api.stubs",
     ],
     patch_module: "java.base",
-    jarjar_rules: "jarjar-strip-annotations-rules.txt",
 }
 
 java_library {
@@ -247,16 +255,16 @@
 java_library {
     name: "stable.core.platform.api.no.annotations.stubs",
     visibility: core_platform_visibility,
+    defaults: [
+        "system-modules-no-annotations",
+    ],
     hostdex: true,
     compile_dex: true,
 
-    sdk_version: "none",
-    system_modules: "none",
     static_libs: [
         "stable.core.platform.api.stubs",
     ],
     patch_module: "java.base",
-    jarjar_rules: "jarjar-strip-annotations-rules.txt",
 }
 
 // Used when compiling higher-level code against *.core.platform.api.stubs.
@@ -307,12 +315,6 @@
         // the UnsupportedAppUsage, CorePlatformApi and IntraCoreApi
         // annotations.
         "art.module.api.annotations.for.system.modules",
-
-        // Make nullability annotations available when compiling public stubs.
-        // They are provided as a separate library because while the
-        // annotations are not themselves part of the public API provided by
-        // this module they are used in the stubs.
-        "stub-annotations",
     ],
 }
 
@@ -349,3 +351,7 @@
         "art-module-intra-core-api-stubs-system-modules-lib",
     ],
 }
+
+build = [
+    "TxtStubLibraries.bp",
+]
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
new file mode 100644
index 0000000..b63ce42
--- /dev/null
+++ b/java/core-libraries/TxtStubLibraries.bp
@@ -0,0 +1,142 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file contains java_system_modules provided by the SDK.
+// These system modules transitively depend on core stub libraries generated from .txt files.
+
+// Same as core-public-stubs-system-modules, but the stubs are generated from .txt files
+java_system_modules {
+    name: "core-public-stubs-system-modules.from-text",
+    visibility: ["//visibility:public"],
+    libs: [
+        "core-current-stubs-for-system-modules-no-annotations.from-text",
+    ],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+java_library {
+    name: "core-current-stubs-for-system-modules-no-annotations.from-text",
+    visibility: ["//visibility:private"],
+    defaults: [
+        "system-modules-no-annotations",
+    ],
+    static_libs: [
+        "core.current.stubs.from-txt",
+        "core-lambda-stubs-for-system-modules",
+    ],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+// Same as core-module-lib-stubs-system-modules, but the stubs are generated from .txt files
+java_system_modules {
+    name: "core-module-lib-stubs-system-modules.from-text",
+    visibility: ["//visibility:public"],
+    libs: [
+        "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
+    ],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+java_library {
+    name: "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
+    visibility: ["//visibility:private"],
+    defaults: [
+        "system-modules-no-annotations",
+    ],
+    static_libs: [
+        "core.module_lib.stubs.txt",
+        "core-lambda-stubs-for-system-modules",
+    ],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+java_library {
+    name: "core.module_lib.stubs.from-text",
+    static_libs: [
+        "art.module.public.api.stubs.module_lib.from-text",
+
+        // Replace the following with the module-lib correspondence when Conscrypt or i18N module
+        // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
+        // @SystemApi(MODULE_LIBRARIES).
+        "conscrypt.module.public.api.stubs.from-text",
+        "i18n.module.public.api.stubs.from-text",
+    ],
+    sdk_version: "none",
+    system_modules: "none",
+    visibility: ["//visibility:private"],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+// Same as legacy-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
+java_system_modules {
+    name: "legacy-core-platform-api-stubs-system-modules.from-text",
+    visibility: core_platform_visibility,
+    libs: [
+        "legacy.core.platform.api.no.annotations.stubs.from-text",
+        "core-lambda-stubs-for-system-modules",
+    ],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+java_library {
+    name: "legacy.core.platform.api.no.annotations.stubs.from-text",
+    visibility: core_platform_visibility,
+    defaults: [
+        "system-modules-no-annotations",
+    ],
+    hostdex: true,
+    compile_dex: true,
+
+    static_libs: [
+        "legacy.core.platform.api.stubs.from-text",
+    ],
+    patch_module: "java.base",
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+// Same as stable-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
+java_system_modules {
+    name: "stable-core-platform-api-stubs-system-modules.from-text",
+    visibility: core_platform_visibility,
+    libs: [
+        "stable.core.platform.api.no.annotations.stubs.from-text",
+        "core-lambda-stubs-for-system-modules",
+    ],
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
+
+java_library {
+    name: "stable.core.platform.api.no.annotations.stubs.from-text",
+    visibility: core_platform_visibility,
+    defaults: [
+        "system-modules-no-annotations",
+    ],
+    hostdex: true,
+    compile_dex: true,
+
+    static_libs: [
+        "stable.core.platform.api.stubs.from-text",
+    ],
+    patch_module: "java.base",
+    // TODO: Enable after stub generation from .txt file is available
+    enabled: false,
+}
diff --git a/java/java.go b/java/java.go
index 499a6b6..97d5514 100644
--- a/java/java.go
+++ b/java/java.go
@@ -388,6 +388,8 @@
 	jniLibTag               = dependencyTag{name: "jnilib", runtimeLinked: true}
 	r8LibraryJarTag         = dependencyTag{name: "r8-libraryjar", runtimeLinked: true}
 	syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
+	javaApiContributionTag  = dependencyTag{name: "java-api-contribution"}
+	depApiSrcsTag           = dependencyTag{name: "dep-api-srcs"}
 	jniInstallTag           = installDependencyTag{name: "jni install"}
 	binaryInstallTag        = installDependencyTag{name: "binary install"}
 	usesLibReqTag           = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false)
@@ -1609,6 +1611,13 @@
 	})
 }
 
+type JavaApiLibraryDepsInfo struct {
+	StubsJar    android.Path
+	StubsSrcJar android.Path
+}
+
+var JavaApiLibraryDepsProvider = blueprint.NewProvider(JavaApiLibraryDepsInfo{})
+
 type ApiLibrary struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -1618,8 +1627,10 @@
 
 	properties JavaApiLibraryProperties
 
-	stubsSrcJar android.WritablePath
-	stubsJar    android.WritablePath
+	stubsSrcJar               android.WritablePath
+	stubsJar                  android.WritablePath
+	stubsJarWithoutStaticLibs android.WritablePath
+	extractedSrcJar           android.WritablePath
 	// .dex of stubs, used for hiddenapi processing
 	dexJarFile OptionalDexJarPath
 }
@@ -1645,8 +1656,13 @@
 	Libs []string
 
 	// List of java libs that this module has static dependencies to and will be
-	// passed in metalava invocation
+	// merge zipped after metalava invocation
 	Static_libs []string
+
+	// Java Api library to provide the full API surface text files and jar file.
+	// If this property is set, the provided full API surface text files and
+	// jar file are passed to metalava invocation.
+	Dep_api_srcs *string
 }
 
 func ApiLibraryFactory() android.Module {
@@ -1725,7 +1741,36 @@
 	}
 }
 
-var javaApiContributionTag = dependencyTag{name: "java-api-contribution"}
+// This method extracts the stub java files from the srcjar file provided from dep_api_srcs module
+// and replaces the java stubs generated by invoking metalava in this module.
+// This method is used because metalava can generate compilable from-text stubs only when
+// the codebase encompasses all classes listed in the input API text file, but a class can extend
+// a class that is not within the same API domain.
+func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.RuleBuilder, stubsDir android.OptionalPath, depApiSrcsSrcJar android.Path) {
+	generatedStubsList := android.PathForModuleOut(ctx, "metalava", "sources.txt")
+	unzippedSrcJarDir := android.PathForModuleOut(ctx, "metalava", "unzipDir")
+
+	rule.Command().
+		BuiltTool("list_files").
+		Text(stubsDir.String()).
+		FlagWithOutput("--out ", generatedStubsList).
+		FlagWithArg("--extensions ", ".java").
+		FlagWithArg("--root ", unzippedSrcJarDir.String())
+
+	rule.Command().
+		Text("unzip").
+		Flag("-q").
+		Input(depApiSrcsSrcJar).
+		FlagWithArg("-d ", unzippedSrcJarDir.String())
+
+	rule.Command().
+		BuiltTool("soong_zip").
+		Flag("-srcjar").
+		Flag("-write_if_changed").
+		FlagWithArg("-C ", unzippedSrcJarDir.String()).
+		FlagWithInput("-l ", generatedStubsList).
+		FlagWithOutput("-o ", al.stubsSrcJar)
+}
 
 func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	apiContributions := al.properties.Api_contributions
@@ -1734,6 +1779,9 @@
 	}
 	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
+	if al.properties.Dep_api_srcs != nil {
+		ctx.AddVariationDependencies(nil, depApiSrcsTag, String(al.properties.Dep_api_srcs))
+	}
 }
 
 func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1754,6 +1802,7 @@
 	var srcFiles android.Paths
 	var classPaths android.Paths
 	var staticLibs android.Paths
+	var depApiSrcsStubsSrcJar android.Path
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		tag := ctx.OtherModuleDependencyTag(dep)
 		switch tag {
@@ -1770,6 +1819,10 @@
 		case staticLibTag:
 			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
 			staticLibs = append(staticLibs, provider.HeaderJars...)
+		case depApiSrcsTag:
+			provider := ctx.OtherModuleProvider(dep, JavaApiLibraryDepsProvider).(JavaApiLibraryDepsInfo)
+			classPaths = append(classPaths, provider.StubsJar)
+			depApiSrcsStubsSrcJar = provider.StubsSrcJar
 		}
 	})
 
@@ -1780,21 +1833,31 @@
 		srcFiles = append(srcFiles, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), api))
 	}
 
+	if srcFiles == nil {
+		ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
+	}
+
 	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir)
 
 	al.stubsFlags(ctx, cmd, stubsDir)
 
 	al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
-	rule.Command().
-		BuiltTool("soong_zip").
-		Flag("-write_if_changed").
-		Flag("-jar").
-		FlagWithOutput("-o ", al.stubsSrcJar).
-		FlagWithArg("-C ", stubsDir.String()).
-		FlagWithArg("-D ", stubsDir.String())
+
+	if depApiSrcsStubsSrcJar != nil {
+		al.extractApiSrcs(ctx, rule, stubsDir, depApiSrcsStubsSrcJar)
+	} else {
+		rule.Command().
+			BuiltTool("soong_zip").
+			Flag("-write_if_changed").
+			Flag("-jar").
+			FlagWithOutput("-o ", al.stubsSrcJar).
+			FlagWithArg("-C ", stubsDir.String()).
+			FlagWithArg("-D ", stubsDir.String())
+	}
 
 	rule.Build("metalava", "metalava merged")
-	compiledStubs := android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar")
+
+	al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar")
 	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
 
 	var flags javaBuilderFlags
@@ -1802,14 +1865,14 @@
 	flags.javacFlags = strings.Join(al.properties.Javacflags, " ")
 	flags.classpath = classpath(classPaths)
 
-	TransformJavaToClasses(ctx, compiledStubs, 0, android.Paths{},
+	TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{},
 		android.Paths{al.stubsSrcJar}, flags, android.Paths{})
 
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().
 		BuiltTool("merge_zips").
 		Output(al.stubsJar).
-		Inputs(android.Paths{compiledStubs}).
+		Inputs(android.Paths{al.stubsJarWithoutStaticLibs}).
 		Inputs(staticLibs)
 	builder.Build("merge_zips", "merge jar files")
 
@@ -1835,6 +1898,11 @@
 		ImplementationJars:             android.PathsIfNonNil(al.stubsJar),
 		AidlIncludeDirs:                android.Paths{},
 	})
+
+	ctx.SetProvider(JavaApiLibraryDepsProvider, JavaApiLibraryDepsInfo{
+		StubsJar:    al.stubsJar,
+		StubsSrcJar: al.stubsSrcJar,
+	})
 }
 
 func (al *ApiLibrary) DexJarBuildPath() OptionalDexJarPath {
@@ -2772,7 +2840,7 @@
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{
 					Rule_class:        "aidl_library",
-					Bzl_load_location: "//build/bazel/rules/aidl:library.bzl",
+					Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
 				},
 				android.CommonAttributes{Name: aidlLibName},
 				&aidlLibraryAttributes{
@@ -2787,7 +2855,7 @@
 		ctx.CreateBazelTargetModule(
 			bazel.BazelTargetModuleProperties{
 				Rule_class:        "java_aidl_library",
-				Bzl_load_location: "//build/bazel/rules/java:aidl_library.bzl",
+				Bzl_load_location: "//build/bazel/rules/java:java_aidl_library.bzl",
 			},
 			android.CommonAttributes{Name: javaAidlLibName},
 			&javaAidlLibraryAttributes{
diff --git a/java/java_test.go b/java/java_test.go
index 68b749b..553b762 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2209,6 +2209,50 @@
 	}
 }
 
+func TestJavaApiLibraryDepApiSrcs(t *testing.T) {
+	provider_bp_a := `
+	java_api_contribution {
+		name: "foo1",
+		api_file: "foo1.txt",
+	}
+	`
+	provider_bp_b := `
+	java_api_contribution {
+		name: "foo2",
+		api_file: "foo2.txt",
+	}
+	`
+	lib_bp_a := `
+	java_api_library {
+		name: "lib1",
+		api_surface: "public",
+		api_contributions: ["foo1", "foo2"],
+	}
+	`
+
+	ctx, _ := testJavaWithFS(t, `
+		java_api_library {
+			name: "bar1",
+			api_surface: "public",
+			api_contributions: ["foo1"],
+			dep_api_srcs: "lib1",
+		}
+		`,
+		map[string][]byte{
+			"a/Android.bp": []byte(provider_bp_a),
+			"b/Android.bp": []byte(provider_bp_b),
+			"c/Android.bp": []byte(lib_bp_a),
+		})
+
+	m := ctx.ModuleForTests("bar1", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
+	manifestCommand := sboxProto.Commands[0].GetCommand()
+
+	android.AssertStringDoesContain(t, "Command expected to contain module srcjar file", manifestCommand, "bar1-stubs.srcjar")
+	android.AssertStringDoesContain(t, "Command expected to contain output files list text file flag", manifestCommand, "--out __SBOX_SANDBOX_DIR__/out/sources.txt")
+}
+
 func TestTradefedOptions(t *testing.T) {
 	result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
 java_test_host {
diff --git a/java/sdk.go b/java/sdk.go
index 72a5006..1b18ba4 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -148,10 +148,11 @@
 	toModule := func(module string, aidl android.Path) sdkDep {
 		// Select the kind of system modules needed for the sdk version.
 		systemModulesKind := systemModuleKind(sdkVersion.Kind, android.FutureApiLevel)
+		systemModules := android.JavaApiLibraryName(ctx.Config(), fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind))
 		return sdkDep{
 			useModule:          true,
 			bootclasspath:      []string{module, config.DefaultLambdaStubsLibrary},
-			systemModules:      fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind),
+			systemModules:      systemModules,
 			java9Classpath:     []string{module},
 			frameworkResModule: "framework-res",
 			aidl:               android.OptionalPathForPath(aidl),
@@ -196,8 +197,8 @@
 	case android.SdkCore:
 		return sdkDep{
 			useModule:        true,
-			bootclasspath:    []string{"core.current.stubs", config.DefaultLambdaStubsLibrary},
-			systemModules:    "core-public-stubs-system-modules",
+			bootclasspath:    []string{android.SdkCore.JavaLibraryName(ctx.Config()), config.DefaultLambdaStubsLibrary},
+			systemModules:    android.JavaApiLibraryName(ctx.Config(), "core-public-stubs-system-modules"),
 			noFrameworksLibs: true,
 		}
 	case android.SdkModule:
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 5477ed6..103f1ac 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1267,7 +1267,10 @@
 func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
 	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
 		// Add dependencies to the stubs library
-		ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
+		stubModuleName := module.stubsLibraryModuleName(apiScope)
+		// Use JavaApiLibraryName function to be redirected to stubs generated from .txt if applicable
+		stubModuleName = android.JavaApiLibraryName(ctx.Config(), stubModuleName)
+		ctx.AddVariationDependencies(nil, apiScope.stubsTag, stubModuleName)
 
 		// Add a dependency on the stubs source in order to access both stubs source and api information.
 		ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
diff --git a/java/testing.go b/java/testing.go
index 63d7dba..8a0db9c 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -368,6 +368,15 @@
 		"core.current.stubs",
 		"legacy.core.platform.api.stubs",
 		"stable.core.platform.api.stubs",
+		"android_stubs_current.from-text",
+		"android_system_stubs_current.from-text",
+		"android_test_stubs_current.from-text",
+		"android_module_lib_stubs_current.from-text",
+		"android_system_server_stubs_current.from-text",
+		"core.current.stubs.from-text",
+		"legacy.core.platform.api.stubs.from-text",
+		"stable.core.platform.api.stubs.from-text",
+
 		"kotlin-stdlib",
 		"kotlin-stdlib-jdk7",
 		"kotlin-stdlib-jdk8",
@@ -409,6 +418,10 @@
 		"core-module-lib-stubs-system-modules",
 		"legacy-core-platform-api-stubs-system-modules",
 		"stable-core-platform-api-stubs-system-modules",
+		"core-public-stubs-system-modules.from-text",
+		"core-module-lib-stubs-system-modules.from-text",
+		"legacy-core-platform-api-stubs-system-modules.from-text",
+		"stable-core-platform-api-stubs-system-modules.from-text",
 	}
 
 	for _, extra := range systemModules {
diff --git a/rust/afdo.go b/rust/afdo.go
index 996fd7e..3534ee6 100644
--- a/rust/afdo.go
+++ b/rust/afdo.go
@@ -17,7 +17,10 @@
 import (
 	"fmt"
 
+	"android/soong/android"
 	"android/soong/cc"
+
+	"github.com/google/blueprint"
 )
 
 const afdoFlagFormat = "-Zprofile-sample-use=%s"
@@ -30,19 +33,49 @@
 	return []interface{}{&afdo.Properties}
 }
 
-func (afdo *afdo) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
+	// afdo is not supported outside of Android
+	if ctx.Host() {
+		return
+	}
+
+	if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() {
+		fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName())
+		if err != nil {
+			ctx.ModuleErrorf("%s", err.Error())
+		}
+		if fdoProfileName != nil {
+			actx.AddFarVariationDependencies(
+				[]blueprint.Variation{
+					{Mutator: "arch", Variation: actx.Target().ArchVariation()},
+					{Mutator: "os", Variation: "android"},
+				},
+				cc.FdoProfileTag,
+				[]string{*fdoProfileName}...,
+			)
+		}
+	}
+}
+
+func (afdo *afdo) flags(ctx android.ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
 	if ctx.Host() {
 		return flags, deps
 	}
 
-	if afdo != nil && afdo.Properties.Afdo {
-		if profileFile := afdo.Properties.GetAfdoProfileFile(ctx, ctx.ModuleName()); profileFile.Valid() {
-			profileUseFlag := fmt.Sprintf(afdoFlagFormat, profileFile)
+	if !afdo.Properties.Afdo {
+		return flags, deps
+	}
+
+	ctx.VisitDirectDepsWithTag(cc.FdoProfileTag, func(m android.Module) {
+		if ctx.OtherModuleHasProvider(m, cc.FdoProfileProvider) {
+			info := ctx.OtherModuleProvider(m, cc.FdoProfileProvider).(cc.FdoProfileInfo)
+			path := info.Path
+			profileUseFlag := fmt.Sprintf(afdoFlagFormat, path.String())
 			flags.RustFlags = append(flags.RustFlags, profileUseFlag)
 
-			profileFilePath := profileFile.Path()
-			deps.AfdoProfiles = append(deps.AfdoProfiles, profileFilePath)
+			deps.AfdoProfiles = append(deps.AfdoProfiles, path)
 		}
-	}
+	})
+
 	return flags, deps
 }
diff --git a/rust/afdo_test.go b/rust/afdo_test.go
index fa20eef..0cdf704 100644
--- a/rust/afdo_test.go
+++ b/rust/afdo_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/cc"
 	"fmt"
 	"strings"
 	"testing"
@@ -31,13 +32,27 @@
 `
 	result := android.GroupFixturePreparers(
 		prepareForRustTest,
-		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo.afdo", ""),
+		cc.PrepareForTestWithFdoProfile,
+		android.FixtureAddTextFile("afdo_profiles_package/foo.afdo", ""),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.AfdoProfiles = []string{
+				"foo://afdo_profiles_package:foo_afdo",
+			}
+		}),
+		android.MockFS{
+			"afdo_profiles_package/Android.bp": []byte(`
+				fdo_profile {
+					name: "foo_afdo",
+					profile: "foo.afdo",
+				}
+			`),
+		}.AddToFixture(),
 		rustMockedFiles.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
 	foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
-	expectedCFlag := fmt.Sprintf(afdoFlagFormat, "toolchain/pgo-profiles/sampling/foo.afdo")
+	expectedCFlag := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo.afdo")
 
 	if !strings.Contains(foo.Args["rustcFlags"], expectedCFlag) {
 		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", expectedCFlag, foo.Args["rustcFlags"])
@@ -55,16 +70,37 @@
 `
 	result := android.GroupFixturePreparers(
 		prepareForRustTest,
-		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm.afdo", ""),
-		android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/foo_arm64.afdo", ""),
+		cc.PrepareForTestWithFdoProfile,
+		android.FixtureAddTextFile("afdo_profiles_package/foo_arm.afdo", ""),
+		android.FixtureAddTextFile("afdo_profiles_package/foo_arm64.afdo", ""),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.AfdoProfiles = []string{
+				"foo://afdo_profiles_package:foo_afdo",
+			}
+		}),
+		android.MockFS{
+			"afdo_profiles_package/Android.bp": []byte(`
+				fdo_profile {
+					name: "foo_afdo",
+					arch: {
+						arm: {
+							profile: "foo_arm.afdo",
+						},
+						arm64: {
+							profile: "foo_arm64.afdo",
+						}
+					}
+				}
+			`),
+		}.AddToFixture(),
 		rustMockedFiles.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
 	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Rule("rustc")
 	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
-	expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "toolchain/pgo-profiles/sampling/foo_arm.afdo")
-	expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "toolchain/pgo-profiles/sampling/foo_arm64.afdo")
+	expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm.afdo")
+	expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm64.afdo")
 
 	if !strings.Contains(fooArm.Args["rustcFlags"], expectedCFlagArm) {
 		t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm, fooArm.Args["rustcFlags"])
diff --git a/rust/builder.go b/rust/builder.go
index b89e7ad..0aef13d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -208,6 +208,9 @@
 			outDirPrefix = ""
 		}
 		envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String()))
+	} else {
+		// TODO(pcc): Change this to "OUT_DIR=" after fixing crates to not rely on this value.
+		envVars = append(envVars, "OUT_DIR=out")
 	}
 
 	return envVars
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 88e80fe..e30f25d 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -73,7 +73,7 @@
 	outDir := android.PathForModuleOut(ctx)
 	protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
 	grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
-	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust-deprecated")
 
 	commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
 	commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
@@ -206,7 +206,7 @@
 
 func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
 	deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
-	deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
+	deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
 	deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
 
 	if len(proto.Properties.Grpc_protos) > 0 {
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index f0f5ec0..0aa4549 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -42,14 +42,14 @@
 	`)
 	// Check that libprotobuf is added as a dependency.
 	librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
-	if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
-		t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
+	if !android.InList("libprotobuf_deprecated", librust_proto.Properties.AndroidMkDylibs) {
+		t.Errorf("libprotobuf_deprecated dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
 	}
 
 	// Make sure the correct plugin is being used.
 	librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
 	cmd := librust_proto_out.RuleParams.Command
-	if w := "protoc-gen-rust"; !strings.Contains(cmd, w) {
+	if w := "protoc-gen-rust-deprecated"; !strings.Contains(cmd, w) {
 		t.Errorf("expected %q in %q", w, cmd)
 	}
 
diff --git a/rust/rust.go b/rust/rust.go
index f85babc..56b4631 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -39,7 +39,6 @@
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
 		ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
-
 	})
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
@@ -920,7 +919,7 @@
 
 	// Calculate rustc flags
 	if mod.afdo != nil {
-		flags, deps = mod.afdo.flags(ctx, flags, deps)
+		flags, deps = mod.afdo.flags(actx, flags, deps)
 	}
 	if mod.compiler != nil {
 		flags = mod.compiler.compilerFlags(ctx, flags)
@@ -1516,7 +1515,7 @@
 		for _, lib := range deps.Rustlibs {
 			if autoDep.depTag == rlibDepTag {
 				// Handle the rlib deptag case
-				addRlibDependency(actx, lib, mod, snapshotInfo, rlibDepVariations)
+				addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations)
 			} else {
 				// autoDep.depTag is a dylib depTag. Not all rustlibs may be available as a dylib however.
 				// Check for the existence of the dylib deptag variant. Select it if available,
@@ -1527,7 +1526,7 @@
 					actx.AddVariationDependencies(autoDepVariations, autoDep.depTag, lib)
 				} else {
 					// If there's no dylib dependency available, try to add the rlib dependency instead.
-					addRlibDependency(actx, lib, mod, snapshotInfo, rlibDepVariations)
+					addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations)
 				}
 			}
 		}
@@ -1613,11 +1612,13 @@
 
 	// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
 	actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
+
+	mod.afdo.addDep(ctx, actx)
 }
 
 // addRlibDependency will add an rlib dependency, rewriting to the snapshot library if available.
-func addRlibDependency(actx android.BottomUpMutatorContext, lib string, mod *Module, snapshotInfo *cc.SnapshotInfo, variations []blueprint.Variation) {
-	lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
+func addRlibDependency(actx android.BottomUpMutatorContext, lib string, mod *Module, snapshotInfo **cc.SnapshotInfo, variations []blueprint.Variation) {
+	lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, snapshotInfo, actx).Rlibs)
 	actx.AddVariationDependencies(variations, rlibDepTag, lib)
 }
 
diff --git a/rust/testing.go b/rust/testing.go
index 24ca3d6..a33d948 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -127,7 +127,7 @@
 			min_sdk_version: "29",
 		}
 		rust_library {
-			name: "libprotobuf",
+			name: "libprotobuf_deprecated",
 			crate_name: "protobuf",
 			srcs: ["foo.rs"],
 			host_supported: true,
diff --git a/tests/lib.sh b/tests/lib.sh
index 26608b8..715eac1 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -94,9 +94,11 @@
   symlink_directory external/compiler-rt
   symlink_directory external/go-cmp
   symlink_directory external/golang-protobuf
+  symlink_directory external/licenseclassifier
   symlink_directory external/starlark-go
   symlink_directory external/python
   symlink_directory external/sqlite
+  symlink_directory external/spdx-tools
 
   touch "$MOCK_TOP/Android.bp"
 }
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 6066d70..a507349 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -37,9 +37,14 @@
   out_dir=out
   droid_target=
 fi
+
+function run_soong {
+  TARGET_PRODUCT="aosp_cf_x86_64_phone" TARGET_BUILD_VARIANT=userdebug OUT_DIR=$out_dir \
+    build/soong/soong_ui.bash --make-mode "$@"
+}
+
 # m droid, build sbom later in case additional dependencies might be built and included in partition images.
-TARGET_PRODUCT="aosp_cf_x86_64_phone" TARGET_BUILD_VARIANT=userdebug OUT_DIR=$out_dir \
-  build/soong/soong_ui.bash --make-mode $droid_target dump.erofs
+run_soong $droid_target dump.erofs lz4
 
 product_out=$out_dir/target/product/vsoc_x86_64
 sbom_test=$product_out/sbom_test
@@ -47,11 +52,11 @@
 cp $product_out/*.img $sbom_test
 
 # m sbom
-TARGET_PRODUCT="aosp_cf_x86_64_phone" TARGET_BUILD_VARIANT=userdebug OUT_DIR=$out_dir \
-  build/soong/soong_ui.bash --make-mode sbom
+run_soong sbom
 
 # Generate installed file list from .img files in PRODUCT_OUT
 dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
+lz4=$out_dir/host/linux-x86/bin/lz4
 
 declare -A diff_excludes
 diff_excludes[odm]="-I /odm/lib/modules"
@@ -60,24 +65,12 @@
  -I /vendor/lib/modules \
  -I /vendor/odm"
 diff_excludes[system]=\
-"-I /acct/ \
- -I /adb_keys \
- -I /apex/ \
- -I /bin \
+"-I /bin \
  -I /bugreports \
  -I /cache \
- -I /config/ \
  -I /d \
- -I /data/ \
- -I /data_mirror/ \
- -I /debug_ramdisk/ \
- -I /dev/ \
  -I /etc \
  -I /init \
- -I /init.environ.rc \
- -I /linkerconfig/ \
- -I /metadata/ \
- -I /mnt/ \
  -I /odm/app \
  -I /odm/bin \
  -I /odm_dlkm/etc \
@@ -89,16 +82,7 @@
  -I /odm/overlay \
  -I /odm/priv-app \
  -I /odm/usr \
- -I /oem/ \
- -I /postinstall/ \
- -I /proc/ \
- -I /product/ \
  -I /sdcard \
- -I /second_stage_resources/ \
- -I /storage/ \
- -I /sys/ \
- -I /system_dlkm/ \
- -I /system_ext/ \
  -I /system/lib64/android.hardware.confirmationui@1.0.so \
  -I /system/lib64/android.hardware.confirmationui-V1-ndk.so \
  -I /system/lib64/android.hardware.keymaster@4.1.so \
@@ -121,15 +105,29 @@
  -I /system/system_ext \
  -I /system/usr/icu \
  -I /system/vendor \
- -I /vendor/ \
  -I /vendor_dlkm/etc"
 
+ function diff_files {
+   file_list_file="$1";
+   files_in_spdx_file="$2"
+   partition_name="$3"
+   exclude=
+   if [ -v 'diff_excludes[$partition_name]' ]; then
+     exclude=${diff_excludes[$partition_name]}
+   fi
+
+   diff "$file_list_file" "$files_in_spdx_file" $exclude
+   if [ $? != "0" ]; then
+     echo Found diffs in $f and SBOM.
+     exit 1
+   else
+     echo No diffs.
+   fi
+ }
+
 # Example output of dump.erofs is as below, and the data used in the test start
 # at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name.
-# Each line is captured in variable "entry", sed is used to trim the leading
-# spaces and cut is used to get field 1 every time. Once a field is extracted,
-# "cut --complement" is used to remove the extracted field so next field can be
-# processed in the same way and to be processed field is always field 1.
+# Each line is captured in variable "entry", awk is used to get type and name.
 # Output of dump.erofs:
 #     File : /
 #     Size: 160  On-disk size: 160  directory
@@ -170,16 +168,13 @@
     all_dirs=$(echo "$all_dirs" | cut -d ' ' -f1 --complement -s)
     entries=$($dump_erofs --ls --path "$dir" $f | tail -n +11)
     while read -r entry; do
-      nid=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
-      entry=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1 --complement)
-      type=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
-      entry=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1 --complement)
-      name=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
+      type=$(echo $entry | awk -F ' ' '{print $2}')
+      name=$(echo $entry | awk -F ' ' '{print $3}')
       case $type in
         "2")  # directory
           all_dirs=$(echo "$all_dirs $dir/$name" | sed 's/^\s*//')
           ;;
-        *)
+        "1"|"7")  # 1: file, 7: symlink
           (
           if [ "$partition_name" != "system" ]; then
             # system partition is mounted to /, not to prepend partition name.
@@ -193,18 +188,26 @@
   done
   sort -n -o "$file_list_file" "$file_list_file"
 
-  # Diff
+  grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' > "$files_in_spdx_file"
+  if [ "$partition_name" = "system" ]; then
+    # system partition is mounted to /, so include FileName starts with /root/ too.
+    grep "FileName: /root/" $product_out/sbom.spdx | sed 's/^FileName: \/root//' >> "$files_in_spdx_file"
+  fi
+  sort -n -o "$files_in_spdx_file" "$files_in_spdx_file"
+
   echo ============ Diffing files in $f and SBOM
+  diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
+done
+
+RAMDISK_IMAGES="$product_out/ramdisk.img"
+for f in $RAMDISK_IMAGES; do
+  partition_name=$(basename $f | cut -d. -f1)
+  file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
+  files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+  $lz4 -c -d $f | cpio -tv 2>/dev/null | grep '^[-l]' | awk -F ' ' '{print $9}' | sed "s:^:/$partition_name/:" | sort -n > "$file_list_file"
+
   grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"
-  exclude=
-  if [ -v 'diff_excludes[$partition_name]' ]; then
-    exclude=${diff_excludes[$partition_name]}
-  fi
-  diff "$file_list_file" "$files_in_spdx_file" $exclude
-  if [ $? != "0" ]; then
-    echo Found diffs in $f and SBOM.
-    exit 1
-  else
-    echo No diffs.
-  fi
+
+  echo ============ Diffing files in $f and SBOM
+  diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
 done
\ No newline at end of file