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