Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 537ea3d0 authored by Paul Duffin's avatar Paul Duffin
Browse files

Generate monolithic hidden API files direct from class jars

Previously, the monolithic hidden API files, e.g. hiddenapi-index.csv
file, were generated in two steps. First, each module created its own
files using the information in its class jars. Then, the monolithic
files were created by merging those module specific files into a larger
file.

This change switches to generating the monolithic files directly from
the class jar files and bypassing the intermediate files.

In order to ensure that this change did not change the monolithic files
it is necessary for the hiddenapi-metadata.csv to go through a
reformatting step. Hopefully, this will be able to be removed in a
follow up change.

Bug: 179354495
Test: verified that the monolithic out/soong/hiddenapi/... files are
      unchanged by this change
Change-Id: I5a78e747516014b7c0f402a4b4431b14be6a84b2
parent 850e61f2
Loading
Loading
Loading
Loading
+16 −16
Original line number Diff line number Diff line
@@ -4564,7 +4564,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
	checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedInputs string) {
		t.Helper()
		platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common")
		indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index")
		indexRule := platformBootclasspath.Rule("monolithic_hidden_API_index")
		java.CheckHiddenAPIRuleInputs(t, expectedInputs, indexRule)
	}

@@ -4602,10 +4602,10 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")

		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
		// Verify the correct module jars contribute to the hiddenapi index file.
		checkHiddenAPIIndexInputs(t, ctx, `
.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
.intermediates/libbar.stubs/android_common/combined/libbar.stubs.jar
.intermediates/libfoo/android_common_myapex/combined/libfoo.jar
`)
	})

@@ -4636,10 +4636,10 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")

		// Make sure that the dex file from the apex_set contributes to the hiddenapi index file.
		// Verify the correct module jars contribute to the hiddenapi index file.
		checkHiddenAPIIndexInputs(t, ctx, `
.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
.intermediates/libbar.stubs/android_common/combined/libbar.stubs.jar
.intermediates/libfoo/android_common_myapex/combined/libfoo.jar
`)
	})

@@ -4743,10 +4743,10 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")

		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
		// Verify the correct module jars contribute to the hiddenapi index file.
		checkHiddenAPIIndexInputs(t, ctx, `
.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv
.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
.intermediates/prebuilt_libbar.stubs/android_common/combined/libbar.stubs.jar
.intermediates/prebuilt_libfoo/android_common_myapex/combined/libfoo.jar
`)
	})

@@ -4810,10 +4810,10 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar")

		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
		// Verify the correct module jars contribute to the hiddenapi index file.
		checkHiddenAPIIndexInputs(t, ctx, `
.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
.intermediates/libfoo/android_common_apex10000/hiddenapi/index.csv
.intermediates/libbar/android_common_myapex/javac/libbar.jar
.intermediates/libfoo/android_common_apex10000/javac/libfoo.jar
`)
	})

@@ -4879,10 +4879,10 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")

		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
		// Verify the correct module jars contribute to the hiddenapi index file.
		checkHiddenAPIIndexInputs(t, ctx, `
.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv
.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
.intermediates/prebuilt_libbar.stubs/android_common/combined/libbar.stubs.jar
.intermediates/prebuilt_libfoo/android_common_myapex/combined/libfoo.jar
`)
	})
}
+6 −4
Original line number Diff line number Diff line
@@ -129,7 +129,7 @@ type commonBootclasspathFragment interface {
	// produceHiddenAPIAllFlagsFile produces the all-flags.csv and intermediate files.
	//
	// Updates the supplied flagFileInfo with the paths to the generated files set.
	produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo)
	produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo)
}

func bootclasspathFragmentFactory() android.Module {
@@ -465,9 +465,11 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.
	// Resolve the properties to paths.
	flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)

	hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, contents)

	// Delegate the production of the hidden API all flags file to a module type specific method.
	common := ctx.Module().(commonBootclasspathFragment)
	common.produceHiddenAPIAllFlagsFile(ctx, contents, stubJarsByKind, &flagFileInfo)
	common.produceHiddenAPIAllFlagsFile(ctx, hiddenAPIModules, stubJarsByKind, &flagFileInfo)

	// Store the information for use by platform_bootclasspath.
	ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
@@ -475,7 +477,7 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.

