Generate "exportable" stubs library in java_sdk_library

Given that now the droidstubs module generates the "exportable" stubs,
this change modifies java_sdk_library to generate the java_library
modules that compiles the "exportable" stubs per api scope.
The detailed naming scheme of the generated modules are available in the
bug linked in the footer.

Similar to the from-text java_api_library vs from-source java_library
static lib selection for the "everything" stubs, the "exportable" stubs
module can also toggle between the stubs java_api_library and the
java_library module. However, given that the "exportable" stubs
generation has not been implemented for from-text stubs, the module
always default to depend on the from-source "exportable" stubs compiling
java_library module.

Test: go test ./java
Bug: 315495926
Change-Id: I5798312c1338c55625b2030da728b056385171a4
This commit is contained in:
Jihoon Kang
2023-12-20 02:53:38 +00:00
parent 78f8914fed
commit fa4a90d434
3 changed files with 194 additions and 69 deletions

View File

@@ -1329,7 +1329,9 @@ type PrebuiltStubsSources struct {
func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) { func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
switch tag { switch tag {
case "": // prebuilt droidstubs does not output "exportable" stubs.
// Output the "everything" stubs srcjar file if the tag is ".exportable".
case "", ".exportable":
return android.Paths{p.stubsSrcJar}, nil return android.Paths{p.stubsSrcJar}, nil
default: default:
return nil, fmt.Errorf("unsupported module reference tag %q", tag) return nil, fmt.Errorf("unsupported module reference tag %q", tag)

View File

@@ -231,6 +231,10 @@ func (scope *apiScope) stubsLibraryModuleNameSuffix() string {
return ".stubs" + scope.moduleSuffix return ".stubs" + scope.moduleSuffix
} }
func (scope *apiScope) exportableStubsLibraryModuleNameSuffix() string {
return ".stubs.exportable" + scope.moduleSuffix
}
func (scope *apiScope) apiLibraryModuleName(baseName string) string { func (scope *apiScope) apiLibraryModuleName(baseName string) string {
return scope.stubsLibraryModuleName(baseName) + ".from-text" return scope.stubsLibraryModuleName(baseName) + ".from-text"
} }
@@ -239,10 +243,18 @@ func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string {
return scope.stubsLibraryModuleName(baseName) + ".from-source" return scope.stubsLibraryModuleName(baseName) + ".from-source"
} }
func (scope *apiScope) exportableSourceStubsLibraryModuleName(baseName string) string {
return scope.exportableStubsLibraryModuleName(baseName) + ".from-source"
}
func (scope *apiScope) stubsLibraryModuleName(baseName string) string { func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
return baseName + scope.stubsLibraryModuleNameSuffix() return baseName + scope.stubsLibraryModuleNameSuffix()
} }
func (scope *apiScope) exportableStubsLibraryModuleName(baseName string) string {
return baseName + scope.exportableStubsLibraryModuleNameSuffix()
}
func (scope *apiScope) stubsSourceModuleName(baseName string) string { func (scope *apiScope) stubsSourceModuleName(baseName string) string {
return baseName + ".stubs.source" + scope.moduleSuffix return baseName + ".stubs.source" + scope.moduleSuffix
} }
@@ -895,6 +907,12 @@ func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope)
return c.namingScheme.stubsLibraryModuleName(apiScope, baseName) return c.namingScheme.stubsLibraryModuleName(apiScope, baseName)
} }
// Name of the java_library module that compiles the exportable stubs source.
func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string {
baseName := c.module.BaseModuleName()
return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName)
}
// Name of the droidstubs module that generates the stubs source and may also // Name of the droidstubs module that generates the stubs source and may also
// generate/check the API. // generate/check the API.
func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string { func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string {
@@ -911,9 +929,16 @@ func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) s
// Name of the java_library module that compiles the stubs // Name of the java_library module that compiles the stubs
// generated from source Java files. // generated from source Java files.
func (c *commonToSdkLibraryAndImport) sourceStubLibraryModuleName(apiScope *apiScope) string { func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string {
baseName := c.module.BaseModuleName() baseName := c.module.BaseModuleName()
return c.namingScheme.sourceStubLibraryModuleName(apiScope, baseName) return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName)
}
// Name of the java_library module that compiles the exportable stubs
// generated from source Java files.
func (c *commonToSdkLibraryAndImport) exportableSourceStubsLibraryModuleName(apiScope *apiScope) string {
baseName := c.module.BaseModuleName()
return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName)
} }
// The component names for different outputs of the java_sdk_library. // The component names for different outputs of the java_sdk_library.
@@ -1629,36 +1654,34 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext)
mctx.CreateModule(LibraryFactory, properties...) mctx.CreateModule(LibraryFactory, properties...)
} }
// Creates a static java library that has API stubs type libraryProperties struct {
func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { Name *string
props := struct { Visibility []string
Name *string Srcs []string
Visibility []string Installable *bool
Srcs []string Sdk_version *string
Installable *bool System_modules *string
Sdk_version *string Patch_module *string
System_modules *string Libs []string
Patch_module *string Static_libs []string
Libs []string Compile_dex *bool
Static_libs []string Java_version *string
Compile_dex *bool Openjdk9 struct {
Java_version *string Srcs []string
Openjdk9 struct { Javacflags []string
Srcs []string }
Javacflags []string Dist struct {
} Targets []string
Dist struct { Dest *string
Targets []string Dir *string
Dest *string Tag *string
Dir *string }
Tag *string }
}
}{}
props.Name = proptools.StringPtr(module.sourceStubLibraryModuleName(apiScope)) func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
props := libraryProperties{}
props.Visibility = []string{"//visibility:override", "//visibility:private"} props.Visibility = []string{"//visibility:override", "//visibility:private"}
// sources are generated from the droiddoc // sources are generated from the droiddoc
props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
props.Sdk_version = proptools.StringPtr(sdkVersion) props.Sdk_version = proptools.StringPtr(sdkVersion)
props.System_modules = module.deviceProperties.System_modules props.System_modules = module.deviceProperties.System_modules
@@ -1678,6 +1701,25 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
// interop with older developer tools that don't support 1.9. // interop with older developer tools that don't support 1.9.
props.Java_version = proptools.StringPtr("1.8") props.Java_version = proptools.StringPtr("1.8")
return props
}
// Creates a static java library that has API stubs
func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
props := module.stubsLibraryProps(mctx, apiScope)
props.Name = proptools.StringPtr(module.sourceStubsLibraryModuleName(apiScope))
props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
// Create a static java library that compiles the "exportable" stubs
func (module *SdkLibrary) createExportableStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
props := module.stubsLibraryProps(mctx, apiScope)
props.Name = proptools.StringPtr(module.exportableSourceStubsLibraryModuleName(apiScope))
props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope) + "{.exportable}"}
mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
} }
@@ -1908,43 +1950,15 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext,
mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
} }
func (module *SdkLibrary) createTopLevelStubsLibrary( func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) { props := libraryProperties{}
props := struct {
Name *string
Visibility []string
Sdk_version *string
Static_libs []string
System_modules *string
Dist struct {
Targets []string
Dest *string
Dir *string
Tag *string
}
Compile_dex *bool
}{}
props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
props.Sdk_version = proptools.StringPtr(sdkVersion) props.Sdk_version = proptools.StringPtr(sdkVersion)
// Add the stub compiling java_library/java_api_library as static lib based on build config
staticLib := module.sourceStubLibraryModuleName(apiScope)
if mctx.Config().BuildFromTextStub() && contributesToApiSurface {
staticLib = module.apiLibraryModuleName(apiScope)
}
props.Static_libs = append(props.Static_libs, staticLib)
props.System_modules = module.deviceProperties.System_modules props.System_modules = module.deviceProperties.System_modules
// Dist the class jar artifact for sdk builds.
if !Bool(module.sdkLibraryProperties.No_dist) {
props.Dist.Targets = []string{"sdk", "win_sdk"}
props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
props.Dist.Tag = proptools.StringPtr(".jar")
}
// The imports need to be compiled to dex if the java_sdk_library requests it. // The imports need to be compiled to dex if the java_sdk_library requests it.
compileDex := module.dexProperties.Compile_dex compileDex := module.dexProperties.Compile_dex
if module.stubLibrariesCompiledForDex() { if module.stubLibrariesCompiledForDex() {
@@ -1952,6 +1966,43 @@ func (module *SdkLibrary) createTopLevelStubsLibrary(
} }
props.Compile_dex = compileDex props.Compile_dex = compileDex
return props
}
func (module *SdkLibrary) createTopLevelStubsLibrary(
mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) {
props := module.topLevelStubsLibraryProps(mctx, apiScope)
props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
// Add the stub compiling java_library/java_api_library as static lib based on build config
staticLib := module.sourceStubsLibraryModuleName(apiScope)
if mctx.Config().BuildFromTextStub() && contributesToApiSurface {
staticLib = module.apiLibraryModuleName(apiScope)
}
props.Static_libs = append(props.Static_libs, staticLib)
mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
func (module *SdkLibrary) createTopLevelExportableStubsLibrary(
mctx android.DefaultableHookContext, apiScope *apiScope) {
props := module.topLevelStubsLibraryProps(mctx, apiScope)
props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope))
// Dist the class jar artifact for sdk builds.
// "exportable" stubs are copied to dist for sdk builds instead of the "everything" stubs.
if !Bool(module.sdkLibraryProperties.No_dist) {
props.Dist.Targets = []string{"sdk", "win_sdk"}
props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
props.Dist.Tag = proptools.StringPtr(".jar")
}
staticLib := module.exportableSourceStubsLibraryModuleName(apiScope)
props.Static_libs = append(props.Static_libs, staticLib)
mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
} }
@@ -2157,6 +2208,7 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs) module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
module.createStubsLibrary(mctx, scope) module.createStubsLibrary(mctx, scope)
module.createExportableStubsLibrary(mctx, scope)
alternativeFullApiSurfaceStubLib := "" alternativeFullApiSurfaceStubLib := ""
if scope == apiScopePublic { if scope == apiScopePublic {
@@ -2168,6 +2220,7 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
} }
module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface) module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface)
module.createTopLevelExportableStubsLibrary(mctx, scope)
} }
if module.requiresRuntimeImplementationLibrary() { if module.requiresRuntimeImplementationLibrary() {
@@ -2223,7 +2276,11 @@ type sdkLibraryComponentNamingScheme interface {
apiLibraryModuleName(scope *apiScope, baseName string) string apiLibraryModuleName(scope *apiScope, baseName string) string
sourceStubLibraryModuleName(scope *apiScope, baseName string) string sourceStubsLibraryModuleName(scope *apiScope, baseName string) string
exportableStubsLibraryModuleName(scope *apiScope, baseName string) string
exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string
} }
type defaultNamingScheme struct { type defaultNamingScheme struct {
@@ -2241,34 +2298,47 @@ func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName str
return scope.apiLibraryModuleName(baseName) return scope.apiLibraryModuleName(baseName)
} }
func (s *defaultNamingScheme) sourceStubLibraryModuleName(scope *apiScope, baseName string) string { func (s *defaultNamingScheme) sourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
return scope.sourceStubLibraryModuleName(baseName) return scope.sourceStubLibraryModuleName(baseName)
} }
func (s *defaultNamingScheme) exportableStubsLibraryModuleName(scope *apiScope, baseName string) string {
return scope.exportableStubsLibraryModuleName(baseName)
}
func (s *defaultNamingScheme) exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
return scope.exportableSourceStubsLibraryModuleName(baseName)
}
var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil) var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
func hasStubsLibrarySuffix(name string, apiScope *apiScope) bool {
return strings.HasSuffix(name, apiScope.stubsLibraryModuleNameSuffix()) ||
strings.HasSuffix(name, apiScope.exportableStubsLibraryModuleNameSuffix())
}
func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) { func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
name = strings.TrimSuffix(name, ".from-source") name = strings.TrimSuffix(name, ".from-source")
// This suffix-based approach is fragile and could potentially mis-trigger. // This suffix-based approach is fragile and could potentially mis-trigger.
// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly. // TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) { if hasStubsLibrarySuffix(name, apiScopePublic) {
if name == "hwbinder.stubs" || name == "libcore_private.stubs" { if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
// Due to a previous bug, these modules were not considered stubs, so we retain that. // Due to a previous bug, these modules were not considered stubs, so we retain that.
return false, javaPlatform return false, javaPlatform
} }
return true, javaSdk return true, javaSdk
} }
if strings.HasSuffix(name, apiScopeSystem.stubsLibraryModuleNameSuffix()) { if hasStubsLibrarySuffix(name, apiScopeSystem) {
return true, javaSystem return true, javaSystem
} }
if strings.HasSuffix(name, apiScopeModuleLib.stubsLibraryModuleNameSuffix()) { if hasStubsLibrarySuffix(name, apiScopeModuleLib) {
return true, javaModule return true, javaModule
} }
if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) { if hasStubsLibrarySuffix(name, apiScopeTest) {
return true, javaSystem return true, javaSystem
} }
if strings.HasSuffix(name, apiScopeSystemServer.stubsLibraryModuleNameSuffix()) { if hasStubsLibrarySuffix(name, apiScopeSystemServer) {
return true, javaSystemServer return true, javaSystemServer
} }
return false, javaPlatform return false, javaPlatform

