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) {
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
default:
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
}
func (scope *apiScope) exportableStubsLibraryModuleNameSuffix() string {
return ".stubs.exportable" + scope.moduleSuffix
}
func (scope *apiScope) apiLibraryModuleName(baseName string) string {
return scope.stubsLibraryModuleName(baseName) + ".from-text"
}
@@ -239,10 +243,18 @@ func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string {
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 {
return baseName + scope.stubsLibraryModuleNameSuffix()
}
func (scope *apiScope) exportableStubsLibraryModuleName(baseName string) string {
return baseName + scope.exportableStubsLibraryModuleNameSuffix()
}
func (scope *apiScope) stubsSourceModuleName(baseName string) string {
return baseName + ".stubs.source" + scope.moduleSuffix
}
@@ -895,6 +907,12 @@ func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope)
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
// generate/check the API.
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
// generated from source Java files.
func (c *commonToSdkLibraryAndImport) sourceStubLibraryModuleName(apiScope *apiScope) string {
func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string {
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.
@@ -1629,9 +1654,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext)
mctx.CreateModule(LibraryFactory, properties...)
}
// Creates a static java library that has API stubs
func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
props := struct {
type libraryProperties struct {
Name *string
Visibility []string
Srcs []string
@@ -1653,12 +1676,12 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
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"}
// sources are generated from the droiddoc
props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
props.Sdk_version = proptools.StringPtr(sdkVersion)
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.
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())
}
@@ -1908,43 +1950,15 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext,
mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
func (module *SdkLibrary) createTopLevelStubsLibrary(
mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) {
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))
func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
props := libraryProperties{}
props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
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
// 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.
compileDex := module.dexProperties.Compile_dex
if module.stubLibrariesCompiledForDex() {
@@ -1952,6 +1966,43 @@ func (module *SdkLibrary) createTopLevelStubsLibrary(
}
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())
}
@@ -2157,6 +2208,7 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
module.createStubsLibrary(mctx, scope)
module.createExportableStubsLibrary(mctx, scope)
alternativeFullApiSurfaceStubLib := ""
if scope == apiScopePublic {
@@ -2168,6 +2220,7 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
}
module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface)
module.createTopLevelExportableStubsLibrary(mctx, scope)
}
if module.requiresRuntimeImplementationLibrary() {
@@ -2223,7 +2276,11 @@ type sdkLibraryComponentNamingScheme interface {
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 {
@@ -2241,34 +2298,47 @@ func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName str
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)
}
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)
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) {
name = strings.TrimSuffix(name, ".from-source")
// 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.
if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) {
if hasStubsLibrarySuffix(name, apiScopePublic) {
if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
// Due to a previous bug, these modules were not considered stubs, so we retain that.
return false, javaPlatform
}
return true, javaSdk
}
if strings.HasSuffix(name, apiScopeSystem.stubsLibraryModuleNameSuffix()) {
if hasStubsLibrarySuffix(name, apiScopeSystem) {
return true, javaSystem
}
if strings.HasSuffix(name, apiScopeModuleLib.stubsLibraryModuleNameSuffix()) {
if hasStubsLibrarySuffix(name, apiScopeModuleLib) {
return true, javaModule
}
if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) {
if hasStubsLibrarySuffix(name, apiScopeTest) {
return true, javaSystem
}
if strings.HasSuffix(name, apiScopeSystemServer.stubsLibraryModuleNameSuffix()) {
if hasStubsLibrarySuffix(name, apiScopeSystemServer) {
return true, javaSystemServer
}
return false, javaPlatform

View File

@@ -1423,7 +1423,7 @@ func TestJavaSdkLibraryDist(t *testing.T) {
for _, tt := range testCases {
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()
if len(dists) != 1 {
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\"`)
}
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)
}