Filter ABI dumps by LLNDK headers and version scripts

This commit changes the parameters to create LLNDK ABI dumps for 202404
and later versions. Soong invokes header-abi-linker with LLNDK headers
and version script rather than the implementation library's parameters.
The output dump contains more precise ABI information.

When soong compares the ABI with the prebuilt dumps in old versions,
it creates the source ABI dumps with the old parameters.

Test: make findlsdumps
Bug: 314010764
Change-Id: I228736188d07029ee1588b3502fd7c0061c104b9
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 74fae04..d4955c6 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -998,12 +998,30 @@
 			expectedDirs, f.IncludeDirs)
 	}
 
-	checkExportedIncludeDirs("libllndk", "android_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk", "android_vendor_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk_with_external_headers", "android_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk_with_external_headers", "android_vendor_arm64_armv8-a_shared", "include_llndk")
-	checkExportedIncludeDirs("libllndk_with_override_headers", "android_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk_with_override_headers", "android_vendor_arm64_armv8-a_shared", "include_llndk")
+	checkExportedIncludeDirs("libllndk", coreVariant, "include")
+	checkExportedIncludeDirs("libllndk", vendorVariant, "include")
+	checkExportedIncludeDirs("libllndk_with_external_headers", coreVariant, "include")
+	checkExportedIncludeDirs("libllndk_with_external_headers", vendorVariant, "include_llndk")
+	checkExportedIncludeDirs("libllndk_with_override_headers", coreVariant, "include")
+	checkExportedIncludeDirs("libllndk_with_override_headers", vendorVariant, "include_llndk")
+
+	checkAbiLinkerIncludeDirs := func(module string) {
+		t.Helper()
+		coreModule := result.ModuleForTests(module, coreVariant)
+		abiCheckFlags := ""
+		for _, output := range coreModule.AllOutputs() {
+			if strings.HasSuffix(output, ".so.llndk.lsdump") {
+				abiCheckFlags = coreModule.Output(output).Args["exportedHeaderFlags"]
+			}
+		}
+		vendorModule := result.ModuleForTests(module, vendorVariant).Module()
+		vendorInfo, _ := android.SingletonModuleProvider(result, vendorModule, FlagExporterInfoProvider)
+		android.AssertStringEquals(t, module+" has different exported include dirs for vendor variant and ABI check",
+			android.JoinPathsWithPrefix(vendorInfo.IncludeDirs, "-I"), abiCheckFlags)
+	}
+	checkAbiLinkerIncludeDirs("libllndk")
+	checkAbiLinkerIncludeDirs("libllndk_with_override_headers")
+	checkAbiLinkerIncludeDirs("libllndk_with_external_headers")
 }
 
 func TestLlndkHeaders(t *testing.T) {
diff --git a/cc/library.go b/cc/library.go
index 9119821..2677d28 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1153,7 +1153,7 @@
 	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...)
 
 	library.coverageOutputFile = transformCoverageFilesToZip(ctx, objs, library.getLibName(ctx))
-	library.linkSAbiDumpFiles(ctx, objs, fileName, unstrippedOutputFile)
+	library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile)
 
 	var transitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
 	if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 {
@@ -1222,6 +1222,45 @@
 	return exportIncludeDirs
 }
 
+func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string {
+	// The ABI checker does not need the preprocess which adds macro guards to function declarations.
+	includeDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings()
+
+	if library.Properties.Llndk.Override_export_include_dirs != nil {
+		includeDirs = append(includeDirs, android.PathsForModuleSrc(
+			ctx, library.Properties.Llndk.Override_export_include_dirs).Strings()...)
+	} else {
+		includeDirs = append(includeDirs, library.flagExporter.exportedIncludes(ctx).Strings()...)
+		// Ignore library.sabi.Properties.ReexportedIncludes because
+		// LLNDK does not reexport the implementation's dependencies, such as export_header_libs.
+	}
+
+	systemIncludeDirs := []string{}
+	if Bool(library.Properties.Llndk.Export_headers_as_system) {
+		systemIncludeDirs = append(systemIncludeDirs, includeDirs...)
+		includeDirs = nil
+	}
+	// Header libs.
+	includeDirs = append(includeDirs, deps.LlndkIncludeDirs.Strings()...)
+	systemIncludeDirs = append(systemIncludeDirs, deps.LlndkSystemIncludeDirs.Strings()...)
+	// The ABI checker does not distinguish normal and system headers.
+	return append(includeDirs, systemIncludeDirs...)
+}
+
+func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext,
+	deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string,
+	excludeSymbolVersions, excludeSymbolTags []string) android.Path {
+	// NDK symbols in version 34 are LLNDK symbols. Those in version 35 are not.
+	// TODO(b/314010764): Add parameters to read LLNDK symbols from the symbol file.
+	return transformDumpToLinkedDump(ctx,
+		sAbiDumpFiles, soFile, libFileName+".llndk",
+		library.llndkIncludeDirsForAbiCheck(ctx, deps),
+		android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file),
+		append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...),
+		append([]string{"platform-only"}, excludeSymbolTags...),
+		"34")
+}
+
 func getRefAbiDumpFile(ctx android.ModuleInstallPathContext,
 	versionedDumpDir, fileName string) android.OptionalPath {
 
@@ -1332,13 +1371,15 @@
 		false /* isLlndkOrNdk */, false /* allowExtensions */, "current", errorMessage)
 }
 
