Soong generates libraries.txt files for vndk

These files were generated by Make. This is an effort to converting make
to soong.

These files are created under a known location: $SOONG_OUT_DIR/vndk
- llndk.libraries.txt
- vndksp.libraries.txt
- vndkcore.libraries.txt
- vndkprivate.libraries.txt
- vndkcorevariant.libraries.txt
- vndk.libraries.txt: merged all of above with tags

The last one is used by 'check-vndk-list'.
(See the topic)

Others will be packaged by VNDK APEX of current VNDK.
(This is not merged yet. After landing, a follow-up CL will be
followed.)

Bug: 141019581
Bug: 141450808
Test: m check-vndk-list
Change-Id: I9a24f6975bd4b226a94f61a13d43857dcdce6b88
diff --git a/cc/cc.go b/cc/cc.go
index 806a6ed..57f5ab8 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -215,6 +215,10 @@
 	// Allows this module to use non-APEX version of libraries. Useful
 	// for building binaries that are started before APEXes are activated.
 	Bootstrap *bool
+
+	// Even if DeviceConfig().VndkUseCoreVariant() is set, this module must use vendor variant.
+	// see soong/cc/config/vndk.go
+	MustUseVendorVariant bool `blueprint:"mutated"`
 }
 
 type VendorProperties struct {
@@ -586,7 +590,7 @@
 
 func (c *Module) isLlndk(config android.Config) bool {
 	// Returns true for both LLNDK (public) and LLNDK-private libs.
-	return inList(c.Name(), *llndkLibraries(config))
+	return inList(c.BaseModuleName(), *llndkLibraries(config))
 }
 
 func (c *Module) isLlndkPublic(config android.Config) bool {
@@ -596,7 +600,7 @@
 
 func (c *Module) isVndkPrivate(config android.Config) bool {
 	// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
-	return inList(c.Name(), *vndkPrivateLibraries(config))
+	return inList(c.BaseModuleName(), *vndkPrivateLibraries(config))
 }
 
 func (c *Module) isVndk() bool {
@@ -639,7 +643,7 @@
 }
 
 func (c *Module) mustUseVendorVariant() bool {
-	return c.isVndkSp() || inList(c.Name(), config.VndkMustUseVendorVariantList)
+	return c.isVndkSp() || c.Properties.MustUseVendorVariant
 }
 
 func (c *Module) getVndkExtendsModuleName() string {
@@ -2113,7 +2117,6 @@
 }
 
 func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
-	name := actx.ModuleName()
 	if c.useVndk() {
 		if lib, ok := c.linker.(*llndkStubDecorator); ok {
 			if Bool(lib.Properties.Vendor_available) {
@@ -2135,7 +2138,7 @@
 		// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
 		//family, link := getNdkStlFamilyAndLinkType(c)
 		//return fmt.Sprintf("native:ndk:%s:%s", family, link)
-	} else if inList(name, *vndkUsingCoreVariantLibraries(actx.Config())) {
+	} else if actx.DeviceConfig().VndkUseCoreVariant() && !c.mustUseVendorVariant() {
 		return "native:platform_vndk"
 	} else {
 		return "native:platform"
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 689aacd..f13bee5 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -264,6 +264,13 @@
 	}
 }
 
+func checkVndkOutput(t *testing.T, ctx *android.TestContext, output string, expected []string) {
+	t.Helper()
+	vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
+	actual := strings.FieldsFunc(strings.ReplaceAll(vndkSnapshot.Output(output).Args["content"], "\\n", "\n"), func(r rune) bool { return r == '\n' })
+	assertArrayString(t, actual, expected)
+}
+
 func TestVndk(t *testing.T) {
 	config := android.TestArchConfig(buildDir, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
@@ -336,6 +343,69 @@
 	checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLib2ndPath, variant2nd)
 	checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLibPath, variant)
 	checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLib2ndPath, variant2nd)
+
+	checkVndkOutput(t, ctx, "vndk/llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libm.so"})
+	checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{"libvndk.so", "libvndk_private.so"})
+	checkVndkOutput(t, ctx, "vndk/vndkprivate.libraries.txt", []string{"libft2.so", "libvndk_private.so", "libvndk_sp_private.so"})
+	checkVndkOutput(t, ctx, "vndk/vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp.so", "libvndk_sp_private.so"})
+	checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", nil)
+	// merged & tagged & filtered-out(libclang_rt)
+	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
+		"LLNDK: libc.so",
+		"LLNDK: libdl.so",
+		"LLNDK: libft2.so",
+		"LLNDK: libm.so",
+		"VNDK-SP: libc++.so",
+		"VNDK-SP: libvndk_sp.so",
+		"VNDK-SP: libvndk_sp_private.so",
+		"VNDK-core: libvndk.so",
+		"VNDK-core: libvndk_private.so",
+		"VNDK-private: libft2.so",
+		"VNDK-private: libvndk_private.so",
+		"VNDK-private: libvndk_sp_private.so",
+	})
+}
+
+func TestVndkUsingCoreVariant(t *testing.T) {
+	config := android.TestArchConfig(buildDir, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
+
+	setVndkMustUseVendorVariantListForTest(config, []string{"libvndk"})
+
+	ctx := testCcWithConfig(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk2",
+			vendor_available: false,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+	`, config)
+
+	checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{"libvndk.so", "libvndk2.so"})
+	checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", []string{"libvndk2.so"})
 }
 
 func TestVndkDepError(t *testing.T) {
@@ -1340,9 +1410,9 @@
 	assertArrayString(t, *vndkSpLibraries(config),
 		[]string{"libc++", "libvndksp"})
 	assertArrayString(t, *llndkLibraries(config),
-		[]string{"libc", "libdl", "libllndk", "libllndkprivate", "libm"})
+		[]string{"libc", "libdl", "libft2", "libllndk", "libllndkprivate", "libm"})
 	assertArrayString(t, *vndkPrivateLibraries(config),
-		[]string{"libllndkprivate", "libvndkprivate"})
+		[]string{"libft2", "libllndkprivate", "libvndkprivate"})
 
 	vendorVariant27 := "android_arm64_armv8-a_vendor.27_shared"
 
diff --git a/cc/testing.go b/cc/testing.go
index 6fa6ea7..fafaeb0 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -145,6 +145,18 @@
 			symbol_file: "",
 		}
 		cc_library {
+			name: "libft2",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			recovery_available: true,
+		}
+		llndk_library {
+			name: "libft2",
+			symbol_file: "",
+			vendor_available: false,
+		}
+		cc_library {
 			name: "libc++_static",
 			no_libcrt: true,
 			nocrt: true,
diff --git a/cc/vndk.go b/cc/vndk.go
index 14bbf11..57ee62a 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -194,14 +194,16 @@
 }
 
 var (
-	vndkCoreLibrariesKey             = android.NewOnceKey("vndkCoreLibrarires")
-	vndkSpLibrariesKey               = android.NewOnceKey("vndkSpLibrarires")
-	llndkLibrariesKey                = android.NewOnceKey("llndkLibrarires")
-	vndkPrivateLibrariesKey          = android.NewOnceKey("vndkPrivateLibrarires")
-	vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibrarires")
-	modulePathsKey                   = android.NewOnceKey("modulePaths")
-	vndkSnapshotOutputsKey           = android.NewOnceKey("vndkSnapshotOutputs")
-	vndkLibrariesLock                sync.Mutex
+	vndkCoreLibrariesKey                = android.NewOnceKey("vndkCoreLibrarires")
+	vndkSpLibrariesKey                  = android.NewOnceKey("vndkSpLibrarires")
+	llndkLibrariesKey                   = android.NewOnceKey("llndkLibrarires")
+	vndkPrivateLibrariesKey             = android.NewOnceKey("vndkPrivateLibrarires")
+	vndkUsingCoreVariantLibrariesKey    = android.NewOnceKey("vndkUsingCoreVariantLibrarires")
+	modulePathsKey                      = android.NewOnceKey("modulePaths")
+	vndkSnapshotOutputsKey              = android.NewOnceKey("vndkSnapshotOutputs")
+	vndkMustUseVendorVariantListKey     = android.NewOnceKey("vndkMustUseVendorVariantListKey")
+	testVndkMustUseVendorVariantListKey = android.NewOnceKey("testVndkMustUseVendorVariantListKey")
+	vndkLibrariesLock                   sync.Mutex
 
 	headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
 )
@@ -248,6 +250,26 @@
 	}).(*android.RuleBuilderInstalls)
 }
 
+func vndkMustUseVendorVariantList(cfg android.Config) []string {
+	return cfg.Once(vndkMustUseVendorVariantListKey, func() interface{} {
+		override := cfg.Once(testVndkMustUseVendorVariantListKey, func() interface{} {
+			return []string(nil)
+		}).([]string)
+		if override != nil {
+			return override
+		}
+		return config.VndkMustUseVendorVariantList
+	}).([]string)
+}
+
+// test may call this to override global configuration(config.VndkMustUseVendorVariantList)
+// when it is called, it must be before the first call to vndkMustUseVendorVariantList()
+func setVndkMustUseVendorVariantListForTest(config android.Config, mustUseVendorVariantList []string) {
+	config.Once(testVndkMustUseVendorVariantListKey, func() interface{} {
+		return mustUseVendorVariantList
+	})
+}
+
 func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
 	lib := m.linker.(*llndkStubDecorator)
 	name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
@@ -276,7 +298,10 @@
 	defer vndkLibrariesLock.Unlock()
 
 	modulePaths := modulePaths(mctx.Config())
-	if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
+	if inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
+		m.Properties.MustUseVendorVariant = true
+	}
+	if mctx.DeviceConfig().VndkUseCoreVariant() && !m.mustUseVendorVariant() {
 		vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
 		if !inList(name, *vndkUsingCoreVariantLibraries) {
 			*vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
@@ -365,6 +390,8 @@
 		return
 	}
 
+	c.buildVndkLibrariesTxtFiles(ctx)
+
 	outputs := vndkSnapshotOutputs(ctx.Config())
 
 	snapshotDir := "vndk-snapshot"
@@ -604,3 +631,88 @@
 	installSnapshotFileFromContent(modulePathTxtBuilder.String(),
 		filepath.Join(configsDir, "module_paths.txt"))
 }
+
+func installListFile(ctx android.SingletonContext, list []string, pathComponents ...string) android.OutputPath {
+	out := android.PathForOutput(ctx, pathComponents...)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      out,
+		Description: "Writing " + out.String(),
+		Args: map[string]string{
+			"content": strings.Join(list, "\\n"),
+		},
+	})
+	return out
+}
+
+func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) {
+	var (
+		llndk, vndkcore, vndksp, vndkprivate, vndkcorevariant, merged []string
+	)
+	vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
+	config := ctx.Config()
+	ctx.VisitAllModules(func(m android.Module) {
+		if !m.Enabled() {
+			return
+		}
+		c, ok := m.(*Module)
+		if !ok || c.Os().Class != android.Device {
+			return
+		}
+		lib, ok := c.linker.(interface{ shared() bool })
+		if !ok || !lib.shared() {
+			return
+		}
+
+		if !c.OutputFile().Valid() {
+			return
+		}
+
+		filename := c.OutputFile().Path().Base()
+		if c.isLlndk(config) {
+			llndk = append(llndk, filename)
+			if c.isVndkPrivate(config) {
+				vndkprivate = append(vndkprivate, filename)
+			}
+		} else if c.vndkVersion() == vndkVersion && c.isVndk() && !c.isVndkExt() {
+			if c.isVndkSp() {
+				vndksp = append(vndksp, filename)
+			} else {
+				vndkcore = append(vndkcore, filename)
+			}
+			if c.isVndkPrivate(config) {
+				vndkprivate = append(vndkprivate, filename)
+			}
+			if ctx.DeviceConfig().VndkUseCoreVariant() && !c.mustUseVendorVariant() {
+				vndkcorevariant = append(vndkcorevariant, filename)
+			}
+		}
+	})
+	llndk = android.SortedUniqueStrings(llndk)
+	vndkcore = android.SortedUniqueStrings(vndkcore)
+	vndksp = android.SortedUniqueStrings(vndksp)
+	vndkprivate = android.SortedUniqueStrings(vndkprivate)
+	vndkcorevariant = android.SortedUniqueStrings(vndkcorevariant)
+
+	installListFile(ctx, llndk, "vndk", "llndk.libraries.txt")
+	installListFile(ctx, vndkcore, "vndk", "vndkcore.libraries.txt")
+	installListFile(ctx, vndksp, "vndk", "vndksp.libraries.txt")
+	installListFile(ctx, vndkprivate, "vndk", "vndkprivate.libraries.txt")
+	installListFile(ctx, vndkcorevariant, "vndk", "vndkcorevariant.libraries.txt")
+
+	// merged & tagged & filtered-out(libclang_rt)
+	filterOutLibClangRt := func(libList []string) (filtered []string) {
+		for _, lib := range libList {
+			if !strings.HasPrefix(lib, "libclang_rt.") {
+				filtered = append(filtered, lib)
+			}
+		}
+		return
+	}
+	merged = append(merged, addPrefix(filterOutLibClangRt(llndk), "LLNDK: ")...)
+	merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...)
+	merged = append(merged, addPrefix(filterOutLibClangRt(vndkcore), "VNDK-core: ")...)
+	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
+
+	installListFile(ctx, merged, "vndk", "vndk.libraries.txt")
+}