Loading java/droiddoc.go +10 −1 Original line number Original line Diff line number Diff line Loading @@ -350,11 +350,16 @@ type ApiFilePath interface { ApiFilePath() android.Path ApiFilePath() android.Path } } type ApiStubsSrcProvider interface { StubsSrcJar() android.Path } // Provider of information about API stubs, used by java_sdk_library. // Provider of information about API stubs, used by java_sdk_library. type ApiStubsProvider interface { type ApiStubsProvider interface { ApiFilePath ApiFilePath RemovedApiFilePath() android.Path RemovedApiFilePath() android.Path StubsSrcJar() android.Path ApiStubsSrcProvider } } // // Loading Loading @@ -1912,6 +1917,10 @@ func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) { } } } } func (d *PrebuiltStubsSources) StubsSrcJar() android.Path { return d.stubsSrcJar } func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") Loading java/java_test.go +147 −0 Original line number Original line Diff line number Diff line Loading @@ -575,6 +575,7 @@ func TestJavaSdkLibraryImport(t *testing.T) { }, }, test: { test: { jars: ["c.jar"], jars: ["c.jar"], stub_srcs: ["c.java"], }, }, } } `) `) Loading Loading @@ -1229,6 +1230,113 @@ func TestJavaSdkLibrary(t *testing.T) { } } } } func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) { testJava(t, ` java_sdk_library { name: "foo", srcs: ["a.java"], api_packages: ["foo"], public: { enabled: true, }, } java_library { name: "bar", srcs: ["b.java", ":foo{.public.stubs.source}"], } `) } func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) { testJavaError(t, `"foo" does not provide api scope system`, ` java_sdk_library { name: "foo", srcs: ["a.java"], api_packages: ["foo"], public: { enabled: true, }, } java_library { name: "bar", srcs: ["b.java", ":foo{.system.stubs.source}"], } `) } func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { testJava(t, ` java_sdk_library_import { name: "foo", public: { jars: ["a.jar"], stub_srcs: ["a.java"], current_api: "api/current.txt", removed_api: "api/removed.txt", }, } java_library { name: "bar", srcs: [":foo{.public.stubs.source}"], java_resources: [ ":foo{.public.api.txt}", ":foo{.public.removed-api.txt}", ], } `) } func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { bp := ` java_sdk_library_import { name: "foo", public: { jars: ["a.jar"], }, } ` t.Run("stubs.source", func(t *testing.T) { testJavaError(t, `stubs.source not available for api scope public`, bp+` java_library { name: "bar", srcs: [":foo{.public.stubs.source}"], java_resources: [ ":foo{.public.api.txt}", ":foo{.public.removed-api.txt}", ], } `) }) t.Run("api.txt", func(t *testing.T) { testJavaError(t, `api.txt not available for api scope public`, bp+` java_library { name: "bar", srcs: ["a.java"], java_resources: [ ":foo{.public.api.txt}", ], } `) }) t.Run("removed-api.txt", func(t *testing.T) { testJavaError(t, `removed-api.txt not available for api scope public`, bp+` java_library { name: "bar", srcs: ["a.java"], java_resources: [ ":foo{.public.removed-api.txt}", ], } `) }) } func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, ` testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, ` java_sdk_library { java_sdk_library { Loading Loading @@ -1261,6 +1369,45 @@ func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { `) `) } } func TestJavaSdkLibrary_MissingScope(t *testing.T) { testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, ` java_sdk_library { name: "foo", srcs: ["a.java"], public: { enabled: false, }, } java_library { name: "baz", srcs: ["a.java"], libs: ["foo"], sdk_version: "module_current", } `) } func TestJavaSdkLibrary_FallbackScope(t *testing.T) { testJava(t, ` java_sdk_library { name: "foo", srcs: ["a.java"], system: { enabled: true, }, } java_library { name: "baz", srcs: ["a.java"], libs: ["foo"], // foo does not have module-lib scope so it should fallback to system sdk_version: "module_current", } `) } var compilerFlagsTestCases = []struct { var compilerFlagsTestCases = []struct { in string in string out bool out bool Loading java/sdk_library.go +236 −75 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ import ( "path" "path" "path/filepath" "path/filepath" "reflect" "reflect" "regexp" "sort" "sort" "strings" "strings" "sync" "sync" Loading Loading @@ -145,6 +146,8 @@ type apiScope struct { // Initialize a scope, creating and adding appropriate dependency tags // Initialize a scope, creating and adding appropriate dependency tags func initApiScope(scope *apiScope) *apiScope { func initApiScope(scope *apiScope) *apiScope { name := scope.name name := scope.name scopeByName[name] = scope allScopeNames = append(allScopeNames, name) scope.propertyName = strings.ReplaceAll(name, "-", "_") scope.propertyName = strings.ReplaceAll(name, "-", "_") scope.fieldName = proptools.FieldNameForProperty(scope.propertyName) scope.fieldName = proptools.FieldNameForProperty(scope.propertyName) scope.stubsTag = scopeDependencyTag{ scope.stubsTag = scopeDependencyTag{ Loading Loading @@ -217,6 +220,8 @@ func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string { } } var ( var ( scopeByName = make(map[string]*apiScope) allScopeNames []string apiScopePublic = initApiScope(&apiScope{ apiScopePublic = initApiScope(&apiScope{ name: "public", name: "public", Loading Loading @@ -433,12 +438,30 @@ type sdkLibraryProperties struct { //Html_doc *bool //Html_doc *bool } } // Paths to outputs from java_sdk_library and java_sdk_library_import. // // Fields that are android.Paths are always set (during GenerateAndroidBuildActions). // OptionalPaths are always set by java_sdk_library but may not be set by // java_sdk_library_import as not all instances provide that information. type scopePaths struct { type scopePaths struct { // The path (represented as Paths for convenience when returning) to the stubs header jar. // // That is the jar that is created by turbine. stubsHeaderPath android.Paths stubsHeaderPath android.Paths // The path (represented as Paths for convenience when returning) to the stubs implementation jar. // // This is not the implementation jar, it still only contains stubs. stubsImplPath android.Paths stubsImplPath android.Paths currentApiFilePath android.Path removedApiFilePath android.Path // The API specification file, e.g. system_current.txt. stubsSrcJar android.Path currentApiFilePath android.OptionalPath // The specification of API elements removed since the last release. removedApiFilePath android.OptionalPath // The stubs source jar. stubsSrcJar android.OptionalPath } } func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error { func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error { Loading @@ -460,9 +483,18 @@ func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action f } } } } func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider)) error { if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok { action(apiStubsProvider) return nil } else { return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs") } } func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) { func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) { paths.currentApiFilePath = provider.ApiFilePath() paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath()) paths.removedApiFilePath = provider.RemovedApiFilePath() paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath()) } } func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { Loading @@ -471,12 +503,12 @@ func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { }) }) } } func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsProvider) { func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider) { paths.stubsSrcJar = provider.StubsSrcJar() paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar()) } } func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error { func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error { return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) { return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) { paths.extractStubsSourceInfoFromApiStubsProviders(provider) paths.extractStubsSourceInfoFromApiStubsProviders(provider) }) }) } } Loading Loading @@ -551,7 +583,83 @@ func (c *commonToSdkLibraryAndImport) apiModuleName(apiScope *apiScope) string { return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName()) return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName()) } } func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths { // The component names for different outputs of the java_sdk_library. // // They are similar to the names used for the child modules it creates const ( stubsSourceComponentName = "stubs.source" apiTxtComponentName = "api.txt" removedApiTxtComponentName = "removed-api.txt" ) // A regular expression to match tags that reference a specific stubs component. // // It will only match if given a valid scope and a valid component. It is verfy strict // to ensure it does not accidentally match a similar looking tag that should be processed // by the embedded Library. var tagSplitter = func() *regexp.Regexp { // Given a list of literal string items returns a regular expression that will // match any one of the items. choice := func(items ...string) string { return `\Q` + strings.Join(items, `\E|\Q`) + `\E` } // Regular expression to match one of the scopes. scopesRegexp := choice(allScopeNames...) // Regular expression to match one of the components. componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName) // Regular expression to match any combination of one scope and one component. return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp)) }() // For OutputFileProducer interface // // .<scope>.stubs.source // .<scope>.api.txt // .<scope>.removed-api.txt func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) { if groups := tagSplitter.FindStringSubmatch(tag); groups != nil { scopeName := groups[1] component := groups[2] if scope, ok := scopeByName[scopeName]; ok { paths := c.findScopePaths(scope) if paths == nil { return nil, fmt.Errorf("%q does not provide api scope %s", c.moduleBase.BaseModuleName(), scopeName) } switch component { case stubsSourceComponentName: if paths.stubsSrcJar.Valid() { return android.Paths{paths.stubsSrcJar.Path()}, nil } case apiTxtComponentName: if paths.currentApiFilePath.Valid() { return android.Paths{paths.currentApiFilePath.Path()}, nil } case removedApiTxtComponentName: if paths.removedApiFilePath.Valid() { return android.Paths{paths.removedApiFilePath.Path()}, nil } } return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName) } else { return nil, fmt.Errorf("unknown scope %s in %s", scope, tag) } } else { return nil, nil } } func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths { if c.scopePaths == nil { if c.scopePaths == nil { c.scopePaths = make(map[*apiScope]*scopePaths) c.scopePaths = make(map[*apiScope]*scopePaths) } } Loading @@ -564,6 +672,62 @@ func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths return paths return paths } } func (c *commonToSdkLibraryAndImport) findScopePaths(scope *apiScope) *scopePaths { if c.scopePaths == nil { return nil } return c.scopePaths[scope] } // If this does not support the requested api scope then find the closest available // scope it does support. Returns nil if no such scope is available. func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *scopePaths { for s := scope; s != nil; s = s.extends { if paths := c.findScopePaths(s); paths != nil { return paths } } // This should never happen outside tests as public should be the base scope for every // scope and is enabled by default. return nil } func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { // If a specific numeric version has been requested then use prebuilt versions of the sdk. if sdkVersion.version.isNumbered() { return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion) } var apiScope *apiScope switch sdkVersion.kind { case sdkSystem: apiScope = apiScopeSystem case sdkModule: apiScope = apiScopeModuleLib case sdkTest: apiScope = apiScopeTest default: apiScope = apiScopePublic } paths := c.findClosestScopePath(apiScope) if paths == nil { var scopes []string for _, s := range allApiScopes { if c.findScopePaths(s) != nil { scopes = append(scopes, s.name) } } ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.moduleBase.BaseModuleName(), scopes) return nil } return paths.stubsHeaderPath } type SdkLibrary struct { type SdkLibrary struct { Library Library Loading Loading @@ -664,6 +828,15 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { module.Library.deps(ctx) module.Library.deps(ctx) } } func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) { paths, err := module.commonOutputFiles(tag) if paths == nil && err == nil { return module.Library.OutputFiles(tag) } else { return paths, err } } func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Don't build an implementation library if this is api only. // Don't build an implementation library if this is api only. if !proptools.Bool(module.sdkLibraryProperties.Api_only) { if !proptools.Bool(module.sdkLibraryProperties.Api_only) { Loading @@ -679,7 +852,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Extract information from any of the scope specific dependencies. // Extract information from any of the scope specific dependencies. if scopeTag, ok := tag.(scopeDependencyTag); ok { if scopeTag, ok := tag.(scopeDependencyTag); ok { apiScope := scopeTag.apiScope apiScope := scopeTag.apiScope scopePaths := module.getScopePaths(apiScope) scopePaths := module.getScopePathsCreateIfNeeded(apiScope) // Extract information from the dependency. The exact information extracted // Extract information from the dependency. The exact information extracted // is determined by the nature of the dependency which is determined by the tag. // is determined by the nature of the dependency which is determined by the tag. Loading Loading @@ -1012,41 +1185,20 @@ func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) and return android.Paths{jarPath.Path()} return android.Paths{jarPath.Path()} } } func (module *SdkLibrary) sdkJars( func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { // If a specific numeric version has been requested then use prebuilt versions of the sdk. // Check any special cases for java_sdk_library. if sdkVersion.version.isNumbered() { return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion) } else { if !sdkVersion.specified() { if !sdkVersion.specified() { if headerJars { if headerJars { return module.HeaderJars() return module.HeaderJars() } else { } else { return module.ImplementationJars() return module.ImplementationJars() } } } } else if sdkVersion.kind == sdkPrivate { var apiScope *apiScope switch sdkVersion.kind { case sdkSystem: apiScope = apiScopeSystem case sdkTest: apiScope = apiScopeTest case sdkPrivate: return module.HeaderJars() return module.HeaderJars() default: apiScope = apiScopePublic } } paths := module.getScopePaths(apiScope) return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion) if headerJars { return paths.stubsHeaderPath } else { return paths.stubsImplPath } } } } // to satisfy SdkLibraryDependency interface // to satisfy SdkLibraryDependency interface Loading Loading @@ -1277,10 +1429,10 @@ type sdkLibraryScopeProperties struct { Stub_srcs []string `android:"path"` Stub_srcs []string `android:"path"` // The current.txt // The current.txt Current_api string `android:"path"` Current_api *string `android:"path"` // The removed.txt // The removed.txt Removed_api string `android:"path"` Removed_api *string `android:"path"` } } type sdkLibraryImportProperties struct { type sdkLibraryImportProperties struct { Loading Loading @@ -1390,8 +1542,10 @@ func (module *sdkLibraryImport) createInternalModules(mctx android.DefaultableHo module.createJavaImportForStubs(mctx, apiScope, scopeProperties) module.createJavaImportForStubs(mctx, apiScope, scopeProperties) if len(scopeProperties.Stub_srcs) > 0 { module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties) module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties) } } } javaSdkLibraries := javaSdkLibraries(mctx.Config()) javaSdkLibraries := javaSdkLibraries(mctx.Config()) javaSdkLibrariesLock.Lock() javaSdkLibrariesLock.Lock() Loading Loading @@ -1442,45 +1596,48 @@ func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) // Add dependencies to the prebuilt stubs library // Add dependencies to the prebuilt stubs library ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope)) ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope)) if len(scopeProperties.Stub_srcs) > 0 { // Add dependencies to the prebuilt stubs source library ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope)) } } } } } func (module *sdkLibraryImport) OutputFiles(tag string) (android.Paths, error) { return module.commonOutputFiles(tag) } func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Record the paths to the prebuilt stubs library. // Record the paths to the prebuilt stubs library and stubs source. ctx.VisitDirectDeps(func(to android.Module) { ctx.VisitDirectDeps(func(to android.Module) { tag := ctx.OtherModuleDependencyTag(to) tag := ctx.OtherModuleDependencyTag(to) if lib, ok := to.(Dependency); ok { // Extract information from any of the scope specific dependencies. if scopeTag, ok := tag.(scopeDependencyTag); ok { if scopeTag, ok := tag.(scopeDependencyTag); ok { apiScope := scopeTag.apiScope apiScope := scopeTag.apiScope scopePaths := module.getScopePaths(apiScope) scopePaths := module.getScopePathsCreateIfNeeded(apiScope) scopePaths.stubsHeaderPath = lib.HeaderJars() } // Extract information from the dependency. The exact information extracted // is determined by the nature of the dependency which is determined by the tag. scopeTag.extractDepInfo(ctx, to, scopePaths) } } }) }) } func (module *sdkLibraryImport) sdkJars( ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { // If a specific numeric version has been requested then use prebuilt versions of the sdk. // Populate the scope paths with information from the properties. if sdkVersion.version.isNumbered() { for apiScope, scopeProperties := range module.scopeProperties { return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion) if len(scopeProperties.Jars) == 0 { continue } } var apiScope *apiScope paths := module.getScopePathsCreateIfNeeded(apiScope) switch sdkVersion.kind { paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api) case sdkSystem: paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api) apiScope = apiScopeSystem } case sdkTest: apiScope = apiScopeTest default: apiScope = apiScopePublic } } paths := module.getScopePaths(apiScope) func (module *sdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { return paths.stubsHeaderPath return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion) } } // to satisfy SdkLibraryDependency interface // to satisfy SdkLibraryDependency interface Loading Loading @@ -1653,15 +1810,19 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Scopes = make(map[*apiScope]scopeProperties) s.Scopes = make(map[*apiScope]scopeProperties) for _, apiScope := range allApiScopes { for _, apiScope := range allApiScopes { paths := sdk.getScopePaths(apiScope) paths := sdk.findScopePaths(apiScope) if paths == nil { continue } jars := paths.stubsImplPath jars := paths.stubsImplPath if len(jars) > 0 { if len(jars) > 0 { properties := scopeProperties{} properties := scopeProperties{} properties.Jars = jars properties.Jars = jars properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope) properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope) properties.StubsSrcJar = paths.stubsSrcJar properties.StubsSrcJar = paths.stubsSrcJar.Path() properties.CurrentApiFile = paths.currentApiFilePath properties.CurrentApiFile = paths.currentApiFilePath.Path() properties.RemovedApiFile = paths.removedApiFilePath properties.RemovedApiFile = paths.removedApiFilePath.Path() s.Scopes[apiScope] = properties s.Scopes[apiScope] = properties } } } } Loading Loading
java/droiddoc.go +10 −1 Original line number Original line Diff line number Diff line Loading @@ -350,11 +350,16 @@ type ApiFilePath interface { ApiFilePath() android.Path ApiFilePath() android.Path } } type ApiStubsSrcProvider interface { StubsSrcJar() android.Path } // Provider of information about API stubs, used by java_sdk_library. // Provider of information about API stubs, used by java_sdk_library. type ApiStubsProvider interface { type ApiStubsProvider interface { ApiFilePath ApiFilePath RemovedApiFilePath() android.Path RemovedApiFilePath() android.Path StubsSrcJar() android.Path ApiStubsSrcProvider } } // // Loading Loading @@ -1912,6 +1917,10 @@ func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) { } } } } func (d *PrebuiltStubsSources) StubsSrcJar() android.Path { return d.stubsSrcJar } func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") Loading
java/java_test.go +147 −0 Original line number Original line Diff line number Diff line Loading @@ -575,6 +575,7 @@ func TestJavaSdkLibraryImport(t *testing.T) { }, }, test: { test: { jars: ["c.jar"], jars: ["c.jar"], stub_srcs: ["c.java"], }, }, } } `) `) Loading Loading @@ -1229,6 +1230,113 @@ func TestJavaSdkLibrary(t *testing.T) { } } } } func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) { testJava(t, ` java_sdk_library { name: "foo", srcs: ["a.java"], api_packages: ["foo"], public: { enabled: true, }, } java_library { name: "bar", srcs: ["b.java", ":foo{.public.stubs.source}"], } `) } func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) { testJavaError(t, `"foo" does not provide api scope system`, ` java_sdk_library { name: "foo", srcs: ["a.java"], api_packages: ["foo"], public: { enabled: true, }, } java_library { name: "bar", srcs: ["b.java", ":foo{.system.stubs.source}"], } `) } func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { testJava(t, ` java_sdk_library_import { name: "foo", public: { jars: ["a.jar"], stub_srcs: ["a.java"], current_api: "api/current.txt", removed_api: "api/removed.txt", }, } java_library { name: "bar", srcs: [":foo{.public.stubs.source}"], java_resources: [ ":foo{.public.api.txt}", ":foo{.public.removed-api.txt}", ], } `) } func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { bp := ` java_sdk_library_import { name: "foo", public: { jars: ["a.jar"], }, } ` t.Run("stubs.source", func(t *testing.T) { testJavaError(t, `stubs.source not available for api scope public`, bp+` java_library { name: "bar", srcs: [":foo{.public.stubs.source}"], java_resources: [ ":foo{.public.api.txt}", ":foo{.public.removed-api.txt}", ], } `) }) t.Run("api.txt", func(t *testing.T) { testJavaError(t, `api.txt not available for api scope public`, bp+` java_library { name: "bar", srcs: ["a.java"], java_resources: [ ":foo{.public.api.txt}", ], } `) }) t.Run("removed-api.txt", func(t *testing.T) { testJavaError(t, `removed-api.txt not available for api scope public`, bp+` java_library { name: "bar", srcs: ["a.java"], java_resources: [ ":foo{.public.removed-api.txt}", ], } `) }) } func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, ` testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, ` java_sdk_library { java_sdk_library { Loading Loading @@ -1261,6 +1369,45 @@ func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { `) `) } } func TestJavaSdkLibrary_MissingScope(t *testing.T) { testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, ` java_sdk_library { name: "foo", srcs: ["a.java"], public: { enabled: false, }, } java_library { name: "baz", srcs: ["a.java"], libs: ["foo"], sdk_version: "module_current", } `) } func TestJavaSdkLibrary_FallbackScope(t *testing.T) { testJava(t, ` java_sdk_library { name: "foo", srcs: ["a.java"], system: { enabled: true, }, } java_library { name: "baz", srcs: ["a.java"], libs: ["foo"], // foo does not have module-lib scope so it should fallback to system sdk_version: "module_current", } `) } var compilerFlagsTestCases = []struct { var compilerFlagsTestCases = []struct { in string in string out bool out bool Loading
java/sdk_library.go +236 −75 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ import ( "path" "path" "path/filepath" "path/filepath" "reflect" "reflect" "regexp" "sort" "sort" "strings" "strings" "sync" "sync" Loading Loading @@ -145,6 +146,8 @@ type apiScope struct { // Initialize a scope, creating and adding appropriate dependency tags // Initialize a scope, creating and adding appropriate dependency tags func initApiScope(scope *apiScope) *apiScope { func initApiScope(scope *apiScope) *apiScope { name := scope.name name := scope.name scopeByName[name] = scope allScopeNames = append(allScopeNames, name) scope.propertyName = strings.ReplaceAll(name, "-", "_") scope.propertyName = strings.ReplaceAll(name, "-", "_") scope.fieldName = proptools.FieldNameForProperty(scope.propertyName) scope.fieldName = proptools.FieldNameForProperty(scope.propertyName) scope.stubsTag = scopeDependencyTag{ scope.stubsTag = scopeDependencyTag{ Loading Loading @@ -217,6 +220,8 @@ func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string { } } var ( var ( scopeByName = make(map[string]*apiScope) allScopeNames []string apiScopePublic = initApiScope(&apiScope{ apiScopePublic = initApiScope(&apiScope{ name: "public", name: "public", Loading Loading @@ -433,12 +438,30 @@ type sdkLibraryProperties struct { //Html_doc *bool //Html_doc *bool } } // Paths to outputs from java_sdk_library and java_sdk_library_import. // // Fields that are android.Paths are always set (during GenerateAndroidBuildActions). // OptionalPaths are always set by java_sdk_library but may not be set by // java_sdk_library_import as not all instances provide that information. type scopePaths struct { type scopePaths struct { // The path (represented as Paths for convenience when returning) to the stubs header jar. // // That is the jar that is created by turbine. stubsHeaderPath android.Paths stubsHeaderPath android.Paths // The path (represented as Paths for convenience when returning) to the stubs implementation jar. // // This is not the implementation jar, it still only contains stubs. stubsImplPath android.Paths stubsImplPath android.Paths currentApiFilePath android.Path removedApiFilePath android.Path // The API specification file, e.g. system_current.txt. stubsSrcJar android.Path currentApiFilePath android.OptionalPath // The specification of API elements removed since the last release. removedApiFilePath android.OptionalPath // The stubs source jar. stubsSrcJar android.OptionalPath } } func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error { func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error { Loading @@ -460,9 +483,18 @@ func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action f } } } } func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider)) error { if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok { action(apiStubsProvider) return nil } else { return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs") } } func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) { func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) { paths.currentApiFilePath = provider.ApiFilePath() paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath()) paths.removedApiFilePath = provider.RemovedApiFilePath() paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath()) } } func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { Loading @@ -471,12 +503,12 @@ func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { }) }) } } func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsProvider) { func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider) { paths.stubsSrcJar = provider.StubsSrcJar() paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar()) } } func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error { func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error { return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) { return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) { paths.extractStubsSourceInfoFromApiStubsProviders(provider) paths.extractStubsSourceInfoFromApiStubsProviders(provider) }) }) } } Loading Loading @@ -551,7 +583,83 @@ func (c *commonToSdkLibraryAndImport) apiModuleName(apiScope *apiScope) string { return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName()) return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName()) } } func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths { // The component names for different outputs of the java_sdk_library. // // They are similar to the names used for the child modules it creates const ( stubsSourceComponentName = "stubs.source" apiTxtComponentName = "api.txt" removedApiTxtComponentName = "removed-api.txt" ) // A regular expression to match tags that reference a specific stubs component. // // It will only match if given a valid scope and a valid component. It is verfy strict // to ensure it does not accidentally match a similar looking tag that should be processed // by the embedded Library. var tagSplitter = func() *regexp.Regexp { // Given a list of literal string items returns a regular expression that will // match any one of the items. choice := func(items ...string) string { return `\Q` + strings.Join(items, `\E|\Q`) + `\E` } // Regular expression to match one of the scopes. scopesRegexp := choice(allScopeNames...) // Regular expression to match one of the components. componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName) // Regular expression to match any combination of one scope and one component. return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp)) }() // For OutputFileProducer interface // // .<scope>.stubs.source // .<scope>.api.txt // .<scope>.removed-api.txt func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) { if groups := tagSplitter.FindStringSubmatch(tag); groups != nil { scopeName := groups[1] component := groups[2] if scope, ok := scopeByName[scopeName]; ok { paths := c.findScopePaths(scope) if paths == nil { return nil, fmt.Errorf("%q does not provide api scope %s", c.moduleBase.BaseModuleName(), scopeName) } switch component { case stubsSourceComponentName: if paths.stubsSrcJar.Valid() { return android.Paths{paths.stubsSrcJar.Path()}, nil } case apiTxtComponentName: if paths.currentApiFilePath.Valid() { return android.Paths{paths.currentApiFilePath.Path()}, nil } case removedApiTxtComponentName: if paths.removedApiFilePath.Valid() { return android.Paths{paths.removedApiFilePath.Path()}, nil } } return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName) } else { return nil, fmt.Errorf("unknown scope %s in %s", scope, tag) } } else { return nil, nil } } func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths { if c.scopePaths == nil { if c.scopePaths == nil { c.scopePaths = make(map[*apiScope]*scopePaths) c.scopePaths = make(map[*apiScope]*scopePaths) } } Loading @@ -564,6 +672,62 @@ func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths return paths return paths } } func (c *commonToSdkLibraryAndImport) findScopePaths(scope *apiScope) *scopePaths { if c.scopePaths == nil { return nil } return c.scopePaths[scope] } // If this does not support the requested api scope then find the closest available // scope it does support. Returns nil if no such scope is available. func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *scopePaths { for s := scope; s != nil; s = s.extends { if paths := c.findScopePaths(s); paths != nil { return paths } } // This should never happen outside tests as public should be the base scope for every // scope and is enabled by default. return nil } func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { // If a specific numeric version has been requested then use prebuilt versions of the sdk. if sdkVersion.version.isNumbered() { return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion) } var apiScope *apiScope switch sdkVersion.kind { case sdkSystem: apiScope = apiScopeSystem case sdkModule: apiScope = apiScopeModuleLib case sdkTest: apiScope = apiScopeTest default: apiScope = apiScopePublic } paths := c.findClosestScopePath(apiScope) if paths == nil { var scopes []string for _, s := range allApiScopes { if c.findScopePaths(s) != nil { scopes = append(scopes, s.name) } } ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.moduleBase.BaseModuleName(), scopes) return nil } return paths.stubsHeaderPath } type SdkLibrary struct { type SdkLibrary struct { Library Library Loading Loading @@ -664,6 +828,15 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { module.Library.deps(ctx) module.Library.deps(ctx) } } func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) { paths, err := module.commonOutputFiles(tag) if paths == nil && err == nil { return module.Library.OutputFiles(tag) } else { return paths, err } } func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Don't build an implementation library if this is api only. // Don't build an implementation library if this is api only. if !proptools.Bool(module.sdkLibraryProperties.Api_only) { if !proptools.Bool(module.sdkLibraryProperties.Api_only) { Loading @@ -679,7 +852,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Extract information from any of the scope specific dependencies. // Extract information from any of the scope specific dependencies. if scopeTag, ok := tag.(scopeDependencyTag); ok { if scopeTag, ok := tag.(scopeDependencyTag); ok { apiScope := scopeTag.apiScope apiScope := scopeTag.apiScope scopePaths := module.getScopePaths(apiScope) scopePaths := module.getScopePathsCreateIfNeeded(apiScope) // Extract information from the dependency. The exact information extracted // Extract information from the dependency. The exact information extracted // is determined by the nature of the dependency which is determined by the tag. // is determined by the nature of the dependency which is determined by the tag. Loading Loading @@ -1012,41 +1185,20 @@ func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) and return android.Paths{jarPath.Path()} return android.Paths{jarPath.Path()} } } func (module *SdkLibrary) sdkJars( func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { // If a specific numeric version has been requested then use prebuilt versions of the sdk. // Check any special cases for java_sdk_library. if sdkVersion.version.isNumbered() { return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion) } else { if !sdkVersion.specified() { if !sdkVersion.specified() { if headerJars { if headerJars { return module.HeaderJars() return module.HeaderJars() } else { } else { return module.ImplementationJars() return module.ImplementationJars() } } } } else if sdkVersion.kind == sdkPrivate { var apiScope *apiScope switch sdkVersion.kind { case sdkSystem: apiScope = apiScopeSystem case sdkTest: apiScope = apiScopeTest case sdkPrivate: return module.HeaderJars() return module.HeaderJars() default: apiScope = apiScopePublic } } paths := module.getScopePaths(apiScope) return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion) if headerJars { return paths.stubsHeaderPath } else { return paths.stubsImplPath } } } } // to satisfy SdkLibraryDependency interface // to satisfy SdkLibraryDependency interface Loading Loading @@ -1277,10 +1429,10 @@ type sdkLibraryScopeProperties struct { Stub_srcs []string `android:"path"` Stub_srcs []string `android:"path"` // The current.txt // The current.txt Current_api string `android:"path"` Current_api *string `android:"path"` // The removed.txt // The removed.txt Removed_api string `android:"path"` Removed_api *string `android:"path"` } } type sdkLibraryImportProperties struct { type sdkLibraryImportProperties struct { Loading Loading @@ -1390,8 +1542,10 @@ func (module *sdkLibraryImport) createInternalModules(mctx android.DefaultableHo module.createJavaImportForStubs(mctx, apiScope, scopeProperties) module.createJavaImportForStubs(mctx, apiScope, scopeProperties) if len(scopeProperties.Stub_srcs) > 0 { module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties) module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties) } } } javaSdkLibraries := javaSdkLibraries(mctx.Config()) javaSdkLibraries := javaSdkLibraries(mctx.Config()) javaSdkLibrariesLock.Lock() javaSdkLibrariesLock.Lock() Loading Loading @@ -1442,45 +1596,48 @@ func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) // Add dependencies to the prebuilt stubs library // Add dependencies to the prebuilt stubs library ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope)) ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope)) if len(scopeProperties.Stub_srcs) > 0 { // Add dependencies to the prebuilt stubs source library ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope)) } } } } } func (module *sdkLibraryImport) OutputFiles(tag string) (android.Paths, error) { return module.commonOutputFiles(tag) } func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Record the paths to the prebuilt stubs library. // Record the paths to the prebuilt stubs library and stubs source. ctx.VisitDirectDeps(func(to android.Module) { ctx.VisitDirectDeps(func(to android.Module) { tag := ctx.OtherModuleDependencyTag(to) tag := ctx.OtherModuleDependencyTag(to) if lib, ok := to.(Dependency); ok { // Extract information from any of the scope specific dependencies. if scopeTag, ok := tag.(scopeDependencyTag); ok { if scopeTag, ok := tag.(scopeDependencyTag); ok { apiScope := scopeTag.apiScope apiScope := scopeTag.apiScope scopePaths := module.getScopePaths(apiScope) scopePaths := module.getScopePathsCreateIfNeeded(apiScope) scopePaths.stubsHeaderPath = lib.HeaderJars() } // Extract information from the dependency. The exact information extracted // is determined by the nature of the dependency which is determined by the tag. scopeTag.extractDepInfo(ctx, to, scopePaths) } } }) }) } func (module *sdkLibraryImport) sdkJars( ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { // If a specific numeric version has been requested then use prebuilt versions of the sdk. // Populate the scope paths with information from the properties. if sdkVersion.version.isNumbered() { for apiScope, scopeProperties := range module.scopeProperties { return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion) if len(scopeProperties.Jars) == 0 { continue } } var apiScope *apiScope paths := module.getScopePathsCreateIfNeeded(apiScope) switch sdkVersion.kind { paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api) case sdkSystem: paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api) apiScope = apiScopeSystem } case sdkTest: apiScope = apiScopeTest default: apiScope = apiScopePublic } } paths := module.getScopePaths(apiScope) func (module *sdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { return paths.stubsHeaderPath return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion) } } // to satisfy SdkLibraryDependency interface // to satisfy SdkLibraryDependency interface Loading Loading @@ -1653,15 +1810,19 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Scopes = make(map[*apiScope]scopeProperties) s.Scopes = make(map[*apiScope]scopeProperties) for _, apiScope := range allApiScopes { for _, apiScope := range allApiScopes { paths := sdk.getScopePaths(apiScope) paths := sdk.findScopePaths(apiScope) if paths == nil { continue } jars := paths.stubsImplPath jars := paths.stubsImplPath if len(jars) > 0 { if len(jars) > 0 { properties := scopeProperties{} properties := scopeProperties{} properties.Jars = jars properties.Jars = jars properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope) properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope) properties.StubsSrcJar = paths.stubsSrcJar properties.StubsSrcJar = paths.stubsSrcJar.Path() properties.CurrentApiFile = paths.currentApiFilePath properties.CurrentApiFile = paths.currentApiFilePath.Path() properties.RemovedApiFile = paths.removedApiFilePath properties.RemovedApiFile = paths.removedApiFilePath.Path() s.Scopes[apiScope] = properties s.Scopes[apiScope] = properties } } } } Loading