Merge "Implement API surface import with APEX stub"
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c94bbbb..707cc63 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -9788,30 +9788,85 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
-			native_shared_libs: ["libfoo"],
+			native_shared_libs: ["libbaz"],
+			binaries: ["binfoo"],
 			min_sdk_version: "29",
 		}
 		apex_key {
 			name: "myapex.key",
 		}
-		cc_library {
-			name: "libfoo",
-			shared_libs: ["libc"],
+		cc_binary {
+			name: "binfoo",
+			shared_libs: ["libbar", "libbaz", "libqux",],
 			apex_available: ["myapex"],
 			min_sdk_version: "29",
+			recovery_available: false,
+		}
+		cc_library {
+			name: "libbar",
+			srcs: ["libbar.cc"],
+			stubs: {
+				symbol_file: "libbar.map.txt",
+				versions: [
+					"29",
+				],
+			},
+		}
+		cc_library {
+			name: "libbaz",
+			srcs: ["libbaz.cc"],
+			apex_available: ["myapex"],
+			min_sdk_version: "29",
+			stubs: {
+				symbol_file: "libbaz.map.txt",
+				versions: [
+					"29",
+				],
+			},
 		}
 		cc_api_library {
-			name: "libc",
-			src: "libc.so",
+			name: "libbar",
+			src: "libbar_stub.so",
 			min_sdk_version: "29",
-			recovery_available: true,
+			variants: ["apex.29"],
+		}
+		cc_api_variant {
+			name: "libbar",
+			variant: "apex",
+			version: "29",
+			src: "libbar_apex_29.so",
+		}
+		cc_api_library {
+			name: "libbaz",
+			src: "libbaz_stub.so",
+			min_sdk_version: "29",
+			variants: ["apex.29"],
+		}
+		cc_api_variant {
+			name: "libbaz",
+			variant: "apex",
+			version: "29",
+			src: "libbaz_apex_29.so",
+		}
+		cc_api_library {
+			name: "libqux",
+			src: "libqux_stub.so",
+			min_sdk_version: "29",
+			variants: ["apex.29"],
+		}
+		cc_api_variant {
+			name: "libqux",
+			variant: "apex",
+			version: "29",
+			src: "libqux_apex_29.so",
 		}
 		api_imports {
 			name: "api_imports",
-			shared_libs: [
-				"libc",
+			apex_shared_libs: [
+				"libbar",
+				"libbaz",
+				"libqux",
 			],
-			header_libs: [],
 		}
 		`
 	result := testApex(t, bp)
@@ -9827,17 +9882,107 @@
 		return found
 	}
 
-	libfooApexVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex29").Module()
-	libcApexVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared_apex29").Module()
+	// Library defines stubs and cc_api_library should be used with cc_api_library
+	binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Module()
+	libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+	libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
 
-	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(libfooApexVariant, libcApexVariant))
+	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
+	android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
 
-	// libfoo core variant should be buildable in the same inner tree since
-	// certain mcombo files might build system and apexes in the same inner tree
-	// libfoo core variant should link against source libc
-	libfooCoreVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
-	libcCoreVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared").Module()
-	android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
+	binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Rule("ld").Args["libFlags"]
+	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
+	android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
+	android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
+
+	// Library defined in the same APEX should be linked with original definition instead of cc_api_library
+	libbazApexVariant := result.ModuleForTests("libbaz", "android_arm64_armv8-a_shared_apex29").Module()
+	libbazApiImportCoreVariant := result.ModuleForTests("libbaz.apiimport", "android_arm64_armv8-a_shared").Module()
+	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even from same APEX", true, hasDep(binfooApexVariant, libbazApiImportCoreVariant))
+	android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbazApexVariant))
+
+	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbaz.so")
+	android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbaz.apiimport.so")
+	android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbaz.apex.29.apiimport.so")
+
+	// cc_api_library defined without original library should be linked with cc_api_library
+	libquxApiImportApexVariant := result.ModuleForTests("libqux.apiimport", "android_arm64_armv8-a_shared").Module()
+	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even original library definition does not exist", true, hasDep(binfooApexVariant, libquxApiImportApexVariant))
+	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libqux.apex.29.apiimport.so")
+}
+
+func TestPlatformBinaryBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
+	bp := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libbar"],
+			min_sdk_version: "29",
+		}
+		apex_key {
+			name: "myapex.key",
+		}
+		cc_binary {
+			name: "binfoo",
+			shared_libs: ["libbar"],
+			recovery_available: false,
+		}
+		cc_library {
+			name: "libbar",
+			srcs: ["libbar.cc"],
+			apex_available: ["myapex"],
+			min_sdk_version: "29",
+			stubs: {
+				symbol_file: "libbar.map.txt",
+				versions: [
+					"29",
+				],
+			},
+		}
+		cc_api_library {
+			name: "libbar",
+			src: "libbar_stub.so",
+			variants: ["apex.29"],
+		}
+		cc_api_variant {
+			name: "libbar",
+			variant: "apex",
+			version: "29",
+			src: "libbar_apex_29.so",
+		}
+		api_imports {
+			name: "api_imports",
+			apex_shared_libs: [
+				"libbar",
+			],
+		}
+		`
+
+	result := testApex(t, bp)
+
+	hasDep := func(m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		result.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	// Library defines stubs and cc_api_library should be used with cc_api_library
+	binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Module()
+	libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+	libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
+	android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
+
+	binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
+	android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
+	android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
+	android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
 }
 
 func TestTrimmedApex(t *testing.T) {
diff --git a/cc/cc.go b/cc/cc.go
index c07d836..0e88c56 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2416,6 +2416,27 @@
 	return nonVariantLibs, variantLibs
 }
 
+func (c *Module) shouldUseApiSurface() bool {
+	if c.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+		if GetImageVariantType(c) == vendorImageVariant || GetImageVariantType(c) == productImageVariant {
+			// LLNDK Variant
+			return true
+		}
+
+		if c.Properties.IsSdkVariant {
+			// NDK Variant
+			return true
+		}
+
+		if c.isImportedApiLibrary() {
+			// API Library should depend on API headers
+			return true
+		}
+	}
+
+	return false
+}
+
 func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
 	if !c.Enabled() {
 		return
@@ -2435,7 +2456,7 @@
 	apiNdkLibs := []string{}
 	apiLateNdkLibs := []string{}
 
-	if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+	if c.shouldUseApiSurface() {
 		deps.SharedLibs, apiNdkLibs = rewriteLibsForApiImports(c, deps.SharedLibs, apiImportInfo.SharedLibs, ctx.Config())
 		deps.LateSharedLibs, apiLateNdkLibs = rewriteLibsForApiImports(c, deps.LateSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
 		deps.SystemSharedLibs, _ = rewriteLibsForApiImports(c, deps.SystemSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
@@ -2466,7 +2487,7 @@
 		}
 
 		// Check header lib replacement from API surface first, and then check again with VSDK
-		if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+		if c.shouldUseApiSurface() {
 			lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
 		}
 		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
@@ -2550,12 +2571,22 @@
 		}
 
 		name, version := StubsLibNameAndVersion(lib)
+		if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) {
+			name = apiLibraryName
+		}
 		sharedLibNames = append(sharedLibNames, name)
 
 		variations := []blueprint.Variation{
 			{Mutator: "link", Variation: "shared"},
 		}
-		AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
+
+		if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
+			AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
+		}
+
+		if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
+			AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, apiLibraryName, version, false)
+		}
 	}
 
 	for _, lib := range deps.LateStaticLibs {
@@ -2898,10 +2929,58 @@
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	c.apexSdkVersion = findApexSdkVersion(ctx, apexInfo)
 
+	skipModuleList := map[string]bool{}
+
+	var apiImportInfo multitree.ApiImportInfo
+	hasApiImportInfo := false
+
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		if dep.Name() == "api_imports" {
+			apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+			hasApiImportInfo = true
+		}
+	})
+
+	if hasApiImportInfo {
+		targetStubModuleList := map[string]string{}
+		targetOrigModuleList := map[string]string{}
+
+		// Search for dependency which both original module and API imported library with APEX stub exists
+		ctx.VisitDirectDeps(func(dep android.Module) {
+			depName := ctx.OtherModuleName(dep)
+			if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
+				targetStubModuleList[apiLibrary] = depName
+			}
+		})
+		ctx.VisitDirectDeps(func(dep android.Module) {
+			depName := ctx.OtherModuleName(dep)
+			if origLibrary, ok := targetStubModuleList[depName]; ok {
+				targetOrigModuleList[origLibrary] = depName
+			}
+		})
+
+		// Decide which library should be used between original and API imported library
+		ctx.VisitDirectDeps(func(dep android.Module) {
+			depName := ctx.OtherModuleName(dep)
+			if apiLibrary, ok := targetOrigModuleList[depName]; ok {
+				if shouldUseStubForApex(ctx, dep) {
+					skipModuleList[depName] = true
+				} else {
+					skipModuleList[apiLibrary] = true
+				}
+			}
+		})
+	}
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
 
