Enable non-"everything" stubs generation in java_api_library

This change adds support to generate non-"everything" (i.e. "runtime"
and "exportable") stubs in java_api_library, which generates the stubs
from the api signature files.

Unlike droidstubs module that generates "everything", "exportable" and
"runtime" stubs in a single module, java_api_library generates a single
set of stubs per module, which is set by the default-"everything"
property `stubs_type`. This is because java_api_library is responsible
for both generation and the compilation of the stubs srcjar, and
compilation of the stubs srcjar are done in separate java_library
modules for from-source stubs.

Utilization of this feature will be done in a follow up change that
generates the "exportable" java_api_library modules in java_sdk_library.

Test: m nothing --no-skip-soong-tests
Bug: 318009570
Change-Id: I1051544ac3bcdb3ba1f78bfec28eba4e9fad9c2d
This commit is contained in:
Jihoon Kang 2024-02-15 21:53:49 +00:00
parent 60bdd05b21
commit 5d701272e4
7 changed files with 148 additions and 6 deletions

View file

@ -64,6 +64,7 @@ java_api_library {
"stub-annotations",
],
enable_validation: false,
stubs_type: "everything",
}
java_library {
@ -248,6 +249,7 @@ java_api_library {
"stub-annotations",
],
visibility: ["//visibility:private"],
stubs_type: "everything",
}
// Produces a dist file that is used by the
@ -358,6 +360,7 @@ java_api_library {
libs: [
"stub-annotations",
],
stubs_type: "everything",
}
java_library {
@ -446,6 +449,7 @@ java_api_library {
libs: [
"stub-annotations",
],
stubs_type: "everything",
}
java_library {

View file

@ -52,6 +52,19 @@ func (s StubsType) String() string {
}
}
func StringToStubsType(s string) StubsType {
switch strings.ToLower(s) {
case Everything.String():
return Everything
case Runtime.String():
return Runtime
case Exportable.String():
return Exportable
default:
return Unavailable
}
}
func init() {
RegisterStubsBuildComponents(android.InitRegistrationContext)
}
@ -731,7 +744,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
// 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) {
func generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) {
if len(aconfigFlagsPaths) == 0 {
cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
@ -1106,7 +1119,7 @@ func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsComm
cmd := d.commonMetalavaStubCmd(ctx, rule, params)
d.generateRevertAnnotationArgs(ctx, cmd, params.stubConfig.stubsType, params.stubConfig.deps.aconfigProtoFiles)
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.

View file

@ -337,6 +337,7 @@ func TestGeneratedApiContributionVisibilityTest(t *testing.T) {
name: "bar",
api_surface: "public",
api_contributions: ["foo.api.contribution"],
stubs_type: "everything",
}
`
ctx, _ := testJavaWithFS(t, `

View file

@ -24,6 +24,7 @@ import (
"sort"
"strings"
"android/soong/aconfig"
"android/soong/remoteexec"
"android/soong/testing"
@ -1863,6 +1864,10 @@ type ApiLibrary struct {
dexJarFile OptionalDexJarPath
validationPaths android.Paths
stubsType StubsType
aconfigProtoFiles android.Paths
}
type JavaApiLibraryProperties struct {
@ -1904,6 +1909,20 @@ type JavaApiLibraryProperties struct {
// in sync with the source Java files. However, the environment variable
// DISABLE_STUB_VALIDATION has precedence over this property.
Enable_validation *bool
// Type of stubs the module should generate. Must be one of "everything", "runtime" or
// "exportable". Defaults to "everything".
// - "everything" stubs include all non-flagged apis and flagged apis, regardless of the state
// of the flag.
// - "runtime" stubs include all non-flagged apis and flagged apis that are ENABLED or
// READ_WRITE, and all other flagged apis are stripped.
// - "exportable" stubs include all non-flagged apis and flagged apis that are ENABLED and
// READ_ONLY, and all other flagged apis are stripped.
Stubs_type *string
// List of aconfig_declarations module names that the stubs generated in this module
// depend on.
Aconfig_declarations []string
}
func ApiLibraryFactory() android.Module {
@ -2067,6 +2086,9 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
if al.properties.System_modules != nil {
ctx.AddVariationDependencies(nil, systemModulesTag, String(al.properties.System_modules))
}
for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations {
ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName)
}
}
// Map where key is the api scope name and value is the int value
@ -2087,7 +2109,23 @@ func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFiles
return srcFilesInfo
}
var validstubsType = []StubsType{Everything, Runtime, Exportable}
func (al *ApiLibrary) validateProperties(ctx android.ModuleContext) {
if al.properties.Stubs_type == nil {
ctx.ModuleErrorf("java_api_library module type must specify stubs_type property.")
} else {
al.stubsType = StringToStubsType(proptools.String(al.properties.Stubs_type))
}
if !android.InList(al.stubsType, validstubsType) {
ctx.PropertyErrorf("stubs_type", "%s is not a valid stubs_type property value. "+
"Must be one of %s.", proptools.String(al.properties.Stubs_type), validstubsType)
}
}
func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
al.validateProperties(ctx)
rule := android.NewRuleBuilder(pctx, ctx)
@ -2131,6 +2169,18 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if currentApiTimestampProvider, ok := dep.(currentApiTimestampProvider); ok {
al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp())
}
case aconfigDeclarationTag:
if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPath)
} else if provider, ok := android.OtherModuleProvider(ctx, dep, aconfig.CodegenInfoProvider); ok {
al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPaths...)
} else {
ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+
"module type is allowed for flags_packages property, but %s is neither "+
"of these supported module types",
dep.Name(),
)
}
}
})
@ -2156,6 +2206,8 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
al.addValidation(ctx, cmd, al.validationPaths)
generateRevertAnnotationArgs(ctx, cmd, al.stubsType, al.aconfigProtoFiles)
al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, "metalava", "stubs.jar")
al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))

