Generate hidden API flags for a bootclasspath_fragment

This change adds support for generating the hidden API flags for the
contents of a bootclasspath_fragment. Currently, it will only work for
the art-bootclasspath-fragment as it has no support for creating
dependencies between bootclasspath_fragment modules which will be
needed for handling any other bootclasspath_fragment.

The hidden API flag generation added by this change is completely
separate to the normal hidden API processing and is not as yet encoded
in dex jars so will have no effect on the runtime.

The generated files are provided for use by other modules and copied
into the sdk snapshot. That is needed to allow the build to verify that
the hidden API flags generated by the individual bootclasspath_fragment
modules are consistent with the flags generated for the whole
bootclasspath, whether building from source or prebuilts.

Bug: 179354495
Test: m art-module-sdk
      m out/soong/.intermediates/art/build/boot/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/all-flags.csv
      m out/soong/hiddenapi/hiddenapi-flags.csv
      - test that the former file is a subset of the latter and that
        where they overlap they are identical.
Change-Id: Ie27303e2960953db1b7abe95510e3bca4411b09a
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 335f5b8..8174524 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -166,7 +166,7 @@
 //
 // The rule is initialized but not built so that the caller can modify it and select an appropriate
 // name.
-func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.OutputPath, bootDexJars android.Paths, sdkKindToPathList map[android.SdkKind]android.Paths) *android.RuleBuilder {
+func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, sdkKindToPathList map[android.SdkKind]android.Paths) *android.RuleBuilder {
 	// Singleton rule which applies hiddenapi on all boot class path dex files.
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -338,23 +338,49 @@
 	},
 }
 
-// hiddenAPIFlagFileInfo contains paths resolved from HiddenAPIFlagFileProperties
+// hiddenAPIFlagFileInfo contains paths resolved from HiddenAPIFlagFileProperties and also generated
+// by hidden API processing.
+//
+// This is used both for an individual bootclasspath_fragment to provide it to other modules and
+// for a module to collate the files from the fragments it depends upon. That is why the fields are
+// all Paths even though they are initialized with a single path.
 type hiddenAPIFlagFileInfo struct {
 	// categoryToPaths maps from the flag file category to the paths containing information for that
 	// category.
 	categoryToPaths map[*hiddenAPIFlagFileCategory]android.Paths
+
+	// The paths to the generated stub-flags.csv files.
+	StubFlagsPaths android.Paths
+
+	// The paths to the generated annotation-flags.csv files.
+	AnnotationFlagsPaths android.Paths
+
+	// The paths to the generated metadata.csv files.
+	MetadataPaths android.Paths
+
+	// The paths to the generated index.csv files.
+	IndexPaths android.Paths
+
+	// The paths to the generated all-flags.csv files.
+	AllFlagsPaths android.Paths
 }
 
 func (i *hiddenAPIFlagFileInfo) append(other hiddenAPIFlagFileInfo) {
 	for _, category := range hiddenAPIFlagFileCategories {
 		i.categoryToPaths[category] = append(i.categoryToPaths[category], other.categoryToPaths[category]...)
 	}
+	i.StubFlagsPaths = append(i.StubFlagsPaths, other.StubFlagsPaths...)
+	i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPaths...)
+	i.MetadataPaths = append(i.MetadataPaths, other.MetadataPaths...)
+	i.IndexPaths = append(i.IndexPaths, other.IndexPaths...)
+	i.AllFlagsPaths = append(i.AllFlagsPaths, other.AllFlagsPaths...)
 }
 
 var hiddenAPIFlagFileInfoProvider = blueprint.NewProvider(hiddenAPIFlagFileInfo{})
 
-// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
-// flags from all the modules, the stub flags, augmented with some additional configuration files.
+// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
+// the flags from all the modules, the stub flags, augmented with some additional configuration
+// files.
 //
 // baseFlagsPath is the path to the flags file containing all the information from the stubs plus
 // an entry for every single member in the dex implementation jars of the individual modules. Every
@@ -365,19 +391,7 @@
 //
 // augmentationInfo is a struct containing paths to files that augment the information provided by
 // the moduleSpecificFlagsPaths.
-// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
-// flags from all the modules, the stub flags, augmented with some additional configuration files.
-//
-// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
-// an entry for every single member in the dex implementation jars of the individual modules. Every
-// signature in any of the other files MUST be included in this file.
-//
-// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
-// information from the baseFlagsPath as well as from annotations within the source.
-//
-// augmentationInfo is a struct containing paths to files that augment the information provided by
-// the moduleSpecificFlagsPaths.
-func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIFlagFileInfo) {
+func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
 	tempPath := tempPathForRestat(ctx, outputPath)
 	rule := android.NewRuleBuilder(pctx, ctx)
 	command := rule.Command().
@@ -388,7 +402,7 @@
 
 	// Add the options for the different categories of flag files.
 	for _, category := range hiddenAPIFlagFileCategories {
-		paths := augmentationInfo.categoryToPaths[category]
+		paths := flagFileInfo.categoryToPaths[category]
 		for _, path := range paths {
 			category.commandMutator(command, path)
 		}
@@ -396,5 +410,103 @@
 
 	commitChangeForRestat(rule, tempPath, outputPath)
 
-	rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
+	rule.Build(name, desc)
+}
+
+// hiddenAPIGenerateAllFlagsForBootclasspathFragment will generate all the flags for a fragment
+// of the bootclasspath.
+//
+// It takes:
+// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
+// * The list of modules that are the contents of the fragment.
+// * The additional manually curated flag files to use.
+//
+// It generates:
+// * stub-flags.csv
+// * annotation-flags.csv
+// * metadata.csv
+// * index.csv
+// * all-flags.csv
+func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
+
+	hiddenApiSubDir := "modular-hiddenapi"
+
+	bootDexJars := android.Paths{}
+	classesJars := android.Paths{}
+	for _, module := range contents {
+		if hiddenAPI, ok := module.(hiddenAPIIntf); ok {
+			classesJars = append(classesJars, hiddenAPI.classesJars()...)
+			bootDexJar := hiddenAPI.bootDexJar()
+			if bootDexJar == nil {
+				ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+			} else {
+				bootDexJars = append(bootDexJars, bootDexJar)
+			}
+		} else {
+			ctx.ModuleErrorf("module %s does not implement hiddenAPIIntf", module)
+		}
+	}
+
+	// Generate the stub-flags.csv.
+	stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
+	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, stubJarsByKind)
+	rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
+
+	// Generate the set of flags from the annotations in the source code.
+	annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        hiddenAPIGenerateCSVRule,
+		Description: "modular hiddenapi annotation flags",
+		Inputs:      classesJars,
+		Output:      annotationFlagsCSV,
+		Implicit:    stubFlagsCSV,
+		Args: map[string]string{
+			"outFlag":      "--write-flags-csv",
+			"stubAPIFlags": stubFlagsCSV.String(),
+		},
+	})
+
+	// Generate the metadata from the annotations in the source code.
+	metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        hiddenAPIGenerateCSVRule,
+		Description: "modular hiddenapi metadata",
+		Inputs:      classesJars,
+		Output:      metadataCSV,
+		Implicit:    stubFlagsCSV,
+		Args: map[string]string{
+			"outFlag":      "--write-metadata-csv",
+			"stubAPIFlags": stubFlagsCSV.String(),
+		},
+	})
+
+	// Generate the index file from the annotations in the source code.
+	indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
+	rule = android.NewRuleBuilder(pctx, ctx)
+	rule.Command().
+		BuiltTool("merge_csv").
+		Flag("--zip_input").
+		Flag("--key_field signature").
+		FlagWithOutput("--output=", indexCSV).
+		Inputs(classesJars)
+	rule.Build("modular-hiddenapi-index", "modular hiddenapi index")
+
+	// Removed APIs need to be marked and in order to do that the flagFileInfo needs to specify files
+	// containing dex signatures of all the removed APIs. In the monolithic files that is done by
+	// manually combining all the removed.txt files for each API and then converting them to dex
+	// signatures, see the combined-removed-dex module. That will all be done automatically in future.
+	// For now removed APIs are ignored.
+	// TODO(b/179354495): handle removed apis automatically.
+
+	// Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
+	// files.
+	outputPath := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
+	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", outputPath, stubFlagsCSV, android.Paths{annotationFlagsCSV}, flagFileInfo)
+
+	// Store the paths in the info for use by other modules and sdk snapshot generation.
+	flagFileInfo.StubFlagsPaths = android.Paths{stubFlagsCSV}
+	flagFileInfo.AnnotationFlagsPaths = android.Paths{annotationFlagsCSV}
+	flagFileInfo.MetadataPaths = android.Paths{metadataCSV}
+	flagFileInfo.IndexPaths = android.Paths{indexCSV}
+	flagFileInfo.AllFlagsPaths = android.Paths{outputPath}
 }