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