Build proguard zips in soong-only builds

This builds the zips but doesn't dist them, I'll do that in a followup.

Bug: 395160816
Test: Diffed proguard-dict.zip proguard-usage.zip and proguard-dict-mapping.textproto between soong and make
Change-Id: Ic112427e4a2fdaf92a1d0a96d0f1c100b57be37a
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 959ef37..3b8bf93 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -17,16 +17,24 @@
 import (
 	"cmp"
 	"fmt"
+	"path/filepath"
 	"slices"
 	"strings"
 	"sync/atomic"
 
 	"android/soong/android"
+	"android/soong/java"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
+var proguardDictToProto = pctx.AndroidStaticRule("proguard_dict_to_proto", blueprint.RuleParams{
+	Command:     `${symbols_map} -r8 $in -location $location -write_if_changed $out`,
+	Restat:      true,
+	CommandDeps: []string{"${symbols_map}"},
+}, "location")
+
 type PartitionNameProperties struct {
 	// Name of the super partition filesystem module
 	Super_partition_name *string
@@ -161,7 +169,11 @@
 		}
 	}
 
+	allInstalledModules := a.allInstalledModules(ctx)
+
 	a.buildTargetFilesZip(ctx)
+	a.buildProguardZips(ctx, allInstalledModules)
+
 	var deps []android.Path
 	if proptools.String(a.partitionProps.Super_partition_name) != "" {
 		superImage := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
@@ -305,6 +317,52 @@
 	}
 }
 
+func (a *androidDevice) buildProguardZips(ctx android.ModuleContext, allInstalledModules []android.Module) {
+	dictZip := android.PathForModuleOut(ctx, "proguard-dict.zip")
+	dictZipBuilder := android.NewRuleBuilder(pctx, ctx)
+	dictZipCmd := dictZipBuilder.Command().BuiltTool("soong_zip").Flag("-d").FlagWithOutput("-o ", dictZip)
+
+	dictMapping := android.PathForModuleOut(ctx, "proguard-dict-mapping.textproto")
+	dictMappingBuilder := android.NewRuleBuilder(pctx, ctx)
+	dictMappingCmd := dictMappingBuilder.Command().BuiltTool("symbols_map").Flag("-merge").Output(dictMapping)
+
+	protosDir := android.PathForModuleOut(ctx, "proguard_mapping_protos")
+
+	usageZip := android.PathForModuleOut(ctx, "proguard-usage.zip")
+	usageZipBuilder := android.NewRuleBuilder(pctx, ctx)
+	usageZipCmd := usageZipBuilder.Command().BuiltTool("merge_zips").Output(usageZip)
+
+	for _, mod := range allInstalledModules {
+		if proguardInfo, ok := android.OtherModuleProvider(ctx, mod, java.ProguardProvider); ok {
+			// Maintain these out/target/common paths for backwards compatibility. They may be able
+			// to be changed if tools look up file locations from the protobuf, but I'm not
+			// exactly sure how that works.
+			dictionaryFakePath := fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/proguard_dictionary", proguardInfo.Class, proguardInfo.ModuleName)
+			dictZipCmd.FlagWithArg("-e ", dictionaryFakePath)
+			dictZipCmd.FlagWithInput("-f ", proguardInfo.ProguardDictionary)
+			dictZipCmd.Textf("-e out/target/common/obj/%s/%s_intermediates/classes.jar", proguardInfo.Class, proguardInfo.ModuleName)
+			dictZipCmd.FlagWithInput("-f ", proguardInfo.ClassesJar)
+
+			protoFile := protosDir.Join(ctx, filepath.Dir(dictionaryFakePath), "proguard_dictionary.textproto")
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   proguardDictToProto,
+				Input:  proguardInfo.ProguardDictionary,
+				Output: protoFile,
+				Args: map[string]string{
+					"location": dictionaryFakePath,
+				},
+			})
+			dictMappingCmd.Input(protoFile)
+
+			usageZipCmd.Input(proguardInfo.ProguardUsageZip)
+		}
+	}
+
+	dictZipBuilder.Build("proguard_dict_zip", "Building proguard dictionary zip")
+	dictMappingBuilder.Build("proguard_dict_mapping_proto", "Building proguard mapping proto")
+	usageZipBuilder.Build("proguard_usage_zip", "Building proguard usage zip")
+}
+
 // Helper structs for target_files.zip creation
 type targetFilesZipCopy struct {
 	srcModule  *string