Skip to content

Commit

Permalink
Generate runtime stubs in droidstubs
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jihoonkang0829 committed Feb 27, 2024
1 parent 6b93b38 commit ca2f9e8
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 9 deletions.
2 changes: 2 additions & 0 deletions java/droiddoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
56 changes: 53 additions & 3 deletions java/droidstubs.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ type currentApiTimestampProvider interface {
type annotationFlagsParams struct {
migratingNullability bool
validatingNullability bool
extractAnnotations bool
nullabilityWarningsFile android.WritablePath
annotationsZip android.WritablePath
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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) != "")
Expand All @@ -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 {
Expand Down
36 changes: 30 additions & 6 deletions java/droidstubs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit ca2f9e8

Please sign in to comment.