+		if _, ok := skipModuleList[depName]; ok {
+			// skip this module because original module or API imported module matching with this should be used instead.
+			return
+		}
+
 		if depTag == android.DarwinUniversalVariantTag {
 			depPaths.DarwinSecondArchOutput = dep.(*Module).OutputFile()
 			return
@@ -3237,21 +3316,8 @@
 	return depPaths
 }
 
-// ChooseStubOrImpl determines whether a given dependency should be redirected to the stub variant
-// of the dependency or not, and returns the SharedLibraryInfo and FlagExporterInfo for the right
-// dependency. The stub variant is selected when the dependency crosses a boundary where each side
-// has different level of updatability. For example, if a library foo in an APEX depends on a
-// library bar which provides stable interface and exists in the platform, foo uses the stub variant
-// of bar. If bar doesn't provide a stable interface (i.e. buildStubs() == false) or is in the
-// same APEX as foo, the non-stub variant of bar is used.
-func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibraryInfo, FlagExporterInfo) {
+func shouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool {
 	depName := ctx.OtherModuleName(dep)
-	depTag := ctx.OtherModuleDependencyTag(dep)
-	libDepTag, ok := depTag.(libraryDependencyTag)
-	if !ok || !libDepTag.shared() {
-		panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
-	}
-
 	thisModule, ok := ctx.Module().(android.ApexModule)
 	if !ok {
 		panic(fmt.Errorf("Not an APEX module: %q", ctx.ModuleName()))
@@ -3266,62 +3332,93 @@
 		bootstrap = linkable.Bootstrap()
 	}
 
+	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+
+	useStubs := false
+
+	if lib := moduleLibraryInterface(dep); lib.buildStubs() && useVndk { // LLNDK
+		if !apexInfo.IsForPlatform() {
+			// For platform libraries, use current version of LLNDK
+			// If this is for use_vendor apex we will apply the same rules
+			// of apex sdk enforcement below to choose right version.
+			useStubs = true
+		}
+	} else if apexInfo.IsForPlatform() || apexInfo.UsePlatformApis {
+		// If not building for APEX or the containing APEX allows the use of
+		// platform APIs, use stubs only when it is from an APEX (and not from
+		// platform) However, for host, ramdisk, vendor_ramdisk, recovery or
+		// bootstrap modules, always link to non-stub variant
+		isNotInPlatform := dep.(android.ApexModule).NotInPlatform()
+
+		isApexImportedApiLibrary := false
+
+		if cc, ok := dep.(*Module); ok {
+			if apiLibrary, ok := cc.linker.(*apiLibraryDecorator); ok {
+				if apiLibrary.hasApexStubs() {
+					isApexImportedApiLibrary = true
+				}
+			}
+		}
+
+		useStubs = (isNotInPlatform || isApexImportedApiLibrary) && !bootstrap
+
+		if useStubs {
+			// Another exception: if this module is a test for an APEX, then
+			// it is linked with the non-stub variant of a module in the APEX
+			// as if this is part of the APEX.
+			testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
+			for _, apexContents := range testFor.ApexContents {
+				if apexContents.DirectlyInApex(depName) {
+					useStubs = false
+					break
+				}
+			}
+		}
+		if useStubs {
+			// Yet another exception: If this module and the dependency are
+			// available to the same APEXes then skip stubs between their
+			// platform variants. This complements the test_for case above,
+			// which avoids the stubs on a direct APEX library dependency, by
+			// avoiding stubs for indirect test dependencies as well.
+			//
+			// TODO(b/183882457): This doesn't work if the two libraries have
+			// only partially overlapping apex_available. For that test_for
+			// modules would need to be split into APEX variants and resolved
+			// separately for each APEX they have access to.
+			if !isApexImportedApiLibrary && android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
+				useStubs = false
+			}
+		}
+	} else {
+		// If building for APEX, use stubs when the parent is in any APEX that
+		// the child is not in.
+		useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
+	}
+
+	return useStubs
+}
+
+// ChooseStubOrImpl determines whether a given dependency should be redirected to the stub variant
+// of the dependency or not, and returns the SharedLibraryInfo and FlagExporterInfo for the right
+// dependency. The stub variant is selected when the dependency crosses a boundary where each side
+// has different level of updatability. For example, if a library foo in an APEX depends on a
+// library bar which provides stable interface and exists in the platform, foo uses the stub variant
+// of bar. If bar doesn't provide a stable interface (i.e. buildStubs() == false) or is in the
+// same APEX as foo, the non-stub variant of bar is used.
+func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibraryInfo, FlagExporterInfo) {
+	depTag := ctx.OtherModuleDependencyTag(dep)
+	libDepTag, ok := depTag.(libraryDependencyTag)
+	if !ok || !libDepTag.shared() {
+		panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
+	}
+
 	sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
 	depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
 	sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo)
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 
 	if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