// produceHiddenAPIAllFlagsFile produces the hidden API all-flags.csv file (and supporting files)
// for the fragment.
func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []android.Module, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
	// If no stubs have been provided then don't perform hidden API processing. This is a temporary
	// workaround to avoid existing bootclasspath_fragments that do not provide stubs breaking the
	// build.
@@ -722,7 +724,7 @@ func (module *prebuiltBootclasspathFragmentModule) Name() string {

// produceHiddenAPIAllFlagsFile returns a path to the prebuilt all-flags.csv or nil if none is
// specified.
func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, _ []android.Module, _ map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
	pathsForOptionalSrc := func(src *string) android.Paths {
		if src == nil {
			// TODO(b/179354495): Fail if this is not provided once prebuilts have been updated.
+7 −15
Original line number Diff line number Diff line
@@ -91,31 +91,22 @@ type hiddenAPI struct {
	classesJarPaths android.Paths
}

func (h *hiddenAPI) flagsCSV() android.Path {
	return h.flagsCSVPath
}

func (h *hiddenAPI) metadataCSV() android.Path {
	return h.metadataCSVPath
}

func (h *hiddenAPI) bootDexJar() android.Path {
	return h.bootDexJarPath
}

func (h *hiddenAPI) indexCSV() android.Path {
	return h.indexCSVPath
}

func (h *hiddenAPI) classesJars() android.Paths {
	return h.classesJarPaths
}

// hiddenAPIModule is the interface a module that embeds the hiddenAPI structure must implement.
type hiddenAPIModule interface {
	android.Module
	hiddenAPIIntf
}

type hiddenAPIIntf interface {
	bootDexJar() android.Path
	flagsCSV() android.Path
	indexCSV() android.Path
	metadataCSV() android.Path
	classesJars() android.Paths
}

@@ -312,6 +303,7 @@ func buildRuleToGenerateIndex(ctx android.ModuleContext, desc string, classesJar
		BuiltTool("merge_csv").
		Flag("--zip_input").
		Flag("--key_field signature").
		FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
		FlagWithOutput("--output=", indexCSV).
		Inputs(classesJars)
	rule.Build(desc, desc)
+51 −26
Original line number Diff line number Diff line
@@ -417,12 +417,12 @@ func pathForValidation(ctx android.PathContext, path android.WritablePath) andro
// 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.
// annotationFlags is the path to the annotation flags file generated from annotation information
// in each module.
//
// augmentationInfo is a struct containing paths to files that augment the information provided by
// the moduleSpecificFlagsPaths.
func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
// flagFileInfo is a struct containing paths to files that augment the information provided by
// the annotationFlags.
func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlags android.Path, flagFileInfo *hiddenAPIFlagFileInfo) {

	// The file which is used to record that the flags file is valid.
	var validFile android.WritablePath
@@ -452,7 +452,7 @@ func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc st
	command := rule.Command().
		BuiltTool("generate_hiddenapi_lists").
		FlagWithInput("--csv ", baseFlagsPath).
		Inputs(moduleSpecificFlagsPaths).
		Input(annotationFlags).
		FlagWithOutput("--output ", tempPath)

	// Add the options for the different categories of flag files.
@@ -490,31 +490,18 @@ func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc st
// * metadata.csv
// * index.csv
// * all-flags.csv
func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {

func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []hiddenAPIModule, 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.
	bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, contents)
	stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, stubJarsByKind)
	rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")

	// Extract the classes jars from the contents.
	classesJars := extractClassJarsFromHiddenAPIModules(ctx, contents)

	// Generate the set of flags from the annotations in the source code.
	annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
	buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
@@ -523,7 +510,7 @@ func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext
	metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
	buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)

	// Generate the index file from the annotations in the source code.
	// Generate the index file from the CSV files in the classes jars.
	indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
	buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)

@@ -537,7 +524,7 @@ func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext
	// 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)
	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", outputPath, stubFlagsCSV, annotationFlagsCSV, flagFileInfo)

	// Store the paths in the info for use by other modules and sdk snapshot generation.
	flagFileInfo.StubFlagsPaths = android.Paths{stubFlagsCSV}
@@ -546,3 +533,41 @@ func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext
	flagFileInfo.IndexPaths = android.Paths{indexCSV}
	flagFileInfo.AllFlagsPaths = android.Paths{outputPath}
}

