Define cc_api_headers module

Define cc_api_headers module to import from API surfaces and replace
existing header definition if needed.

Tested with :
cc_api_headers {
  name: "libc_headers",
  export_system_include_dirs: [
    "include",
  ],
  min_sdk_version: "1",
  sdk_version: "1",
  vendor_available: true,
  native_bridge_supported: true,
  ...
}

Bug: 236087698
Test: ALLOW_MISSING_DEPENDENCIES=true m -j vendorimage succeeded
Change-Id: I2c3294fe19a272453a168d8c7beeee9859bd4583
diff --git a/cc/androidmk.go b/cc/androidmk.go
index a957246..a9ba1a9 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -644,6 +644,16 @@
 	})
 }
 
+func (a *apiHeadersDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "HEADER_LIBRARIES"
+	entries.SubName += multitree.GetApiImportSuffix()
+
+	entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		a.libraryDecorator.androidMkWriteExportedFlags(entries)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+	})
+}
+
 func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, entries *android.AndroidMkEntries) {
 	allow := linker.Properties.Allow_undefined_symbols
 	if allow != nil {
diff --git a/cc/cc.go b/cc/cc.go
index 99a8d7c..cded946 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2302,9 +2302,14 @@
 		deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
 	}
 
-	for idx, lib := range deps.HeaderLibs {
-		deps.HeaderLibs[idx] = GetReplaceModuleName(lib, apiImports.HeaderLibs)
+	for idx, lib := range deps.SystemSharedLibs {
+		deps.SystemSharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
 	}
+
+	for idx, lib := range deps.ReexportSharedLibHeaders {
+		deps.ReexportSharedLibHeaders[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+	}
+
 	return deps
 }
 
@@ -2348,12 +2353,14 @@
 			depTag.reexportFlags = true
 		}
 
+		// Check header lib replacement from API surface first, and then check again with VSDK
+		lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
 		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
 
 		if c.isNDKStubLibrary() {
 			// ndk_headers do not have any variations
 			actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib)
-		} else if c.IsStubs() {
+		} else if c.IsStubs() && !c.isImportedApiLibrary() {
 			actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
 				depTag, lib)
 		} else {
@@ -3258,11 +3265,6 @@
 
 			return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix()
 		}
-
-		// Remove API import suffix if exists
-		if _, ok := ccDepModule.linker.(*apiLibraryDecorator); ok {
-			libName = strings.TrimSuffix(libName, multitree.GetApiImportSuffix())
-		}
 	}
 
 	if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() &&
@@ -3598,9 +3600,6 @@
 	if _, ok := c.linker.(prebuiltLinkerInterface); ok {
 		return nil
 	}
-	if _, ok := c.linker.(*apiLibraryDecorator); ok {
-		return nil
-	}
 
 	minSdkVersion := c.MinSdkVersion()
 	if minSdkVersion == "apex_inherit" {
@@ -3781,6 +3780,11 @@
 	return c.Properties.IsSdkVariant
 }
 
+func (c *Module) isImportedApiLibrary() bool {
+	_, ok := c.linker.(*apiLibraryDecorator)
+	return ok
+}
+
 func kytheExtractAllFactory() android.Singleton {
 	return &kytheExtractAllSingleton{}
 }
diff --git a/cc/library_stub.go b/cc/library_stub.go
index fa6c279..2ebb6ef 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -17,7 +17,6 @@
 import (
 	"android/soong/android"
 	"android/soong/multitree"
-	"strings"
 )
 
 func init() {
@@ -25,8 +24,10 @@
 }
 
 func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
-	// cc_api_stub_library shares a lot of ndk_library, and this will be refactored later
 	ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
+	ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory)
+
+	// cc_api_stub_library shares a lot of ndk_library, and this will be refactored later
 	ctx.RegisterModuleType("cc_api_stub_library", CcApiStubLibraryFactory)
 	ctx.RegisterModuleType("cc_api_contribution", CcApiContributionFactory)
 }
@@ -81,6 +82,14 @@
 }
 
 func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
+	// Export headers as system include dirs if specified. Mostly for libc
+	if Bool(d.libraryDecorator.Properties.Llndk.Export_headers_as_system) {
+		d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
+			d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
+			d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
+		d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
+	}
+
 	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
 	d.libraryDecorator.flagExporter.exportIncludes(ctx)
 	d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
@@ -114,9 +123,51 @@
 	return true
 }
 
-func (d *apiLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
-	d.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), multitree.GetApiImportSuffix())
-	return d.libraryDecorator.linkerFlags(ctx, flags)
+// '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.
+type apiHeadersDecorator struct {
+	*libraryDecorator
+}
+
+func CcApiHeadersFactory() android.Module {
+	module, decorator := NewLibrary(android.DeviceSupported)
+	apiHeadersDecorator := &apiHeadersDecorator{
+		libraryDecorator: decorator,
+	}
+	apiHeadersDecorator.HeaderOnly()
+
+	module.stl = nil
+	module.sanitize = nil
+	decorator.disableStripping()
+
+	module.compiler = nil
+	module.linker = apiHeadersDecorator
+	module.installer = nil
+
+	// Mark module as stub, so APEX would not include this stub in the package.
+	module.library.setBuildStubs(true)
+
+	// Prevent default system libs (libc, libm, and libdl) from being linked
+	if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil {
+		apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{}
+	}
+
+	apiHeadersDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true)
+	apiHeadersDecorator.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+	module.Init()
+
+	return module
+}
+
+func (d *apiHeadersDecorator) Name(basename string) string {
+	return basename + multitree.GetApiImportSuffix()
+}
+
+func (d *apiHeadersDecorator) availableFor(what string) bool {
+	// Stub from API surface should be available for any APEX.
+	return true
 }
 
 func CcApiStubLibraryFactory() android.Module {
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index c2ac941..cd06172 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -216,3 +216,112 @@
 	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))
+}