-		useStubs := false
-
-		if lib := moduleLibraryInterface(dep); lib.buildStubs() && useVndk { // LLNDK
-			if !apexInfo.IsForPlatform() {
-				// For platform libraries, use current version of LLNDK
-				// If this is for use_vendor apex we will apply the same rules
-				// of apex sdk enforcement below to choose right version.
-				useStubs = true
-			}
-		} else if apexInfo.IsForPlatform() || apexInfo.UsePlatformApis {
-			// If not building for APEX or the containing APEX allows the use of
-			// platform APIs, use stubs only when it is from an APEX (and not from
-			// platform) However, for host, ramdisk, vendor_ramdisk, recovery or
-			// bootstrap modules, always link to non-stub variant
-			useStubs = dep.(android.ApexModule).NotInPlatform() && !bootstrap
-			if useStubs {
-				// Another exception: if this module is a test for an APEX, then
-				// it is linked with the non-stub variant of a module in the APEX
-				// as if this is part of the APEX.
-				testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
-				for _, apexContents := range testFor.ApexContents {
-					if apexContents.DirectlyInApex(depName) {
-						useStubs = false
-						break
-					}
-				}
-			}
-			if useStubs {
-				// Yet another exception: If this module and the dependency are
-				// available to the same APEXes then skip stubs between their
-				// platform variants. This complements the test_for case above,
-				// which avoids the stubs on a direct APEX library dependency, by
-				// avoiding stubs for indirect test dependencies as well.
-				//
-				// TODO(b/183882457): This doesn't work if the two libraries have
-				// only partially overlapping apex_available. For that test_for
-				// modules would need to be split into APEX variants and resolved
-				// separately for each APEX they have access to.
-				if android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
-					useStubs = false
-				}
-			}
-		} else {
-			// If building for APEX, use stubs when the parent is in any APEX that
-			// the child is not in.
-			useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
-		}
-
 		// when to use (unspecified) stubs, use the latest one.
