Make vndk*.libraries.txt as soong modules

Migrating from Make to Soong.

These files are generated by singleton and had to be defined as PREBUILT
modules in Make (system/core/rootdir/Android.mk)

Now, they are converted as soong modules.

To make things easier, a special kind of module 'vndk_libraries_txt' is
added which works like prebuilt_etc but its src file is generated by
soong.

Bug: 141450808
Test: m llndk.libraries.txt
Change-Id: Ia77e6af73f760fcd77020218c5bc37892b2cda1f
diff --git a/cc/cc_test.go b/cc/cc_test.go
index dcf117c..80a6361 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -264,11 +264,24 @@
 	}
 }
 
+func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
+	t.Helper()
+	assertString(t, params.Rule.String(), android.WriteFile.String())
+	actual := strings.FieldsFunc(strings.ReplaceAll(params.Args["content"], "\\n", "\n"), func(r rune) bool { return r == '\n' })
+	assertArrayString(t, actual, expected)
+}
+
 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)
+	checkWriteFileOutput(t, vndkSnapshot.Output(output), expected)
+}
+
+func checkVndkLibrariesOutput(t *testing.T, ctx *android.TestContext, module string, expected []string) {
+	t.Helper()
+	vndkLibraries := ctx.ModuleForTests(module, "")
+	output := insertVndkVersion(module, "VER")
+	checkWriteFileOutput(t, vndkLibraries.Output(output), expected)
 }
 
 func TestVndk(t *testing.T) {
@@ -321,6 +334,21 @@
 				},
 			},
 		}
+		vndk_libraries_txt {
+			name: "llndk.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndkcore.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndksp.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndkprivate.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndkcorevariant.libraries.txt",
+		}
 	`, config)
 
 	checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
@@ -355,7 +383,6 @@
 	checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so"})
 	checkVndkOutput(t, ctx, "vndk/vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so"})
 	checkVndkOutput(t, ctx, "vndk/vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.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",
@@ -371,19 +398,25 @@
 		"VNDK-private: libvndk-private.so",
 		"VNDK-private: libvndk_sp_private-x.so",
 	})
-	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-private.so", "libvndk.so",
-	})
-	checkVndkOutput(t, ctx, "vndk/vndksp.libraries.txt", []string{
-		"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so",
-	})
-	checkVndkOutput(t, ctx, "vndk/vndkprivate.libraries.txt", []string{
-		"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so",
-	})
-	checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", []string{})
+	checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libm.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", nil)
+}
+
+func TestVndkLibrariesTxtAndroidMk(t *testing.T) {
+	config := android.TestArchConfig(buildDir, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := testCcWithConfig(t, `
+		vndk_libraries_txt {
+			name: "llndk.libraries.txt",
+		}`, config)
+
+	module := ctx.ModuleForTests("llndk.libraries.txt", "")
+	entries := android.AndroidMkEntriesForTest(t, config, "", module.Module())
+	assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.VER.txt"})
 }
 
 func TestVndkUsingCoreVariant(t *testing.T) {
@@ -422,20 +455,17 @@
 			},
 			nocrt: true,
 		}
+
+		vndk_libraries_txt {
+			name: "vndkcorevariant.libraries.txt",
+		}
 	`, config)
 
-	checkVndkOutput(t, ctx, "vndk/vndkcore.libraries.txt", []string{"libvndk.so", "libvndk2.so"})
-	checkVndkOutput(t, ctx, "vndk/vndkcorevariant.libraries.txt", []string{
-		"libc++.so", "libvndk2.so", "libvndk_sp.so",
-	})
+	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", []string{"libc++.so", "libvndk2.so", "libvndk_sp.so"})
 }
 
 func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
-	config := android.TestArchConfig(buildDir, nil)
-	config.TestProductVariables.DeviceVndkVersion = nil
-	config.TestProductVariables.Platform_vndk_version = nil
-
-	ctx := testCcWithConfig(t, `
+	ctx := testCcNoVndk(t, `
 		cc_library {
 			name: "libvndk",
 			vendor_available: true,
@@ -444,7 +474,7 @@
 			},
 			nocrt: true,
 		}
-	`, config)
+	`)
 
 	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
 		"LLNDK: libc.so",
diff --git a/cc/testing.go b/cc/testing.go
index fafaeb0..4d6e50e 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -269,6 +269,7 @@
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
 	ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(VndkPrebuiltSharedFactory))
+	ctx.RegisterModuleType("vndk_libraries_txt", android.ModuleFactoryAdaptor(VndkLibrariesTxt))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("image", ImageMutator).Parallel()
 		ctx.BottomUp("link", LinkageMutator).Parallel()
diff --git a/cc/vndk.go b/cc/vndk.go
index bb4aafc..0b65aca 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -360,22 +360,99 @@
 }
 
 func init() {
+	android.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxt)
 	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 }
 
