Move LLNDK related logic to llndk_library

Currently VNDK contains some logic for LLNDK libraries as they are
treated in a similar way with VNDK. However, those logics should stay from
VNDK deprecation. To keep the logic, this change moves LLNDK related
logic into llndk_library.

Bug: 330100430
Test: Soong tests passed
Test: llndk.libraries.txt did not change from CF build
Change-Id: I1d02a3c2a398f1b1060b4f2bdd23af32310503bb
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 9e727a1..ae9da98 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -16,12 +16,12 @@
 
 import (
 	"android/soong/android"
+	"android/soong/etc"
 	"strings"
 )
 
 var (
 	llndkLibrarySuffix = ".llndk"
-	llndkHeadersSuffix = ".llndk"
 )
 
 // Holds properties to describe a stub shared library based on the provided version file.
@@ -78,3 +78,138 @@
 	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
 		strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " "))
 }
+
+func init() {
+	RegisterLlndkLibraryTxtType(android.InitRegistrationContext)
+}
+
+func RegisterLlndkLibraryTxtType(ctx android.RegistrationContext) {
+	ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
+}
+
+type llndkLibrariesTxtModule struct {
+	android.SingletonModuleBase
+
+	outputFile  android.OutputPath
+	moduleNames []string
+	fileNames   []string
+}
+
+var _ etc.PrebuiltEtcModule = &llndkLibrariesTxtModule{}
+var _ android.OutputFileProducer = &llndkLibrariesTxtModule{}
+
+// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries
+// generated by Soong but can be referenced by other modules.
+// For example, apex_vndk can depend on these files as prebuilt.
+// Make uses LLNDK_LIBRARIES to determine which libraries to install.
+// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+// Therefore, by removing the library here, we cause it to only be installed if libc
+// depends on it.
+func llndkLibrariesTxtFactory() android.SingletonModule {
+	m := &llndkLibrariesTxtModule{}
+	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+	return m
+}
+
+func (txt *llndkLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	filename := txt.Name()
+
+	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
+
+	installPath := android.PathForModuleInstall(ctx, "etc")
+	ctx.InstallFile(installPath, filename, txt.outputFile)
+}
+
+func (txt *llndkLibrariesTxtModule) GenerateSingletonBuildActions(ctx android.SingletonContext) {
+	ctx.VisitAllModules(func(m android.Module) {
+		if c, ok := m.(*Module); ok && c.VendorProperties.IsLLNDK && !c.Header() && !c.IsVndkPrebuiltLibrary() {
+			filename, err := getVndkFileName(c)
+			if err != nil {
+				ctx.ModuleErrorf(m, "%s", err)
+			}
+
+			if !strings.HasPrefix(ctx.ModuleName(m), "libclang_rt.hwasan") {
+				txt.moduleNames = append(txt.moduleNames, ctx.ModuleName(m))
+			}
+			txt.fileNames = append(txt.fileNames, filename)
+		}
+	})
+	txt.moduleNames = android.SortedUniqueStrings(txt.moduleNames)
+	txt.fileNames = android.SortedUniqueStrings(txt.fileNames)
+
+	android.WriteFileRule(ctx, txt.outputFile, strings.Join(txt.fileNames, "\n"))
+}
+
+func (txt *llndkLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(txt.outputFile),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base())
+			},
+		},
+	}}
+}
+
+func (txt *llndkLibrariesTxtModule) MakeVars(ctx android.MakeVarsContext) {
+	ctx.Strict("LLNDK_LIBRARIES", strings.Join(txt.moduleNames, " "))
+}
+
+// PrebuiltEtcModule interface
+func (txt *llndkLibrariesTxtModule) OutputFile() android.OutputPath {
+	return txt.outputFile
+}
+
+// PrebuiltEtcModule interface
+func (txt *llndkLibrariesTxtModule) BaseDir() string {
+	return "etc"
+}
+
+// PrebuiltEtcModule interface
+func (txt *llndkLibrariesTxtModule) SubDir() string {
+	return ""
+}
+
+func (txt *llndkLibrariesTxtModule) OutputFiles(tag string) (android.Paths, error) {
+	return android.Paths{txt.outputFile}, nil
+}
+
+func llndkMutator(mctx android.BottomUpMutatorContext) {
+	m, ok := mctx.Module().(*Module)
+	if !ok {
+		return
+	}
+
+	if shouldSkipLlndkMutator(m) {
+		return
+	}
+
+	lib, isLib := m.linker.(*libraryDecorator)
+	prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker)
+
+	if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() {
+		m.VendorProperties.IsLLNDK = true
+	}
+	if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
+		m.VendorProperties.IsLLNDK = true
+	}
+
+	if m.IsVndkPrebuiltLibrary() && !m.IsVndk() {
+		m.VendorProperties.IsLLNDK = true
+	}
+}
+
+// Check for modules that mustn't be LLNDK
+func shouldSkipLlndkMutator(m *Module) bool {
+	if !m.Enabled() {
+		return true
+	}
+	if !m.Device() {
+		return true
+	}
+	if m.Target().NativeBridge == android.NativeBridgeEnabled {
+		return true
+	}
+	return false
+}