| // Copyright 2024 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package java |
| |
| import ( |
| "android/soong/android" |
| "android/soong/etc" |
| "fmt" |
| "path" |
| "strings" |
| |
| "github.com/google/blueprint/proptools" |
| ) |
| |
| // --------------------------------------------------------------------------------------------- |
| // Naming scheme of the submodules generated by java_sdk_library and java_sdk_library_import |
| // --------------------------------------------------------------------------------------------- |
| |
| const ( |
| sdkXmlFileSuffix = ".xml" |
| implLibSuffix = ".impl" |
| ) |
| |
| func implLibraryModuleName(sdkLibName string) string { |
| return sdkLibName + implLibSuffix |
| } |
| |
| // Module name of the runtime implementation library |
| func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string { |
| return implLibraryModuleName(c.module.RootLibraryName()) |
| } |
| |
| // Module name of the XML file for the lib |
| func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string { |
| return c.module.RootLibraryName() + sdkXmlFileSuffix |
| } |
| |
| // Name of the java_library module that compiles the stubs source. |
| func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string { |
| baseName := c.module.RootLibraryName() |
| return apiScope.stubsLibraryModuleName(baseName) |
| } |
| |
| // Name of the java_library module that compiles the exportable stubs source. |
| func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string { |
| baseName := c.module.RootLibraryName() |
| return apiScope.exportableStubsLibraryModuleName(baseName) |
| } |
| |
| // Name of the droidstubs module that generates the stubs source and may also |
| // generate/check the API. |
| func (c *commonToSdkLibraryAndImport) droidstubsModuleName(apiScope *apiScope) string { |
| baseName := c.module.RootLibraryName() |
| return apiScope.stubsSourceModuleName(baseName) |
| } |
| |
| // Name of the java_api_library module that generates the from-text stubs source |
| // and compiles to a jar file. |
| func (c *commonToSdkLibraryAndImport) fromTextStubsLibraryModuleName(apiScope *apiScope) string { |
| baseName := c.module.RootLibraryName() |
| return apiScope.apiLibraryModuleName(baseName) |
| } |
| |
| // Name of the java_library module that compiles the stubs |
| // generated from source Java files. |
| func (c *commonToSdkLibraryAndImport) fromSourceStubsLibraryModuleName(apiScope *apiScope) string { |
| baseName := c.module.RootLibraryName() |
| return apiScope.sourceStubsLibraryModuleName(baseName) |
| } |
| |
| // Name of the java_library module that compiles the exportable stubs |
| // generated from source Java files. |
| func (c *commonToSdkLibraryAndImport) exportableFromSourceStubsLibraryModuleName(apiScope *apiScope) string { |
| baseName := c.module.RootLibraryName() |
| return apiScope.exportableSourceStubsLibraryModuleName(baseName) |
| } |
| |
| // --------------------------------------------------------------------------------------------- |
| // Build rules of the submodules generated by java_sdk_library. |
| // java_sdk_library "framework-foo" generates the following submodules: |
| // |
| // - "framework-foo.impl" (type: [Library]): the implementation library, which generates the |
| // compilation outputs that include the implementation details and the private apis |
| // (i.e. class/methods that are annotated @hide). |
| // |
| // - "framework-foo.stubs.source.<[apiScope.name]>" (type: [Droidstubs]): droidstubs module that |
| // generates the stubs and the api files for the given api scope. |
| // |
| // - "framework-foo.stubs.<[apiScope.name]>" (type: [Library]): stub library module that |
| // provides the compilation output of the stubs to the reverse dependencies. The module |
| // itself does not perform any compilation actions; the module statically depends on one of |
| // the from-source stub module or the from-text stub configuration based on the build |
| // configuration. |
| // |
| // - "framework-foo.stubs.<[apiScope.name]>.from-source" (type: [Library]): stub library module |
| // that compiles the stubs generated by the droidstubs submodule. This module is a static |
| // dependency of the stub library module when |
| // [android/soong/android/config.BuildFromTextStub()] is false. |
| // |
| // - "framework-foo.stubs.<[apiScope.name]>.from-text" (type: [ApiLibrary]): api library module |
| // that generates and compiles the stubs from the api files checked in the tree instead of |
| // the source Java files (e.g. *-current.txt files). This module is a static dependency of |
| // the stub library module when [android/soong/android/config.BuildFromTextStub()] is true. |
| // |
| // - "framework-foo.stubs.exportable.<[apiScope.name]>" (type: [Library]): stub library module |
| // that provides the "exportable" stubs. "exportable" stubs are the stubs that do not |
| // include in-development flagged apis. This module is only used for SDK builds to generate |
| // the SDK artifacts, and not purposed for consumption for other modules. |
| // |
| // - "framework-foo.stubs.exportable.<[apiScope.name]>.from-source" (type: [Library]): stub |
| // library module that compiles the "exportable" stubs generated by the droidstubs |
| // submodule. This module is always a static dependency of the "exportable" stub library |
| // module given that from-text stubs cannot be used for SDK builds as it does not contain |
| // documentations. |
| // |
| // - "framework-foo.xml" (type: [sdkLibraryXml]): xml library that generates the permission xml |
| // file, which allows [SdkLibrary] to be used with <uses-permission> tag in the |
| // AndroidManifest.xml files. |
| // --------------------------------------------------------------------------------------------- |
| |
| // Creates the implementation [Library] with ".impl" suffix. |
| func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) { |
| visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility) |
| |
| staticLibs := module.properties.Static_libs.Clone() |
| staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs) |
| props := struct { |
| Name *string |
| Enabled proptools.Configurable[bool] |
| Visibility []string |
| Libs []string |
| Static_libs proptools.Configurable[[]string] |
| Apex_available []string |
| Stem *string |
| }{ |
| Name: proptools.StringPtr(module.implLibraryModuleName()), |
| Enabled: module.EnabledProperty(), |
| Visibility: visibility, |
| |
| Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...), |
| |
| Static_libs: staticLibs, |
| // Pass the apex_available settings down so that the impl library can be statically |
| // embedded within a library that is added to an APEX. Needed for updatable-media. |
| Apex_available: module.ApexAvailable(), |
| |
| Stem: proptools.StringPtr(module.Name()), |
| } |
| |
| properties := []interface{}{ |
| &module.properties, |
| &module.protoProperties, |
| &module.deviceProperties, |
| &module.dexProperties, |
| &module.dexpreoptProperties, |
| &module.linter.properties, |
| &module.overridableProperties, |
| &props, |
| module.sdkComponentPropertiesForChildLibrary(), |
| } |
| mctx.CreateModule(LibraryFactory, properties...) |
| } |
| |
| // Creates the [Droidstubs] module with ".stubs.source.<[apiScope.name]>" that creates stubs |
| // source files from the given full source files and also updates and checks the API |
| // specification files (i.e. "*-current.txt", "*-removed.txt" files). |
| func (module *SdkLibrary) createDroidstubs(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) { |
| props := struct { |
| Name *string |
| Enabled proptools.Configurable[bool] |
| Visibility []string |
| Srcs []string |
| Installable *bool |
| Sdk_version *string |
| Api_surface *string |
| System_modules *string |
| Libs proptools.Configurable[[]string] |
| Output_javadoc_comments *bool |
| Arg_files []string |
| Args *string |
| Java_version *string |
| Annotations_enabled *bool |
| Merge_annotations_dirs []string |
| Merge_inclusion_annotations_dirs []string |
| Generate_stubs *bool |
| Previous_api *string |
| Aconfig_declarations []string |
| Check_api struct { |
| Current ApiToCheck |
| Last_released ApiToCheck |
| |
| Api_lint struct { |
| Enabled *bool |
| New_since *string |
| Baseline_file *string |
| } |
| } |
| Aidl struct { |
| Include_dirs []string |
| Local_include_dirs []string |
| } |
| Dists []android.Dist |
| }{} |
| |
| // The stubs source processing uses the same compile time classpath when extracting the |
| // API from the implementation library as it does when compiling it. i.e. the same |
| // * sdk version |
| // * system_modules |
| // * libs (static_libs/libs) |
| |
| props.Name = proptools.StringPtr(name) |
| props.Enabled = module.EnabledProperty() |
| props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility) |
| props.Srcs = append(props.Srcs, module.properties.Srcs...) |
| props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...) |
| props.Sdk_version = module.deviceProperties.Sdk_version |
| props.Api_surface = &apiScope.name |
| props.System_modules = module.deviceProperties.System_modules |
| props.Installable = proptools.BoolPtr(false) |
| // A droiddoc module has only one Libs property and doesn't distinguish between |
| // shared libs and static libs. So we need to add both of these libs to Libs property. |
| props.Libs = proptools.NewConfigurable[[]string](nil, nil) |
| props.Libs.AppendSimpleValue(module.properties.Libs) |
| props.Libs.Append(module.properties.Static_libs) |
| props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) |
| props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) |
| props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs |
| props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs |
| props.Java_version = module.properties.Java_version |
| |
| props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled |
| props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs |
| props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs |
| props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations |
| |
| droidstubsArgs := []string{} |
| if len(module.sdkLibraryProperties.Api_packages) != 0 { |
| droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":")) |
| } |
| droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...) |
| disabledWarnings := []string{"HiddenSuperclass"} |
| if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) { |
| disabledWarnings = append(disabledWarnings, |
| "BroadcastBehavior", |
| "DeprecationMismatch", |
| "MissingPermission", |
| "SdkConstant", |
| "Todo", |
| ) |
| } |
| droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) |
| |
| // Output Javadoc comments for public scope. |
| if apiScope == apiScopePublic { |
| props.Output_javadoc_comments = proptools.BoolPtr(true) |
| } |
| |
| // Add in scope specific arguments. |
| droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...) |
| props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files |
| props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " ")) |
| |
| // List of APIs identified from the provided source files are created. They are later |
| // compared against to the not-yet-released (a.k.a current) list of APIs and to the |
| // last-released (a.k.a numbered) list of API. |
| currentApiFileName := apiScope.apiFilePrefix + "current.txt" |
| removedApiFileName := apiScope.apiFilePrefix + "removed.txt" |
| apiDir := module.getApiDir() |
| currentApiFileName = path.Join(apiDir, currentApiFileName) |
| removedApiFileName = path.Join(apiDir, removedApiFileName) |
| |
| // check against the not-yet-release API |
| props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) |
| props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) |
| |
| if module.compareAgainstLatestApi(apiScope) { |
| // check against the latest released API |
| latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) |
| props.Previous_api = latestApiFilegroupName |
| props.Check_api.Last_released.Api_file = latestApiFilegroupName |
| props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( |
| module.latestRemovedApiFilegroupName(apiScope)) |
| props.Check_api.Last_released.Baseline_file = proptools.StringPtr( |
| module.latestIncompatibilitiesFilegroupName(apiScope)) |
| |
| if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) { |
| // Enable api lint. |
| props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true) |
| props.Check_api.Api_lint.New_since = latestApiFilegroupName |
| |
| // If it exists then pass a lint-baseline.txt through to droidstubs. |
| baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt") |
| baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath) |
| paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil) |
| if err != nil { |
| mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err) |
| } |
| if len(paths) == 1 { |
| props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath) |
| } else if len(paths) != 0 { |
| mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths) |
| } |
| } |
| } |
| |
| if !Bool(module.sdkLibraryProperties.No_dist) { |
| // Dist the api txt and removed api txt artifacts for sdk builds. |
| distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api")) |
| stubsTypeTagPrefix := "" |
| if mctx.Config().ReleaseHiddenApiExportableStubs() { |
| stubsTypeTagPrefix = ".exportable" |
| } |
| for _, p := range []struct { |
| tag string |
| pattern string |
| }{ |
| // "exportable" api files are copied to the dist directory instead of the |
| // "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag |
| // is set. Otherwise, the "everything" api files are copied to the dist directory. |
| {tag: "%s.api.txt", pattern: "%s.txt"}, |
| {tag: "%s.removed-api.txt", pattern: "%s-removed.txt"}, |
| } { |
| props.Dists = append(props.Dists, android.Dist{ |
| Targets: []string{"sdk", "win_sdk"}, |
| Dir: distDir, |
| Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())), |
| Tag: proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)), |
| }) |
| } |
| } |
| |
| mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx) |
| } |
| |
| type libraryProperties struct { |
| Name *string |
| Enabled proptools.Configurable[bool] |
| Visibility []string |
| Srcs []string |
| Installable *bool |
| Sdk_version *string |
| System_modules *string |
| Patch_module *string |
| Libs []string |
| Static_libs []string |
| Compile_dex *bool |
| Java_version *string |
| Openjdk9 struct { |
| Srcs []string |
| Javacflags []string |
| } |
| Dist struct { |
| Targets []string |
| Dest *string |
| Dir *string |
| Tag *string |
| } |
| Is_stubs_module *bool |
| Stub_contributing_api *string |
| } |
| |
| func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties { |
| props := libraryProperties{} |
| props.Enabled = module.EnabledProperty() |
| props.Visibility = []string{"//visibility:override", "//visibility:private"} |
| // sources are generated from the droiddoc |
| sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) |
| props.Sdk_version = proptools.StringPtr(sdkVersion) |
| props.System_modules = module.deviceProperties.System_modules |
| props.Patch_module = module.properties.Patch_module |
| props.Installable = proptools.BoolPtr(false) |
| props.Libs = module.sdkLibraryProperties.Stub_only_libs |
| props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...) |
| props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs |
| // The stub-annotations library contains special versions of the annotations |
| // with CLASS retention policy, so that they're kept. |
| if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { |
| props.Libs = append(props.Libs, "stub-annotations") |
| } |
| props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs |
| props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags |
| // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential |
| // interop with older developer tools that don't support 1.9. |
| props.Java_version = proptools.StringPtr("1.8") |
| props.Is_stubs_module = proptools.BoolPtr(true) |
| props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) |
| |
| return props |
| } |
| |
| // Creates the from-source stub [Library] with ".stubs.<[apiScope.name]>.from-source" suffix. |
| func (module *SdkLibrary) createFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { |
| |
| props := module.stubsLibraryProps(mctx, apiScope) |
| props.Name = proptools.StringPtr(module.fromSourceStubsLibraryModuleName(apiScope)) |
| props.Srcs = []string{":" + module.droidstubsModuleName(apiScope)} |
| |
| mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| // Creates the "exportable" from-source stub [Library] with |
| // ".stubs.exportable.<[apiScope.name]>" suffix. |
| func (module *SdkLibrary) createExportableFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { |
| props := module.stubsLibraryProps(mctx, apiScope) |
| props.Name = proptools.StringPtr(module.exportableFromSourceStubsLibraryModuleName(apiScope)) |
| props.Srcs = []string{":" + module.droidstubsModuleName(apiScope) + "{.exportable}"} |
| |
| mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| // Creates the from-text stub [ApiLibrary] with ".stubs.<[apiScope.name]>.from-text" suffix. |
| func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { |
| props := struct { |
| Name *string |
| Enabled proptools.Configurable[bool] |
| Visibility []string |
| Api_contributions []string |
| Libs proptools.Configurable[[]string] |
| Static_libs []string |
| System_modules *string |
| Enable_validation *bool |
| Stubs_type *string |
| Sdk_version *string |
| Previous_api *string |
| }{} |
| |
| props.Name = proptools.StringPtr(module.fromTextStubsLibraryModuleName(apiScope)) |
| props.Enabled = module.EnabledProperty() |
| props.Visibility = []string{"//visibility:override", "//visibility:private"} |
| |
| apiContributions := []string{} |
| |
| // Api surfaces are not independent of each other, but have subset relationships, |
| // and so does the api files. To generate from-text stubs for api surfaces other than public, |
| // all subset api domains' api_contriubtions must be added as well. |
| scope := apiScope |
| for scope != nil { |
| apiContributions = append(apiContributions, module.droidstubsModuleName(scope)+".api.contribution") |
| scope = scope.extends |
| } |
| if apiScope == apiScopePublic { |
| additionalApiContribution := module.apiLibraryAdditionalApiContribution() |
| if additionalApiContribution != "" { |
| apiContributions = append(apiContributions, additionalApiContribution) |
| } |
| } |
| |
| props.Api_contributions = apiContributions |
| |
| // Ensure that stub-annotations is added to the classpath before any other libs |
| props.Libs = proptools.NewConfigurable[[]string](nil, nil) |
| props.Libs.AppendSimpleValue([]string{"stub-annotations"}) |
| props.Libs.AppendSimpleValue(module.properties.Libs) |
| props.Libs.Append(module.properties.Static_libs) |
| props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) |
| props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) |
| props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs |
| |
| props.System_modules = module.deviceProperties.System_modules |
| props.Enable_validation = proptools.BoolPtr(true) |
| props.Stubs_type = proptools.StringPtr("everything") |
| |
| if module.deviceProperties.Sdk_version != nil { |
| props.Sdk_version = module.deviceProperties.Sdk_version |
| } |
| |
| if module.compareAgainstLatestApi(apiScope) { |
| // check against the latest released API |
| latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) |
| props.Previous_api = latestApiFilegroupName |
| } |
| |
| mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties { |
| props := libraryProperties{} |
| |
| props.Enabled = module.EnabledProperty() |
| props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) |
| sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) |
| props.Sdk_version = proptools.StringPtr(sdkVersion) |
| |
| props.System_modules = module.deviceProperties.System_modules |
| |
| // The imports need to be compiled to dex if the java_sdk_library requests it. |
| compileDex := module.dexProperties.Compile_dex |
| if module.stubLibrariesCompiledForDex() { |
| compileDex = proptools.BoolPtr(true) |
| } |
| props.Compile_dex = compileDex |
| |
| props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) |
| |
| if !Bool(module.sdkLibraryProperties.No_dist) && doDist { |
| 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") |
| } |
| props.Is_stubs_module = proptools.BoolPtr(true) |
| |
| return props |
| } |
| |
| // Creates the stub [Library] with ".stubs.<[apiScope.name]>" suffix. |
| func (module *SdkLibrary) createTopLevelStubsLibrary( |
| mctx android.DefaultableHookContext, apiScope *apiScope) { |
| |
| // Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false |
| doDist := !mctx.Config().ReleaseHiddenApiExportableStubs() |
| props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) |
| 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.fromSourceStubsLibraryModuleName(apiScope) |
| if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() { |
| staticLib = module.fromTextStubsLibraryModuleName(apiScope) |
| } |
| props.Static_libs = append(props.Static_libs, staticLib) |
| |
| mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| // Creates the "exportable" stub [Library] with ".stubs.exportable.<[apiScope.name]>" suffix. |
| func (module *SdkLibrary) createTopLevelExportableStubsLibrary( |
| mctx android.DefaultableHookContext, apiScope *apiScope) { |
| |
| // Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true |
| doDist := mctx.Config().ReleaseHiddenApiExportableStubs() |
| props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) |
| props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope)) |
| |
| staticLib := module.exportableFromSourceStubsLibraryModuleName(apiScope) |
| props.Static_libs = append(props.Static_libs, staticLib) |
| |
| mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| // Creates the [sdkLibraryXml] with ".xml" suffix. |
| func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { |
| moduleMinApiLevel := module.Library.MinSdkVersion(mctx) |
| var moduleMinApiLevelStr = moduleMinApiLevel.String() |
| if moduleMinApiLevel == android.NoneApiLevel { |
| moduleMinApiLevelStr = "current" |
| } |
| props := struct { |
| Name *string |
| Enabled proptools.Configurable[bool] |
| Lib_name *string |
| Apex_available []string |
| On_bootclasspath_since *string |
| On_bootclasspath_before *string |
| Min_device_sdk *string |
| Max_device_sdk *string |
| Sdk_library_min_api_level *string |
| Uses_libs_dependencies []string |
| }{ |
| Name: proptools.StringPtr(module.xmlPermissionsModuleName()), |
| Enabled: module.EnabledProperty(), |
| Lib_name: proptools.StringPtr(module.BaseModuleName()), |
| Apex_available: module.ApexProperties.Apex_available, |
| On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since, |
| On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before, |
| Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk, |
| Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk, |
| Sdk_library_min_api_level: &moduleMinApiLevelStr, |
| Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs, |
| } |
| |
| mctx.CreateModule(sdkLibraryXmlFactory, &props) |
| } |
| |
| // --------------------------------------------------------------------------------------------- |
| // Build rules of the submodules generated by java_sdk_library_import. |
| // Note that the java_sdk_library_import module does not generate the implementation library. |
| // Instead, it will create a dependency to the source implemenetation library if one exists. |
| // java_sdk_library_import "framework-foo" generates the following submodules: |
| // |
| // - "framework-foo.stubs.<[apiScope.name]>" (type: [Import]): prebuilt stub library module that |
| // provides the stub jar file checked in the tree. |
| // |
| // - "framework-foo.stubs.source.<[apiScope.name]>" (type: [PrebuiltStubsSources]): prebuilt |
| // droidstubs module that provides the stub source jar file checked in the tree. |
| // |
| // - "framework-foo.stubs.source.<[apiScope.name]>.api.contribution" |
| // (type [JavaApiContributionImport]): prebuilt java_api_contribution module that provides |
| // the prebuilt api file for previously released from-text stub generation. |
| // --------------------------------------------------------------------------------------------- |
| |
| // Creates the prebuilt stub [Import] with ".stubs.<[apiScope.name]>" suffix. |
| func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { |
| // Creates a java import for the jar with ".stubs" suffix |
| props := struct { |
| Name *string |
| Source_module_name *string |
| Created_by_java_sdk_library_name *string |
| Sdk_version *string |
| Libs []string |
| Jars []string |
| Compile_dex *bool |
| Is_stubs_module *bool |
| |
| android.UserSuppliedPrebuiltProperties |
| }{} |
| props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) |
| props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName())) |
| props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) |
| props.Sdk_version = scopeProperties.Sdk_version |
| // Prepend any of the libs from the legacy public properties to the libs for each of the |
| // scopes to avoid having to duplicate them in each scope. |
| props.Libs = append(module.properties.Libs, scopeProperties.Libs...) |
| props.Jars = scopeProperties.Jars |
| |
| // The imports are preferred if the java_sdk_library_import is preferred. |
| props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) |
| |
| // The imports need to be compiled to dex if the java_sdk_library_import requests it. |
| compileDex := module.properties.Compile_dex |
| if module.stubLibrariesCompiledForDex() { |
| compileDex = proptools.BoolPtr(true) |
| } |
| props.Compile_dex = compileDex |
| props.Is_stubs_module = proptools.BoolPtr(true) |
| |
| mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { |
| props := struct { |
| Name *string |
| Source_module_name *string |
| Created_by_java_sdk_library_name *string |
| Srcs []string |
| |
| android.UserSuppliedPrebuiltProperties |
| }{} |
| props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope)) |
| props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName())) |
| props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) |
| props.Srcs = scopeProperties.Stub_srcs |
| |
| // The stubs source is preferred if the java_sdk_library_import is preferred. |
| props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) |
| |
| mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| // Creates the prebuilt api contribution [JavaApiContributionImport] with |
| // ".stubs.source.<[apiScope.name]>.api.contribution" suffix. |
| func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { |
| api_file := scopeProperties.Current_api |
| api_surface := &apiScope.name |
| |
| props := struct { |
| Name *string |
| Source_module_name *string |
| Created_by_java_sdk_library_name *string |
| Api_surface *string |
| Api_file *string |
| Visibility []string |
| }{} |
| |
| props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope) + ".api.contribution") |
| props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution") |
| props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) |
| props.Api_surface = api_surface |
| props.Api_file = api_file |
| props.Visibility = []string{"//visibility:override", "//visibility:public"} |
| |
| mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) |
| } |
| |
| // --------------------------------------------------------------------------------------------- |
| // End of the build rules of the submodules generated by java_sdk_library_import. |
| // --------------------------------------------------------------------------------------------- |
| |
| // Definition of the [sdkLibraryXml] module. The module generates the permissions xml file, |
| // so that the apps can specify the java_sdk_library using <uses-permission> tag in the |
| // AndroidManifest.xml file. |
| type sdkLibraryXml struct { |
| android.ModuleBase |
| android.DefaultableModuleBase |
| android.ApexModuleBase |
| |
| properties sdkLibraryXmlProperties |
| |
| outputFilePath android.OutputPath |
| installDirPath android.InstallPath |
| |
| hideApexVariantFromMake bool |
| } |
| |
| type sdkLibraryXmlProperties struct { |
| // canonical name of the lib |
| Lib_name *string |
| |
| // Signals that this shared library is part of the bootclasspath starting |
| // on the version indicated in this attribute. |
| // |
| // This will make platforms at this level and above to ignore |
| // <uses-library> tags with this library name because the library is already |
| // available |
| On_bootclasspath_since *string |
| |
| // Signals that this shared library was part of the bootclasspath before |
| // (but not including) the version indicated in this attribute. |
| // |
| // The system will automatically add a <uses-library> tag with this library to |
| // apps that target any SDK less than the version indicated in this attribute. |
| On_bootclasspath_before *string |
| |
| // Indicates that PackageManager should ignore this shared library if the |
| // platform is below the version indicated in this attribute. |
| // |
| // This means that the device won't recognise this library as installed. |
| Min_device_sdk *string |
| |
| // Indicates that PackageManager should ignore this shared library if the |
| // platform is above the version indicated in this attribute. |
| // |
| // This means that the device won't recognise this library as installed. |
| Max_device_sdk *string |
| |
| // The SdkLibrary's min api level as a string |
| // |
| // This value comes from the ApiLevel of the MinSdkVersion property. |
| Sdk_library_min_api_level *string |
| |
| // Uses-libs dependencies that the shared library requires to work correctly. |
| // |
| // This will add dependency="foo:bar" to the <library> section. |
| Uses_libs_dependencies []string |
| } |
| |
| // java_sdk_library_xml builds the permission xml file for a java_sdk_library. |
| // Not to be used directly by users. java_sdk_library internally uses this. |
| func sdkLibraryXmlFactory() android.Module { |
| module := &sdkLibraryXml{} |
| |
| module.AddProperties(&module.properties) |
| |
| android.InitApexModule(module) |
| android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) |
| |
| return module |
| } |
| |
| func (module *sdkLibraryXml) UniqueApexVariations() bool { |
| // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the |
| // mounted APEX, which contains the name of the APEX. |
| return true |
| } |
| |
| // from android.PrebuiltEtcModule |
| func (module *sdkLibraryXml) BaseDir() string { |
| return "etc" |
| } |
| |
| // from android.PrebuiltEtcModule |
| func (module *sdkLibraryXml) SubDir() string { |
| return "permissions" |
| } |
| |
| var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil) |
| |
| // from android.ApexModule |
| func (module *sdkLibraryXml) AvailableFor(what string) bool { |
| return true |
| } |
| |
| func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { |
| // do nothing |
| } |
| |
| var _ android.ApexModule = (*sdkLibraryXml)(nil) |
| |
| // Implements android.ApexModule |
| func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, |
| sdkVersion android.ApiLevel) error { |
| // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked |
| return nil |
| } |
| |
| // File path to the runtime implementation library |
| func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string { |
| implName := proptools.String(module.properties.Lib_name) |
| if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() { |
| // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name. |
| // In most cases, this works fine. But when apex_name is set or override_apex is used |
| // this can be wrong. |
| return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.BaseApexName, implName) |
| } |
| partition := "system" |
| if module.SocSpecific() { |
| partition = "vendor" |
| } else if module.DeviceSpecific() { |
| partition = "odm" |
| } else if module.ProductSpecific() { |
| partition = "product" |
| } else if module.SystemExtSpecific() { |
| partition = "system_ext" |
| } |
| return "/" + partition + "/framework/" + implName + ".jar" |
| } |
| |
| func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string { |
| if value == nil { |
| return "" |
| } |
| apiLevel, err := android.ApiLevelFromUser(ctx, *value) |
| if err != nil { |
| // attributes in bp files have underscores but in the xml have dashes. |
| ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error()) |
| return "" |
| } |
| if apiLevel.IsCurrent() { |
| // passing "current" would always mean a future release, never the current (or the current in |
| // progress) which means some conditions would never be triggered. |
| ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), |
| `"current" is not an allowed value for this attribute`) |
| return "" |
| } |
| // "safeValue" is safe because it translates finalized codenames to a string |
| // with their SDK int. |
| safeValue := apiLevel.String() |
| return formattedOptionalAttribute(attrName, &safeValue) |
| } |
| |
| // formats an attribute for the xml permissions file if the value is not null |
| // returns empty string otherwise |
| func formattedOptionalAttribute(attrName string, value *string) string { |
| if value == nil { |
| return "" |
| } |
| return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value) |
| } |
| |
| func formattedDependenciesAttribute(dependencies []string) string { |
| if dependencies == nil { |
| return "" |
| } |
| return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":")) |
| } |
| |
| func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string { |
| libName := proptools.String(module.properties.Lib_name) |
| libNameAttr := formattedOptionalAttribute("name", &libName) |
| filePath := module.implPath(ctx) |
| filePathAttr := formattedOptionalAttribute("file", &filePath) |
| implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since) |
| implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before) |
| minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk) |
| maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk) |
| dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies) |
| // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that). |
| // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T |
| var libraryTag string |
| if module.properties.Min_device_sdk != nil { |
| libraryTag = " <apex-library\n" |
| } else { |
| libraryTag = " <library\n" |
| } |
| |
| return strings.Join([]string{ |
| "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", |
| "<!-- Copyright (C) 2018 The Android Open Source Project\n", |
| "\n", |
| " Licensed under the Apache License, Version 2.0 (the \"License\");\n", |
| " you may not use this file except in compliance with the License.\n", |
| " You may obtain a copy of the License at\n", |
| "\n", |
| " http://www.apache.org/licenses/LICENSE-2.0\n", |
| "\n", |
| " Unless required by applicable law or agreed to in writing, software\n", |
| " distributed under the License is distributed on an \"AS IS\" BASIS,\n", |
| " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", |
| " See the License for the specific language governing permissions and\n", |
| " limitations under the License.\n", |
| "-->\n", |
| "<permissions>\n", |
| libraryTag, |
| libNameAttr, |
| filePathAttr, |
| implicitFromAttr, |
| implicitUntilAttr, |
| minSdkAttr, |
| maxSdkAttr, |
| dependenciesAttr, |
| " />\n", |
| "</permissions>\n", |
| }, "") |
| } |
| |
| func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
| apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) |
| module.hideApexVariantFromMake = !apexInfo.IsForPlatform() |
| |
| libName := proptools.String(module.properties.Lib_name) |
| module.selfValidate(ctx) |
| xmlContent := module.permissionsContents(ctx) |
| |
| module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath |
| android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent) |
| |
| module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir()) |
| ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath) |
| |
| ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "") |
| } |
| |
| func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { |
| if module.hideApexVariantFromMake { |
| return []android.AndroidMkEntries{{ |
| Disabled: true, |
| }} |
| } |
| |
| return []android.AndroidMkEntries{{ |
| Class: "ETC", |
| OutputFile: android.OptionalPathForPath(module.outputFilePath), |
| ExtraEntries: []android.AndroidMkExtraEntriesFunc{ |
| func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { |
| entries.SetString("LOCAL_MODULE_TAGS", "optional") |
| entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String()) |
| entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base()) |
| }, |
| }, |
| }} |
| } |
| |
| func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) { |
| module.validateAtLeastTAttributes(ctx) |
| module.validateMinAndMaxDeviceSdk(ctx) |
| module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx) |
| module.validateOnBootclasspathBeforeRequirements(ctx) |
| } |
| |
| func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) { |
| t := android.ApiLevelOrPanic(ctx, "Tiramisu") |
| module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk") |
| module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk") |
| module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before") |
| module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since") |
| } |
| |
| func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) { |
| if attr != nil { |
| if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil { |
| // we will inform the user of invalid inputs when we try to write the |
| // permissions xml file so we don't need to do it here |
| if t.GreaterThan(level) { |
| ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T") |
| } |
| } |
| } |
| } |
| |
| func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) { |
| if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil { |
| min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) |
| max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) |
| if minErr == nil && maxErr == nil { |
| // we will inform the user of invalid inputs when we try to write the |
| // permissions xml file so we don't need to do it here |
| if min.GreaterThan(max) { |
| ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk") |
| } |
| } |
| } |
| } |
| |
| func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) { |
| moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) |
| if module.properties.Min_device_sdk != nil { |
| api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) |
| if err == nil { |
| if moduleMinApi.GreaterThan(api) { |
| ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) |
| } |
| } |
| } |
| if module.properties.Max_device_sdk != nil { |
| api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) |
| if err == nil { |
| if moduleMinApi.GreaterThan(api) { |
| ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) |
| } |
| } |
| } |
| } |
| |
| func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) { |
| moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) |
| if module.properties.On_bootclasspath_before != nil { |
| t := android.ApiLevelOrPanic(ctx, "Tiramisu") |
| // if we use the attribute, then we need to do this validation |
| if moduleMinApi.LessThan(t) { |
| // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+) |
| if module.properties.Min_device_sdk == nil { |
| ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T") |
| } |
| } |
| } |
| } |