// gatherHiddenAPIModuleFromContents gathers the hiddenAPIModule from the supplied contents.
func gatherHiddenAPIModuleFromContents(ctx android.ModuleContext, contents []android.Module) []hiddenAPIModule {
	hiddenAPIModules := []hiddenAPIModule{}
	for _, module := range contents {
		if hiddenAPI, ok := module.(hiddenAPIModule); ok {
			hiddenAPIModules = append(hiddenAPIModules, hiddenAPI)
		} else if _, ok := module.(*DexImport); ok {
			// Ignore this for the purposes of hidden API processing
		} else {
			ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
		}
	}
	return hiddenAPIModules
}

// extractBootDexJarsFromHiddenAPIModules extracts the boot dex jars from the supplied modules.
func extractBootDexJarsFromHiddenAPIModules(ctx android.ModuleContext, contents []hiddenAPIModule) android.Paths {
	bootDexJars := android.Paths{}
	for _, module := range contents {
		bootDexJar := module.bootDexJar()
		if bootDexJar == nil {
			ctx.ModuleErrorf("module %s does not provide a dex jar", module)
		} else {
			bootDexJars = append(bootDexJars, bootDexJar)
		}
	}
	return bootDexJars
}

// extractClassJarsFromHiddenAPIModules extracts the class jars from the supplied modules.
func extractClassJarsFromHiddenAPIModules(ctx android.ModuleContext, contents []hiddenAPIModule) android.Paths {
	classesJars := android.Paths{}
	for _, module := range contents {
		classesJars = append(classesJars, module.classesJars()...)
	}
	return classesJars
}
+32 −112
Original line number Diff line number Diff line
@@ -257,17 +257,6 @@ func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleCont
	return defaultBootImageConfig(ctx)
}

// hiddenAPISupportingModule encapsulates the information provided by any module that contributes to
// the hidden API processing.
type hiddenAPISupportingModule struct {
	module android.Module

	bootDexJar  android.Path
	flagsCSV    android.Path
	indexCSV    android.Path
	metadataCSV android.Path
}

// generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) {

@@ -290,67 +279,6 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.
		return
	}

	// nilPathHandler will check the supplied path and if it is nil then it will either immediately
	// report an error, or it will defer the error reporting until it is actually used, depending
	// whether missing dependencies are allowed.
	var nilPathHandler func(path android.Path, name string, module android.Module) android.Path
	if ctx.Config().AllowMissingDependencies() {
		nilPathHandler = func(path android.Path, name string, module android.Module) android.Path {
			if path == nil {
				outputPath := android.PathForModuleOut(ctx, "missing", module.Name(), name)
				path = outputPath

				// Create an error rule that pretends to create the output file but will actually fail if it
				// is run.
				ctx.Build(pctx, android.BuildParams{
					Rule:   android.ErrorRule,
					Output: outputPath,
					Args: map[string]string{
						"error": fmt.Sprintf("missing hidden API file: %s for %s", name, module),
					},
				})
			}
			return path
		}
	} else {
		nilPathHandler = func(path android.Path, name string, module android.Module) android.Path {
			if path == nil {
				ctx.ModuleErrorf("module %s does not provide a %s file", module, name)
			}
			return path
		}
	}

	hiddenAPISupportingModules := []hiddenAPISupportingModule{}
	for _, module := range modules {
		if h, ok := module.(hiddenAPIIntf); ok {
			hiddenAPISupportingModule := hiddenAPISupportingModule{
				module:      module,
				bootDexJar:  nilPathHandler(h.bootDexJar(), "bootDexJar", module),
				flagsCSV:    nilPathHandler(h.flagsCSV(), "flagsCSV", module),
				indexCSV:    nilPathHandler(h.indexCSV(), "indexCSV", module),
				metadataCSV: nilPathHandler(h.metadataCSV(), "metadataCSV", module),
			}

			// If any errors were reported when trying to populate the hiddenAPISupportingModule struct
			// then don't add it to the list.
			if ctx.Failed() {
				continue
			}

			hiddenAPISupportingModules = append(hiddenAPISupportingModules, hiddenAPISupportingModule)
		} else if _, ok := module.(*DexImport); ok {
			// Ignore this for the purposes of hidden API processing
		} else {
			ctx.ModuleErrorf("module %s of type %s does not support hidden API processing", module, ctx.OtherModuleType(module))
		}
	}

	moduleSpecificFlagsPaths := android.Paths{}
	for _, module := range hiddenAPISupportingModules {
		moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV)
	}

	flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
	for _, fragment := range fragments {
		if ctx.OtherModuleHasProvider(fragment, hiddenAPIFlagFileInfoProvider) {
@@ -362,61 +290,53 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.
	// Store the information for testing.
	ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)

	outputPath := hiddenAPISingletonPaths(ctx).flags
	baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
	buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "hiddenapi flags", outputPath, baseFlagsPath, moduleSpecificFlagsPaths, &flagFileInfo)

	b.generateHiddenAPIStubFlagsRules(ctx, hiddenAPISupportingModules)
	b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules)
	b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules)
}