View file

@ -1756,6 +1756,7 @@ func TestJavaApiContributionEmptyApiFile(t *testing.T) {
name: "bar",
api_surface: "public",
api_contributions: ["foo"],
stubs_type: "everything",
}
`)
}
@ -1792,12 +1793,14 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) {
name: "bar1",
api_surface: "public",
api_contributions: ["foo1"],
stubs_type: "everything",
}
java_api_library {
name: "bar2",
api_surface: "system",
api_contributions: ["foo1", "foo2"],
stubs_type: "everything",
}
`)
@ -1885,12 +1888,14 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) {
name: "bar1",
api_surface: "public",
api_contributions: ["foo1"],
stubs_type: "everything",
}
java_api_library {
name: "bar2",
api_surface: "public",
defaults:["baz1"],
stubs_type: "everything",
}
java_api_library {
@ -1898,6 +1903,7 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) {
api_surface: "system",
defaults:["baz1", "baz2"],
api_contributions: ["foo4"],
stubs_type: "everything",
}
`)
@ -1962,12 +1968,14 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) {
name: "bar1",
api_surface: "public",
api_contributions: ["foo1"],
stubs_type: "everything",
}
java_api_library {
name: "bar2",
api_surface: "system",
api_contributions: ["foo1", "foo2"],
stubs_type: "everything",
}
`)
@ -2044,6 +2052,7 @@ func TestJavaApiLibraryLibsLink(t *testing.T) {
api_surface: "public",
api_contributions: ["foo1"],
libs: ["lib1"],
stubs_type: "everything",
}
java_api_library {
@ -2051,6 +2060,7 @@ func TestJavaApiLibraryLibsLink(t *testing.T) {
api_surface: "system",
api_contributions: ["foo1", "foo2"],
libs: ["lib1", "lib2", "bar1"],
stubs_type: "everything",
}
`)
@ -2130,6 +2140,7 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) {
api_surface: "public",
api_contributions: ["foo1"],
static_libs: ["lib1"],
stubs_type: "everything",
}
java_api_library {
@ -2137,6 +2148,7 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) {
api_surface: "system",
api_contributions: ["foo1", "foo2"],
static_libs: ["lib1", "lib2", "bar1"],
stubs_type: "everything",
}
`)
@ -2184,6 +2196,7 @@ func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) {
name: "lib1",
api_surface: "public",
api_contributions: ["foo1", "foo2"],
stubs_type: "everything",
}
`
@ -2207,6 +2220,7 @@ func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) {
api_surface: "public",
api_contributions: ["foo1"],
full_api_surface_stub: "lib1",
stubs_type: "everything",
}
`)
@ -2368,6 +2382,7 @@ func TestJavaApiContributionImport(t *testing.T) {
java_api_library {
name: "foo",
api_contributions: ["bar"],
stubs_type: "everything",
}
java_api_contribution_import {
name: "bar",
@ -2394,6 +2409,7 @@ func TestJavaApiLibraryApiFilesSorting(t *testing.T) {
"module-lib-api-stubs-docs-non-updatable.api.contribution",
"api-stubs-docs-non-updatable.api.contribution",
],
stubs_type: "everything",
}
`)
m := ctx.ModuleForTests("foo", "android_common")
@ -2466,6 +2482,7 @@ func TestApiLibraryDroidstubsDependency(t *testing.T) {
"api-stubs-docs-non-updatable.api.contribution",
],
enable_validation: true,
stubs_type: "everything",
}
java_api_library {
name: "bar",
@ -2473,6 +2490,7 @@ func TestApiLibraryDroidstubsDependency(t *testing.T) {
"api-stubs-docs-non-updatable.api.contribution",
],
enable_validation: false,
stubs_type: "everything",
}
`)
@ -2624,3 +2642,54 @@ func TestMultiplePrebuilts(t *testing.T) {
android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "bar", entries.EntryMap["LOCAL_MODULE"][0])
}
}
func TestApiLibraryAconfigDeclarations(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForJavaTest,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
}),
android.FixtureMergeMockFs(map[string][]byte{
"a/A.java": nil,
"a/current.txt": nil,
"a/removed.txt": nil,
}),
).RunTestWithBp(t, `
aconfig_declarations {
name: "bar",
package: "com.example.package",
srcs: [
"bar.aconfig",
],
}
java_api_contribution {
name: "baz",
api_file: "a/current.txt",
api_surface: "public",
}
java_api_library {
name: "foo",
api_surface: "public",
api_contributions: [
"baz",
],
aconfig_declarations: [
"bar",
],
stubs_type: "exportable",
enable_validation: false,
}
`)
// Check if java_api_library depends 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")
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.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")
}

View file

@ -2024,6 +2024,7 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext,
Full_api_surface_stub *string
System_modules *string
Enable_validation *bool
Stubs_type *string
}{}
props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
@ -2073,6 +2074,7 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext,
props.System_modules = module.deviceProperties.System_modules
props.Enable_validation = proptools.BoolPtr(true)
props.Stubs_type = proptools.StringPtr("everything")
mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}

View file

@ -523,10 +523,11 @@ func gatherRequiredDepsForTest() string {
for libName, droidstubs := range extraApiLibraryModules {
bp += fmt.Sprintf(`
java_api_library {
name: "%s",
api_contributions: ["%s"],
}
java_api_library {
name: "%s",
api_contributions: ["%s"],
stubs_type: "everything",
}
`, libName, droidstubs.name+".api.contribution")
}