-		if useStubs {
+		if shouldUseStubForApex(ctx, dep) {
 			stubs := sharedLibraryStubsInfo.SharedStubLibraries
 			toUse := stubs[len(stubs)-1]
 			sharedLibraryInfo = toUse.SharedLibraryInfo
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 08a5eb6..18d3f21 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -23,7 +23,8 @@
 )
 
 var (
-	ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
+	ndkVariantRegex  = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
+	stubVariantRegex = regexp.MustCompile("apex\\.([a-zA-Z0-9]+)")
 )
 
 func init() {
@@ -60,6 +61,12 @@
 			variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
 			ctx.AddDependency(m, nil, variantName)
 		}
+	} else if m.IsStubs() {
+		targetVariant := "apex." + m.StubsVersion()
+		if inList(targetVariant, apiLibrary.properties.Variants) {
+			variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
+			ctx.AddDependency(m, nil, variantName)
+		}
 	}
 }
 
@@ -153,15 +160,15 @@
 		in = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), src)
 	}
 
-	// LLNDK variant
-	if m.UseVndk() && d.hasLLNDKStubs() {
-		apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+	libName := m.BaseModuleName() + multitree.GetApiImportSuffix()
 
+	load_cc_variant := func(apiVariantModule string) {
 		var mod android.Module
 
 		ctx.VisitDirectDeps(func(depMod android.Module) {
 			if depMod.Name() == apiVariantModule {
 				mod = depMod
+				libName = apiVariantModule
 			}
 		})
 
@@ -184,37 +191,17 @@
 				}
 			}
 		}
