From ca2f9e8bf4f5e3d54a449e132691a031e7cc628d Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Fri, 26 Jan 2024 01:45:12 +0000 Subject: [PATCH] Generate runtime stubs in droidstubs Similar to how the exportable stubs are generated in droidstubs, this change adds the rule to generate the runtime stubs in droidstubs. Unlike the exportable stubs, which the artifacts are dist'ed during the sdk build, the runtime stubs will only used in the hiddenapi flags generation. Therefore, only the stubs are generated and no other artifacts are generated during the "runtime" metalava invocation. When `aconfig_declarations` property is not defined (i.e. no flags are enabled, thus the exportable and the runtime stubs are identical), the runtime stubs are simple copied from the exportable stubs. Note that the runtime stubs are not a dependency of `droid` as of now. The dependency of the hiddenapi flags will be replaced to the runtime stubs in the child CL. Test: m nothing --no-skip-soong-tests && m api-stubs-docs-non-updatable Bug: 319162970 Change-Id: I14928b7b5619522c4caab1dfc795bc9c7e929639 --- java/droiddoc.go | 2 ++ java/droidstubs.go | 56 ++++++++++++++++++++++++++++++++++++++--- java/droidstubs_test.go | 36 +++++++++++++++++++++----- 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/java/droiddoc.go b/java/droiddoc.go index 6a66f45ec5..df40d016c0 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -222,6 +222,8 @@ type Javadoc struct { stubsSrcJar android.WritablePath exportableStubsSrcJar android.WritablePath + + runtimeStubsSrcJar android.WritablePath } func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) { diff --git a/java/droidstubs.go b/java/droidstubs.go index 6ca59d1dbb..b1126146ca 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -214,6 +214,7 @@ type currentApiTimestampProvider interface { type annotationFlagsParams struct { migratingNullability bool validatingNullability bool + extractAnnotations bool nullabilityWarningsFile android.WritablePath annotationsZip android.WritablePath } @@ -241,6 +242,7 @@ type stubsCommandConfigParams struct { 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 @@ -525,7 +527,9 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru cmd.FlagWithOutput("--nullability-warnings-txt ", params.nullabilityWarningsFile) } - cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip) + if params.extractAnnotations { + cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip) + } if len(d.properties.Merge_annotations_dirs) != 0 { d.mergeAnnoDirFlags(ctx, cmd) @@ -571,7 +575,9 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a } else if stubsType == Exportable { apiVersions = s.exportableArtifacts.apiVersionsXml } 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 { ctx.PropertyErrorf("api_levels_module", @@ -805,6 +811,7 @@ func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *andr annotationParams := annotationFlagsParams{ migratingNullability: params.stubConfig.migratingNullability, validatingNullability: params.stubConfig.validatingNullability, + extractAnnotations: params.stubConfig.extractAnnotations, nullabilityWarningsFile: params.nullabilityWarningsFile, annotationsZip: params.annotationsZip, } @@ -1053,6 +1060,38 @@ func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCo 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) { params.srcJarDir = android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "srcjars") @@ -1124,6 +1163,8 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { annotationsEnabled := Bool(d.properties.Annotations_enabled) + extractAnnotations := annotationsEnabled + 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) != "") @@ -1145,17 +1186,26 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { validatingNullability: validatingNullability, annotationsEnabled: annotationsEnabled, apiLevelsAnnotationsEnabled: apiLevelsAnnotationsEnabled, + extractAnnotations: extractAnnotations, } 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 + // The module generates "exportable" 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) + // "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 len(d.Javadoc.properties.Out) > 0 { diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go index e5ffd28472..ca34e0ef13 100644 --- a/java/droidstubs_test.go +++ b/java/droidstubs_test.go @@ -396,23 +396,47 @@ func TestAconfigDeclarations(t *testing.T) { "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 android.AssertBoolEquals(t, "foo expected to depend on bar", 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", - 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 - 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") + exportableManifest := fooModule.Output("metalava_exportable.sbox.textproto") + exportableCmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, exportableManifest).Commands[0].Command) + android.AssertStringDoesContain(t, "flagged api hide command not included", exportableCmdline, "revert-annotations-exportable.txt") 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) {