+type vndkLibrariesTxt struct {
+	android.ModuleBase
+	outputFile android.OutputPath
+}
+
+// vndk_libraries_txt is a special kind of module type in that it name is one of
+// - llndk.libraries.txt
+// - vndkcore.libraries.txt
+// - vndksp.libraries.txt
+// - vndkprivate.libraries.txt
+// - vndkcorevariant.libraries.txt
+// A module behaves like a prebuilt_etc but its content is generated by soong.
+// By being a soong module, these files can be referenced by other soong modules.
+// For example, apex_vndk can depend on these files as prebuilt.
+func VndkLibrariesTxt() android.Module {
+	m := &vndkLibrariesTxt{}
+	android.InitAndroidModule(m)
+	return m
+}
+
+func insertVndkVersion(filename string, vndkVersion string) string {
+	if index := strings.LastIndex(filename, "."); index != -1 {
+		return filename[:index] + "." + vndkVersion + filename[index:]
+	}
+	return filename
+}
+
+func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	var list []string
+	switch txt.Name() {
+	case "llndk.libraries.txt":
+		for _, filename := range android.SortedStringMapValues(llndkLibraries(ctx.Config())) {
+			if strings.HasPrefix(filename, "libclang_rt.hwasan-") {
+				continue
+			}
+			list = append(list, filename)
+		}
+	case "vndkcore.libraries.txt":
+		list = android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
+	case "vndksp.libraries.txt":
+		list = android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
+	case "vndkprivate.libraries.txt":
+		list = android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
+	case "vndkcorevariant.libraries.txt":
+		list = android.SortedStringMapValues(vndkUsingCoreVariantLibraries(ctx.Config()))
+	default:
+		ctx.ModuleErrorf("name(%s) is unknown.", txt.Name())
+		return
+	}
+
+	filename := insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
+	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      txt.outputFile,
+		Description: "Writing " + txt.outputFile.String(),
+		Args: map[string]string{
+			"content": strings.Join(list, "\\n"),
+		},
+	})
+
+	installPath := android.PathForModuleInstall(ctx, "etc")
+	ctx.InstallFile(installPath, filename, txt.outputFile)
+}
+
+func (txt *vndkLibrariesTxt) AndroidMkEntries() android.AndroidMkEntries {
+	return android.AndroidMkEntries{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(txt.outputFile),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base())
+			},
+		},
+	}
+}
+
 func VndkSnapshotSingleton() android.Singleton {
 	return &vndkSnapshotSingleton{}
 }
 
 type vndkSnapshotSingleton struct {
-	installedLlndkLibraries      []string
-	llndkLibrariesFile           android.Path
-	vndkSpLibrariesFile          android.Path
-	vndkCoreLibrariesFile        android.Path
-	vndkPrivateLibrariesFile     android.Path
-	vndkCoreVariantLibrariesFile android.Path
-	vndkLibrariesFile            android.Path
-	vndkSnapshotZipFile          android.OptionalPath
+	installedLlndkLibraries  []string
+	llndkLibrariesFile       android.Path
+	vndkSpLibrariesFile      android.Path
+	vndkCoreLibrariesFile    android.Path
+	vndkPrivateLibrariesFile android.Path
+	vndkLibrariesFile        android.Path
+	vndkSnapshotZipFile      android.OptionalPath
 }
 
 func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -768,15 +845,13 @@
 	vndkcore := android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
 	vndksp := android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
 	vndkprivate := android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
-	vndkcorevariant := android.SortedStringMapValues(vndkUsingCoreVariantLibraries(ctx.Config()))
 
 	c.llndkLibrariesFile = installListFile(llndk, "llndk.libraries.txt")
 	c.vndkCoreLibrariesFile = installListFile(vndkcore, "vndkcore.libraries.txt")
 	c.vndkSpLibrariesFile = installListFile(vndksp, "vndksp.libraries.txt")
 	c.vndkPrivateLibrariesFile = installListFile(vndkprivate, "vndkprivate.libraries.txt")
-	c.vndkCoreVariantLibrariesFile = installListFile(vndkcorevariant, "vndkcorevariant.libraries.txt")
 
-	// merged & tagged & filtered-out(libclang_rt)
+	// Build list of vndk libs as merged & tagged & filter-out(libclang_rt):
 	// Since each target have different set of libclang_rt.* files,
 	// keep the common set of files in vndk.libraries.txt
 	var merged []string
@@ -812,12 +887,6 @@
 	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkPrivateLibraries(ctx.Config())), " "))
 	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(android.SortedStringKeys(vndkUsingCoreVariantLibraries(ctx.Config())), " "))
 
-	ctx.Strict("LLNDK_LIBRARIES_FILE", c.llndkLibrariesFile.String())
-	ctx.Strict("VNDKCORE_LIBRARIES_FILE", c.vndkCoreLibrariesFile.String())
-	ctx.Strict("VNDKSP_LIBRARIES_FILE", c.vndkSpLibrariesFile.String())
-	ctx.Strict("VNDKPRIVATE_LIBRARIES_FILE", c.vndkPrivateLibrariesFile.String())
-	ctx.Strict("VNDKCOREVARIANT_LIBRARIES_FILE", c.vndkCoreVariantLibrariesFile.String())
-
 	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
 	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
 }