diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index 3857b206b..a7c1e78a8 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -133,8 +133,8 @@ type BootclasspathFragmentModule struct { 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 []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) *HiddenAPIFlagOutput + // Updates the supplied hiddenAPIInfo with the paths to the generated files set. + produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput } var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil) @@ -538,45 +538,61 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. return nil } - // Convert the kind specific lists of modules into kind specific lists of jars. - stubJarsByKind := hiddenAPIGatherStubLibDexJarPaths(ctx, contents) + // Create hidden API input structure. + input := b.createHiddenAPIFlagInput(ctx, contents) // Performing hidden API processing without stubs is not supported and it is unlikely to ever be // required as the whole point of adding something to the bootclasspath fragment is to add it to // the bootclasspath in order to be used by something else in the system. Without any stubs it // cannot do that. - if len(stubJarsByKind) == 0 { + if len(input.StubDexJarsByKind) == 0 { return nil } // Store the information for use by other modules. - bootclasspathApiInfo := bootclasspathApiInfo{stubJarsByKind: stubJarsByKind} + bootclasspathApiInfo := bootclasspathApiInfo{stubJarsByKind: input.StubDexJarsByKind} ctx.SetProvider(bootclasspathApiInfoProvider, bootclasspathApiInfo) - // 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) - output := common.produceHiddenAPIAllFlagsFile(ctx, hiddenAPIModules, stubJarsByKind, &flagFileInfo) + output := common.produceHiddenAPIAllFlagsFile(ctx, hiddenAPIModules, input) - // Copy the output into the flagFileInfo - flagFileInfo.HiddenAPIFlagOutput = *output + // Initialize a hiddenAPIFlagFileInfo structure and provide it for use by other modules. + flagFileInfo := hiddenAPIFlagFileInfo{ + // The monolithic hidden API processing needs access to the flag files from all the fragments. + FlagFilesByCategory: input.FlagFilesByCategory, - // Store the information for use by platform_bootclasspath. + // The monolithic hidden API processing also needs access to all the output files produced by + // hidden API processing of this fragment. + HiddenAPIFlagOutput: *output, + } ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo) return output } +// createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived +// from the properties on this module and its dependencies. +func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module) HiddenAPIFlagInput { + input := newHiddenAPIFlagInput() + + // Update the input structure with information obtained from the stub libraries. + input.gatherStubLibInfo(ctx, contents) + + // Populate with flag file paths from the properties. + input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api) + + return input +} + // produceHiddenAPIAllFlagsFile produces the hidden API all-flags.csv file (and supporting files) // for the fragment. -func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) *HiddenAPIFlagOutput { - // Generate the rules to create the hidden API flags and update the supplied flagFileInfo with the +func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput { + // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the // paths to the created files. - return hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, stubJarsByKind, flagFileInfo) + return hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, input) } // generateBootImageBuildActions generates ninja rules to create the boot image if required for this @@ -800,7 +816,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, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) *HiddenAPIFlagOutput { +func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, _ HiddenAPIFlagInput) *HiddenAPIFlagOutput { pathForOptionalSrc := func(src *string) android.Path { if src == nil { // TODO(b/179354495): Fail if this is not provided once prebuilts have been updated. diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 99485b4ed..b5969e904 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -127,42 +127,6 @@ func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, sdkKind } } -// hiddenAPIGatherStubLibDexJarPaths gathers the paths to the dex jars from the dependencies added -// in hiddenAPIAddStubLibDependencies. -func hiddenAPIGatherStubLibDexJarPaths(ctx android.ModuleContext, contents []android.Module) map[android.SdkKind]android.Paths { - m := map[android.SdkKind]android.Paths{} - - // If the contents includes any java_sdk_library modules then add them to the stubs. - for _, module := range contents { - if _, ok := module.(SdkLibraryDependency); ok { - for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} { - dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind) - if dexJar != nil { - m[kind] = append(m[kind], dexJar) - } - } - } - } - - ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) { - tag := ctx.OtherModuleDependencyTag(module) - if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok { - kind := hiddenAPIStubsTag.sdkKind - dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind) - if dexJar != nil { - m[kind] = append(m[kind], dexJar) - } - } - }) - - // Normalize the paths, i.e. remove duplicates and sort. - for k, v := range m { - m[k] = android.SortedUniquePaths(v) - } - - return m -} - // hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if // available, or reports an error. func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path { @@ -193,7 +157,7 @@ var sdkKindToHiddenapiListOption = map[android.SdkKind]string{ // // 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.WritablePath, bootDexJars android.Paths, sdkKindToPathList map[android.SdkKind]android.Paths) *android.RuleBuilder { +func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput) *android.RuleBuilder { // Singleton rule which applies hiddenapi on all boot class path dex files. rule := android.NewRuleBuilder(pctx, ctx) @@ -206,7 +170,7 @@ func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath // Iterate over the sdk kinds in a fixed order. for _, sdkKind := range hiddenAPIRelevantSdkKinds { - paths := sdkKindToPathList[sdkKind] + paths := input.StubDexJarsByKind[sdkKind] if len(paths) > 0 { option := sdkKindToHiddenapiListOption[sdkKind] command.FlagWithInputList("--"+option+"=", paths, ":") @@ -260,15 +224,6 @@ type HiddenAPIFlagFileProperties struct { Unsupported_packages []string `android:"path"` } -func (p *HiddenAPIFlagFileProperties) hiddenAPIFlagFileInfo(ctx android.ModuleContext) hiddenAPIFlagFileInfo { - info := hiddenAPIFlagFileInfo{FlagFilesByCategory: FlagFilesByCategory{}} - for _, category := range hiddenAPIFlagFileCategories { - paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p)) - info.FlagFilesByCategory[category] = paths - } - return info -} - type hiddenAPIFlagFileCategory struct { // propertyName is the name of the property for this category. propertyName string @@ -400,6 +355,93 @@ type hiddenAPIFlagFileInfo struct { var hiddenAPIFlagFileInfoProvider = blueprint.NewProvider(hiddenAPIFlagFileInfo{}) +// StubDexJarsByKind maps an android.SdkKind to the paths to stub dex jars appropriate for that +// level. See hiddenAPIRelevantSdkKinds for a list of the acceptable android.SdkKind values. +type StubDexJarsByKind map[android.SdkKind]android.Paths + +// append appends the supplied kind specific stub dex jar pargs to the corresponding kind in this +// map. +func (s StubDexJarsByKind) append(other StubDexJarsByKind) { + for _, kind := range hiddenAPIRelevantSdkKinds { + s[kind] = append(s[kind], other[kind]...) + } +} + +// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and +// deterministic order. +func (s StubDexJarsByKind) dedupAndSort() { + for kind, paths := range s { + s[kind] = android.SortedUniquePaths(paths) + } +} + +// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are +// needed for hidden API flag generation. +type HiddenAPIFlagInput struct { + // FlagFilesByCategory contains the flag files that override the initial flags that are derived + // from the stub dex files. + FlagFilesByCategory FlagFilesByCategory + + // StubDexJarsByKind contains the stub dex jars for different android.SdkKind and which determine + // the initial flags for each dex member. + StubDexJarsByKind StubDexJarsByKind +} + +// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct. +func newHiddenAPIFlagInput() HiddenAPIFlagInput { + input := HiddenAPIFlagInput{ + FlagFilesByCategory: FlagFilesByCategory{}, + StubDexJarsByKind: StubDexJarsByKind{}, + } + + return input +} + +// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the +// dependencies added in hiddenAPIAddStubLibDependencies. +// +// That includes paths to the stub dex jars as well as paths to the *removed.txt files. +func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) { + addFromModule := func(ctx android.ModuleContext, module android.Module, kind android.SdkKind) { + dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind) + if dexJar != nil { + i.StubDexJarsByKind[kind] = append(i.StubDexJarsByKind[kind], dexJar) + } + } + + // If the contents includes any java_sdk_library modules then add them to the stubs. + for _, module := range contents { + if _, ok := module.(SdkLibraryDependency); ok { + // Add information for every possible kind needed by hidden API. SdkCorePlatform is not used + // as the java_sdk_library does not have special support for core_platform API, instead it is + // implemented as a customized form of SdkPublic. + for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} { + addFromModule(ctx, module, kind) + } + } + } + + ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) { + tag := ctx.OtherModuleDependencyTag(module) + if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok { + kind := hiddenAPIStubsTag.sdkKind + addFromModule(ctx, module, kind) + } + }) + + // Normalize the paths, i.e. remove duplicates and sort. + i.StubDexJarsByKind.dedupAndSort() +} + +// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the +// supplied properties and stores them in this struct. +func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) { + for _, category := range hiddenAPIFlagFileCategories { + paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p)) + i.FlagFilesByCategory[category] = paths + } +} + // HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a // bootclasspath_fragment module. type HiddenAPIFlagOutput struct { @@ -510,13 +552,15 @@ func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc st // * metadata.csv // * index.csv // * all-flags.csv -func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) *HiddenAPIFlagOutput { +func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput { hiddenApiSubDir := "modular-hiddenapi" - // Generate the stub-flags.csv. + // Gather the dex files for the boot libraries provided by this fragment. bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, contents) + + // Generate the stub-flags.csv. stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv") - rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, stubJarsByKind) + rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, input) rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags") // Extract the classes jars from the contents. @@ -544,7 +588,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, annotationFlagsCSV, flagFileInfo.FlagFilesByCategory, nil) + buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", outputPath, stubFlagsCSV, annotationFlagsCSV, input.FlagFilesByCategory, nil) // Store the paths in the info for use by other modules and sdk snapshot generation. output := HiddenAPIFlagOutput{ diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index df0ba2a42..854179e2c 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -281,14 +281,22 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, fragments) - sdkKindToStubPaths := hiddenAPIGatherStubLibDexJarPaths(ctx, nil) + // Create the input to pass to ruleToGenerateHiddenAPIStubFlagsFile + input := newHiddenAPIFlagInput() + + // Gather stub library information from the dependencies on modules provided by + // hiddenAPIComputeMonolithicStubLibModules. + input.gatherStubLibInfo(ctx, nil) + + // Use the flag files from this module and all the fragments. + input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, modules) // Generate the monolithic stub-flags.csv file. bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, hiddenAPIModules) stubFlags := hiddenAPISingletonPaths(ctx).stubFlags - rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, sdkKindToStubPaths) + rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, input) rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags") // Extract the classes jars from the contents. @@ -322,8 +330,16 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. // createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for // testing. func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, fragments []android.Module) MonolithicHiddenAPIInfo { - flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx) - monolithicInfo := newMonolithicHiddenAPIInfo(ctx, flagFileInfo.FlagFilesByCategory, fragments) + // Create a temporary input structure in which to collate information provided directly by this + // module, either through properties or direct dependencies. + temporaryInput := newHiddenAPIFlagInput() + + // Create paths to the flag files specified in the properties. + temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api) + + // Create the monolithic info, by starting with the flag files specified on this and then merging + // in information from all the fragment dependencies of this. + monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, fragments) // Store the information for testing. ctx.SetProvider(monolithicHiddenAPIInfoProvider, monolithicInfo)