+	}
+
+	if m.UseVndk() && d.hasLLNDKStubs() {
+		// LLNDK variant
+		load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", ""))
 	} else if m.IsSdkVariant() {
 		// NDK Variant
-		apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion())
-
-		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 NDK properties to cc_api_library module
-				d.libraryDecorator.flagExporter.Properties.Export_include_dirs = append(
-					d.libraryDecorator.flagExporter.Properties.Export_include_dirs,
-					variantMod.exportProperties.Export_include_dirs...)
-
-				// Export headers as system include dirs if specified. Mostly for libc
-				if 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
-				}
-			}
-		}
+		load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion()))
+	} else if m.IsStubs() {
+		// APEX Variant
+		load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "apex", m.StubsVersion()))
 	}
 
 	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
@@ -237,20 +224,58 @@
 	d.libraryDecorator.flagExporter.setProvider(ctx)
 
 	d.unstrippedOutputFile = in
-	libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
+	libName += flags.Toolchain.ShlibSuffix()
 
 	tocFile := android.PathForModuleOut(ctx, libName+".toc")
 	d.tocFile = android.OptionalPathForPath(tocFile)
 	TransformSharedObjectToToc(ctx, in, tocFile)
 
+	outputFile := android.PathForModuleOut(ctx, libName)
+
+	// TODO(b/270485584) This copies with a new name, just to avoid conflict with prebuilts.
+	// We can just use original input if there is any way to avoid name conflict without copy.
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cp,
+		Description: "API surface imported library",
+		Input:       in,
+		Output:      outputFile,
+		Args: map[string]string{
+			"cpFlags": "-L",
+		},
+	})
+
 	ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
-		SharedLibrary: in,
+		SharedLibrary: outputFile,
 		Target:        ctx.Target(),
 
 		TableOfContents: d.tocFile,
 	})
 
-	return in
+	d.shareStubs(ctx)
+
+	return outputFile
+}
+
+// Share additional information about stub libraries with provider
+func (d *apiLibraryDecorator) shareStubs(ctx ModuleContext) {
+	stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
+	if len(stubs) > 0 {
+		var stubsInfo []SharedStubLibrary
+		for _, stub := range stubs {
+			stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
+			flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
+			stubsInfo = append(stubsInfo, SharedStubLibrary{
+				Version:           moduleLibraryInterface(stub).stubsVersion(),
+				SharedLibraryInfo: stubInfo,
+				FlagExporterInfo:  flagInfo,
+			})
+		}
+		ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+			SharedStubLibraries: stubsInfo,
+
+			IsLLNDK: ctx.IsLlndk(),
+		})
+	}
 }
 
 func (d *apiLibraryDecorator) availableFor(what string) bool {
@@ -258,6 +283,19 @@
 	return true
 }
 
+func (d *apiLibraryDecorator) hasApexStubs() bool {
+	for _, variant := range d.properties.Variants {
+		if strings.HasPrefix(variant, "apex") {
+			return true
+		}
+	}
+	return false
+}
+
+func (d *apiLibraryDecorator) hasStubsVariants() bool {
+	return d.hasApexStubs()
+}
+
 func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
 	m, ok := ctx.Module().(*Module)
 
@@ -265,14 +303,8 @@
 		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.IsSdkVariant() {
 		// TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant.
 		if d.hasNDKStubs() {
@@ -280,6 +312,17 @@
 		}
 	}
 
+	if d.hasLLNDKStubs() && m.UseVndk() {
+		// LLNDK libraries only need a single stubs variant.
+		return []string{android.FutureApiLevel.String()}
+	}
+
+	stubsVersions := d.getStubVersions()
+
+	if len(stubsVersions) != 0 {
+		return stubsVersions
+	}
+
 	if m.MinSdkVersion() == "" {
 		return nil
 	}
