Generate META/apexkeys.txt

This file contains information about public/private keys of
_installed_ apexes

Details
- In GenerateAndroidBuildActions of apexBundle, prebuiltApex, apexSet,
  set a provider with the filepath of the apex's key information
- In GenerateAndroidBuildActions of androidDevice, iterate over
  `allInstalledModules`. If a module has a provider with ApexKeyInfo, it
will be concatenated to META/apexkeys.txt

Test: verified that META/apexkeys.txt is identical between make and
soong
Bug: 388633394
Change-Id: I7ac40839c0dfb6a7efabad6a8ff51f30ed393b68

Change-Id: I97c8cf82186ab47ed3ff2a647bf592a96a53b5e4
diff --git a/apex/apex.go b/apex/apex.go
index 4dd3d4c..bda5f2f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2263,6 +2263,8 @@
 		FlatListPath: a.FlatListPath(),
 		Updatable:    a.Updatable(),
 	})
+
+	android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{a.apexKeysPath})
 }
 
 // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 0a97027..89b0091 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -21,6 +21,7 @@
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
+	"android/soong/filesystem"
 	"android/soong/java"
 	"android/soong/provenance"
 
@@ -677,6 +678,8 @@
 	}
 
 	ctx.SetOutputFiles(android.Paths{p.outputApex}, "")
+
+	android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{p.apexKeysPath})
 }
 
 func (p *Prebuilt) ProvenanceMetaDataFile() android.Path {
@@ -873,4 +876,6 @@
 	}
 
 	ctx.SetOutputFiles(android.Paths{a.outputApex}, "")
+
+	android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{a.apexKeysPath})
 }
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 31678aa..8b0dc15 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -175,7 +175,7 @@
 
 	allInstalledModules := a.allInstalledModules(ctx)
 
-	a.buildTargetFilesZip(ctx)
+	a.buildTargetFilesZip(ctx, allInstalledModules)
 	a.buildProguardZips(ctx, allInstalledModules)
 
 	var deps []android.Path
@@ -393,7 +393,7 @@
 	destSubdir string
 }
 
-func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext) {
+func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstalledModules []android.Module) {
 	targetFilesDir := android.PathForModuleOut(ctx, "target_files_dir")
 	targetFilesZip := android.PathForModuleOut(ctx, "target_files.zip")
 
@@ -497,7 +497,7 @@
 	}
 
 	a.copyImagesToTargetZip(ctx, builder, targetFilesDir)
-	a.copyMetadataToTargetZip(ctx, builder, targetFilesDir)
+	a.copyMetadataToTargetZip(ctx, builder, targetFilesDir, allInstalledModules)
 
 	builder.Command().
 		BuiltTool("soong_zip").
@@ -549,7 +549,7 @@
 	}
 }
 
-func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath) {
+func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath, allInstalledModules []android.Module) {
 	// Create a META/ subdirectory
 	builder.Command().Textf("mkdir -p %s/META", targetFilesDir.String())
 	if proptools.Bool(a.deviceProps.Ab_ota_updater) {
@@ -597,8 +597,24 @@
 	if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil {
 		builder.Command().Textf("cp").Input(releaseTools).Textf(" %s/META/", targetFilesDir.String())
 	}
+	// apexkeys.txt
+	var installedApexKeys []android.Path
+	for _, installedModule := range allInstalledModules {
+		if info, ok := android.OtherModuleProvider(ctx, installedModule, ApexKeyPathInfoProvider); ok {
+			installedApexKeys = append(installedApexKeys, info.ApexKeyPath)
+		}
+	}
+	installedApexKeys = android.SortedUniquePaths(installedApexKeys) // Sort by keypath to match make
+	builder.Command().Text("cat").Inputs(installedApexKeys).Textf(" >> %s/META/apexkeys.txt", targetFilesDir.String())
+
 }
 
+type ApexKeyPathInfo struct {
+	ApexKeyPath android.Path
+}
+
+var ApexKeyPathInfoProvider = blueprint.NewProvider[ApexKeyPathInfo]()
+
 // Filenames for the partition specific fs_config files.
 // Hardcode the ramdisk files to their boot image prefix
 func (a *androidDevice) filesystemConfigNameForTargetFiles(partition string) string {