Merge changes I14928b7b,Ia009df3d into main

* changes:
  Generate runtime stubs in droidstubs
  Additional cleanup prior to adding the runtime stubs
This commit is contained in:
Jihoon Kang 2024-02-28 00:29:08 +00:00 committed by Gerrit Code Review
commit 60bdd05b21
3 changed files with 141 additions and 57 deletions

View file

@ -222,6 +222,8 @@ type Javadoc struct {
stubsSrcJar android.WritablePath stubsSrcJar android.WritablePath
exportableStubsSrcJar android.WritablePath exportableStubsSrcJar android.WritablePath
runtimeStubsSrcJar android.WritablePath
} }
func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) { func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) {

View file

@ -214,6 +214,7 @@ type currentApiTimestampProvider interface {
type annotationFlagsParams struct { type annotationFlagsParams struct {
migratingNullability bool migratingNullability bool
validatingNullability bool validatingNullability bool
extractAnnotations bool
nullabilityWarningsFile android.WritablePath nullabilityWarningsFile android.WritablePath
annotationsZip android.WritablePath annotationsZip android.WritablePath
} }
@ -229,16 +230,19 @@ type stubsCommandParams struct {
stubConfig stubsCommandConfigParams stubConfig stubsCommandConfigParams
} }
type stubsCommandConfigParams struct { type stubsCommandConfigParams struct {
stubsType StubsType stubsType StubsType
javaVersion javaVersion javaVersion javaVersion
deps deps deps deps
checkApi bool checkApi bool
generateStubs bool generateStubs bool
doApiLint bool doApiLint bool
doCheckReleased bool doCheckReleased bool
writeSdkValues bool writeSdkValues bool
migratingNullability bool migratingNullability bool
validatingNullability bool validatingNullability bool
annotationsEnabled bool
apiLevelsAnnotationsEnabled bool
extractAnnotations bool
} }
// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be // droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
@ -508,30 +512,30 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil
} }
func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, params annotationFlagsParams) { func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, params annotationFlagsParams) {
if Bool(d.properties.Annotations_enabled) { cmd.Flag(config.MetalavaAnnotationsFlags)
cmd.Flag(config.MetalavaAnnotationsFlags)
if params.migratingNullability { if params.migratingNullability {
previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api)) previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
cmd.FlagWithInput("--migrate-nullness ", previousApi) cmd.FlagWithInput("--migrate-nullness ", previousApi)
}
if s := String(d.properties.Validate_nullability_from_list); s != "" {
cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
}
if params.validatingNullability {
cmd.FlagWithOutput("--nullability-warnings-txt ", params.nullabilityWarningsFile)
}
cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip)
if len(d.properties.Merge_annotations_dirs) != 0 {
d.mergeAnnoDirFlags(ctx, cmd)
}
cmd.Flag(config.MetalavaAnnotationsWarningsFlags)
} }
if s := String(d.properties.Validate_nullability_from_list); s != "" {
cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
}
if params.validatingNullability {
cmd.FlagWithOutput("--nullability-warnings-txt ", params.nullabilityWarningsFile)
}
if params.extractAnnotations {
cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip)
}
if len(d.properties.Merge_annotations_dirs) != 0 {
d.mergeAnnoDirFlags(ctx, cmd)
}
cmd.Flag(config.MetalavaAnnotationsWarningsFlags)
} }
func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
@ -556,9 +560,11 @@ func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *a
}) })
} }
func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) { func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, params stubsCommandParams) {
var apiVersions android.Path var apiVersions android.Path
if proptools.Bool(d.properties.Api_levels_annotations_enabled) { stubsType := params.stubConfig.stubsType
apiVersionsXml := params.apiVersionsXml
if params.stubConfig.apiLevelsAnnotationsEnabled {
d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml) d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml)
apiVersions = apiVersionsXml apiVersions = apiVersionsXml
} else { } else {
@ -569,7 +575,9 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a
} else if stubsType == Exportable { } else if stubsType == Exportable {
apiVersions = s.exportableArtifacts.apiVersionsXml apiVersions = s.exportableArtifacts.apiVersionsXml
} else { } else {
ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String()) // if the stubs type does not generate api-versions.xml file, default to using the
// everything artifacts
apiVersions = s.everythingArtifacts.apiVersionsXml
} }
} else { } else {
ctx.PropertyErrorf("api_levels_module", ctx.PropertyErrorf("api_levels_module",
@ -803,13 +811,16 @@ func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *andr
annotationParams := annotationFlagsParams{ annotationParams := annotationFlagsParams{
migratingNullability: params.stubConfig.migratingNullability, migratingNullability: params.stubConfig.migratingNullability,
validatingNullability: params.stubConfig.validatingNullability, validatingNullability: params.stubConfig.validatingNullability,
extractAnnotations: params.stubConfig.extractAnnotations,
nullabilityWarningsFile: params.nullabilityWarningsFile, nullabilityWarningsFile: params.nullabilityWarningsFile,
annotationsZip: params.annotationsZip, annotationsZip: params.annotationsZip,
} }
d.annotationsFlags(ctx, cmd, annotationParams) if params.stubConfig.annotationsEnabled {
d.annotationsFlags(ctx, cmd, annotationParams)
}
d.inclusionAnnotationsFlags(ctx, cmd) d.inclusionAnnotationsFlags(ctx, cmd)
d.apiLevelsAnnotationsFlags(ctx, cmd, params.stubConfig.stubsType, params.apiVersionsXml) d.apiLevelsAnnotationsFlags(ctx, cmd, params)
d.expandArgs(ctx, cmd) d.expandArgs(ctx, cmd)
@ -839,13 +850,13 @@ func (d *Droidstubs) everythingStubCmd(ctx android.ModuleContext, params stubsCo
d.everythingArtifacts.metadataZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-metadata.zip") d.everythingArtifacts.metadataZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-metadata.zip")
} }
if Bool(d.properties.Annotations_enabled) { if params.annotationsEnabled {
if params.validatingNullability { if params.validatingNullability {
d.everythingArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_nullability_warnings.txt") d.everythingArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_nullability_warnings.txt")
} }
d.everythingArtifacts.annotationsZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_annotations.zip") d.everythingArtifacts.annotationsZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_annotations.zip")
} }
if Bool(d.properties.Api_levels_annotations_enabled) { if params.apiLevelsAnnotationsEnabled {
d.everythingArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, Everything.String(), "api-versions.xml") d.everythingArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, Everything.String(), "api-versions.xml")
} }
@ -1023,7 +1034,7 @@ func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCo
optionalCmdParams.metadataDir = d.exportableArtifacts.metadataDir optionalCmdParams.metadataDir = d.exportableArtifacts.metadataDir
} }
if Bool(d.properties.Annotations_enabled) { if params.annotationsEnabled {
if params.validatingNullability { if params.validatingNullability {
d.exportableArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_nullability_warnings.txt") d.exportableArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_nullability_warnings.txt")
optionalCmdParams.nullabilityWarningsFile = d.exportableArtifacts.nullabilityWarningsFile optionalCmdParams.nullabilityWarningsFile = d.exportableArtifacts.nullabilityWarningsFile
@ -1031,7 +1042,7 @@ func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCo
d.exportableArtifacts.annotationsZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_annotations.zip") d.exportableArtifacts.annotationsZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_annotations.zip")
optionalCmdParams.annotationsZip = d.exportableArtifacts.annotationsZip optionalCmdParams.annotationsZip = d.exportableArtifacts.annotationsZip
} }
if Bool(d.properties.Api_levels_annotations_enabled) { if params.apiLevelsAnnotationsEnabled {
d.exportableArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, params.stubsType.String(), "api-versions.xml") d.exportableArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, params.stubsType.String(), "api-versions.xml")
optionalCmdParams.apiVersionsXml = d.exportableArtifacts.apiVersionsXml optionalCmdParams.apiVersionsXml = d.exportableArtifacts.apiVersionsXml
} }
@ -1049,6 +1060,38 @@ func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCo
d.optionalStubCmd(ctx, optionalCmdParams) d.optionalStubCmd(ctx, optionalCmdParams)
} }
// Sandbox rule for generating runtime stubs
func (d *Droidstubs) runtimeStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) {
// We are only interested in generating the stubs srcjar,
// not other artifacts for the runtime stubs
params.checkApi = false
params.writeSdkValues = false
params.validatingNullability = false
params.extractAnnotations = false
params.apiLevelsAnnotationsEnabled = false
optionalCmdParams := stubsCommandParams{
stubConfig: params,
}
d.Javadoc.runtimeStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
optionalCmdParams.stubsSrcJar = d.Javadoc.runtimeStubsSrcJar
// If aconfig_declarations property is not defined, all flagged apis symbols are stripped
// as no aconfig flags are enabled. In such case, the runtime stubs are identical to the
// exportable stubs, thus no additional metalava invocation is needed.
if len(d.properties.Aconfig_declarations) == 0 {
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
Text("cp").Flag("-f").
Input(d.exportableStubsSrcJar).Output(d.runtimeStubsSrcJar)
rule.Build(fmt.Sprintf("metalava_%s", params.stubsType.String()), "metalava merged")
} else {
d.optionalStubCmd(ctx, optionalCmdParams)
}
}
func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsCommandParams) { func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsCommandParams) {
params.srcJarDir = android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "srcjars") params.srcJarDir = android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "srcjars")
@ -1120,6 +1163,8 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
annotationsEnabled := Bool(d.properties.Annotations_enabled) annotationsEnabled := Bool(d.properties.Annotations_enabled)
extractAnnotations := annotationsEnabled
migratingNullability := annotationsEnabled && String(d.properties.Previous_api) != "" migratingNullability := annotationsEnabled && String(d.properties.Previous_api) != ""
validatingNullability := annotationsEnabled && (strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") || validatingNullability := annotationsEnabled && (strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
String(d.properties.Validate_nullability_from_list) != "") String(d.properties.Validate_nullability_from_list) != "")
@ -1127,27 +1172,40 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
checkApi := apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || checkApi := apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released")
apiLevelsAnnotationsEnabled := proptools.Bool(d.properties.Api_levels_annotations_enabled)
stubCmdParams := stubsCommandConfigParams{ stubCmdParams := stubsCommandConfigParams{
javaVersion: javaVersion, javaVersion: javaVersion,
deps: deps, deps: deps,
checkApi: checkApi, checkApi: checkApi,
generateStubs: generateStubs, generateStubs: generateStubs,
doApiLint: doApiLint, doApiLint: doApiLint,
doCheckReleased: doCheckReleased, doCheckReleased: doCheckReleased,
writeSdkValues: writeSdkValues, writeSdkValues: writeSdkValues,
migratingNullability: migratingNullability, migratingNullability: migratingNullability,
validatingNullability: validatingNullability, validatingNullability: validatingNullability,
annotationsEnabled: annotationsEnabled,
apiLevelsAnnotationsEnabled: apiLevelsAnnotationsEnabled,
extractAnnotations: extractAnnotations,
} }
stubCmdParams.stubsType = Everything stubCmdParams.stubsType = Everything
// Create default (i.e. "everything" stubs) rule for metalava // Create default (i.e. "everything" stubs) rule for metalava
d.everythingStubCmd(ctx, stubCmdParams) d.everythingStubCmd(ctx, stubCmdParams)
// The module generates "exportable" (and "runtime" eventually) stubs regardless of whether // The module generates "exportable" stubs regardless of whether
// aconfig_declarations property is defined or not. If the property is not defined, the module simply // 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 // strips all flagged apis to generate the "exportable" stubs
stubCmdParams.stubsType = Exportable stubCmdParams.stubsType = Exportable
d.exportableStubCmd(ctx, stubCmdParams) d.exportableStubCmd(ctx, stubCmdParams)
// "runtime" stubs do not generate any other artifacts than the stubs.
// Therefore, metalava does not have to run for "runtime" configuration
// when the module does not generate stubs.
if stubCmdParams.generateStubs {
stubCmdParams.stubsType = Runtime
d.runtimeStubCmd(ctx, stubCmdParams)
}
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
if len(d.Javadoc.properties.Out) > 0 { if len(d.Javadoc.properties.Out) > 0 {

View file

@ -396,23 +396,47 @@ func TestAconfigDeclarations(t *testing.T) {
"bar", "bar",
], ],
} }
droidstubs {
name: "baz",
srcs: ["a/A.java"],
api_surface: "public",
check_api: {
current: {
api_file: "a/current.txt",
removed_api_file: "a/removed.txt",
}
},
}
`) `)
// Check that droidstubs depend on aconfig_declarations // Check that droidstubs depend on aconfig_declarations
android.AssertBoolEquals(t, "foo expected to depend on bar", android.AssertBoolEquals(t, "foo expected to depend on bar",
CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true) CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true)
m := result.ModuleForTests("foo", "android_common") fooModule := result.ModuleForTests("foo", "android_common")
android.AssertStringDoesContain(t, "foo generates revert annotations file", android.AssertStringDoesContain(t, "foo generates revert annotations file",
strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt") strings.Join(fooModule.AllOutputs(), ""), "revert-annotations-exportable.txt")
// revert-annotations.txt passed to exportable stubs generation metalava command // revert-annotations.txt passed to exportable stubs generation metalava command
manifest := m.Output("metalava_exportable.sbox.textproto") exportableManifest := fooModule.Output("metalava_exportable.sbox.textproto")
cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command) exportableCmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, exportableManifest).Commands[0].Command)
android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt") android.AssertStringDoesContain(t, "flagged api hide command not included", exportableCmdline, "revert-annotations-exportable.txt")
android.AssertStringDoesContain(t, "foo generates exportable stubs jar", android.AssertStringDoesContain(t, "foo generates exportable stubs jar",
strings.Join(m.AllOutputs(), ""), "exportable/foo-stubs.srcjar") strings.Join(fooModule.AllOutputs(), ""), "exportable/foo-stubs.srcjar")
// revert-annotations.txt passed to runtime stubs generation metalava command
runtimeManifest := fooModule.Output("metalava_runtime.sbox.textproto")
runtimeCmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, runtimeManifest).Commands[0].Command)
android.AssertStringDoesContain(t, "flagged api hide command not included", runtimeCmdline, "revert-annotations-runtime.txt")
android.AssertStringDoesContain(t, "foo generates runtime stubs jar",
strings.Join(fooModule.AllOutputs(), ""), "runtime/foo-stubs.srcjar")
// If aconfig_declarations property is not defined, the runtime stubs is a copy of the exportable stubs
bazModule := result.ModuleForTests("baz", "android_common")
bazRuntimeCmdline := bazModule.Rule("metalava_runtime").RuleParams.Command
android.AssertStringDoesContain(t, "copy command should include the input stub", bazRuntimeCmdline, "exportable/baz-stubs.srcjar")
} }
func TestReleaseExportRuntimeApis(t *testing.T) { func TestReleaseExportRuntimeApis(t *testing.T) {