@@ -319,6 +362,18 @@
 	return ndkVersions
 }
 
+func (d *apiLibraryDecorator) getStubVersions() []string {
+	stubVersions := []string{}
+
+	for _, variant := range d.properties.Variants {
+		if match := stubVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
+			stubVersions = append(stubVersions, match[1])
+		}
+	}
+
+	return stubVersions
+}
+
 // '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.
@@ -433,7 +488,7 @@
 // Implement ImageInterface to generate image variants
 func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {}
 func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	return String(v.properties.Variant) == "ndk"
+	return inList(String(v.properties.Variant), []string{"ndk", "apex"})
 }
 func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool       { return false }
 func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 868447a..528577a 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -41,6 +41,7 @@
 		cc_library {
 			name: "libfoo",
 			shared_libs: ["libbar"],
+			vendor_available: true,
 		}
 
 		cc_library {
@@ -49,6 +50,7 @@
 
 		cc_api_library {
 			name: "libbar",
+			vendor_available: true,
 			src: "libbar.so",
 		}
 
@@ -57,7 +59,6 @@
 			shared_libs: [
 				"libbar",
 			],
-			header_libs: [],
 		}
 	`
 
@@ -67,8 +68,14 @@
 	libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
 	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
 
-	android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbar))
-	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+	android.AssertBoolEquals(t, "original library should be linked with non-stub variant", true, hasDirectDependency(t, ctx, libfoo, libbar))
+	android.AssertBoolEquals(t, "Stub library from API surface should be not linked with non-stub variant", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+
+	libfooVendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
+	libbarApiImportVendor := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
+
+	android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfooVendor, libbar))
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfooVendor, libbarApiImportVendor))
 }
 
 func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) {
@@ -76,11 +83,13 @@
 		cc_library {
 			name: "libfoo",
 			shared_libs: ["libbar"],
+			vendor: true,
 		}
 
 		cc_api_library {
 			name: "libbar",
 			src: "libbar.so",
+			vendor_available: true,
 		}
 
 		api_imports {
@@ -88,14 +97,13 @@
 			shared_libs: [
 				"libbar",
 			],
-			header_libs: [],
 		}
 	`
 
 	ctx := prepareForCcTest.RunTestWithBp(t, bp)
 
-	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
-	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+	libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
+	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
 
 	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
 }