func (b *platformBootclasspathModule) generateHiddenAPIStubFlagsRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
	bootDexJars := android.Paths{}
	for _, module := range modules {
		bootDexJars = append(bootDexJars, module.bootDexJar)
	}
	hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, modules)

	sdkKindToStubPaths := hiddenAPIGatherStubLibDexJarPaths(ctx, nil)

	outputPath := hiddenAPISingletonPaths(ctx).stubFlags
	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, outputPath, bootDexJars, sdkKindToStubPaths)
	// Generate the monolithic stub-flags.csv file.
	bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, hiddenAPIModules)
	stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
	rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, sdkKindToStubPaths)
	rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags")
}

func (b *platformBootclasspathModule) generateHiddenAPIIndexRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
	indexes := android.Paths{}
	for _, module := range modules {
		indexes = append(indexes, module.indexCSV)
	}
	// Extract the classes jars from the contents.
	classesJars := extractClassJarsFromHiddenAPIModules(ctx, hiddenAPIModules)

	rule := android.NewRuleBuilder(pctx, ctx)
	rule.Command().
		BuiltTool("merge_csv").
		Flag("--key_field signature").
		FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
		FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index).
		Inputs(indexes)
	rule.Build("platform-bootclasspath-monolithic-hiddenapi-index", "monolithic hidden API index")
}
	// Generate the annotation-flags.csv file from all the module annotations.
	annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags.csv")
	buildRuleToGenerateAnnotationFlags(ctx, "monolithic hiddenapi flags", classesJars, stubFlags, annotationFlags)

func (b *platformBootclasspathModule) generatedHiddenAPIMetadataRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
	metadataCSVFiles := android.Paths{}
	for _, module := range modules {
		metadataCSVFiles = append(metadataCSVFiles, module.metadataCSV)
	}
	// Generate the monotlithic hiddenapi-flags.csv file.
	allFlags := hiddenAPISingletonPaths(ctx).flags
	buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "hiddenapi flags", allFlags, stubFlags, annotationFlags, &flagFileInfo)

	rule := android.NewRuleBuilder(pctx, ctx)
	// Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations
	// in the source code.
	intermediateMetadataCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "intermediate-metadata.csv")
	buildRuleToGenerateMetadata(ctx, "monolithic hidden API metadata", classesJars, stubFlags, intermediateMetadataCSV)

	outputPath := hiddenAPISingletonPaths(ctx).metadata
	// Reformat the intermediate file to add | quotes just in case that is important for the tools
	// that consume the metadata file.
	// TODO(b/179354495): Investigate whether it is possible to remove this reformatting step.
	metadataCSV := hiddenAPISingletonPaths(ctx).metadata
	b.buildRuleMergeCSV(ctx, "reformat monolithic hidden API metadata", android.Paths{intermediateMetadataCSV}, metadataCSV)

	// Generate the monolithic hiddenapi-index.csv file directly from the CSV files in the classes
	// jars.
	indexCSV := hiddenAPISingletonPaths(ctx).index
	buildRuleToGenerateIndex(ctx, "monolithic hidden API index", classesJars, indexCSV)
}

func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) {
	rule := android.NewRuleBuilder(pctx, ctx)
	rule.Command().
		BuiltTool("merge_csv").
		Flag("--key_field signature").
		FlagWithOutput("--output=", outputPath).
		Inputs(metadataCSVFiles)
		Inputs(inputPaths)

	rule.Build("platform-bootclasspath-monolithic-hiddenapi-metadata", "monolithic hidden API metadata")
	rule.Build(desc, desc)
}

// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g.
Loading