1// Copyright 2024 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package java 16 17import ( 18 "fmt" 19 "path" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/etc" 24 25 "github.com/google/blueprint/proptools" 26) 27 28// --------------------------------------------------------------------------------------------- 29// Naming scheme of the submodules generated by java_sdk_library and java_sdk_library_import 30// --------------------------------------------------------------------------------------------- 31 32const ( 33 sdkXmlFileSuffix = ".xml" 34 implLibSuffix = ".impl" 35) 36 37func implLibraryModuleName(sdkLibName string) string { 38 return sdkLibName + implLibSuffix 39} 40 41// Module name of the runtime implementation library 42func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string { 43 return implLibraryModuleName(c.module.RootLibraryName()) 44} 45 46// Module name of the XML file for the lib 47func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string { 48 return c.module.RootLibraryName() + sdkXmlFileSuffix 49} 50 51// Name of the java_library module that compiles the stubs source. 52func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string { 53 baseName := c.module.RootLibraryName() 54 return apiScope.stubsLibraryModuleName(baseName) 55} 56 57// Name of the java_library module that compiles the exportable stubs source. 58func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string { 59 baseName := c.module.RootLibraryName() 60 return apiScope.exportableStubsLibraryModuleName(baseName) 61} 62 63// Name of the droidstubs module that generates the stubs source and may also 64// generate/check the API. 65func (c *commonToSdkLibraryAndImport) droidstubsModuleName(apiScope *apiScope) string { 66 baseName := c.module.RootLibraryName() 67 return apiScope.stubsSourceModuleName(baseName) 68} 69 70// Name of the java_api_library module that generates the from-text stubs source 71// and compiles to a jar file. 72func (c *commonToSdkLibraryAndImport) fromTextStubsLibraryModuleName(apiScope *apiScope) string { 73 baseName := c.module.RootLibraryName() 74 return apiScope.apiLibraryModuleName(baseName) 75} 76 77// Name of the java_library module that compiles the stubs 78// generated from source Java files. 79func (c *commonToSdkLibraryAndImport) fromSourceStubsLibraryModuleName(apiScope *apiScope) string { 80 baseName := c.module.RootLibraryName() 81 return apiScope.sourceStubsLibraryModuleName(baseName) 82} 83 84// Name of the java_library module that compiles the exportable stubs 85// generated from source Java files. 86func (c *commonToSdkLibraryAndImport) exportableFromSourceStubsLibraryModuleName(apiScope *apiScope) string { 87 baseName := c.module.RootLibraryName() 88 return apiScope.exportableSourceStubsLibraryModuleName(baseName) 89} 90 91// --------------------------------------------------------------------------------------------- 92// Build rules of the submodules generated by java_sdk_library. 93// java_sdk_library "framework-foo" generates the following submodules: 94// 95// - "framework-foo.impl" (type: [Library]): the implementation library, which generates the 96// compilation outputs that include the implementation details and the private apis 97// (i.e. class/methods that are annotated @hide). 98// 99// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [Droidstubs]): droidstubs module that 100// generates the stubs and the api files for the given api scope. 101// 102// - "framework-foo.stubs.<[apiScope.name]>" (type: [Library]): stub library module that 103// provides the compilation output of the stubs to the reverse dependencies. The module 104// itself does not perform any compilation actions; the module statically depends on one of 105// the from-source stub module or the from-text stub configuration based on the build 106// configuration. 107// 108// - "framework-foo.stubs.<[apiScope.name]>.from-source" (type: [Library]): stub library module 109// that compiles the stubs generated by the droidstubs submodule. This module is a static 110// dependency of the stub library module when 111// [android/soong/android/config.BuildFromTextStub()] is false. 112// 113// - "framework-foo.stubs.<[apiScope.name]>.from-text" (type: [ApiLibrary]): api library module 114// that generates and compiles the stubs from the api files checked in the tree instead of 115// the source Java files (e.g. *-current.txt files). This module is a static dependency of 116// the stub library module when [android/soong/android/config.BuildFromTextStub()] is true. 117// 118// - "framework-foo.stubs.exportable.<[apiScope.name]>" (type: [Library]): stub library module 119// that provides the "exportable" stubs. "exportable" stubs are the stubs that do not 120// include in-development flagged apis. This module is only used for SDK builds to generate 121// the SDK artifacts, and not purposed for consumption for other modules. 122// 123// - "framework-foo.stubs.exportable.<[apiScope.name]>.from-source" (type: [Library]): stub 124// library module that compiles the "exportable" stubs generated by the droidstubs 125// submodule. This module is always a static dependency of the "exportable" stub library 126// module given that from-text stubs cannot be used for SDK builds as it does not contain 127// documentations. 128// 129// - "framework-foo.xml" (type: [sdkLibraryXml]): xml library that generates the permission xml 130// file, which allows [SdkLibrary] to be used with <uses-permission> tag in the 131// AndroidManifest.xml files. 132// --------------------------------------------------------------------------------------------- 133 134// Creates the implementation [Library] with ".impl" suffix. 135func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) { 136 visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility) 137 138 staticLibs := module.properties.Static_libs.Clone() 139 staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs) 140 props := struct { 141 Name *string 142 Enabled proptools.Configurable[bool] 143 Visibility []string 144 Libs []string 145 Static_libs proptools.Configurable[[]string] 146 Apex_available []string 147 Stem *string 148 }{ 149 Name: proptools.StringPtr(module.implLibraryModuleName()), 150 Enabled: module.EnabledProperty(), 151 Visibility: visibility, 152 153 Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...), 154 155 Static_libs: staticLibs, 156 // Pass the apex_available settings down so that the impl library can be statically 157 // embedded within a library that is added to an APEX. Needed for updatable-media. 158 Apex_available: module.ApexAvailable(), 159 160 Stem: proptools.StringPtr(module.Name()), 161 } 162 163 properties := []interface{}{ 164 &module.properties, 165 &module.protoProperties, 166 &module.deviceProperties, 167 &module.dexProperties, 168 &module.dexpreoptProperties, 169 &module.linter.properties, 170 &module.overridableProperties, 171 &props, 172 module.sdkComponentPropertiesForChildLibrary(), 173 } 174 mctx.CreateModule(LibraryFactory, properties...) 175} 176 177// getApiSurfaceForScope returns the api surface name to use for the apiScope. If one is specified 178// in the corresponding ApiScopeProperties.Api_surface property that is used, otherwise the name of 179// the apiScope is used. 180func (module *SdkLibrary) getApiSurfaceForScope(apiScope *apiScope) *string { 181 scopeProperties := module.scopeToProperties[apiScope] 182 183 apiSurface := scopeProperties.Api_surface 184 if apiSurface == nil { 185 apiSurface = &apiScope.name 186 } 187 188 return apiSurface 189} 190 191// Creates the [Droidstubs] module with ".stubs.source.<[apiScope.name]>" that creates stubs 192// source files from the given full source files and also updates and checks the API 193// specification files (i.e. "*-current.txt", "*-removed.txt" files). 194func (module *SdkLibrary) createDroidstubs(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) { 195 props := struct { 196 Name *string 197 Enabled proptools.Configurable[bool] 198 Visibility []string 199 Srcs []string 200 Installable *bool 201 Sdk_version *string 202 Api_surface *string 203 System_modules *string 204 Libs proptools.Configurable[[]string] 205 Output_javadoc_comments *bool 206 Arg_files []string 207 Args *string 208 Java_version *string 209 Annotations_enabled *bool 210 Merge_annotations_dirs []string 211 Merge_inclusion_annotations_dirs []string 212 Generate_stubs *bool 213 Previous_api *string 214 Aconfig_declarations []string 215 Check_api struct { 216 Current ApiToCheck 217 Last_released ApiToCheck 218 219 Api_lint struct { 220 Enabled *bool 221 New_since *string 222 Baseline_file *string 223 } 224 } 225 Aidl struct { 226 Include_dirs []string 227 Local_include_dirs []string 228 } 229 Dists []android.Dist 230 }{} 231 232 // The stubs source processing uses the same compile time classpath when extracting the 233 // API from the implementation library as it does when compiling it. i.e. the same 234 // * sdk version 235 // * system_modules 236 // * libs (static_libs/libs) 237 238 props.Name = proptools.StringPtr(name) 239 props.Enabled = module.EnabledProperty() 240 props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility) 241 props.Srcs = append(props.Srcs, module.properties.Srcs...) 242 props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...) 243 props.Sdk_version = module.deviceProperties.Sdk_version 244 props.Api_surface = module.getApiSurfaceForScope(apiScope) 245 props.System_modules = module.deviceProperties.System_modules 246 props.Installable = proptools.BoolPtr(false) 247 // A droiddoc module has only one Libs property and doesn't distinguish between 248 // shared libs and static libs. So we need to add both of these libs to Libs property. 249 props.Libs = proptools.NewConfigurable[[]string](nil, nil) 250 props.Libs.AppendSimpleValue(module.properties.Libs) 251 props.Libs.Append(module.properties.Static_libs) 252 props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) 253 props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) 254 props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs 255 props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs 256 props.Java_version = module.properties.Java_version 257 258 props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled 259 props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs 260 props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs 261 props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations 262 263 droidstubsArgs := []string{} 264 if len(module.sdkLibraryProperties.Api_packages) != 0 { 265 droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":")) 266 } 267 droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...) 268 disabledWarnings := []string{"HiddenSuperclass"} 269 if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) { 270 disabledWarnings = append(disabledWarnings, 271 "BroadcastBehavior", 272 "DeprecationMismatch", 273 "MissingPermission", 274 "SdkConstant", 275 "Todo", 276 ) 277 } 278 droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) 279 280 // Output Javadoc comments for public scope. 281 if apiScope == apiScopePublic { 282 props.Output_javadoc_comments = proptools.BoolPtr(true) 283 } 284 285 // Add in scope specific arguments. 286 droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...) 287 props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files 288 props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " ")) 289 290 // List of APIs identified from the provided source files are created. They are later 291 // compared against to the not-yet-released (a.k.a current) list of APIs and to the 292 // last-released (a.k.a numbered) list of API. 293 currentApiFileName := apiScope.apiFilePrefix + "current.txt" 294 removedApiFileName := apiScope.apiFilePrefix + "removed.txt" 295 apiDir := module.getApiDir() 296 currentApiFileName = path.Join(apiDir, currentApiFileName) 297 removedApiFileName = path.Join(apiDir, removedApiFileName) 298 299 // check against the not-yet-release API 300 props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) 301 props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) 302 303 if module.compareAgainstLatestApi(apiScope) { 304 // check against the latest released API 305 latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) 306 props.Previous_api = latestApiFilegroupName 307 props.Check_api.Last_released.Api_file = latestApiFilegroupName 308 props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( 309 module.latestRemovedApiFilegroupName(apiScope)) 310 props.Check_api.Last_released.Baseline_file = proptools.StringPtr( 311 module.latestIncompatibilitiesFilegroupName(apiScope)) 312 313 if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) { 314 // Enable api lint. 315 props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true) 316 props.Check_api.Api_lint.New_since = latestApiFilegroupName 317 318 // If it exists then pass a lint-baseline.txt through to droidstubs. 319 baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt") 320 baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath) 321 paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil) 322 if err != nil { 323 mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err) 324 } 325 if len(paths) == 1 { 326 props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath) 327 } else if len(paths) != 0 { 328 mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths) 329 } 330 } 331 } 332 333 if !Bool(module.sdkLibraryProperties.No_dist) { 334 // Dist the api txt and removed api txt artifacts for sdk builds. 335 distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api")) 336 stubsTypeTagPrefix := "" 337 if mctx.Config().ReleaseHiddenApiExportableStubs() { 338 stubsTypeTagPrefix = ".exportable" 339 } 340 for _, p := range []struct { 341 tag string 342 pattern string 343 }{ 344 // "exportable" api files are copied to the dist directory instead of the 345 // "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag 346 // is set. Otherwise, the "everything" api files are copied to the dist directory. 347 {tag: "%s.api.txt", pattern: "%s.txt"}, 348 {tag: "%s.removed-api.txt", pattern: "%s-removed.txt"}, 349 } { 350 props.Dists = append(props.Dists, android.Dist{ 351 Targets: []string{"sdk", "win_sdk"}, 352 Dir: distDir, 353 Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())), 354 Tag: proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)), 355 }) 356 } 357 } 358 359 mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx) 360} 361 362type libraryProperties struct { 363 Name *string 364 Enabled proptools.Configurable[bool] 365 Visibility []string 366 Srcs []string 367 Installable *bool 368 Sdk_version *string 369 System_modules *string 370 Patch_module *string 371 Libs []string 372 Static_libs []string 373 Compile_dex *bool 374 Java_version *string 375 Openjdk9 struct { 376 Srcs []string 377 Javacflags []string 378 } 379 Dist struct { 380 Targets []string 381 Dest *string 382 Dir *string 383 Tag *string 384 } 385 Is_stubs_module *bool 386 Stub_contributing_api *string 387} 388 389func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties { 390 props := libraryProperties{} 391 props.Enabled = module.EnabledProperty() 392 props.Visibility = []string{"//visibility:override", "//visibility:private"} 393 // sources are generated from the droiddoc 394 sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) 395 props.Sdk_version = proptools.StringPtr(sdkVersion) 396 props.System_modules = module.deviceProperties.System_modules 397 props.Patch_module = module.properties.Patch_module 398 props.Installable = proptools.BoolPtr(false) 399 props.Libs = module.sdkLibraryProperties.Stub_only_libs 400 props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...) 401 props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs 402 // The stub-annotations library contains special versions of the annotations 403 // with CLASS retention policy, so that they're kept. 404 if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { 405 props.Libs = append(props.Libs, "stub-annotations") 406 } 407 props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs 408 props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags 409 // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential 410 // interop with older developer tools that don't support 1.9. 411 props.Java_version = proptools.StringPtr("1.8") 412 props.Is_stubs_module = proptools.BoolPtr(true) 413 props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) 414 415 return props 416} 417 418// Creates the from-source stub [Library] with ".stubs.<[apiScope.name]>.from-source" suffix. 419func (module *SdkLibrary) createFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { 420 421 props := module.stubsLibraryProps(mctx, apiScope) 422 props.Name = proptools.StringPtr(module.fromSourceStubsLibraryModuleName(apiScope)) 423 props.Srcs = []string{":" + module.droidstubsModuleName(apiScope)} 424 425 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 426} 427 428// Creates the "exportable" from-source stub [Library] with 429// ".stubs.exportable.<[apiScope.name]>" suffix. 430func (module *SdkLibrary) createExportableFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { 431 props := module.stubsLibraryProps(mctx, apiScope) 432 props.Name = proptools.StringPtr(module.exportableFromSourceStubsLibraryModuleName(apiScope)) 433 props.Srcs = []string{":" + module.droidstubsModuleName(apiScope) + "{.exportable}"} 434 435 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 436} 437 438// Creates the from-text stub [ApiLibrary] with ".stubs.<[apiScope.name]>.from-text" suffix. 439func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { 440 props := struct { 441 Name *string 442 Enabled proptools.Configurable[bool] 443 Visibility []string 444 Api_contributions []string 445 Libs proptools.Configurable[[]string] 446 Static_libs []string 447 System_modules *string 448 Enable_validation *bool 449 Stubs_type *string 450 Sdk_version *string 451 Previous_api *string 452 }{} 453 454 props.Name = proptools.StringPtr(module.fromTextStubsLibraryModuleName(apiScope)) 455 props.Enabled = module.EnabledProperty() 456 props.Visibility = []string{"//visibility:override", "//visibility:private"} 457 458 apiContributions := []string{} 459 460 // Api surfaces are not independent of each other, but have subset relationships, 461 // and so does the api files. To generate from-text stubs for api surfaces other than public, 462 // all subset api domains' api_contriubtions must be added as well. 463 scope := apiScope 464 for scope != nil { 465 apiContributions = append(apiContributions, module.droidstubsModuleName(scope)+".api.contribution") 466 scope = scope.extends 467 } 468 if apiScope == apiScopePublic { 469 additionalApiContribution := module.apiLibraryAdditionalApiContribution() 470 if additionalApiContribution != "" { 471 apiContributions = append(apiContributions, additionalApiContribution) 472 } 473 } 474 475 props.Api_contributions = apiContributions 476 477 // Ensure that stub-annotations is added to the classpath before any other libs 478 props.Libs = proptools.NewConfigurable[[]string](nil, nil) 479 props.Libs.AppendSimpleValue([]string{"stub-annotations"}) 480 props.Libs.AppendSimpleValue(module.properties.Libs) 481 props.Libs.Append(module.properties.Static_libs) 482 props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) 483 props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) 484 props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs 485 486 props.System_modules = module.deviceProperties.System_modules 487 props.Enable_validation = proptools.BoolPtr(true) 488 props.Stubs_type = proptools.StringPtr("everything") 489 490 if module.deviceProperties.Sdk_version != nil { 491 props.Sdk_version = module.deviceProperties.Sdk_version 492 } 493 494 if module.compareAgainstLatestApi(apiScope) { 495 // check against the latest released API 496 latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) 497 props.Previous_api = latestApiFilegroupName 498 } 499 500 mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 501} 502 503func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties { 504 props := libraryProperties{} 505 506 props.Enabled = module.EnabledProperty() 507 props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) 508 sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) 509 props.Sdk_version = proptools.StringPtr(sdkVersion) 510 511 props.System_modules = module.deviceProperties.System_modules 512 513 // The imports need to be compiled to dex if the java_sdk_library requests it. 514 compileDex := module.dexProperties.Compile_dex 515 if module.stubLibrariesCompiledForDex() { 516 compileDex = proptools.BoolPtr(true) 517 } 518 props.Compile_dex = compileDex 519 520 props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) 521 522 if !Bool(module.sdkLibraryProperties.No_dist) && doDist { 523 props.Dist.Targets = []string{"sdk", "win_sdk"} 524 props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem())) 525 props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope)) 526 props.Dist.Tag = proptools.StringPtr(".jar") 527 } 528 props.Is_stubs_module = proptools.BoolPtr(true) 529 530 return props 531} 532 533// Creates the stub [Library] with ".stubs.<[apiScope.name]>" suffix. 534func (module *SdkLibrary) createTopLevelStubsLibrary( 535 mctx android.DefaultableHookContext, apiScope *apiScope) { 536 537 // Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false 538 doDist := !mctx.Config().ReleaseHiddenApiExportableStubs() 539 props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) 540 props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) 541 542 // Add the stub compiling java_library/java_api_library as static lib based on build config 543 staticLib := module.fromSourceStubsLibraryModuleName(apiScope) 544 if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() { 545 staticLib = module.fromTextStubsLibraryModuleName(apiScope) 546 } 547 props.Static_libs = append(props.Static_libs, staticLib) 548 549 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 550} 551 552// Creates the "exportable" stub [Library] with ".stubs.exportable.<[apiScope.name]>" suffix. 553func (module *SdkLibrary) createTopLevelExportableStubsLibrary( 554 mctx android.DefaultableHookContext, apiScope *apiScope) { 555 556 // Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true 557 doDist := mctx.Config().ReleaseHiddenApiExportableStubs() 558 props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) 559 props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope)) 560 561 staticLib := module.exportableFromSourceStubsLibraryModuleName(apiScope) 562 props.Static_libs = append(props.Static_libs, staticLib) 563 564 mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 565} 566 567// Creates the [sdkLibraryXml] with ".xml" suffix. 568func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { 569 moduleMinApiLevel := module.Library.MinSdkVersion(mctx) 570 var moduleMinApiLevelStr = moduleMinApiLevel.String() 571 if moduleMinApiLevel == android.NoneApiLevel { 572 moduleMinApiLevelStr = "current" 573 } 574 props := struct { 575 Name *string 576 Enabled proptools.Configurable[bool] 577 Lib_name *string 578 Apex_available []string 579 On_bootclasspath_since *string 580 On_bootclasspath_before *string 581 Min_device_sdk *string 582 Max_device_sdk *string 583 Sdk_library_min_api_level *string 584 Uses_libs_dependencies proptools.Configurable[[]string] 585 }{ 586 Name: proptools.StringPtr(module.xmlPermissionsModuleName()), 587 Enabled: module.EnabledProperty(), 588 Lib_name: proptools.StringPtr(module.BaseModuleName()), 589 Apex_available: module.ApexProperties.Apex_available, 590 On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since, 591 On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before, 592 Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk, 593 Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk, 594 Sdk_library_min_api_level: &moduleMinApiLevelStr, 595 Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs.Clone(), 596 } 597 598 mctx.CreateModule(sdkLibraryXmlFactory, &props) 599} 600 601// --------------------------------------------------------------------------------------------- 602// Build rules of the submodules generated by java_sdk_library_import. 603// Note that the java_sdk_library_import module does not generate the implementation library. 604// Instead, it will create a dependency to the source implemenetation library if one exists. 605// java_sdk_library_import "framework-foo" generates the following submodules: 606// 607// - "framework-foo.stubs.<[apiScope.name]>" (type: [Import]): prebuilt stub library module that 608// provides the stub jar file checked in the tree. 609// 610// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [PrebuiltStubsSources]): prebuilt 611// droidstubs module that provides the stub source jar file checked in the tree. 612// 613// - "framework-foo.stubs.source.<[apiScope.name]>.api.contribution" 614// (type [JavaApiContributionImport]): prebuilt java_api_contribution module that provides 615// the prebuilt api file for previously released from-text stub generation. 616// --------------------------------------------------------------------------------------------- 617 618// Creates the prebuilt stub [Import] with ".stubs.<[apiScope.name]>" suffix. 619func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { 620 // Creates a java import for the jar with ".stubs" suffix 621 props := struct { 622 Name *string 623 Source_module_name *string 624 Created_by_java_sdk_library_name *string 625 Sdk_version *string 626 Libs []string 627 Jars []string 628 Compile_dex *bool 629 Is_stubs_module *bool 630 631 android.UserSuppliedPrebuiltProperties 632 }{} 633 props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) 634 props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName())) 635 props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) 636 props.Sdk_version = scopeProperties.Sdk_version 637 // Prepend any of the libs from the legacy public properties to the libs for each of the 638 // scopes to avoid having to duplicate them in each scope. 639 props.Libs = append(module.properties.Libs, scopeProperties.Libs...) 640 props.Jars = scopeProperties.Jars 641 642 // The imports are preferred if the java_sdk_library_import is preferred. 643 props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) 644 645 // The imports need to be compiled to dex if the java_sdk_library_import requests it. 646 compileDex := module.properties.Compile_dex 647 if module.stubLibrariesCompiledForDex() { 648 compileDex = proptools.BoolPtr(true) 649 } 650 props.Compile_dex = compileDex 651 props.Is_stubs_module = proptools.BoolPtr(true) 652 653 mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 654} 655 656func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { 657 props := struct { 658 Name *string 659 Source_module_name *string 660 Created_by_java_sdk_library_name *string 661 Srcs []string 662 663 android.UserSuppliedPrebuiltProperties 664 }{} 665 props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope)) 666 props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName())) 667 props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) 668 props.Srcs = scopeProperties.Stub_srcs 669 670 // The stubs source is preferred if the java_sdk_library_import is preferred. 671 props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) 672 673 mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 674} 675 676// Creates the prebuilt api contribution [JavaApiContributionImport] with 677// ".stubs.source.<[apiScope.name]>.api.contribution" suffix. 678func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { 679 api_file := scopeProperties.Current_api 680 api_surface := &apiScope.name 681 682 props := struct { 683 Name *string 684 Source_module_name *string 685 Created_by_java_sdk_library_name *string 686 Api_surface *string 687 Api_file *string 688 Visibility []string 689 }{} 690 691 props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope) + ".api.contribution") 692 props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution") 693 props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) 694 props.Api_surface = api_surface 695 props.Api_file = api_file 696 props.Visibility = []string{"//visibility:override", "//visibility:public"} 697 698 mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) 699} 700 701// --------------------------------------------------------------------------------------------- 702// End of the build rules of the submodules generated by java_sdk_library_import. 703// --------------------------------------------------------------------------------------------- 704 705// Definition of the [sdkLibraryXml] module. The module generates the permissions xml file, 706// so that the apps can specify the java_sdk_library using <uses-permission> tag in the 707// AndroidManifest.xml file. 708type sdkLibraryXml struct { 709 android.ModuleBase 710 android.DefaultableModuleBase 711 android.ApexModuleBase 712 713 properties sdkLibraryXmlProperties 714 715 outputFilePath android.OutputPath 716 installDirPath android.InstallPath 717 718 hideApexVariantFromMake bool 719} 720 721type sdkLibraryXmlProperties struct { 722 // canonical name of the lib 723 Lib_name *string 724 725 // Signals that this shared library is part of the bootclasspath starting 726 // on the version indicated in this attribute. 727 // 728 // This will make platforms at this level and above to ignore 729 // <uses-library> tags with this library name because the library is already 730 // available 731 On_bootclasspath_since *string 732 733 // Signals that this shared library was part of the bootclasspath before 734 // (but not including) the version indicated in this attribute. 735 // 736 // The system will automatically add a <uses-library> tag with this library to 737 // apps that target any SDK less than the version indicated in this attribute. 738 On_bootclasspath_before *string 739 740 // Indicates that PackageManager should ignore this shared library if the 741 // platform is below the version indicated in this attribute. 742 // 743 // This means that the device won't recognise this library as installed. 744 Min_device_sdk *string 745 746 // Indicates that PackageManager should ignore this shared library if the 747 // platform is above the version indicated in this attribute. 748 // 749 // This means that the device won't recognise this library as installed. 750 Max_device_sdk *string 751 752 // The SdkLibrary's min api level as a string 753 // 754 // This value comes from the ApiLevel of the MinSdkVersion property. 755 Sdk_library_min_api_level *string 756 757 // Uses-libs dependencies that the shared library requires to work correctly. 758 // 759 // This will add dependency="foo:bar" to the <library> section. 760 Uses_libs_dependencies proptools.Configurable[[]string] 761} 762 763// java_sdk_library_xml builds the permission xml file for a java_sdk_library. 764// Not to be used directly by users. java_sdk_library internally uses this. 765func sdkLibraryXmlFactory() android.Module { 766 module := &sdkLibraryXml{} 767 768 module.AddProperties(&module.properties) 769 770 android.InitApexModule(module) 771 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 772 773 return module 774} 775 776func (module *sdkLibraryXml) UniqueApexVariations() bool { 777 // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the 778 // mounted APEX, which contains the name of the APEX. 779 return true 780} 781 782// from android.PrebuiltEtcModule 783func (module *sdkLibraryXml) BaseDir() string { 784 return "etc" 785} 786 787// from android.PrebuiltEtcModule 788func (module *sdkLibraryXml) SubDir() string { 789 return "permissions" 790} 791 792var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil) 793 794// from android.ApexModule 795func (module *sdkLibraryXml) AvailableFor(what string) bool { 796 return android.CheckAvailableForApex(what, module.ApexAvailableFor()) 797} 798 799func (module *sdkLibraryXml) ApexAvailableFor() []string { 800 return []string{android.AvailableToPlatform, android.AvailableToAnyApex} 801} 802 803func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { 804 // do nothing 805} 806 807var _ android.ApexModule = (*sdkLibraryXml)(nil) 808 809// Implements android.ApexModule 810func (m *sdkLibraryXml) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { 811 return android.MinApiLevel 812} 813 814// File path to the runtime implementation library 815func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string { 816 implName := proptools.String(module.properties.Lib_name) 817 if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() { 818 // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name. 819 // In most cases, this works fine. But when apex_name is set or override_apex is used 820 // this can be wrong. 821 return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.BaseApexName, implName) 822 } 823 partition := "system" 824 if module.SocSpecific() { 825 partition = "vendor" 826 } else if module.DeviceSpecific() { 827 partition = "odm" 828 } else if module.ProductSpecific() { 829 partition = "product" 830 } else if module.SystemExtSpecific() { 831 partition = "system_ext" 832 } 833 return "/" + partition + "/framework/" + implName + ".jar" 834} 835 836func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string { 837 if value == nil { 838 return "" 839 } 840 apiLevel, err := android.ApiLevelFromUser(ctx, *value) 841 if err != nil { 842 // attributes in bp files have underscores but in the xml have dashes. 843 ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error()) 844 return "" 845 } 846 if apiLevel.IsCurrent() { 847 // passing "current" would always mean a future release, never the current (or the current in 848 // progress) which means some conditions would never be triggered. 849 ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), 850 `"current" is not an allowed value for this attribute`) 851 return "" 852 } 853 // "safeValue" is safe because it translates finalized codenames to a string 854 // with their SDK int. 855 safeValue := apiLevel.String() 856 return formattedOptionalAttribute(attrName, &safeValue) 857} 858 859// formats an attribute for the xml permissions file if the value is not null 860// returns empty string otherwise 861func formattedOptionalAttribute(attrName string, value *string) string { 862 if value == nil { 863 return "" 864 } 865 return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value) 866} 867 868func formattedDependenciesAttribute(dependencies []string) string { 869 if dependencies == nil { 870 return "" 871 } 872 return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":")) 873} 874 875func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string { 876 libName := proptools.String(module.properties.Lib_name) 877 libNameAttr := formattedOptionalAttribute("name", &libName) 878 filePath := module.implPath(ctx) 879 filePathAttr := formattedOptionalAttribute("file", &filePath) 880 implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since) 881 implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before) 882 minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk) 883 maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk) 884 dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies.GetOrDefault(ctx, nil)) 885 // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that). 886 // 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 887 var libraryTag string 888 if module.properties.Min_device_sdk != nil { 889 libraryTag = " <apex-library\n" 890 } else { 891 libraryTag = " <library\n" 892 } 893 894 return strings.Join([]string{ 895 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", 896 "<!-- Copyright (C) 2018 The Android Open Source Project\n", 897 "\n", 898 " Licensed under the Apache License, Version 2.0 (the \"License\");\n", 899 " you may not use this file except in compliance with the License.\n", 900 " You may obtain a copy of the License at\n", 901 "\n", 902 " http://www.apache.org/licenses/LICENSE-2.0\n", 903 "\n", 904 " Unless required by applicable law or agreed to in writing, software\n", 905 " distributed under the License is distributed on an \"AS IS\" BASIS,\n", 906 " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", 907 " See the License for the specific language governing permissions and\n", 908 " limitations under the License.\n", 909 "-->\n", 910 "<permissions>\n", 911 libraryTag, 912 libNameAttr, 913 filePathAttr, 914 implicitFromAttr, 915 implicitUntilAttr, 916 minSdkAttr, 917 maxSdkAttr, 918 dependenciesAttr, 919 " />\n", 920 "</permissions>\n", 921 }, "") 922} 923 924func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) { 925 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 926 module.hideApexVariantFromMake = !apexInfo.IsForPlatform() 927 928 libName := proptools.String(module.properties.Lib_name) 929 module.selfValidate(ctx) 930 xmlContent := module.permissionsContents(ctx) 931 932 module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath 933 android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent) 934 935 module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir()) 936 ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath) 937 938 ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "") 939 940 etc.SetCommonPrebuiltEtcInfo(ctx, module) 941} 942 943func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { 944 if module.hideApexVariantFromMake { 945 return []android.AndroidMkEntries{{ 946 Disabled: true, 947 }} 948 } 949 950 return []android.AndroidMkEntries{{ 951 Class: "ETC", 952 OutputFile: android.OptionalPathForPath(module.outputFilePath), 953 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 954 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 955 entries.SetString("LOCAL_MODULE_TAGS", "optional") 956 entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String()) 957 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base()) 958 }, 959 }, 960 }} 961} 962 963func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) { 964 module.validateAtLeastTAttributes(ctx) 965 module.validateMinAndMaxDeviceSdk(ctx) 966 module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx) 967 module.validateOnBootclasspathBeforeRequirements(ctx) 968} 969 970func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) { 971 t := android.ApiLevelOrPanic(ctx, "Tiramisu") 972 module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk") 973 module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk") 974 module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before") 975 module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since") 976} 977 978func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) { 979 if attr != nil { 980 if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil { 981 // we will inform the user of invalid inputs when we try to write the 982 // permissions xml file so we don't need to do it here 983 if t.GreaterThan(level) { 984 ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T") 985 } 986 } 987 } 988} 989 990func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) { 991 if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil { 992 min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) 993 max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) 994 if minErr == nil && maxErr == nil { 995 // we will inform the user of invalid inputs when we try to write the 996 // permissions xml file so we don't need to do it here 997 if min.GreaterThan(max) { 998 ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk") 999 } 1000 } 1001 } 1002} 1003 1004func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) { 1005 moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) 1006 if module.properties.Min_device_sdk != nil { 1007 api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) 1008 if err == nil { 1009 if moduleMinApi.GreaterThan(api) { 1010 ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) 1011 } 1012 } 1013 } 1014 if module.properties.Max_device_sdk != nil { 1015 api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) 1016 if err == nil { 1017 if moduleMinApi.GreaterThan(api) { 1018 ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) 1019 } 1020 } 1021 } 1022} 1023 1024func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) { 1025 moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) 1026 if module.properties.On_bootclasspath_before != nil { 1027 t := android.ApiLevelOrPanic(ctx, "Tiramisu") 1028 // if we use the attribute, then we need to do this validation 1029 if moduleMinApi.LessThan(t) { 1030 // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+) 1031 if module.properties.Min_device_sdk == nil { 1032 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") 1033 } 1034 } 1035 } 1036} 1037