| // Copyright 2018 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 ( |
| "errors" |
| "fmt" |
| "path" |
| "path/filepath" |
| "reflect" |
| "sort" |
| "strings" |
| "sync" |
| |
| "github.com/google/blueprint" |
| "github.com/google/blueprint/proptools" |
| |
| "android/soong/android" |
| "android/soong/dexpreopt" |
| ) |
| |
| // A tag to associated a dependency with a specific api scope. |
| type scopeDependencyTag struct { |
| blueprint.BaseDependencyTag |
| name string |
| apiScope *apiScope |
| |
| // Function for extracting appropriate path information from the dependency. |
| depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.Module) error |
| } |
| |
| // Extract tag specific information from the dependency. |
| func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) { |
| err := tag.depInfoExtractor(paths, ctx, dep) |
| if err != nil { |
| ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error()) |
| } |
| } |
| |
| var _ android.ReplaceSourceWithPrebuilt = (*scopeDependencyTag)(nil) |
| |
| func (tag scopeDependencyTag) ReplaceSourceWithPrebuilt() bool { |
| return false |
| } |
| |
| // Provides information about an api scope, e.g. public, system, test. |
| type apiScope struct { |
| // The name of the api scope, e.g. public, system, test |
| name string |
| |
| // The api scope that this scope extends. |
| // |
| // This organizes the scopes into an extension hierarchy. |
| // |
| // If set this means that the API provided by this scope includes the API provided by the scope |
| // set in this field. |
| extends *apiScope |
| |
| // The next api scope that a library that uses this scope can access. |
| // |
| // This organizes the scopes into an access hierarchy. |
| // |
| // If set this means that a library that can access this API can also access the API provided by |
| // the scope set in this field. |
| // |
| // A module that sets sdk_version: "<scope>_current" should have access to the <scope> API of |
| // every java_sdk_library that it depends on. If the library does not provide an API for <scope> |
| // then it will traverse up this access hierarchy to find an API that it does provide. |
| // |
| // If this is not set then it defaults to the scope set in extends. |
| canAccess *apiScope |
| |
| // The legacy enabled status for a specific scope can be dependent on other |
| // properties that have been specified on the library so it is provided by |
| // a function that can determine the status by examining those properties. |
| legacyEnabledStatus func(module *SdkLibrary) bool |
| |
| // The default enabled status for non-legacy behavior, which is triggered by |
| // explicitly enabling at least one api scope. |
| defaultEnabledStatus bool |
| |
| // Gets a pointer to the scope specific properties. |
| scopeSpecificProperties func(module *SdkLibrary) *ApiScopeProperties |
| |
| // The name of the field in the dynamically created structure. |
| fieldName string |
| |
| // The name of the property in the java_sdk_library_import |
| propertyName string |
| |
| // The tag to use to depend on the prebuilt stubs library module |
| prebuiltStubsTag scopeDependencyTag |
| |
| // The tag to use to depend on the everything stubs library module. |
| everythingStubsTag scopeDependencyTag |
| |
| // The tag to use to depend on the exportable stubs library module. |
| exportableStubsTag scopeDependencyTag |
| |
| // The tag to use to depend on the stubs source module (if separate from the API module). |
| stubsSourceTag scopeDependencyTag |
| |
| // The tag to use to depend on the stubs source and API module. |
| stubsSourceAndApiTag scopeDependencyTag |
| |
| // The tag to use to depend on the module that provides the latest version of the API .txt file. |
| latestApiModuleTag scopeDependencyTag |
| |
| // The tag to use to depend on the module that provides the latest version of the API removed.txt |
| // file. |
| latestRemovedApiModuleTag scopeDependencyTag |
| |
| // The scope specific prefix to add to the api file base of "current.txt" or "removed.txt". |
| apiFilePrefix string |
| |
| // The scope specific suffix to add to the sdk library module name to construct a scope specific |
| // module name. |
| moduleSuffix string |
| |
| // SDK version that the stubs library is built against. Note that this is always |
| // *current. Older stubs library built with a numbered SDK version is created from |
| // the prebuilt jar. |
| sdkVersion string |
| |
| // The annotation that identifies this API level, empty for the public API scope. |
| annotation string |
| |
| // Extra arguments to pass to droidstubs for this scope. |
| // |
| // This is not used directly but is used to construct the droidstubsArgs. |
| extraArgs []string |
| |
| // The args that must be passed to droidstubs to generate the API and stubs source |
| // for this scope, constructed dynamically by initApiScope(). |
| // |
| // The API only includes the additional members that this scope adds over the scope |
| // that it extends. |
| // |
| // The stubs source must include the definitions of everything that is in this |
| // api scope and all the scopes that this one extends. |
| droidstubsArgs []string |
| |
| // Whether the api scope can be treated as unstable, and should skip compat checks. |
| unstable bool |
| |
| // Represents the SDK kind of this scope. |
| kind android.SdkKind |
| } |
| |
| // Initialize a scope, creating and adding appropriate dependency tags |
| func initApiScope(scope *apiScope) *apiScope { |
| name := scope.name |
| scopeByName[name] = scope |
| allScopeNames = append(allScopeNames, name) |
| scope.propertyName = strings.ReplaceAll(name, "-", "_") |
| scope.fieldName = proptools.FieldNameForProperty(scope.propertyName) |
| scope.prebuiltStubsTag = scopeDependencyTag{ |
| name: name + "-stubs", |
| apiScope: scope, |
| depInfoExtractor: (*scopePaths).extractStubsLibraryInfoFromDependency, |
| } |
| scope.everythingStubsTag = scopeDependencyTag{ |
| name: name + "-stubs-everything", |
| apiScope: scope, |
| depInfoExtractor: (*scopePaths).extractEverythingStubsLibraryInfoFromDependency, |
| } |
| scope.exportableStubsTag = scopeDependencyTag{ |
| name: name + "-stubs-exportable", |
| apiScope: scope, |
| depInfoExtractor: (*scopePaths).extractExportableStubsLibraryInfoFromDependency, |
| } |
| scope.stubsSourceTag = scopeDependencyTag{ |
| name: name + "-stubs-source", |
| apiScope: scope, |
| depInfoExtractor: (*scopePaths).extractStubsSourceInfoFromDep, |
| } |
| scope.stubsSourceAndApiTag = scopeDependencyTag{ |
| name: name + "-stubs-source-and-api", |
| apiScope: scope, |
| depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider, |
| } |
| scope.latestApiModuleTag = scopeDependencyTag{ |
| name: name + "-latest-api", |
| apiScope: scope, |
| depInfoExtractor: (*scopePaths).extractLatestApiPath, |
| } |
| scope.latestRemovedApiModuleTag = scopeDependencyTag{ |
| name: name + "-latest-removed-api", |
| apiScope: scope, |
| depInfoExtractor: (*scopePaths).extractLatestRemovedApiPath, |
| } |
| |
| // To get the args needed to generate the stubs source append all the args from |
| // this scope and all the scopes it extends as each set of args adds additional |
| // members to the stubs. |
| var scopeSpecificArgs []string |
| if scope.annotation != "" { |
| scopeSpecificArgs = []string{"--show-annotation", scope.annotation} |
| } |
| for s := scope; s != nil; s = s.extends { |
| scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...) |
| |
| // Ensure that the generated stubs includes all the API elements from the API scope |
| // that this scope extends. |
| if s != scope && s.annotation != "" { |
| scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation) |
| } |
| } |
| |
| // By default, a library that can access a scope can also access the scope it extends. |
| if scope.canAccess == nil { |
| scope.canAccess = scope.extends |
| } |
| |
| // Escape any special characters in the arguments. This is needed because droidstubs |
| // passes these directly to the shell command. |
| scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs) |
| |
| return scope |
| } |
| |
| 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" |
| } |
| |
| func (scope *apiScope) sourceStubsLibraryModuleName(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 |
| } |
| |
| func (scope *apiScope) String() string { |
| return scope.name |
| } |
| |
| // snapshotRelativeDir returns the snapshot directory into which the files related to scopes will |
| // be stored. |
| func (scope *apiScope) snapshotRelativeDir() string { |
| return filepath.Join("sdk_library", scope.name) |
| } |
| |
| // snapshotRelativeCurrentApiTxtPath returns the snapshot path to the API .txt file for the named |
| // library. |
| func (scope *apiScope) snapshotRelativeCurrentApiTxtPath(name string) string { |
| return filepath.Join(scope.snapshotRelativeDir(), name+".txt") |
| } |
| |
| // snapshotRelativeRemovedApiTxtPath returns the snapshot path to the removed API .txt file for the |
| // named library. |
| func (scope *apiScope) snapshotRelativeRemovedApiTxtPath(name string) string { |
| return filepath.Join(scope.snapshotRelativeDir(), name+"-removed.txt") |
| } |
| |
| type apiScopes []*apiScope |
| |
| func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string { |
| var list []string |
| for _, scope := range scopes { |
| list = append(list, accessor(scope)) |
| } |
| return list |
| } |
| |
| // Method that maps the apiScopes properties to the index of each apiScopes elements. |
| // apiScopes property to be used as the key can be specified with the input accessor. |
| // Only a string property of apiScope can be used as the key of the map. |
| func (scopes apiScopes) MapToIndex(accessor func(*apiScope) string) map[string]int { |
| ret := make(map[string]int) |
| for i, scope := range scopes { |
| ret[accessor(scope)] = i |
| } |
| return ret |
| } |
| |
| func (scopes apiScopes) ConvertStubsLibraryExportableToEverything(name string) string { |
| for _, scope := range scopes { |
| if strings.HasSuffix(name, scope.exportableStubsLibraryModuleNameSuffix()) { |
| return strings.TrimSuffix(name, scope.exportableStubsLibraryModuleNameSuffix()) + |
| scope.stubsLibraryModuleNameSuffix() |
| } |
| } |
| return name |
| } |
| |
| var ( |
| scopeByName = make(map[string]*apiScope) |
| allScopeNames []string |
| apiScopePublic = initApiScope(&apiScope{ |
| name: "public", |
| |
| // Public scope is enabled by default for both legacy and non-legacy modes. |
| legacyEnabledStatus: func(module *SdkLibrary) bool { |
| return true |
| }, |
| defaultEnabledStatus: true, |
| |
| scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { |
| return &module.sdkLibraryProperties.Public |
| }, |
| sdkVersion: "current", |
| kind: android.SdkPublic, |
| }) |
| apiScopeSystem = initApiScope(&apiScope{ |
| name: "system", |
| extends: apiScopePublic, |
| legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault, |
| scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { |
| return &module.sdkLibraryProperties.System |
| }, |
| apiFilePrefix: "system-", |
| moduleSuffix: ".system", |
| sdkVersion: "system_current", |
| annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)", |
| kind: android.SdkSystem, |
| }) |
| apiScopeTest = initApiScope(&apiScope{ |
| name: "test", |
| extends: apiScopeSystem, |
| legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault, |
| scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { |
| return &module.sdkLibraryProperties.Test |
| }, |
| apiFilePrefix: "test-", |
| moduleSuffix: ".test", |
| sdkVersion: "test_current", |
| annotation: "android.annotation.TestApi", |
| unstable: true, |
| kind: android.SdkTest, |
| }) |
| apiScopeModuleLib = initApiScope(&apiScope{ |
| name: "module-lib", |
| extends: apiScopeSystem, |
| // The module-lib scope is disabled by default in legacy mode. |
| // |
| // Enabling this would break existing usages. |
| legacyEnabledStatus: func(module *SdkLibrary) bool { |
| return false |
| }, |
| scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { |
| return &module.sdkLibraryProperties.Module_lib |
| }, |
| apiFilePrefix: "module-lib-", |
| moduleSuffix: ".module_lib", |
| sdkVersion: "module_current", |
| annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)", |
| kind: android.SdkModule, |
| }) |
| apiScopeSystemServer = initApiScope(&apiScope{ |
| name: "system-server", |
| extends: apiScopePublic, |
| |
| // The system-server scope can access the module-lib scope. |
| // |
| // A module that provides a system-server API is appended to the standard bootclasspath that is |
| // used by the system server. So, it should be able to access module-lib APIs provided by |
| // libraries on the bootclasspath. |
| canAccess: apiScopeModuleLib, |
| |
| // The system-server scope is disabled by default in legacy mode. |
| // |
| // Enabling this would break existing usages. |
| legacyEnabledStatus: func(module *SdkLibrary) bool { |
| return false |
| }, |
| scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { |
| return &module.sdkLibraryProperties.System_server |
| }, |
| apiFilePrefix: "system-server-", |
| moduleSuffix: ".system_server", |
| sdkVersion: "system_server_current", |
| annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)", |
| extraArgs: []string{ |
| "--hide-annotation", "android.annotation.Hide", |
| // com.android.* classes are okay in this interface" |
| "--hide", "InternalClasses", |
| }, |
| kind: android.SdkSystemServer, |
| }) |
| AllApiScopes = apiScopes{ |
| apiScopePublic, |
| apiScopeSystem, |
| apiScopeTest, |
| apiScopeModuleLib, |
| apiScopeSystemServer, |
| } |
| apiLibraryAdditionalProperties = map[string]string{ |
| "legacy.i18n.module.platform.api": "i18n.module.public.api.stubs.source.api.contribution", |
| "stable.i18n.module.platform.api": "i18n.module.public.api.stubs.source.api.contribution", |
| "conscrypt.module.platform.api": "conscrypt.module.public.api.stubs.source.api.contribution", |
| } |
| ) |
| |
| var ( |
| javaSdkLibrariesLock sync.Mutex |
| ) |
| |
| // TODO: these are big features that are currently missing |
| // 1) disallowing linking to the runtime shared lib |
| // 2) HTML generation |
| |
| func init() { |
| RegisterSdkLibraryBuildComponents(android.InitRegistrationContext) |
| |
| android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) { |
| javaSdkLibraries := javaSdkLibraries(ctx.Config()) |
| sort.Strings(*javaSdkLibraries) |
| ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " ")) |
| }) |
| |
| // Register sdk member types. |
| android.RegisterSdkMemberType(javaSdkLibrarySdkMemberType) |
| } |
| |
| func RegisterSdkLibraryBuildComponents(ctx android.RegistrationContext) { |
| ctx.RegisterModuleType("java_sdk_library", SdkLibraryFactory) |
| ctx.RegisterModuleType("java_sdk_library_import", sdkLibraryImportFactory) |
| } |
| |
| // Properties associated with each api scope. |
| type ApiScopeProperties struct { |
| // Indicates whether the api surface is generated. |
| // |
| // If this is set for any scope then all scopes must explicitly specify if they |
| // are enabled. This is to prevent new usages from depending on legacy behavior. |
| // |
| // Otherwise, if this is not set for any scope then the default behavior is |
| // scope specific so please refer to the scope specific property documentation. |
| Enabled *bool |
| |
| // The sdk_version to use for building the stubs. |
| // |
| // If not specified then it will use an sdk_version determined as follows: |
| // |
| // 1) If the sdk_version specified on the java_sdk_library is none then this |
| // will be none. This is used for java_sdk_library instances that are used |
| // to create stubs that contribute to the core_current sdk version. |
| // 2) Otherwise, it is assumed that this library extends but does not |
| // contribute directly to a specific sdk_version and so this uses the |
| // sdk_version appropriate for the api scope. e.g. public will use |
| // sdk_version: current, system will use sdk_version: system_current, etc. |
| // |
| // This does not affect the sdk_version used for either generating the stubs source |
| // or the API file. They both have to use the same sdk_version as is used for |
| // compiling the implementation library. |
| Sdk_version *string |
| |
| // Extra libs used when compiling stubs for this scope. |
| Libs []string |
| } |
| |
| type sdkLibraryProperties struct { |
| // List of source files that are needed to compile the API, but are not part of runtime library. |
| Api_srcs []string `android:"arch_variant"` |
| |
| // Visibility for impl library module. If not specified then defaults to the |
| // visibility property. |
| Impl_library_visibility []string |
| |
| // Visibility for stubs library modules. If not specified then defaults to the |
| // visibility property. |
| Stubs_library_visibility []string |
| |
| // Visibility for stubs source modules. If not specified then defaults to the |
| // visibility property. |
| Stubs_source_visibility []string |
| |
| // List of Java libraries that will be in the classpath when building the implementation lib |
| Impl_only_libs []string `android:"arch_variant"` |
| |
| // List of Java libraries that will included in the implementation lib. |
| Impl_only_static_libs []string `android:"arch_variant"` |
| |
| // List of Java libraries that will be in the classpath when building stubs |
| Stub_only_libs []string `android:"arch_variant"` |
| |
| // List of Java libraries that will included in stub libraries |
| Stub_only_static_libs []string `android:"arch_variant"` |
| |
| // list of package names that will be documented and publicized as API. |
| // This allows the API to be restricted to a subset of the source files provided. |
| // If this is unspecified then all the source files will be treated as being part |
| // of the API. |
| Api_packages []string |
| |
| // the relative path to the directory containing the api specification files. |
| // Defaults to "api". |
| Api_dir *string |
| |
| // Determines whether a runtime implementation library is built; defaults to false. |
| // |
| // If true then it also prevents the module from being used as a shared module, i.e. |
| // it is as if shared_library: false, was set. |
| Api_only *bool |
| |
| // local files that are used within user customized droiddoc options. |
| Droiddoc_option_files []string |
| |
| // additional droiddoc options. |
| // Available variables for substitution: |
| // |
| // $(location <label>): the path to the droiddoc_option_files with name <label> |
| Droiddoc_options []string |
| |
| // is set to true, Metalava will allow framework SDK to contain annotations. |
| Annotations_enabled *bool |
| |
| // a list of top-level directories containing files to merge qualifier annotations |
| // (i.e. those intended to be included in the stubs written) from. |
| Merge_annotations_dirs []string |
| |
| // a list of top-level directories containing Java stub files to merge show/hide annotations from. |
| Merge_inclusion_annotations_dirs []string |
| |
| // If set to true then don't create dist rules. |
| No_dist *bool |
| |
| // The stem for the artifacts that are copied to the dist, if not specified |
| // then defaults to the base module name. |
| // |
| // For each scope the following artifacts are copied to the apistubs/<scope> |
| // directory in the dist. |
| // * stubs impl jar -> <dist-stem>.jar |
| // * API specification file -> api/<dist-stem>.txt |
| // * Removed API specification file -> api/<dist-stem>-removed.txt |
| // |
| // Also used to construct the name of the filegroup (created by prebuilt_apis) |
| // that references the latest released API and remove API specification files. |
| // * API specification filegroup -> <dist-stem>.api.<scope>.latest |
| // * Removed API specification filegroup -> <dist-stem>-removed.api.<scope>.latest |
| // * API incompatibilities baseline filegroup -> <dist-stem>-incompatibilities.api.<scope>.latest |
| Dist_stem *string |
| |
| // The subdirectory for the artifacts that are copied to the dist directory. If not specified |
| // then defaults to "unknown". Should be set to "android" for anything that should be published |
| // in the public Android SDK. |
| Dist_group *string |
| |
| // A compatibility mode that allows historical API-tracking files to not exist. |
| // Do not use. |
| Unsafe_ignore_missing_latest_api bool |
| |
| // indicates whether system and test apis should be generated. |
| Generate_system_and_test_apis bool `blueprint:"mutated"` |
| |
| // The properties specific to the public api scope |
| // |
| // Unless explicitly specified by using public.enabled the public api scope is |
| // enabled by default in both legacy and non-legacy mode. |
| Public ApiScopeProperties |
| |
| // The properties specific to the system api scope |
| // |
| // In legacy mode the system api scope is enabled by default when sdk_version |
| // is set to something other than "none". |
| // |
| // In non-legacy mode the system api scope is disabled by default. |
| System ApiScopeProperties |
| |
| // The properties specific to the test api scope |
| // |
| // In legacy mode the test api scope is enabled by default when sdk_version |
| // is set to something other than "none". |
| // |
| // In non-legacy mode the test api scope is disabled by default. |
| Test ApiScopeProperties |
| |
| // The properties specific to the module-lib api scope |
| // |
| // Unless explicitly specified by using module_lib.enabled the module_lib api |
| // scope is disabled by default. |
| Module_lib ApiScopeProperties |
| |
| // The properties specific to the system-server api scope |
| // |
| // Unless explicitly specified by using system_server.enabled the |
| // system_server api scope is disabled by default. |
| System_server ApiScopeProperties |
| |
| // Determines if the stubs are preferred over the implementation library |
| // for linking, even when the client doesn't specify sdk_version. When this |
| // is set to true, such clients are provided with the widest API surface that |
| // this lib provides. Note however that this option doesn't affect the clients |
| // that are in the same APEX as this library. In that case, the clients are |
| // always linked with the implementation library. Default is false. |
| Default_to_stubs *bool |
| |
| // Properties related to api linting. |
| Api_lint struct { |
| // Enable api linting. |
| Enabled *bool |
| |
| // If API lint is enabled, this flag controls whether a set of legitimate lint errors |
| // are turned off. The default is true. |
| Legacy_errors_allowed *bool |
| } |
| |
| // a list of aconfig_declarations module names that the stubs generated in this module |
| // depend on. |
| Aconfig_declarations []string |
| |
| // Determines if the module generates the stubs from the api signature files |
| // instead of the source Java files. Defaults to true. |
| Build_from_text_stub *bool |
| |
| // TODO: determines whether to create HTML doc or not |
| // 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 { |
| // 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 |
| |
| // 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 |
| |
| // The dex jar for the stubs. |
| // |
| // This is not the implementation jar, it still only contains stubs. |
| stubsDexJarPath OptionalDexJarPath |
| |
| // The exportable dex jar for the stubs. |
| // This is not the implementation jar, it still only contains stubs. |
| // Includes unflagged apis and flagged apis enabled by release configurations. |
| exportableStubsDexJarPath OptionalDexJarPath |
| |
| // The API specification file, e.g. system_current.txt. |
| currentApiFilePath android.OptionalPath |
| |
| // The specification of API elements removed since the last release. |
| removedApiFilePath android.OptionalPath |
| |
| // The stubs source jar. |
| stubsSrcJar android.OptionalPath |
| |
| // Extracted annotations. |
| annotationsZip android.OptionalPath |
| |
| // The path to the latest API file. |
| latestApiPaths android.Paths |
| |
| // The path to the latest removed API file. |
| latestRemovedApiPaths android.Paths |
| } |
| |
| func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { |
| if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { |
| paths.stubsHeaderPath = lib.HeaderJars |
| paths.stubsImplPath = lib.ImplementationJars |
| |
| libDep := dep.(UsesLibraryDependency) |
| paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx) |
| paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx) |
| return nil |
| } else { |
| return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") |
| } |
| } |
| |
| func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { |
| if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { |
| paths.stubsHeaderPath = lib.HeaderJars |
| if !ctx.Config().ReleaseHiddenApiExportableStubs() { |
| paths.stubsImplPath = lib.ImplementationJars |
| } |
| |
| libDep := dep.(UsesLibraryDependency) |
| paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx) |
| return nil |
| } else { |
| return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") |
| } |
| } |
| |
| func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { |
| if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { |
| if ctx.Config().ReleaseHiddenApiExportableStubs() { |
| paths.stubsImplPath = lib.ImplementationJars |
| } |
| |
| libDep := dep.(UsesLibraryDependency) |
| paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx) |
| return nil |
| } else { |
| return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") |
| } |
| } |
| |
| func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider) error) error { |
| if apiStubsProvider, ok := dep.(ApiStubsProvider); ok { |
| err := action(apiStubsProvider) |
| if err != nil { |
| return err |
| } |
| return nil |
| } else { |
| return fmt.Errorf("expected module that implements ExportableApiStubsSrcProvider, e.g. droidstubs") |
| } |
| } |
| |
| func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider) error) error { |
| if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok { |
| err := action(apiStubsProvider) |
| if err != nil { |
| return err |
| } |
| return nil |
| } else { |
| return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs") |
| } |
| } |
| |
| func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider, stubsType StubsType) error { |
| var annotationsZip, currentApiFilePath, removedApiFilePath android.Path |
| annotationsZip, annotationsZipErr := provider.AnnotationsZip(stubsType) |
| currentApiFilePath, currentApiFilePathErr := provider.ApiFilePath(stubsType) |
| removedApiFilePath, removedApiFilePathErr := provider.RemovedApiFilePath(stubsType) |
| |
| combinedError := errors.Join(annotationsZipErr, currentApiFilePathErr, removedApiFilePathErr) |
| |
| if combinedError == nil { |
| paths.annotationsZip = android.OptionalPathForPath(annotationsZip) |
| paths.currentApiFilePath = android.OptionalPathForPath(currentApiFilePath) |
| paths.removedApiFilePath = android.OptionalPathForPath(removedApiFilePath) |
| } |
| return combinedError |
| } |
| |
| func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider, stubsType StubsType) error { |
| stubsSrcJar, err := provider.StubsSrcJar(stubsType) |
| if err == nil { |
| paths.stubsSrcJar = android.OptionalPathForPath(stubsSrcJar) |
| } |
| return err |
| } |
| |
| func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error { |
| stubsType := Everything |
| if ctx.Config().ReleaseHiddenApiExportableStubs() { |
| stubsType = Exportable |
| } |
| return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) error { |
| return paths.extractStubsSourceInfoFromApiStubsProviders(provider, stubsType) |
| }) |
| } |
| |
| func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error { |
| stubsType := Everything |
| if ctx.Config().ReleaseHiddenApiExportableStubs() { |
| stubsType = Exportable |
| } |
| return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) error { |
| extractApiInfoErr := paths.extractApiInfoFromApiStubsProvider(provider, stubsType) |
| extractStubsSourceInfoErr := paths.extractStubsSourceInfoFromApiStubsProviders(provider, stubsType) |
| return errors.Join(extractApiInfoErr, extractStubsSourceInfoErr) |
| }) |
| } |
| |
| func extractOutputPaths(dep android.Module) (android.Paths, error) { |
| var paths android.Paths |
| if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok { |
| paths = sourceFileProducer.Srcs() |
| return paths, nil |
| } else { |
| return nil, fmt.Errorf("module %q does not produce source files", dep) |
| } |
| } |
| |
| func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error { |
| outputPaths, err := extractOutputPaths(dep) |
| paths.latestApiPaths = outputPaths |
| return err |
| } |
| |
| func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error { |
| outputPaths, err := extractOutputPaths(dep) |
| paths.latestRemovedApiPaths = outputPaths |
| return err |
| } |
| |
| type commonToSdkLibraryAndImportProperties struct { |
| // Specifies whether this module can be used as an Android shared library; defaults |
| // to true. |
| // |
| // An Android shared library is one that can be referenced in a <uses-library> element |
| // in an AndroidManifest.xml. |
| Shared_library *bool |
| |
| // Files containing information about supported java doc tags. |
| Doctag_files []string `android:"path"` |
| |
| // 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 |
| } |
| |
| // commonSdkLibraryAndImportModule defines the interface that must be provided by a module that |
| // embeds the commonToSdkLibraryAndImport struct. |
| type commonSdkLibraryAndImportModule interface { |
| android.Module |
| |
| // Returns the name of the root java_sdk_library that creates the child stub libraries |
| // This is the `name` as it appears in Android.bp, and not the name in Soong's build graph |
| // (with the prebuilt_ prefix) |
| // |
| // e.g. in the following java_sdk_library_import |
| // java_sdk_library_import { |
| // name: "framework-foo.v1", |
| // source_module_name: "framework-foo", |
| // } |
| // the values returned by |
| // 1. Name(): prebuilt_framework-foo.v1 # unique |
| // 2. BaseModuleName(): framework-foo # the source |
| // 3. RootLibraryName: framework-foo.v1 # the undecordated `name` from Android.bp |
| RootLibraryName() string |
| } |
| |
| func (m *SdkLibrary) RootLibraryName() string { |
| return m.BaseModuleName() |
| } |
| |
| func (m *SdkLibraryImport) RootLibraryName() string { |
| // m.BaseModuleName refers to the source of the import |
| // use moduleBase.Name to get the name of the module as it appears in the .bp file |
| return m.ModuleBase.Name() |
| } |
| |
| // Common code between sdk library and sdk library import |
| type commonToSdkLibraryAndImport struct { |
| module commonSdkLibraryAndImportModule |
| |
| scopePaths map[*apiScope]*scopePaths |
| |
| commonSdkLibraryProperties commonToSdkLibraryAndImportProperties |
| |
| // Paths to commonSdkLibraryProperties.Doctag_files |
| doctagPaths android.Paths |
| |
| // Functionality related to this being used as a component of a java_sdk_library. |
| EmbeddableSdkLibraryComponent |
| |
| // Path to the header jars of the implementation library |
| // This is non-empty only when api_only is false. |
| implLibraryHeaderJars android.Paths |
| |
| // The reference to the implementation library created by the source module. |
| // Is nil if the source module does not exist. |
| implLibraryModule *Library |
| } |
| |
| func (c *commonToSdkLibraryAndImport) initCommon(module commonSdkLibraryAndImportModule) { |
| c.module = module |
| |
| module.AddProperties(&c.commonSdkLibraryProperties) |
| |
| // Initialize this as an sdk library component. |
| c.initSdkLibraryComponent(module) |
| } |
| |
| func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied() bool { |
| namePtr := proptools.StringPtr(c.module.RootLibraryName()) |
| c.sdkLibraryComponentProperties.SdkLibraryName = namePtr |
| |
| // Only track this sdk library if this can be used as a shared library. |
| if c.sharedLibrary() { |
| // Use the name specified in the module definition as the owner. |
| c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = namePtr |
| } |
| |
| return true |
| } |
| |
| // uniqueApexVariations provides common implementation of the ApexModule.UniqueApexVariations |
| // method. |
| func (c *commonToSdkLibraryAndImport) uniqueApexVariations() bool { |
| // A java_sdk_library that is a shared library produces an XML file that makes the shared library |
| // usable from an AndroidManifest.xml's <uses-library> entry. That XML file contains the name of |
| // the APEX and so it needs a unique variation per APEX. |
| return c.sharedLibrary() |
| } |
| |
| func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) SdkLibraryInfo { |
| c.doctagPaths = android.PathsForModuleSrc(ctx, c.commonSdkLibraryProperties.Doctag_files) |
| |
| everythingStubPaths := make(map[android.SdkKind]OptionalDexJarPath) |
| exportableStubPaths := make(map[android.SdkKind]OptionalDexJarPath) |
| removedApiFilePaths := make(map[android.SdkKind]android.OptionalPath) |
| for kind := android.SdkNone; kind <= android.SdkPrivate; kind += 1 { |
| everythingStubPath := makeUnsetDexJarPath() |
| exportableStubPath := makeUnsetDexJarPath() |
| removedApiFilePath := android.OptionalPath{} |
| if scopePath := c.findClosestScopePath(sdkKindToApiScope(kind)); scopePath != nil { |
| everythingStubPath = scopePath.stubsDexJarPath |
| exportableStubPath = scopePath.exportableStubsDexJarPath |
| removedApiFilePath = scopePath.removedApiFilePath |
| } |
| everythingStubPaths[kind] = everythingStubPath |
| exportableStubPaths[kind] = exportableStubPath |
| removedApiFilePaths[kind] = removedApiFilePath |
| } |
| |
| return SdkLibraryInfo{ |
| EverythingStubDexJarPaths: everythingStubPaths, |
| ExportableStubDexJarPaths: exportableStubPaths, |
| RemovedTxtFiles: removedApiFilePaths, |
| SharedLibrary: c.sharedLibrary(), |
| } |
| } |
| |
| // 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" |
| |
| annotationsComponentName = "annotations.zip" |
| ) |
| |
| func (module *commonToSdkLibraryAndImport) setOutputFiles(ctx android.ModuleContext) { |
| if module.doctagPaths != nil { |
| ctx.SetOutputFiles(module.doctagPaths, ".doctags") |
| } |
| for _, scopeName := range android.SortedKeys(scopeByName) { |
| paths := module.findScopePaths(scopeByName[scopeName]) |
| if paths == nil { |
| continue |
| } |
| componentToOutput := map[string]android.OptionalPath{ |
| stubsSourceComponentName: paths.stubsSrcJar, |
| apiTxtComponentName: paths.currentApiFilePath, |
| removedApiTxtComponentName: paths.removedApiFilePath, |
| annotationsComponentName: paths.annotationsZip, |
| } |
| for _, component := range android.SortedKeys(componentToOutput) { |
| if componentToOutput[component].Valid() { |
| ctx.SetOutputFiles(android.Paths{componentToOutput[component].Path()}, "."+scopeName+"."+component) |
| } |
| } |
| } |
| } |
| |
| func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths { |
| if c.scopePaths == nil { |
| c.scopePaths = make(map[*apiScope]*scopePaths) |
| } |
| paths := c.scopePaths[scope] |
| if paths == nil { |
| paths = &scopePaths{} |
| c.scopePaths[scope] = 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.canAccess { |
| 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 |
| } |
| |
| // sdkKindToApiScope maps from android.SdkKind to apiScope. |
| func sdkKindToApiScope(kind android.SdkKind) *apiScope { |
| var apiScope *apiScope |
| switch kind { |
| case android.SdkSystem: |
| apiScope = apiScopeSystem |
| case android.SdkModule: |
| apiScope = apiScopeModuleLib |
| case android.SdkTest: |
| apiScope = apiScopeTest |
| case android.SdkSystemServer: |
| apiScope = apiScopeSystemServer |
| default: |
| apiScope = apiScopePublic |
| } |
| return apiScope |
| } |
| |
| func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} { |
| componentProps := &struct { |
| SdkLibraryName *string |
| SdkLibraryToImplicitlyTrack *string |
| }{} |
| |
| namePtr := proptools.StringPtr(c.module.RootLibraryName()) |
| componentProps.SdkLibraryName = namePtr |
| |
| if c.sharedLibrary() { |
| // Mark the stubs library as being components of this java_sdk_library so that |
| // any app that includes code which depends (directly or indirectly) on the stubs |
| // library will have the appropriate <uses-library> invocation inserted into its |
| // manifest if necessary. |
| componentProps.SdkLibraryToImplicitlyTrack = namePtr |
| } |
| |
| return componentProps |
| } |
| |
| func (c *commonToSdkLibraryAndImport) sharedLibrary() bool { |
| return proptools.BoolDefault(c.commonSdkLibraryProperties.Shared_library, true) |
| } |
| |
| // Check if the stub libraries should be compiled for dex |
| func (c *commonToSdkLibraryAndImport) stubLibrariesCompiledForDex() bool { |
| // Always compile the dex file files for the stub libraries if they will be used on the |
| // bootclasspath. |
| return !c.sharedLibrary() |
| } |
| |
| // Properties related to the use of a module as an component of a java_sdk_library. |
| type SdkLibraryComponentProperties struct { |
| // The name of the java_sdk_library/_import module. |
| SdkLibraryName *string `blueprint:"mutated"` |
| |
| // The name of the java_sdk_library/_import to add to a <uses-library> entry |
| // in the AndroidManifest.xml of any Android app that includes code that references |
| // this module. If not set then no java_sdk_library/_import is tracked. |
| SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"` |
| } |
| |
| // Structure to be embedded in a module struct that needs to support the |
| // SdkLibraryComponentDependency interface. |
| type EmbeddableSdkLibraryComponent struct { |
| sdkLibraryComponentProperties SdkLibraryComponentProperties |
| } |
| |
| func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(module android.Module) { |
| module.AddProperties(&e.sdkLibraryComponentProperties) |
| } |
| |
| // to satisfy SdkLibraryComponentDependency |
| func (e *EmbeddableSdkLibraryComponent) SdkLibraryName() *string { |
| return e.sdkLibraryComponentProperties.SdkLibraryName |
| } |
| |
| // to satisfy SdkLibraryComponentDependency |
| func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string { |
| // For shared libraries, this is the same as the SDK library name. If a Java library or app |
| // depends on a component library (e.g. a stub library) it still needs to know the name of the |
| // run-time library and the corresponding module that provides the implementation. This name is |
| // passed to manifest_fixer (to be added to AndroidManifest.xml) and added to CLC (to be used |
| // in dexpreopt). |
| // |
| // For non-shared SDK (component or not) libraries this returns `nil`, as they are not |
| // <uses-library> and should not be added to the manifest or to CLC. |
| return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack |
| } |
| |
| // Implemented by modules that are (or possibly could be) a component of a java_sdk_library |
| // (including the java_sdk_library) itself. |
| type SdkLibraryComponentDependency interface { |
| UsesLibraryDependency |
| |
| // SdkLibraryName returns the name of the java_sdk_library/_import module. |
| SdkLibraryName() *string |
| |
| // The name of the implementation library for the optional SDK library or nil, if there isn't one. |
| OptionalSdkLibraryImplementation() *string |
| } |
| |
| // Make sure that all the module types that are components of java_sdk_library/_import |
| // and which can be referenced (directly or indirectly) from an android app implement |
| // the SdkLibraryComponentDependency interface. |
| var _ SdkLibraryComponentDependency = (*Library)(nil) |
| var _ SdkLibraryComponentDependency = (*Import)(nil) |
| var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil) |
| var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil) |
| |
| type SdkLibraryInfo struct { |
| // GeneratingLibs is the names of the library modules that this sdk library |
| // generates. Note that this only includes the name of the modules that other modules can |
| // depend on, and is not a holistic list of generated modules. |
| GeneratingLibs []string |
| |
| // Map of sdk kind to the dex jar for the "everything" stubs. |
| // It is needed by the hiddenapi processing tool which processes dex files. |
| EverythingStubDexJarPaths map[android.SdkKind]OptionalDexJarPath |
| |
| // Map of sdk kind to the dex jar for the "exportable" stubs. |
| // It is needed by the hiddenapi processing tool which processes dex files. |
| ExportableStubDexJarPaths map[android.SdkKind]OptionalDexJarPath |
| |
| // Map of sdk kind to the optional path to the removed.txt file. |
| RemovedTxtFiles map[android.SdkKind]android.OptionalPath |
| |
| // Whether if this can be used as a shared library. |
| SharedLibrary bool |
| } |
| |
| var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]() |
| |
| func getGeneratingLibs(ctx android.ModuleContext, sdkVersion android.SdkSpec, sdkLibraryModuleName string, sdkInfo SdkLibraryInfo) []string { |
| apiLevel := sdkVersion.ApiLevel |
| if apiLevel.IsPreview() { |
| return sdkInfo.GeneratingLibs |
| } |
| |
| generatingPrebuilts := []string{} |
| for _, apiScope := range AllApiScopes { |
| scopePrebuiltModuleName := prebuiltApiModuleName("sdk", sdkLibraryModuleName, apiScope.name, apiLevel.String()) |
| if ctx.OtherModuleExists(scopePrebuiltModuleName) { |
| generatingPrebuilts = append(generatingPrebuilts, scopePrebuiltModuleName) |
| } |
| } |
| return generatingPrebuilts |
| } |
| |
| type SdkLibrary struct { |
| Library |
| |
| sdkLibraryProperties sdkLibraryProperties |
| |
| // Map from api scope to the scope specific property structure. |
| scopeToProperties map[*apiScope]*ApiScopeProperties |
| |
| commonToSdkLibraryAndImport |
| |
| builtInstalledForApex []dexpreopterInstall |
| } |
| |
| func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool { |
| return module.sdkLibraryProperties.Generate_system_and_test_apis |
| } |
| |
| var _ UsesLibraryDependency = (*SdkLibrary)(nil) |
| |
| // To satisfy the UsesLibraryDependency interface |
| func (module *SdkLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { |
| if module.implLibraryModule != nil { |
| return module.implLibraryModule.DexJarBuildPath(ctx) |
| } |
| return makeUnsetDexJarPath() |
| } |
| |
| // To satisfy the UsesLibraryDependency interface |
| func (module *SdkLibrary) DexJarInstallPath() android.Path { |
| if module.implLibraryModule != nil { |
| return module.implLibraryModule.DexJarInstallPath() |
| } |
| return nil |
| } |
| |
| func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) apiScopes { |
| // Check to see if any scopes have been explicitly enabled. If any have then all |
| // must be. |
| anyScopesExplicitlyEnabled := false |
| for _, scope := range AllApiScopes { |
| scopeProperties := module.scopeToProperties[scope] |
| if scopeProperties.Enabled != nil { |
| anyScopesExplicitlyEnabled = true |
| break |
| } |
| } |
| |
| var generatedScopes apiScopes |
| enabledScopes := make(map[*apiScope]struct{}) |
| for _, scope := range AllApiScopes { |
| scopeProperties := module.scopeToProperties[scope] |
| // If any scopes are explicitly enabled then ignore the legacy enabled status. |
| // This is to ensure that any new usages of this module type do not rely on legacy |
| // behaviour. |
| defaultEnabledStatus := false |
| if anyScopesExplicitlyEnabled { |
| defaultEnabledStatus = scope.defaultEnabledStatus |
| } else { |
| defaultEnabledStatus = scope.legacyEnabledStatus(module) |
| } |
| enabled := proptools.BoolDefault(scopeProperties.Enabled, defaultEnabledStatus) |
| if enabled { |
| enabledScopes[scope] = struct{}{} |
| generatedScopes = append(generatedScopes, scope) |
| } |
| } |
| |
| // Now check to make sure that any scope that is extended by an enabled scope is also |
| // enabled. |
| for _, scope := range AllApiScopes { |
| if _, ok := enabledScopes[scope]; ok { |
| extends := scope.extends |
| if extends != nil { |
| if _, ok := enabledScopes[extends]; !ok { |
| ctx.ModuleErrorf("enabled api scope %q depends on disabled scope %q", scope, extends) |
| } |
| } |
| } |
| } |
| |
| return generatedScopes |
| } |
| |
| var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil) |
| |
| func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) { |
| CheckMinSdkVersion(ctx, &module.Library) |
| } |
| |
| func CheckMinSdkVersion(ctx android.ModuleContext, module *Library) { |
| android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.BaseModuleContext, do android.PayloadDepsCallback) { |
| ctx.WalkDeps(func(child android.Module, parent android.Module) bool { |
| isExternal := !module.depIsInSameApex(ctx, child) |
| if am, ok := child.(android.ApexModule); ok { |
| if !do(ctx, parent, am, isExternal) { |
| return false |
| } |
| } |
| return !isExternal |
| }) |
| }) |
| } |
| |
| type sdkLibraryComponentTag struct { |
| blueprint.BaseDependencyTag |
| name string |
| } |
| |
| // Mark this tag so dependencies that use it are excluded from visibility enforcement. |
| func (t sdkLibraryComponentTag) ExcludeFromVisibilityEnforcement() {} |
| |
| var xmlPermissionsFileTag = sdkLibraryComponentTag{name: "xml-permissions-file"} |
| |
| func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool { |
| if dt, ok := depTag.(sdkLibraryComponentTag); ok { |
| return dt == xmlPermissionsFileTag |
| } |
| return false |
| } |
| |
| var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"} |
| |
| var _ android.InstallNeededDependencyTag = sdkLibraryComponentTag{} |
| |
| func (t sdkLibraryComponentTag) InstallDepNeeded() bool { |
| return t.name == "xml-permissions-file" || t.name == "impl-library" |
| } |
| |
| // Add the dependencies on the child modules in the component deps mutator. |
| func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { |
| for _, apiScope := range module.getGeneratedApiScopes(ctx) { |
| // Add dependencies to the stubs library |
| stubModuleName := module.stubsLibraryModuleName(apiScope) |
| ctx.AddVariationDependencies(nil, apiScope.everythingStubsTag, stubModuleName) |
| |
| exportableStubModuleName := module.exportableStubsLibraryModuleName(apiScope) |
| ctx.AddVariationDependencies(nil, apiScope.exportableStubsTag, exportableStubModuleName) |
| |
| // Add a dependency on the stubs source in order to access both stubs source and api information. |
| ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.droidstubsModuleName(apiScope)) |
| |
| if module.compareAgainstLatestApi(apiScope) { |
| // Add dependencies on the latest finalized version of the API .txt file. |
| latestApiModuleName := module.latestApiModuleName(apiScope) |
| ctx.AddDependency(module, apiScope.latestApiModuleTag, latestApiModuleName) |
| |
| // Add dependencies on the latest finalized version of the remove API .txt file. |
| latestRemovedApiModuleName := module.latestRemovedApiModuleName(apiScope) |
| ctx.AddDependency(module, apiScope.latestRemovedApiModuleTag, latestRemovedApiModuleName) |
| } |
| } |
| |
| if module.requiresRuntimeImplementationLibrary() { |
| // Add dependency to the rule for generating the implementation library. |
| ctx.AddDependency(module, implLibraryTag, module.implLibraryModuleName()) |
| |
| if module.sharedLibrary() { |
| // Add dependency to the rule for generating the xml permissions file |
| ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName()) |
| } |
| } |
| } |
| |
| // Add other dependencies as normal. |
| func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { |
| // If the module does not create an implementation library or defaults to stubs, |
| // mark the top level sdk library as stubs module as the module will provide stubs via |
| // "magic" when listed as a dependency in the Android.bp files. |
| notCreateImplLib := proptools.Bool(module.sdkLibraryProperties.Api_only) |
| preferStubs := proptools.Bool(module.sdkLibraryProperties.Default_to_stubs) |
| module.properties.Is_stubs_module = proptools.BoolPtr(notCreateImplLib || preferStubs) |
| |
| var missingApiModules []string |
| for _, apiScope := range module.getGeneratedApiScopes(ctx) { |
| if apiScope.unstable { |
| continue |
| } |
| if m := module.latestApiModuleName(apiScope); !ctx.OtherModuleExists(m) { |
| missingApiModules = append(missingApiModules, m) |
| } |
| if m := module.latestRemovedApiModuleName(apiScope); !ctx.OtherModuleExists(m) { |
| missingApiModules = append(missingApiModules, m) |
| } |
| if m := module.latestIncompatibilitiesModuleName(apiScope); !ctx.OtherModuleExists(m) { |
| missingApiModules = append(missingApiModules, m) |
| } |
| } |
| if len(missingApiModules) != 0 && !module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api { |
| m := module.Name() + " is missing tracking files for previously released library versions.\n" |
| m += "You need to do one of the following:\n" |
| m += "- Add `unsafe_ignore_missing_latest_api: true` to your blueprint (to disable compat tracking)\n" |
| m += "- Add a set of prebuilt txt files representing the last released version of this library for compat checking.\n" |
| m += " (the current set of API files can be used as a seed for this compatibility tracking\n" |
| m += "\n" |
| m += "The following filegroup modules are missing:\n " |
| m += strings.Join(missingApiModules, "\n ") + "\n" |
| m += "Please see the documentation of the prebuilt_apis module type (and a usage example in prebuilts/sdk) for a convenient way to generate these." |
| ctx.ModuleErrorf(m) |
| } |
| } |
| |
| func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
| if disableSourceApexVariant(ctx) { |
| // Prebuilts are active, do not create the installation rules for the source javalib. |
| // Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules. |
| // TODO (b/331665856): Implement a principled solution for this. |
| module.HideFromMake() |
| module.SkipInstall() |
| } |
| |
| module.stem = proptools.StringDefault(module.overridableProperties.Stem, ctx.ModuleName()) |
| |
| module.provideHiddenAPIPropertyInfo(ctx) |
| |
| // Collate the components exported by this module. All scope specific modules are exported but |
| // the impl and xml component modules are not. |
| exportedComponents := map[string]struct{}{} |
| |
| // Record the paths to the header jars of the library (stubs and impl). |
| // When this java_sdk_library is depended upon from others via "libs" property, |
| // the recorded paths will be returned depending on the link type of the caller. |
| ctx.VisitDirectDeps(func(to android.Module) { |
| tag := ctx.OtherModuleDependencyTag(to) |
| |
| // Extract information from any of the scope specific dependencies. |
| if scopeTag, ok := tag.(scopeDependencyTag); ok { |
| apiScope := scopeTag.apiScope |
| scopePaths := module.getScopePathsCreateIfNeeded(apiScope) |
| |
| // 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) |
| |
| exportedComponents[ctx.OtherModuleName(to)] = struct{}{} |
| |
| ctx.Phony(ctx.ModuleName(), scopePaths.stubsHeaderPath...) |
| } |
| |
| if tag == implLibraryTag { |
| if dep, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok { |
| module.implLibraryHeaderJars = append(module.implLibraryHeaderJars, dep.HeaderJars...) |
| module.implLibraryModule = to.(*Library) |
| } |
| } |
| }) |
| |
| sdkLibInfo := module.generateCommonBuildActions(ctx) |
| apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) |
| if !apexInfo.IsForPlatform() { |
| module.hideApexVariantFromMake = true |
| } |
| |
| if module.implLibraryModule != nil { |
| if ctx.Device() { |
| module.classesJarPaths = android.Paths{module.implLibraryModule.implementationJarFile} |
| module.bootDexJarPath = module.implLibraryModule.bootDexJarPath |
| module.uncompressDexState = module.implLibraryModule.uncompressDexState |
| module.active = module.implLibraryModule.active |
| } |
| |
| module.outputFile = module.implLibraryModule.outputFile |
| module.dexJarFile = makeDexJarPathFromPath(module.implLibraryModule.dexJarFile.Path()) |
| module.headerJarFile = module.implLibraryModule.headerJarFile |
| module.implementationAndResourcesJar = module.implLibraryModule.implementationAndResourcesJar |
| module.builtInstalledForApex = module.implLibraryModule.builtInstalledForApex |
| module.dexpreopter.configPath = module.implLibraryModule.dexpreopter.configPath |
| module.dexpreopter.outputProfilePathOnHost = module.implLibraryModule.dexpreopter.outputProfilePathOnHost |
| |
| // Properties required for Library.AndroidMkEntries |
| module.logtagsSrcs = module.implLibraryModule.logtagsSrcs |
| module.dexpreopter.builtInstalled = module.implLibraryModule.dexpreopter.builtInstalled |
| module.jacocoReportClassesFile = module.implLibraryModule.jacocoReportClassesFile |
| module.dexer.proguardDictionary = module.implLibraryModule.dexer.proguardDictionary |
| module.dexer.proguardUsageZip = module.implLibraryModule.dexer.proguardUsageZip |
| module.linter.reports = module.implLibraryModule.linter.reports |
| |
| if lintInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, LintProvider); ok { |
| android.SetProvider(ctx, LintProvider, lintInfo) |
| } |
| |
| if !module.Host() { |
| module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile |
| } |
| |
| if installFilesInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, android.InstallFilesProvider); ok { |
| if installFilesInfo.CheckbuildTarget != nil { |
| ctx.CheckbuildFile(installFilesInfo.CheckbuildTarget) |
| } |
| } |
| android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: module.implLibraryModule.uniqueSrcFiles.Strings()}) |
| } |
| |
| // Make the set of components exported by this module available for use elsewhere. |
| exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedKeys(exportedComponents)} |
| android.SetProvider(ctx, android.ExportedComponentsInfoProvider, exportedComponentInfo) |
| |
| // Provide additional information for inclusion in an sdk's generated .info file. |
| additionalSdkInfo := map[string]interface{}{} |
| additionalSdkInfo["dist_stem"] = module.distStem() |
| baseModuleName := module.distStem() |
| scopes := map[string]interface{}{} |
| additionalSdkInfo["scopes"] = scopes |
| for scope, scopePaths := range module.scopePaths { |
| scopeInfo := map[string]interface{}{} |
| scopes[scope.name] = scopeInfo |
| scopeInfo["current_api"] = scope.snapshotRelativeCurrentApiTxtPath(baseModuleName) |
| scopeInfo["removed_api"] = scope.snapshotRelativeRemovedApiTxtPath(baseModuleName) |
| if p := scopePaths.latestApiPaths; len(p) > 0 { |
| // The last path in the list is the one that applies to this scope, the |
| // preceding ones, if any, are for the scope(s) that it extends. |
| scopeInfo["latest_api"] = p[len(p)-1].String() |
| } |
| if p := scopePaths.latestRemovedApiPaths; len(p) > 0 { |
| // The last path in the list is the one that applies to this scope, the |
| // preceding ones, if any, are for the scope(s) that it extends. |
| scopeInfo["latest_removed_api"] = p[len(p)-1].String() |
| } |
| } |
| android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo}) |
| module.setOutputFiles(ctx) |
| |
| var generatingLibs []string |
| for _, apiScope := range AllApiScopes { |
| if _, ok := module.scopePaths[apiScope]; ok { |
| generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope)) |
| } |
| } |
| |
| if module.requiresRuntimeImplementationLibrary() && module.implLibraryModule != nil { |
| generatingLibs = append(generatingLibs, module.implLibraryModuleName()) |
| setOutputFiles(ctx, module.implLibraryModule.Module) |
| } |
| |
| sdkLibInfo.GeneratingLibs = generatingLibs |
| android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo) |
| } |
| |
| func (module *SdkLibrary) BuiltInstalledForApex() []dexpreopterInstall { |
| return module.builtInstalledForApex |
| } |
| |
| func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries { |
| if !module.requiresRuntimeImplementationLibrary() { |
| return nil |
| } |
| entriesList := module.Library.AndroidMkEntries() |
| entries := &entriesList[0] |
| entries.Required = append(entries.Required, module.implLibraryModuleName()) |
| if module.sharedLibrary() { |
| entries.Required = append(entries.Required, module.xmlPermissionsModuleName()) |
| } |
| return entriesList |
| } |
| |
| // The dist path of the stub artifacts |
| func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string { |
| return path.Join("apistubs", module.distGroup(), apiScope.name) |
| } |
| |
| // Get the sdk version for use when compiling the stubs library. |
| func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope) string { |
| scopeProperties := module.scopeToProperties[apiScope] |
| if scopeProperties.Sdk_version != nil { |
| return proptools.String(scopeProperties.Sdk_version) |
| } |
| |
| sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library)) |
| if sdkDep.hasStandardLibs() { |
| // If building against a standard sdk then use the sdk version appropriate for the scope. |
| return apiScope.sdkVersion |
| } else { |
| // Otherwise, use no system module. |
| return "none" |
| } |
| } |
| |
| func (module *SdkLibrary) distStem() string { |
| return proptools.StringDefault(module.sdkLibraryProperties.Dist_stem, module.BaseModuleName()) |
| } |
| |
| // distGroup returns the subdirectory of the dist path of the stub artifacts. |
| func (module *SdkLibrary) distGroup() string { |
| return proptools.StringDefault(module.sdkLibraryProperties.Dist_group, "unknown") |
| } |
| |
| func latestPrebuiltApiModuleName(name string, apiScope *apiScope) string { |
| return PrebuiltApiModuleName(name, apiScope.name, "latest") |
| } |
| |
| func latestPrebuiltApiCombinedModuleName(name string, apiScope *apiScope) string { |
| return PrebuiltApiCombinedModuleName(name, apiScope.name, "latest") |
| } |
| |
| func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string { |
| return ":" + module.latestApiModuleName(apiScope) |
| } |
| |
| func (module *SdkLibrary) latestApiModuleName(apiScope *apiScope) string { |
| return latestPrebuiltApiCombinedModuleName(module.distStem(), apiScope) |
| } |
| |
| func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string { |
| return ":" + module.latestRemovedApiModuleName(apiScope) |
| } |
| |
| func (module *SdkLibrary) latestRemovedApiModuleName(apiScope *apiScope) string { |
| return latestPrebuiltApiCombinedModuleName(module.distStem()+"-removed", apiScope) |
| } |
| |
| func (module *SdkLibrary) latestIncompatibilitiesFilegroupName(apiScope *apiScope) string { |
| return ":" + module.latestIncompatibilitiesModuleName(apiScope) |
| } |
| |
| func (module *SdkLibrary) latestIncompatibilitiesModuleName(apiScope *apiScope) string { |
| return latestPrebuiltApiModuleName(module.distStem()+"-incompatibilities", apiScope) |
| } |
| |
| // The listed modules' stubs contents do not match the corresponding txt files, |
| // but require additional api contributions to generate the full stubs. |
| // This method returns the name of the additional api contribution module |
| // for corresponding sdk_library modules. |
| func (module *SdkLibrary) apiLibraryAdditionalApiContribution() string { |
| if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok { |
| return val |
| } |
| return "" |
| } |
| |
| func childModuleVisibility(childVisibility []string) []string { |
| if childVisibility == nil { |
| // No child visibility set. The child will use the visibility of the sdk_library. |
| return nil |
| } |
| |
| // Prepend an override to ignore the sdk_library's visibility, and rely on the child visibility. |
| var visibility []string |
| visibility = append(visibility, "//visibility:override") |
| visibility = append(visibility, childVisibility...) |
| return visibility |
| } |
| |
| func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool { |
| return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api) |
| } |
| |
| // Implements android.ApexModule |
| func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool { |
| depTag := mctx.OtherModuleDependencyTag(dep) |
| if depTag == xmlPermissionsFileTag { |
| return true |
| } |
| if dep.Name() == module.implLibraryModuleName() { |
| return true |
| } |
| return module.Library.DepIsInSameApex(mctx, dep) |
| } |
| |
| // Implements android.ApexModule |
| func (module *SdkLibrary) UniqueApexVariations() bool { |
| return module.uniqueApexVariations() |
| } |
| |
| func (module *SdkLibrary) ModuleBuildFromTextStubs() bool { |
| return proptools.BoolDefault(module.sdkLibraryProperties.Build_from_text_stub, true) |
| } |
| |
| var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries") |
| |
| func javaSdkLibraries(config android.Config) *[]string { |
| return config.Once(javaSdkLibrariesKey, func() interface{} { |
| return &[]string{} |
| }).(*[]string) |
| } |
| |
| func (module *SdkLibrary) getApiDir() string { |
| return proptools.StringDefault(module.sdkLibraryProperties.Api_dir, "api") |
| } |
| |
| // For a java_sdk_library module, create internal modules for stubs, docs, |
| // runtime libs and xml file. If requested, the stubs and docs are created twice |
| // once for public API level and once for system API level |
| func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) { |
| if len(module.properties.Srcs) == 0 { |
| mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs") |
| return |
| } |
| |
| // If this builds against standard libraries (i.e. is not part of the core libraries) |
| // then assume it provides both system and test apis. |
| sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library)) |
| hasSystemAndTestApis := sdkDep.hasStandardLibs() |
| module.sdkLibraryProperties.Generate_system_and_test_apis = hasSystemAndTestApis |
| |
| missingCurrentApi := false |
| |
| generatedScopes := module.getGeneratedApiScopes(mctx) |
| |
| apiDir := module.getApiDir() |
| for _, scope := range generatedScopes { |
| for _, api := range []string{"current.txt", "removed.txt"} { |
| path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api) |
| p := android.ExistentPathForSource(mctx, path) |
| if !p.Valid() { |
| if mctx.Config().AllowMissingDependencies() { |
| mctx.AddMissingDependencies([]string{path}) |
| } else { |
| mctx.ModuleErrorf("Current api file %#v doesn't exist", path) |
| missingCurrentApi = true |
| } |
| } |
| } |
| } |
| |
| if missingCurrentApi { |
| script := "build/soong/scripts/gen-java-current-api-files.sh" |
| p := android.ExistentPathForSource(mctx, script) |
| |
| if !p.Valid() { |
| panic(fmt.Sprintf("script file %s doesn't exist", script)) |
| } |
| |
| mctx.ModuleErrorf("One or more current api files are missing. "+ |
| "You can update them by:\n"+ |
| "%s %q %s && m update-api", |
| script, filepath.Join(mctx.ModuleDir(), apiDir), |
| strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " ")) |
| return |
| } |
| |
| for _, scope := range generatedScopes { |
| // Use the stubs source name for legacy reasons. |
| module.createDroidstubs(mctx, scope, module.droidstubsModuleName(scope), scope.droidstubsArgs) |
| |
| module.createFromSourceStubsLibrary(mctx, scope) |
| module.createExportableFromSourceStubsLibrary(mctx, scope) |
| |
| if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() { |
| module.createApiLibrary(mctx, scope) |
| } |
| module.createTopLevelStubsLibrary(mctx, scope) |
| module.createTopLevelExportableStubsLibrary(mctx, scope) |
| } |
| |
| if module.requiresRuntimeImplementationLibrary() { |
| // Create child module to create an implementation library. |
| // |
| // This temporarily creates a second implementation library that can be explicitly |
| // referenced. |
| // |
| // TODO(b/156618935) - update comment once only one implementation library is created. |
| module.createImplLibrary(mctx) |
| |
| // Only create an XML permissions file that declares the library as being usable |
| // as a shared library if required. |
| if module.sharedLibrary() { |
| module.createXmlFile(mctx) |
| } |
| |
| // record java_sdk_library modules so that they are exported to make |
| javaSdkLibraries := javaSdkLibraries(mctx.Config()) |
| javaSdkLibrariesLock.Lock() |
| defer javaSdkLibrariesLock.Unlock() |
| *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName()) |
| } |
| |
| // Add the impl_only_libs and impl_only_static_libs *after* we're done using them in submodules. |
| module.properties.Libs = append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...) |
| module.properties.Static_libs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs) |
| } |
| |
| func (module *SdkLibrary) InitSdkLibraryProperties() { |
| module.addHostAndDeviceProperties() |
| module.AddProperties(&module.sdkLibraryProperties) |
| |
| module.initSdkLibraryComponent(module) |
| |
| module.properties.Installable = proptools.BoolPtr(true) |
| module.deviceProperties.IsSDKLibrary = true |
| } |
| |
| func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool { |
| return !proptools.Bool(module.sdkLibraryProperties.Api_only) |
| } |
| |
| func moduleStubLinkType(j *Module) (stub bool, ret sdkLinkType) { |
| kind := android.ToSdkKind(proptools.String(j.properties.Stub_contributing_api)) |
| switch kind { |
| case android.SdkPublic: |
| return true, javaSdk |
| case android.SdkSystem: |
| return true, javaSystem |
| case android.SdkModule: |
| return true, javaModule |
| case android.SdkTest: |
| return true, javaSystem |
| case android.SdkSystemServer: |
| return true, javaSystemServer |
| // Default value for all modules other than java_sdk_library-generated stub submodules |
| case android.SdkInvalid: |
| return false, javaPlatform |
| default: |
| panic(fmt.Sprintf("stub_contributing_api set as an unsupported sdk kind %s", kind.String())) |
| } |
| } |
| |
| // java_sdk_library is a special Java library that provides optional platform APIs to apps. |
| // In practice, it can be viewed as a combination of several modules: 1) stubs library that clients |
| // are linked against to, 2) droiddoc module that internally generates API stubs source files, |
| // 3) the real runtime shared library that implements the APIs, and 4) XML file for adding |
| // the runtime lib to the classpath at runtime if requested via <uses-library>. |
| func SdkLibraryFactory() android.Module { |
| module := &SdkLibrary{} |
| |
| // Initialize information common between source and prebuilt. |
| module.initCommon(module) |
| |
| module.InitSdkLibraryProperties() |
| android.InitApexModule(module) |
| InitJavaModule(module, android.HostAndDeviceSupported) |
| |
| // Initialize the map from scope to scope specific properties. |
| scopeToProperties := make(map[*apiScope]*ApiScopeProperties) |
| for _, scope := range AllApiScopes { |
| scopeToProperties[scope] = scope.scopeSpecificProperties(module) |
| } |
| module.scopeToProperties = scopeToProperties |
| |
| // Add the properties containing visibility rules so that they are checked. |
| android.AddVisibilityProperty(module, "impl_library_visibility", &module.sdkLibraryProperties.Impl_library_visibility) |
| android.AddVisibilityProperty(module, "stubs_library_visibility", &module.sdkLibraryProperties.Stubs_library_visibility) |
| android.AddVisibilityProperty(module, "stubs_source_visibility", &module.sdkLibraryProperties.Stubs_source_visibility) |
| |
| module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { |
| // If no implementation is required then it cannot be used as a shared library |
| // either. |
| if !module.requiresRuntimeImplementationLibrary() { |
| // If shared_library has been explicitly set to true then it is incompatible |
| // with api_only: true. |
| if proptools.Bool(module.commonSdkLibraryProperties.Shared_library) { |
| ctx.PropertyErrorf("api_only/shared_library", "inconsistent settings, shared_library and api_only cannot both be true") |
| } |
| // Set shared_library: false. |
| module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false) |
| } |
| |
| if module.initCommonAfterDefaultsApplied() { |
| module.CreateInternalModules(ctx) |
| } |
| }) |
| return module |
| } |
| |
| // |
| // SDK library prebuilts |
| // |
| |
| // Properties associated with each api scope. |
| type sdkLibraryScopeProperties struct { |
| Jars []string `android:"path"` |
| |
| Sdk_version *string |
| |
| // List of shared java libs that this module has dependencies to |
| Libs []string |
| |
| // The stubs source. |
| Stub_srcs []string `android:"path"` |
| |
| // The current.txt |
| Current_api *string `android:"path"` |
| |
| // The removed.txt |
| Removed_api *string `android:"path"` |
| |
| // Annotation zip |
| Annotations *string `android:"path"` |
| } |
| |
| type sdkLibraryImportProperties struct { |
| // List of shared java libs, common to all scopes, that this module has |
| // dependencies to |
| Libs []string |
| |
| // If set to true, compile dex files for the stubs. Defaults to false. |
| Compile_dex *bool |
| |
| // If not empty, classes are restricted to the specified packages and their sub-packages. |
| Permitted_packages []string |
| |
| // Name of the source soong module that gets shadowed by this prebuilt |
| // If unspecified, follows the naming convention that the source module of |
| // the prebuilt is Name() without "prebuilt_" prefix |
| Source_module_name *string |
| } |
| |
| type SdkLibraryImport struct { |
| android.ModuleBase |
| android.DefaultableModuleBase |
| prebuilt android.Prebuilt |
| android.ApexModuleBase |
| |
| hiddenAPI |
| dexpreopter |
| |
| properties sdkLibraryImportProperties |
| |
| // Map from api scope to the scope specific property structure. |
| scopeProperties map[*apiScope]*sdkLibraryScopeProperties |
| |
| commonToSdkLibraryAndImport |
| |
| // The reference to the xml permissions module created by the source module. |
| // Is nil if the source module does not exist. |
| xmlPermissionsFileModule *sdkLibraryXml |
| |
| // Build path to the dex implementation jar obtained from the prebuilt_apex, if any. |
| dexJarFile OptionalDexJarPath |
| dexJarFileErr error |
| |
| // Expected install file path of the source module(sdk_library) |
| // or dex implementation jar obtained from the prebuilt_apex, if any. |
| installFile android.Path |
| } |
| |
| // The type of a structure that contains a field of type sdkLibraryScopeProperties |
| // for each apiscope in allApiScopes, e.g. something like: |
| // |
| // struct { |
| // Public sdkLibraryScopeProperties |
| // System sdkLibraryScopeProperties |
| // ... |
| // } |
| var allScopeStructType = createAllScopePropertiesStructType() |
| |
| // Dynamically create a structure type for each apiscope in allApiScopes. |
| func createAllScopePropertiesStructType() reflect.Type { |
| var fields []reflect.StructField |
| for _, apiScope := range AllApiScopes { |
| field := reflect.StructField{ |
| Name: apiScope.fieldName, |
| Type: reflect.TypeOf(sdkLibraryScopeProperties{}), |
| } |
| fields = append(fields, field) |
| } |
| |
| return reflect.StructOf(fields) |
| } |
| |
| // Create an instance of the scope specific structure type and return a map |
| // from apiscope to a pointer to each scope specific field. |
| func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProperties) { |
| allScopePropertiesPtr := reflect.New(allScopeStructType) |
| allScopePropertiesStruct := allScopePropertiesPtr.Elem() |
| scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties) |
| |
| for _, apiScope := range AllApiScopes { |
| field := allScopePropertiesStruct.FieldByName(apiScope.fieldName) |
| scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties) |
| } |
| |
| return allScopePropertiesPtr.Interface(), scopeProperties |
| } |
| |
| // java_sdk_library_import imports a prebuilt java_sdk_library. |
| func sdkLibraryImportFactory() android.Module { |
| module := &SdkLibraryImport{} |
| |
| allScopeProperties, scopeToProperties := createPropertiesInstance() |
| module.scopeProperties = scopeToProperties |
| module.AddProperties(&module.properties, allScopeProperties, &module.importDexpreoptProperties) |
| |
| // Initialize information common between source and prebuilt. |
| module.initCommon(module) |
| |
| android.InitPrebuiltModule(module, &[]string{""}) |
| android.InitApexModule(module) |
| InitJavaModule(module, android.HostAndDeviceSupported) |
| |
| module.SetDefaultableHook(func(mctx android.DefaultableHookContext) { |
| if module.initCommonAfterDefaultsApplied() { |
| module.createInternalModules(mctx) |
| } |
| }) |
| return module |
| } |
| |
| var _ PermittedPackagesForUpdatableBootJars = (*SdkLibraryImport)(nil) |
| |
| func (module *SdkLibraryImport) PermittedPackagesForUpdatableBootJars() []string { |
| return module.properties.Permitted_packages |
| } |
| |
| func (module *SdkLibraryImport) Prebuilt() *android.Prebuilt { |
| return &module.prebuilt |
| } |
| |
| func (module *SdkLibraryImport) Name() string { |
| return module.prebuilt.Name(module.ModuleBase.Name()) |
| } |
| |
| func (module *SdkLibraryImport) BaseModuleName() string { |
| return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name()) |
| } |
| |
| func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) { |
| |
| // If the build is configured to use prebuilts then force this to be preferred. |
| if mctx.Config().AlwaysUsePrebuiltSdks() { |
| module.prebuilt.ForcePrefer() |
| } |
| |
| for apiScope, scopeProperties := range module.scopeProperties { |
| if len(scopeProperties.Jars) == 0 { |
| continue |
| } |
| |
| module.createJavaImportForStubs(mctx, apiScope, scopeProperties) |
| |
| if len(scopeProperties.Stub_srcs) > 0 { |
| module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties) |
| } |
| |
| if scopeProperties.Current_api != nil { |
| module.createPrebuiltApiContribution(mctx, apiScope, scopeProperties) |
| } |
| } |
| |
| javaSdkLibraries := javaSdkLibraries(mctx.Config()) |
| javaSdkLibrariesLock.Lock() |
| defer javaSdkLibrariesLock.Unlock() |
| *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName()) |
| } |
| |
| // Add the dependencies on the child module in the component deps mutator so that it |
| // creates references to the prebuilt and not the source modules. |
| func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { |
| for apiScope, scopeProperties := range module.scopeProperties { |
| if len(scopeProperties.Jars) == 0 { |
| continue |
| } |
| |
| // Add dependencies to the prebuilt stubs library |
| ctx.AddVariationDependencies(nil, apiScope.prebuiltStubsTag, android.PrebuiltNameFromSource(module.stubsLibraryModuleName(apiScope))) |
| |
| if len(scopeProperties.Stub_srcs) > 0 { |
| // Add dependencies to the prebuilt stubs source library |
| ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, android.PrebuiltNameFromSource(module.droidstubsModuleName(apiScope))) |
| } |
| } |
| } |
| |
| // Add other dependencies as normal. |
| func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) { |
| |
| implName := module.implLibraryModuleName() |
| if ctx.OtherModuleExists(implName) { |
| ctx.AddVariationDependencies(nil, implLibraryTag, implName) |
| |
| xmlPermissionsModuleName := module.xmlPermissionsModuleName() |
| if module.sharedLibrary() && ctx.OtherModuleExists(xmlPermissionsModuleName) { |
| // Add dependency to the rule for generating the xml permissions file |
| ctx.AddDependency(module, xmlPermissionsFileTag, xmlPermissionsModuleName) |
| } |
| } |
| } |
| |
| var _ android.ApexModule = (*SdkLibraryImport)(nil) |
| |
| // Implements android.ApexModule |
| func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool { |
| depTag := mctx.OtherModuleDependencyTag(dep) |
| if depTag == xmlPermissionsFileTag { |
| return true |
| } |
| |
| // None of the other dependencies of the java_sdk_library_import are in the same apex |
| // as the one that references this module. |
| return false |
| } |
| |
| // Implements android.ApexModule |
| func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, |
| sdkVersion android.ApiLevel) error { |
| // we don't check prebuilt modules for sdk_version |
| return nil |
| } |
| |
| // Implements android.ApexModule |
| func (module *SdkLibraryImport) UniqueApexVariations() bool { |
| return module.uniqueApexVariations() |
| } |
| |
| // MinSdkVersion - Implements hiddenAPIModule |
| func (module *SdkLibraryImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { |
| return android.NoneApiLevel |
| } |
| |
| var _ hiddenAPIModule = (*SdkLibraryImport)(nil) |
| |
| func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
| // Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework |
| module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar") |
| |
| // Record the paths to the prebuilt stubs library and stubs source. |
| ctx.VisitDirectDeps(func(to android.Module) { |
| tag := ctx.OtherModuleDependencyTag(to) |
| |
| // Extract information from any of the scope specific dependencies. |
| if scopeTag, ok := tag.(scopeDependencyTag); ok { |
| apiScope := scopeTag.apiScope |
| scopePaths := module.getScopePathsCreateIfNeeded(apiScope) |
| |
| // 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) |
| } else if tag == implLibraryTag { |
| if implLibrary, ok := to.(*Library); ok { |
| module.implLibraryModule = implLibrary |
| } else { |
| ctx.ModuleErrorf("implementation library must be of type *java.Library but was %T", to) |
| } |
| } else if tag == xmlPermissionsFileTag { |
| if xmlPermissionsFileModule, ok := to.(*sdkLibraryXml); ok { |
| module.xmlPermissionsFileModule = xmlPermissionsFileModule |
| } else { |
| ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to) |
| } |
| } |
| }) |
| sdkLibInfo := module.generateCommonBuildActions(ctx) |
| |
| // Populate the scope paths with information from the properties. |
| for apiScope, scopeProperties := range module.scopeProperties { |
| if len(scopeProperties.Jars) == 0 { |
| continue |
| } |
| |
| paths := module.getScopePathsCreateIfNeeded(apiScope) |
| paths.annotationsZip = android.OptionalPathForModuleSrc(ctx, scopeProperties.Annotations) |
| paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api) |
| paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api) |
| } |
| |
| if ctx.Device() { |
| // Shared libraries deapexed from prebuilt apexes are no longer supported. |
| // Set the dexJarBuildPath to a fake path. |
| // This allows soong analysis pass, but will be an error during ninja execution if there are |
| // any rdeps. |
| ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) |
| if ai.ForPrebuiltApex { |
| module.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported")) |
| module.initHiddenAPI(ctx, module.dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil) |
| } |
| } |
| |
| var generatingLibs []string |
| for _, apiScope := range AllApiScopes { |
| if scopeProperties, ok := module.scopeProperties[apiScope]; ok { |
| if len(scopeProperties.Jars) == 0 { |
| continue |
| } |
| generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope)) |
| } |
| } |
| |
| module.setOutputFiles(ctx) |
| if module.implLibraryModule != nil { |
| generatingLibs = append(generatingLibs, module.implLibraryModuleName()) |
| setOutputFiles(ctx, module.implLibraryModule.Module) |
| } |
| |
| sdkLibInfo.GeneratingLibs = generatingLibs |
| android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo) |
| } |
| |
| var _ UsesLibraryDependency = (*SdkLibraryImport)(nil) |
| |
| // to satisfy UsesLibraryDependency interface |
| func (module *SdkLibraryImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { |
| // The dex implementation jar extracted from the .apex file should be used in preference to the |
| // source. |
| if module.dexJarFileErr != nil { |
| ctx.ModuleErrorf(module.dexJarFileErr.Error()) |
| } |
| if module.dexJarFile.IsSet() { |
| return module.dexJarFile |
| } |
| if module.implLibraryModule == nil { |
| return makeUnsetDexJarPath() |
| } else { |
| return module.implLibraryModule.DexJarBuildPath(ctx) |
| } |
| } |
| |
| // to satisfy UsesLibraryDependency interface |
| func (module *SdkLibraryImport) DexJarInstallPath() android.Path { |
| return module.installFile |
| } |
| |
| // to satisfy UsesLibraryDependency interface |
| func (module *SdkLibraryImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { |
| return nil |
| } |
| |
| // to satisfy apex.javaDependency interface |
| func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { |
| if module.implLibraryModule == nil { |
| return nil |
| } else { |
| return module.implLibraryModule.JacocoReportClassesFile() |
| } |
| } |
| |
| // to satisfy apex.javaDependency interface |
| func (module *SdkLibraryImport) Stem() string { |
| return module.BaseModuleName() |
| } |
| |
| var _ ApexDependency = (*SdkLibraryImport)(nil) |
| |
| // to satisfy java.ApexDependency interface |
| func (module *SdkLibraryImport) HeaderJars() android.Paths { |
| if module.implLibraryModule == nil { |
| return nil |
| } else { |
| return module.implLibraryModule.HeaderJars() |
| } |
| } |
| |
| // to satisfy java.ApexDependency interface |
| func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths { |
| if module.implLibraryModule == nil { |
| return nil |
| } else { |
| return module.implLibraryModule.ImplementationAndResourcesJars() |
| } |
| } |
| |
| // to satisfy java.DexpreopterInterface interface |
| func (module *SdkLibraryImport) IsInstallable() bool { |
| return true |
| } |
| |
| var _ android.RequiredFilesFromPrebuiltApex = (*SdkLibraryImport)(nil) |
| |
| func (module *SdkLibraryImport) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string { |
| name := module.BaseModuleName() |
| return requiredFilesFromPrebuiltApexForImport(name, &module.dexpreopter) |
| } |
| |
| func (j *SdkLibraryImport) UseProfileGuidedDexpreopt() bool { |
| return proptools.Bool(j.importDexpreoptProperties.Dex_preopt.Profile_guided) |
| } |
| |
| type sdkLibrarySdkMemberType struct { |
| android.SdkMemberTypeBase |
| } |
| |
| func (s *sdkLibrarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) { |
| ctx.AddVariationDependencies(nil, dependencyTag, names...) |
| } |
| |
| func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool { |
| _, ok := module.(*SdkLibrary) |
| return ok |
| } |
| |
| func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { |
| return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_sdk_library_import") |
| } |
| |
| func (s *sdkLibrarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { |
| return &sdkLibrarySdkMemberProperties{} |
| } |
| |
| var javaSdkLibrarySdkMemberType = &sdkLibrarySdkMemberType{ |
| android.SdkMemberTypeBase{ |
| PropertyName: "java_sdk_libs", |
| SupportsSdk: true, |
| }, |
| } |
| |
| type sdkLibrarySdkMemberProperties struct { |
| android.SdkMemberPropertiesBase |
| |
| // Stem name for files in the sdk snapshot. |
| // |
| // This is used to construct the path names of various sdk library files in the sdk snapshot to |
| // make sure that they match the finalized versions of those files in prebuilts/sdk. |
| // |
| // This property is marked as keep so that it will be kept in all instances of this struct, will |
| // not be cleared but will be copied to common structs. That is needed because this field is used |
| // to construct many file names for other parts of this struct and so it needs to be present in |
| // all structs. If it was not marked as keep then it would be cleared in some structs and so would |
| // be unavailable for generating file names if there were other properties that were still set. |
| Stem string `sdk:"keep"` |
| |
| // Scope to per scope properties. |
| Scopes map[*apiScope]*scopeProperties |
| |
| // The Java stubs source files. |
| Stub_srcs []string |
| |
| // The naming scheme. |
| Naming_scheme *string |
| |
| // True if the java_sdk_library_import is for a shared library, false |
| // otherwise. |
| Shared_library *bool |
| |
| // True if the stub imports should produce dex jars. |
| Compile_dex *bool |
| |
| // The paths to the doctag files to add to the prebuilt. |
| Doctag_paths android.Paths |
| |
| Permitted_packages []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 |
| |
| DexPreoptProfileGuided *bool `supported_build_releases:"UpsideDownCake+"` |
| } |
| |
| type scopeProperties struct { |
| Jars android.Paths |
| StubsSrcJar android.Path |
| CurrentApiFile android.Path |
| RemovedApiFile android.Path |
| AnnotationsZip android.Path `supported_build_releases:"Tiramisu+"` |
| SdkVersion string |
| } |
| |
| func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { |
| sdk := variant.(*SdkLibrary) |
| |
| // Copy the stem name for files in the sdk snapshot. |
| s.Stem = sdk.distStem() |
| |
| s.Scopes = make(map[*apiScope]*scopeProperties) |
| for _, apiScope := range AllApiScopes { |
| paths := sdk.findScopePaths(apiScope) |
| if paths == nil { |
| continue |
| } |
| |
| jars := paths.stubsImplPath |
| if len(jars) > 0 { |
| properties := scopeProperties{} |
| properties.Jars = jars |
| properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope) |
| properties.StubsSrcJar = paths.stubsSrcJar.Path() |
| if paths.currentApiFilePath.Valid() { |
| properties.CurrentApiFile = paths.currentApiFilePath.Path() |
| } |
| if paths.removedApiFilePath.Valid() { |
| properties.RemovedApiFile = paths.removedApiFilePath.Path() |
| } |
| // The annotations zip is only available for modules that set annotations_enabled: true. |
| if paths.annotationsZip.Valid() { |
| properties.AnnotationsZip = paths.annotationsZip.Path() |
| } |
| s.Scopes[apiScope] = &properties |
| } |
| } |
| |
| s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary()) |
| s.Compile_dex = sdk.dexProperties.Compile_dex |
| s.Doctag_paths = sdk.doctagPaths |
| s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars() |
| s.On_bootclasspath_since = sdk.commonSdkLibraryProperties.On_bootclasspath_since |
| s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before |
| s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk |
| s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk |
| |
| implLibrary := sdk.implLibraryModule |
| if implLibrary != nil && implLibrary.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided { |
| s.DexPreoptProfileGuided = proptools.BoolPtr(true) |
| } |
| } |
| |
| func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { |
| if s.Naming_scheme != nil { |
| propertySet.AddProperty("naming_scheme", proptools.String(s.Naming_scheme)) |
| } |
| if s.Shared_library != nil { |
| propertySet.AddProperty("shared_library", *s.Shared_library) |
| } |
| if s.Compile_dex != nil { |
| propertySet.AddProperty("compile_dex", *s.Compile_dex) |
| } |
| if len(s.Permitted_packages) > 0 { |
| propertySet.AddProperty("permitted_packages", s.Permitted_packages) |
| } |
| dexPreoptSet := propertySet.AddPropertySet("dex_preopt") |
| if s.DexPreoptProfileGuided != nil { |
| dexPreoptSet.AddProperty("profile_guided", proptools.Bool(s.DexPreoptProfileGuided)) |
| } |
| |
| stem := s.Stem |
| |
| for _, apiScope := range AllApiScopes { |
| if properties, ok := s.Scopes[apiScope]; ok { |
| scopeSet := propertySet.AddPropertySet(apiScope.propertyName) |
| |
| scopeDir := apiScope.snapshotRelativeDir() |
| |
| var jars []string |
| for _, p := range properties.Jars { |
| dest := filepath.Join(scopeDir, stem+"-stubs.jar") |
| ctx.SnapshotBuilder().CopyToSnapshot(p, dest) |
| jars = append(jars, dest) |
| } |
| scopeSet.AddProperty("jars", jars) |
| |
| if ctx.SdkModuleContext().Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_USE_SRCJAR") { |
| // Copy the stubs source jar into the snapshot zip as is. |
| srcJarSnapshotPath := filepath.Join(scopeDir, stem+".srcjar") |
| ctx.SnapshotBuilder().CopyToSnapshot(properties.StubsSrcJar, srcJarSnapshotPath) |
| scopeSet.AddProperty("stub_srcs", []string{srcJarSnapshotPath}) |
| } else { |
| // Merge the stubs source jar into the snapshot zip so that when it is unpacked |
| // the source files are also unpacked. |
| snapshotRelativeDir := filepath.Join(scopeDir, stem+"_stub_sources") |
| ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir) |
| scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir}) |
| } |
| |
| if properties.CurrentApiFile != nil { |
| currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(stem) |
| ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath) |
| scopeSet.AddProperty("current_api", currentApiSnapshotPath) |
| } |
| |
| if properties.RemovedApiFile != nil { |
| removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(stem) |
| ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath) |
| scopeSet.AddProperty("removed_api", removedApiSnapshotPath) |
| } |
| |
| if properties.AnnotationsZip != nil { |
| annotationsSnapshotPath := filepath.Join(scopeDir, stem+"_annotations.zip") |
| ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath) |
| scopeSet.AddProperty("annotations", annotationsSnapshotPath) |
| } |
| |
| if properties.SdkVersion != "" { |
| scopeSet.AddProperty("sdk_version", properties.SdkVersion) |
| } |
| } |
| } |
| |
| if len(s.Doctag_paths) > 0 { |
| dests := []string{} |
| for _, p := range s.Doctag_paths { |
| dest := filepath.Join("doctags", p.Rel()) |
| ctx.SnapshotBuilder().CopyToSnapshot(p, dest) |
| dests = append(dests, dest) |
| } |
| propertySet.AddProperty("doctag_files", dests) |
| } |
| } |