@@ -105,143 +113,36 @@
 		cc_library {
 			name: "libfoo",
 			shared_libs: ["libbar"],
+			vendor_available: true,
 		}
 
 		cc_library {
 			name: "libbar",
+			vendor_available: true,
 		}
 
 		cc_api_library {
 			name: "libbar",
 			src: "libbar.so",
+			vendor_available: true,
 		}
 
 		api_imports {
 			name: "api_imports",
 			shared_libs: [],
-			header_libs: [],
 		}
 	`
 
 	ctx := prepareForCcTest.RunTestWithBp(t, bp)
 
-	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
-	libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
-	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+	libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
+	libbar := ctx.ModuleForTests("libbar", "android_vendor.29_arm64_armv8-a_shared").Module()
+	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
 
 	android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar))
 	android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
 }
 
-func TestApiHeaderReplacesExistingModule(t *testing.T) {
-	bp := `
-		cc_library {
-			name: "libfoo",
-			header_libs: ["libfoo_headers"],
-		}
-
-		cc_api_library {
-			name: "libfoo",
-			header_libs: ["libfoo_headers"],
-			src: "libfoo.so",
-		}
-
-		cc_library_headers {
-			name: "libfoo_headers",
-		}
-
-		cc_api_headers {
-			name: "libfoo_headers",
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libfoo",
-			],
-			header_libs: [
-				"libfoo_headers",
-			],
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
-	libfooApiImport := ctx.ModuleForTests("libfoo.apiimport", "android_arm64_armv8-a_shared").Module()
-	libfooHeader := ctx.ModuleForTests("libfoo_headers", "android_arm64_armv8-a").Module()
-	libfooHeaderApiImport := ctx.ModuleForTests("libfoo_headers.apiimport", "android_arm64_armv8-a").Module()
-
-	android.AssertBoolEquals(t, "original header should not be used for original library", false, hasDirectDependency(t, ctx, libfoo, libfooHeader))
-	android.AssertBoolEquals(t, "Header from API surface should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport))
-	android.AssertBoolEquals(t, "original header should not be used for library imported from API surface", false, hasDirectDependency(t, ctx, libfooApiImport, libfooHeader))
-	android.AssertBoolEquals(t, "Header from API surface should be used for library imported from API surface", true, hasDirectDependency(t, ctx, libfooApiImport, libfooHeaderApiImport))
-}
-
-func TestApiHeadersDoNotRequireOriginalModule(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libfoo",
-		header_libs: ["libfoo_headers"],
-	}
-
-	cc_api_headers {
-		name: "libfoo_headers",
-	}
-
-	api_imports {
-		name: "api_imports",
-		shared_libs: [
-			"libfoo",
-		],
-		header_libs: [
-			"libfoo_headers",
-		],
-	}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
-	libfooHeaderApiImport := ctx.ModuleForTests("libfoo_headers.apiimport", "android_arm64_armv8-a").Module()
-
-	android.AssertBoolEquals(t, "Header from API surface should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport))
-}
-
-func TestApiHeadersShouldNotReplaceWithoutApiImport(t *testing.T) {
-	bp := `
-		cc_library {
-			name: "libfoo",
-			header_libs: ["libfoo_headers"],
-		}
-
-		cc_library_headers {
-			name: "libfoo_headers",
-		}
-
-		cc_api_headers {
-			name: "libfoo_headers",
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libfoo",
-			],
-			header_libs: [],
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
-	libfooHeader := ctx.ModuleForTests("libfoo_headers", "android_arm64_armv8-a").Module()
-	libfooHeaderApiImport := ctx.ModuleForTests("libfoo_headers.apiimport", "android_arm64_armv8-a").Module()
-
-	android.AssertBoolEquals(t, "original header should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeader))
-	android.AssertBoolEquals(t, "Header from API surface should not be used for original library", false, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport))
-}
-
 func TestExportDirFromStubLibrary(t *testing.T) {
 	bp := `
 		cc_library {
@@ -330,7 +231,7 @@
 	android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant))
 
 	binFooLibFlags := 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", binFooLibFlags, "libbar_llndk.so")
+	android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", binFooLibFlags, "libbar.llndk.apiimport.so")
 
 	binFooCFlags := 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", binFooCFlags, "-Ilibbar_llndk_include")
@@ -354,6 +255,17 @@
 			stl: "c++_shared",
 		}
 
+		cc_binary {
+			name: "binqux",
+			srcs: ["binfoo.cc"],
+			shared_libs: ["libbar"],
+		}
+
+		cc_library {
+			name: "libbar",
+			srcs: ["libbar.cc"],
+		}
+
 		cc_api_library {
 			name: "libbar",
 			// TODO(b/244244438) Remove src property once all variants are implemented.
@@ -417,10 +329,14 @@
 	android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
 
 	binFooLibFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("ld").Args["libFlags"]
-	android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar_ndk_29.so")
+	android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar.ndk.29.apiimport.so")
 
 	binFooCFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("cc").Args["cFlags"]
 	android.AssertStringDoesContain(t, "Binary using sdk should include headers from the NDK variant source", binFooCFlags, "-Ilibbar_ndk_29_include")
+
+	binQux := ctx.ModuleForTests("binqux", "android_arm64_armv8-a").Module()
+	android.AssertBoolEquals(t, "NDK Stub library from API surface should not be linked with nonSdk binary", false,
+		(hasDirectDependency(t, ctx, binQux, libbarApiImportv30) || hasDirectDependency(t, ctx, binQux, libbarApiImportv29)))
 }
 
 func TestApiLibraryWithMultipleVariants(t *testing.T) {
@@ -440,6 +356,11 @@
 			shared_libs: ["libbar"],
 		}
 
+		cc_library {
+			name: "libbar",
+			srcs: ["libbar.cc"],
+		}
+
 		cc_api_library {
 			name: "libbar",
 			// TODO(b/244244438) Remove src property once all variants are implemented.
@@ -450,6 +371,9 @@
 				"ndk.29",
 				"ndk.30",
 				"ndk.current",
+				"apex.29",
+				"apex.30",
+				"apex.current",
 			],
 		}
 
