diff options
author | 2023-12-19 02:40:22 +0000 | |
---|---|---|
committer | 2024-01-08 07:56:07 +0000 | |
commit | 3c89f047778863e2701cc7de7562f99acb253152 (patch) | |
tree | 4395bbc4e17b0252ee5406c381c555fd855828cb /java | |
parent | 6592e87dbfe1e49b5c57ca8ead0bb48e6354e261 (diff) |
Generate "exportable" stubs in droidstubs
This change generates rules for "exportable" stubs in the droidstubs
module.
Given that there are a lot of overlap between the currently existing
"everything" stubs rule and the newly introducing "exportable" stubs
rule, the currently existing metalava rule commands are modularized to
be utilized in the "exportable" stubs rule commands.
The currently existing build actions are modularized in the followings:
- commonMetalavaStubCmd(...): metalava commands that are required for
generation of both "everything", "exportable", and potentially
"runtime" stubs
- everythingOptionalCmd(...): metalava commands that are dependent on
"everything" stubs and not dependent on flagged apis annotations, such
as api lint, released api check
Based on this modularization, the "everything" stubs are now generated
in everythingStubCmd(...), which calls commonMetalavaStubCmd(...) and
everythingOptionalCmd(...).
Similarly, the "exportable" stubs are generated in
optionalStubCmd(stubsType=Exportable, ...), which calls
commonMetalavaStubCmd(...) and appends additional flags. Runtime stubs
can be generated similarly in the future with
optionalStubCmd(stubsType=Runtime, ...).
"everything"-related artifacts will now be created in
`everything/` subdirectory, and "exportable"-related artifacts will be
created in `exportable/` subdirectory. For example, the outdir of a
droidstubs module "foo" would look like below:
```
foo
|-- everything
| |-- foo_api.txt
| |-- foo-stubs.srcjar
|
|-- exportable
|-- foo_api.txt
|-- foo-stubs.srcjar
```
The module generates the build rules for the "exportable" stubs
regardless of whether the module defines the `aconfig_declarations`
property or not. All APIs marked with `@FlaggedApis` annotations are
stripped out for the "exportable" stubs when the `aconfig_declarations`
property is not defined. On the other hand, only the `@FlaggedApis` that
are specified in the aconfig_declarations module and are enabled will be
included (and all others are stripped) when the `aconfig_declarations`
propety is defined.
Test: go test ./java && BUILD_FROM_SOURCE_STUBS=true m
Bug: 315490657
Change-Id: I300273cd2a62fa978b046c0268e3a67c35e22b08
Diffstat (limited to 'java')
-rw-r--r-- | java/droiddoc.go | 2 | ||||
-rw-r--r-- | java/droidstubs.go | 429 | ||||
-rw-r--r-- | java/droidstubs_test.go | 8 | ||||
-rw-r--r-- | java/java_test.go | 2 |
4 files changed, 331 insertions, 110 deletions
diff --git a/java/droiddoc.go b/java/droiddoc.go index e05f2309f..7a610344f 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -208,6 +208,8 @@ type Javadoc struct { docZip android.WritablePath stubsSrcJar android.WritablePath + + exportableStubsSrcJar android.WritablePath } func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) { diff --git a/java/droidstubs.go b/java/droidstubs.go index c839dbaaa..abf66406c 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -87,6 +87,14 @@ type Droidstubs struct { metadataZip android.WritablePath metadataDir android.WritablePath + + exportableApiFile android.WritablePath + exportableRemovedApiFile android.WritablePath + exportableNullabilityWarningsFile android.WritablePath + exportableAnnotationsZip android.WritablePath + exportableApiVersionsXml android.WritablePath + exportableMetadataZip android.WritablePath + exportableMetadataDir android.WritablePath } type DroidstubsProperties struct { @@ -200,6 +208,36 @@ type currentApiTimestampProvider interface { CurrentApiTimestamp() android.Path } +type annotationFlagsParams struct { + migratingNullability bool + validatingNullability bool + nullabilityWarningsFile android.WritablePath + annotationsZip android.WritablePath +} +type stubsCommandParams struct { + srcJarDir android.ModuleOutPath + stubsDir android.OptionalPath + stubsSrcJar android.WritablePath + metadataZip android.WritablePath + metadataDir android.WritablePath + apiVersionsXml android.WritablePath + nullabilityWarningsFile android.WritablePath + annotationsZip android.WritablePath + stubConfig stubsCommandConfigParams +} +type stubsCommandConfigParams struct { + stubsType StubsType + javaVersion javaVersion + deps deps + checkApi bool + generateStubs bool + doApiLint bool + doCheckReleased bool + writeSdkValues bool + migratingNullability bool + validatingNullability bool +} + // droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be // documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to // a droiddoc module to generate documentation. @@ -310,36 +348,41 @@ func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) { } } -func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) { - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || - apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || - String(d.properties.Api_filename) != "" { +func (d *Droidstubs) sdkValuesFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, metadataDir android.WritablePath) { + cmd.FlagWithArg("--sdk-values ", metadataDir.String()) +} + +func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath, stubsType StubsType, checkApi bool) { + if checkApi || String(d.properties.Api_filename) != "" { filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt") - uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename) + uncheckedApiFile := android.PathForModuleOut(ctx, stubsType.String(), filename) cmd.FlagWithOutput("--api ", uncheckedApiFile) - d.apiFile = uncheckedApiFile + + if stubsType == Everything { + d.apiFile = uncheckedApiFile + } else if stubsType == Exportable { + d.exportableApiFile = uncheckedApiFile + } } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" { // If check api is disabled then make the source file available for export. d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile) } - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || - apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || - String(d.properties.Removed_api_filename) != "" { + if checkApi || String(d.properties.Removed_api_filename) != "" { filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt") - uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename) + uncheckedRemovedFile := android.PathForModuleOut(ctx, stubsType.String(), filename) cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile) - d.removedApiFile = uncheckedRemovedFile + + if stubsType == Everything { + d.removedApiFile = uncheckedRemovedFile + } else if stubsType == Exportable { + d.exportableRemovedApiFile = uncheckedRemovedFile + } } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" { // If check api is disabled then make the source removed api file available for export. d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile) } - if Bool(d.properties.Write_sdk_values) { - d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata") - cmd.FlagWithArg("--sdk-values ", d.metadataDir.String()) - } - if stubsDir.Valid() { if Bool(d.properties.Create_doc_stubs) { cmd.FlagWithArg("--doc-stubs ", stubsDir.String()) @@ -352,16 +395,11 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil } } -func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { +func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, params annotationFlagsParams) { if Bool(d.properties.Annotations_enabled) { cmd.Flag(config.MetalavaAnnotationsFlags) - validatingNullability := - strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") || - String(d.properties.Validate_nullability_from_list) != "" - - migratingNullability := String(d.properties.Previous_api) != "" - if migratingNullability { + if params.migratingNullability { previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api)) cmd.FlagWithInput("--migrate-nullness ", previousApi) } @@ -370,13 +408,11 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s)) } - if validatingNullability { - d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt") - cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile) + if params.validatingNullability { + cmd.FlagWithOutput("--nullability-warnings-txt ", params.nullabilityWarningsFile) } - d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip") - cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip) + cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip) if len(d.properties.Merge_annotations_dirs) != 0 { d.mergeAnnoDirFlags(ctx, cmd) @@ -408,10 +444,10 @@ func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *a }) } -func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { +func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) { var apiVersions android.Path if proptools.Bool(d.properties.Api_levels_annotations_enabled) { - d.apiLevelsGenerationFlags(ctx, cmd) + d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml) apiVersions = d.apiVersionsXml } else { ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) { @@ -430,14 +466,13 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a } } -func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { +func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) { if len(d.properties.Api_levels_annotations_dirs) == 0 { ctx.PropertyErrorf("api_levels_annotations_dirs", "has to be non-empty if api levels annotations was enabled!") } - d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml") - cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) + cmd.FlagWithOutput("--generate-api-levels ", apiVersionsXml) filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") @@ -569,9 +604,16 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi return cmd } -// Generate flagged apis related flags. Apply transformations and only revert the flagged apis -// that are not enabled via release configurations and are not specified in aconfig_declarations -func (d *Droidstubs) generateRevertAnnotationArgs(ctx android.ModuleContext, stubsType StubsType, aconfigFlagsPaths android.Paths) { +// Pass flagged apis related flags to metalava. When aconfig_declarations property is not +// defined for a module, simply revert all flagged apis annotations. If aconfig_declarations +// property is defined, apply transformations and only revert the flagged apis that are not +// enabled via release configurations and are not specified in aconfig_declarations +func (d *Droidstubs) generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) { + + if len(aconfigFlagsPaths) == 0 { + cmd.Flag("--revert-annotation android.annotation.FlaggedApi") + return + } releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String())) revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String())) @@ -608,81 +650,151 @@ func (d *Droidstubs) generateRevertAnnotationArgs(ctx android.ModuleContext, stu Output: revertAnnotationsFile, Description: fmt.Sprintf("%s revert annotations", stubsType), }) + + cmd.FlagWithInput("@", revertAnnotationsFile) } -func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { - deps := d.Javadoc.collectDeps(ctx) +func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, + params stubsCommandParams) *android.RuleBuilderCommand { + if BoolDefault(d.properties.High_mem, false) { + // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel. + rule.HighMem() + } - javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d)) + if params.stubConfig.generateStubs { + rule.Command().Text("rm -rf").Text(params.stubsDir.String()) + rule.Command().Text("mkdir -p").Text(params.stubsDir.String()) + } + + srcJarList := zipSyncCmd(ctx, rule, params.srcJarDir, d.Javadoc.srcJars) + + homeDir := android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "home") + cmd := metalavaCmd(ctx, rule, params.stubConfig.javaVersion, d.Javadoc.srcFiles, srcJarList, + params.stubConfig.deps.bootClasspath, params.stubConfig.deps.classpath, homeDir) + cmd.Implicits(d.Javadoc.implicits) + + d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi) - // If the module specifies aconfig_declarations property, "exportable" (and "runtime" eventually) stubs are generated - if len(deps.aconfigProtoFiles) > 0 { - // Files required to generate "exportable" stubs - stubsType := Exportable - d.generateRevertAnnotationArgs(ctx, stubsType, deps.aconfigProtoFiles) + if params.stubConfig.writeSdkValues { + d.sdkValuesFlags(ctx, cmd, params.metadataDir) } - // Create rule for metalava + annotationParams := annotationFlagsParams{ + migratingNullability: params.stubConfig.migratingNullability, + validatingNullability: params.stubConfig.validatingNullability, + nullabilityWarningsFile: params.nullabilityWarningsFile, + annotationsZip: params.annotationsZip, + } - srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars") + d.annotationsFlags(ctx, cmd, annotationParams) + d.inclusionAnnotationsFlags(ctx, cmd) + d.apiLevelsAnnotationsFlags(ctx, cmd, params.stubConfig.stubsType, params.apiVersionsXml) - rule := android.NewRuleBuilder(pctx, ctx) + d.expandArgs(ctx, cmd) + + for _, o := range d.Javadoc.properties.Out { + cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) + } - rule.Sbox(android.PathForModuleOut(ctx, "metalava"), + return cmd +} + +// Sandbox rule for generating the everything stubs and other artifacts +func (d *Droidstubs) everythingStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) { + srcJarDir := android.PathForModuleOut(ctx, Everything.String(), "srcjars") + rule := android.NewRuleBuilder(pctx, ctx) + rule.Sbox(android.PathForModuleOut(ctx, Everything.String()), android.PathForModuleOut(ctx, "metalava.sbox.textproto")). SandboxInputs() - if BoolDefault(d.properties.High_mem, false) { - // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel. - rule.HighMem() + var stubsDir android.OptionalPath + if params.generateStubs { + stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, Everything.String(), "stubsDir")) + d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-"+"stubs.srcjar") } - generateStubs := BoolDefault(d.properties.Generate_stubs, true) - var stubsDir android.OptionalPath - if generateStubs { - d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar") - stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir")) - rule.Command().Text("rm -rf").Text(stubsDir.String()) - rule.Command().Text("mkdir -p").Text(stubsDir.String()) + if params.writeSdkValues { + d.metadataDir = android.PathForModuleOut(ctx, Everything.String(), "metadata") + d.metadataZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-metadata.zip") } - srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) + if Bool(d.properties.Annotations_enabled) { + if params.validatingNullability { + d.nullabilityWarningsFile = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_nullability_warnings.txt") + } + d.annotationsZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_annotations.zip") + } + if Bool(d.properties.Api_levels_annotations_enabled) { + d.apiVersionsXml = android.PathForModuleOut(ctx, Everything.String(), "api-versions.xml") + } - homeDir := android.PathForModuleOut(ctx, "metalava", "home") - cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList, - deps.bootClasspath, deps.classpath, homeDir) - cmd.Implicits(d.Javadoc.implicits) + commonCmdParams := stubsCommandParams{ + srcJarDir: srcJarDir, + stubsDir: stubsDir, + stubsSrcJar: d.Javadoc.stubsSrcJar, + metadataDir: d.metadataDir, + apiVersionsXml: d.apiVersionsXml, + nullabilityWarningsFile: d.nullabilityWarningsFile, + annotationsZip: d.annotationsZip, + stubConfig: params, + } - d.stubsFlags(ctx, cmd, stubsDir) + cmd := d.commonMetalavaStubCmd(ctx, rule, commonCmdParams) - d.annotationsFlags(ctx, cmd) - d.inclusionAnnotationsFlags(ctx, cmd) - d.apiLevelsAnnotationsFlags(ctx, cmd) + d.everythingOptionalCmd(ctx, cmd, params.doApiLint, params.doCheckReleased) - d.expandArgs(ctx, cmd) + if params.generateStubs { + rule.Command(). + BuiltTool("soong_zip"). + Flag("-write_if_changed"). + Flag("-jar"). + FlagWithOutput("-o ", d.Javadoc.stubsSrcJar). + FlagWithArg("-C ", stubsDir.String()). + FlagWithArg("-D ", stubsDir.String()) + } - for _, o := range d.Javadoc.properties.Out { - cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) + if params.writeSdkValues { + rule.Command(). + BuiltTool("soong_zip"). + Flag("-write_if_changed"). + Flag("-d"). + FlagWithOutput("-o ", d.metadataZip). + FlagWithArg("-C ", d.metadataDir.String()). + FlagWithArg("-D ", d.metadataDir.String()) } - // Add options for the other optional tasks: API-lint and check-released. - // We generate separate timestamp files for them. + // TODO: We don't really need two separate API files, but this is a reminiscence of how + // we used to run metalava separately for API lint and the "last_released" check. Unify them. + if params.doApiLint { + rule.Command().Text("touch").Output(d.apiLintTimestamp) + } + if params.doCheckReleased { + rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp) + } - doApiLint := false - doCheckReleased := false + // TODO(b/183630617): rewrapper doesn't support restat rules + if !metalavaUseRbe(ctx) { + rule.Restat() + } - // Add API lint options. + zipSyncCleanupCmd(rule, srcJarDir) - if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) { - doApiLint = true + rule.Build("metalava", "metalava merged") +} + +// Sandbox rule for generating the everything artifacts that are not run by +// default but only run based on the module configurations +func (d *Droidstubs) everythingOptionalCmd(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, doApiLint bool, doCheckReleased bool) { + // Add API lint options. + if doApiLint { newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since) if newSince.Valid() { cmd.FlagWithInput("--api-lint ", newSince.Path()) } else { cmd.Flag("--api-lint") } - d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt") + d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt") cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint" // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released. @@ -693,8 +805,8 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { } baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file) - updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt") - d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp") + updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "api_lint_baseline.txt") + d.apiLintTimestamp = android.PathForModuleOut(ctx, Everything.String(), "api_lint.timestamp") // Note this string includes a special shell quote $' ... ', which decodes the "\n"s. // @@ -735,10 +847,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { } // Add "check released" options. (Detect incompatible API changes from the last public release) - - if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") { - doCheckReleased = true - + if doCheckReleased { if len(d.Javadoc.properties.Out) > 0 { ctx.PropertyErrorf("out", "out property may not be combined with check_api") } @@ -746,9 +855,9 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file) - updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt") + updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "last_released_baseline.txt") - d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp") + d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_last_released_api.timestamp") cmd.FlagWithInput("--check-compatibility:api:released ", apiFile) cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile) @@ -773,35 +882,93 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) cmd.FlagWithInput("--use-same-format-as ", currentApiFile) } +} + +// Sandbox rule for generating exportable stubs and other artifacts +func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) { + optionalCmdParams := stubsCommandParams{ + stubConfig: params, + } + + d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar") + optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar + if params.writeSdkValues { + d.exportableMetadataZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-metadata.zip") + d.exportableMetadataDir = android.PathForModuleOut(ctx, params.stubsType.String(), "metadata") + optionalCmdParams.metadataZip = d.exportableMetadataZip + optionalCmdParams.metadataDir = d.exportableMetadataDir + } + + if Bool(d.properties.Annotations_enabled) { + if params.validatingNullability { + d.exportableNullabilityWarningsFile = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_nullability_warnings.txt") + optionalCmdParams.nullabilityWarningsFile = d.exportableNullabilityWarningsFile + } + d.exportableAnnotationsZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_annotations.zip") + optionalCmdParams.annotationsZip = d.exportableAnnotationsZip + } + if Bool(d.properties.Api_levels_annotations_enabled) { + d.exportableApiVersionsXml = android.PathForModuleOut(ctx, params.stubsType.String(), "api-versions.xml") + optionalCmdParams.apiVersionsXml = d.exportableApiVersionsXml + } + + if params.checkApi || String(d.properties.Api_filename) != "" { + filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt") + d.exportableApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename) + } + + if params.checkApi || String(d.properties.Removed_api_filename) != "" { + filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_api.txt") + d.exportableRemovedApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename) + } + + d.optionalStubCmd(ctx, optionalCmdParams) +} + +func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsCommandParams) { + + params.srcJarDir = android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "srcjars") + rule := android.NewRuleBuilder(pctx, ctx) + rule.Sbox(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String()), + android.PathForModuleOut(ctx, fmt.Sprintf("metalava_%s.sbox.textproto", params.stubConfig.stubsType.String()))). + SandboxInputs() + + if params.stubConfig.generateStubs { + params.stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "stubsDir")) + } + + cmd := d.commonMetalavaStubCmd(ctx, rule, params) + + d.generateRevertAnnotationArgs(ctx, cmd, params.stubConfig.stubsType, params.stubConfig.deps.aconfigProtoFiles) + + if params.stubConfig.doApiLint { + // Pass the lint baseline file as an input to resolve the lint errors. + // The exportable stubs generation does not update the lint baseline file. + // Lint baseline file update is handled by the everything stubs + baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file) + if baselineFile.Valid() { + cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path()) + } + } - if generateStubs { + if params.stubConfig.generateStubs { rule.Command(). BuiltTool("soong_zip"). Flag("-write_if_changed"). Flag("-jar"). - FlagWithOutput("-o ", d.Javadoc.stubsSrcJar). - FlagWithArg("-C ", stubsDir.String()). - FlagWithArg("-D ", stubsDir.String()) + FlagWithOutput("-o ", params.stubsSrcJar). + FlagWithArg("-C ", params.stubsDir.String()). + FlagWithArg("-D ", params.stubsDir.String()) } - if Bool(d.properties.Write_sdk_values) { - d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip") + if params.stubConfig.writeSdkValues { rule.Command(). BuiltTool("soong_zip"). Flag("-write_if_changed"). Flag("-d"). - FlagWithOutput("-o ", d.metadataZip). - FlagWithArg("-C ", d.metadataDir.String()). - FlagWithArg("-D ", d.metadataDir.String()) - } - - // TODO: We don't really need two separate API files, but this is a reminiscence of how - // we used to run metalava separately for API lint and the "last_released" check. Unify them. - if doApiLint { - rule.Command().Text("touch").Output(d.apiLintTimestamp) - } - if doCheckReleased { - rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp) + FlagWithOutput("-o ", params.metadataZip). + FlagWithArg("-C ", params.metadataDir.String()). + FlagWithArg("-D ", params.metadataDir.String()) } // TODO(b/183630617): rewrapper doesn't support restat rules @@ -809,9 +976,53 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Restat() } - zipSyncCleanupCmd(rule, srcJarDir) + zipSyncCleanupCmd(rule, params.srcJarDir) - rule.Build("metalava", "metalava merged") + rule.Build(fmt.Sprintf("metalava_%s", params.stubConfig.stubsType.String()), "metalava merged") +} + +func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { + deps := d.Javadoc.collectDeps(ctx) + + javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d)) + generateStubs := BoolDefault(d.properties.Generate_stubs, true) + + // Add options for the other optional tasks: API-lint and check-released. + // We generate separate timestamp files for them. + doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) + doCheckReleased := apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") + + writeSdkValues := Bool(d.properties.Write_sdk_values) + + annotationsEnabled := Bool(d.properties.Annotations_enabled) + + migratingNullability := annotationsEnabled && String(d.properties.Previous_api) != "" + validatingNullability := annotationsEnabled && (strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") || + String(d.properties.Validate_nullability_from_list) != "") + + checkApi := apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || + apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") + + stubCmdParams := stubsCommandConfigParams{ + javaVersion: javaVersion, + deps: deps, + checkApi: checkApi, + generateStubs: generateStubs, + doApiLint: doApiLint, + doCheckReleased: doCheckReleased, + writeSdkValues: writeSdkValues, + migratingNullability: migratingNullability, + validatingNullability: validatingNullability, + } + stubCmdParams.stubsType = Everything + // Create default (i.e. "everything" stubs) rule for metalava + d.everythingStubCmd(ctx, stubCmdParams) + + // The module generates "exportable" (and "runtime" eventually) stubs regardless of whether + // aconfig_declarations property is defined or not. If the property is not defined, the module simply + // strips all flagged apis to generate the "exportable" stubs + stubCmdParams.stubsType = Exportable + d.exportableStubCmd(ctx, stubCmdParams) if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { @@ -827,7 +1038,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName()) } - d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp") + d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_current_api.timestamp") rule := android.NewRuleBuilder(pctx, ctx) @@ -870,7 +1081,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build("metalavaCurrentApiCheck", "check current API") - d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp") + d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "update_current_api.timestamp") // update API rule rule = android.NewRuleBuilder(pctx, ctx) @@ -905,7 +1116,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings)) - d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp") + d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp") msg := fmt.Sprintf(`\n******************************\n`+ `The warnings encountered during nullability annotation validation did\n`+ diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go index 5544890af..379e2403f 100644 --- a/java/droidstubs_test.go +++ b/java/droidstubs_test.go @@ -437,4 +437,12 @@ func TestAconfigDeclarations(t *testing.T) { m := result.ModuleForTests("foo", "android_common") android.AssertStringDoesContain(t, "foo generates revert annotations file", strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt") + + // revert-annotations.txt passed to exportable stubs generation metalava command + manifest := m.Output("metalava_exportable.sbox.textproto") + cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command) + android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt") + + android.AssertStringDoesContain(t, "foo generates exportable stubs jar", + strings.Join(m.AllOutputs(), ""), "exportable/foo-stubs.srcjar") } diff --git a/java/java_test.go b/java/java_test.go index b9dc453b3..8d96184d4 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2465,7 +2465,7 @@ func TestApiLibraryDroidstubsDependency(t *testing.T) { } `) - currentApiTimestampPath := "api-stubs-docs-non-updatable/android_common/metalava/check_current_api.timestamp" + currentApiTimestampPath := "api-stubs-docs-non-updatable/android_common/everything/check_current_api.timestamp" foo := result.ModuleForTests("foo", "android_common").Module().(*ApiLibrary) fooValidationPathsString := strings.Join(foo.validationPaths.Strings(), " ") bar := result.ModuleForTests("bar", "android_common").Module().(*ApiLibrary) |