View File

@@ -1423,7 +1423,7 @@ func TestJavaSdkLibraryDist(t *testing.T) {
for _, tt := range testCases { for _, tt := range testCases {
t.Run(tt.module, func(t *testing.T) { t.Run(tt.module, func(t *testing.T) {
m := result.ModuleForTests(tt.module+".stubs", "android_common").Module().(*Library) m := result.ModuleForTests(apiScopePublic.exportableStubsLibraryModuleName(tt.module), "android_common").Module().(*Library)
dists := m.Dists() dists := m.Dists()
if len(dists) != 1 { if len(dists) != 1 {
t.Fatalf("expected exactly 1 dist entry, got %d", len(dists)) t.Fatalf("expected exactly 1 dist entry, got %d", len(dists))
@@ -1693,3 +1693,56 @@ func TestSdkLibraryDependency(t *testing.T) {
android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barPermissions.RuleParams.Command, `dependency=\"foo\"`) android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barPermissions.RuleParams.Command, `dependency=\"foo\"`)
} }
func TestSdkLibraryExportableStubsLibrary(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("foo"),
android.FixtureModifyConfig(func(config android.Config) {
config.SetApiLibraries([]string{"foo"})
}),
).RunTestWithBp(t, `
aconfig_declarations {
name: "bar",
package: "com.example.package",
srcs: [
"bar.aconfig",
],
}
java_sdk_library {
name: "foo",
srcs: ["a.java", "b.java"],
api_packages: ["foo"],
system: {
enabled: true,
},
module_lib: {
enabled: true,
},
test: {
enabled: true,
},
aconfig_declarations: [
"bar",
],
}
`)
exportableStubsLibraryModuleName := apiScopePublic.exportableStubsLibraryModuleName("foo")
exportableSourceStubsLibraryModuleName := apiScopePublic.exportableSourceStubsLibraryModuleName("foo")
// Check modules generation
topLevelModule := result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
result.ModuleForTests(exportableSourceStubsLibraryModuleName, "android_common")
// Check static lib dependency
android.AssertBoolEquals(t, "exportable top level stubs library module depends on the"+
"exportable source stubs library module", true,
CheckModuleHasDependency(t, result.TestContext, exportableStubsLibraryModuleName,
"android_common", exportableSourceStubsLibraryModuleName),
)
android.AssertArrayString(t, "exportable source stub library is a static lib of the"+
"top level exportable stubs library", []string{exportableSourceStubsLibraryModuleName},
topLevelModule.Module().(*Library).properties.Static_libs)
}