@@ -479,6 +403,30 @@
 
 		cc_api_variant {
 			name: "libbar",
+			variant: "apex",
+			version: "29",
+			src: "libbar_apex_29.so",
+			export_include_dirs: ["libbar_apex_29_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "apex",
+			version: "30",
+			src: "libbar_apex_30.so",
+			export_include_dirs: ["libbar_apex_30_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "apex",
+			version: "current",
+			src: "libbar_apex_current.so",
+			export_include_dirs: ["libbar_apex_current_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
 			variant: "llndk",
 			src: "libbar_llndk.so",
 			export_include_dirs: ["libbar_llndk_include"]
@@ -489,7 +437,9 @@
 			shared_libs: [
 				"libbar",
 			],
-			header_libs: [],
+			apex_shared_libs: [
+				"libbar",
+			],
 		}
 	`
 	ctx := prepareForCcTest.RunTestWithBp(t, bp)
diff --git a/cc/sdk.go b/cc/sdk.go
index 23dd0cb..4f361eb 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -62,21 +62,26 @@
 		} else if isCcModule && ccModule.isImportedApiLibrary() {
 			apiLibrary, _ := ccModule.linker.(*apiLibraryDecorator)
 			if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() {
+				variations := []string{"sdk"}
+				if apiLibrary.hasApexStubs() {
+					variations = append(variations, "")
+				}
 				// Handle cc_api_library module with NDK stubs and variants only which can use SDK
-				modules := ctx.CreateVariations("", "sdk")
-
+				modules := ctx.CreateVariations(variations...)
 				// Mark the SDK variant.
-				modules[1].(*Module).Properties.IsSdkVariant = true
-				// SDK variant is not supposed to be installed
-				modules[1].(*Module).Properties.PreventInstall = true
-
+				modules[0].(*Module).Properties.IsSdkVariant = true
 				if ctx.Config().UnbundledBuildApps() {
-					// For an unbundled apps build, hide the platform variant from Make.
-					modules[0].(*Module).Properties.HideFromMake = true
+					if apiLibrary.hasApexStubs() {
+						// For an unbundled apps build, hide the platform variant from Make.
+						modules[1].(*Module).Properties.HideFromMake = true
+						modules[1].(*Module).Properties.PreventInstall = true
+					}
 				} else {
 					// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
 					// exposed to Make.
-					modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+					modules[0].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+					// SDK variant is not supposed to be installed
+					modules[0].(*Module).Properties.PreventInstall = true
 				}
 			} else {
 				ccModule.Properties.Sdk_version = nil
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
index 6674d3e..07ec7bc 100644
--- a/multitree/api_imports.go
+++ b/multitree/api_imports.go
@@ -40,8 +40,9 @@
 }
 
 type apiImportsProperties struct {
-	Shared_libs []string // List of C shared libraries from API surfaces
-	Header_libs []string // List of C header libraries from API surfaces
+	Shared_libs      []string // List of C shared libraries from API surfaces
+	Header_libs      []string // List of C header libraries from API surfaces
+	Apex_shared_libs []string // List of C shared libraries with APEX stubs
 }
 
 // 'api_imports' is a module which describes modules available from API surfaces.
@@ -60,7 +61,7 @@
 }
 
 type ApiImportInfo struct {
-	SharedLibs, HeaderLibs map[string]string
+	SharedLibs, HeaderLibs, ApexSharedLibs map[string]string
 }
 
 var ApiImportsProvider = blueprint.NewMutatorProvider(ApiImportInfo{}, "deps")
@@ -78,10 +79,12 @@
 
 	sharedLibs := generateNameMapWithSuffix(imports.properties.Shared_libs)
 	headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
+	apexSharedLibs := generateNameMapWithSuffix(imports.properties.Apex_shared_libs)
 
 	ctx.SetProvider(ApiImportsProvider, ApiImportInfo{
-		SharedLibs: sharedLibs,
-		HeaderLibs: headerLibs,
+		SharedLibs:     sharedLibs,
+		HeaderLibs:     headerLibs,
+		ApexSharedLibs: apexSharedLibs,
 	})
 }