-func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
+func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) {
 	if library.sabi.shouldCreateSourceAbiDump() {
 		exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx)
 		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
 		currSdkVersion := currRefAbiDumpSdkVersion(ctx)
 		currVendorVersion := ctx.Config().VendorApiLevel()
-		sourceDump := transformDumpToLinkedDump(ctx,
+
+		// Generate source dumps.
+		implDump := transformDumpToLinkedDump(ctx,
 			objs.sAbiDumpFiles, soFile, fileName,
 			exportedIncludeDirs,
 			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
@@ -1346,8 +1387,25 @@
 			headerAbiChecker.Exclude_symbol_tags,
 			currSdkVersion)
 
-		for _, tag := range classifySourceAbiDump(ctx) {
-			addLsdumpPath(string(tag) + ":" + sourceDump.String())
+		var llndkDump android.Path
+		tags := classifySourceAbiDump(ctx)
+		for _, tag := range tags {
+			if tag == llndkLsdumpTag {
+				if llndkDump == nil {
+					// TODO(b/323447559): Evaluate if replacing sAbiDumpFiles with implDump is faster
+					llndkDump = library.linkLlndkSAbiDumpFiles(ctx,
+						deps, objs.sAbiDumpFiles, soFile, fileName,
+						headerAbiChecker.Exclude_symbol_versions,
+						headerAbiChecker.Exclude_symbol_tags)
+				}
+				addLsdumpPath(string(tag) + ":" + llndkDump.String())
+			} else {
+				addLsdumpPath(string(tag) + ":" + implDump.String())
+			}
+		}
+
+		// Diff source dumps and reference dumps.
+		for _, tag := range tags {
 			dumpDirName := tag.dirName()
 			if dumpDirName == "" {
 				continue
@@ -1362,10 +1420,15 @@
 			}
 			// Check against the previous version.
 			var prevVersion, currVersion string
+			sourceDump := implDump
 			// If this release config does not define VendorApiLevel, fall back to the old policy.
 			if isLlndk && currVendorVersion != "" {
 				prevVersion = ctx.Config().PrevVendorApiLevel()
 				currVersion = currVendorVersion
+				// LLNDK dumps are generated by different rules after trunk stable.
+				if android.IsTrunkStableVendorApiLevel(prevVersion) {
+					sourceDump = llndkDump
+				}
 			} else {
 				prevVersion, currVersion = crossVersionAbiDiffSdkVersions(ctx, dumpDir)
 			}
@@ -1376,8 +1439,12 @@
 					fileName, isLlndk || isNdk, currVersion, nameExt+prevVersion)
 			}
 			// Check against the current version.
+			sourceDump = implDump
 			if isLlndk && currVendorVersion != "" {
 				currVersion = currVendorVersion
+				if android.IsTrunkStableVendorApiLevel(currVersion) {
+					sourceDump = llndkDump
+				}
 			} else {
 				currVersion = currSdkVersion
 			}
@@ -1398,7 +1465,7 @@
 				continue
 			}
 			library.optInAbiDiff(ctx,
-				sourceDump, optInDumpFile.Path(),
+				implDump, optInDumpFile.Path(),
 				fileName, "opt"+strconv.Itoa(i), optInDumpDirPath.String())
 		}
 	}
@@ -1765,9 +1832,6 @@
 	if props := library.getHeaderAbiCheckerProperties(ctx); props.Symbol_file != nil {
 		return props.Symbol_file
 	}
-	if ctx.Module().(*Module).IsLlndk() {
-		return library.Properties.Llndk.Symbol_file
-	}
 	if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
 		return library.Properties.Stubs.Symbol_file
 	}