1// Copyright 2021 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/filepath" 20 "regexp" 21 "strings" 22 23 "github.com/google/blueprint/proptools" 24 25 "android/soong/android" 26 "android/soong/java/config" 27 "android/soong/remoteexec" 28) 29 30// The values allowed for Droidstubs' Api_levels_sdk_type 31var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"} 32 33type StubsType int 34 35const ( 36 Everything StubsType = iota 37 Runtime 38 Exportable 39 Unavailable 40) 41 42func (s StubsType) String() string { 43 switch s { 44 case Everything: 45 return "everything" 46 case Runtime: 47 return "runtime" 48 case Exportable: 49 return "exportable" 50 default: 51 return "" 52 } 53} 54 55func StringToStubsType(s string) StubsType { 56 switch strings.ToLower(s) { 57 case Everything.String(): 58 return Everything 59 case Runtime.String(): 60 return Runtime 61 case Exportable.String(): 62 return Exportable 63 default: 64 return Unavailable 65 } 66} 67 68func init() { 69 RegisterStubsBuildComponents(android.InitRegistrationContext) 70} 71 72func RegisterStubsBuildComponents(ctx android.RegistrationContext) { 73 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory) 74 75 ctx.RegisterModuleType("droidstubs", DroidstubsFactory) 76 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory) 77 78 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory) 79} 80 81type stubsArtifacts struct { 82 nullabilityWarningsFile android.WritablePath 83 annotationsZip android.WritablePath 84 apiVersionsXml android.WritablePath 85 metadataZip android.WritablePath 86 metadataDir android.WritablePath 87} 88 89// Droidstubs 90type Droidstubs struct { 91 Javadoc 92 embeddableInModuleAndImport 93 94 properties DroidstubsProperties 95 apiFile android.Path 96 removedApiFile android.Path 97 98 checkCurrentApiTimestamp android.WritablePath 99 updateCurrentApiTimestamp android.WritablePath 100 checkLastReleasedApiTimestamp android.WritablePath 101 apiLintTimestamp android.WritablePath 102 apiLintReport android.WritablePath 103 104 checkNullabilityWarningsTimestamp android.WritablePath 105 106 everythingArtifacts stubsArtifacts 107 exportableArtifacts stubsArtifacts 108 109 exportableApiFile android.WritablePath 110 exportableRemovedApiFile android.WritablePath 111} 112 113type DroidstubsProperties struct { 114 // The generated public API filename by Metalava, defaults to <module>_api.txt 115 Api_filename *string 116 117 // the generated removed API filename by Metalava, defaults to <module>_removed.txt 118 Removed_api_filename *string 119 120 Check_api struct { 121 Last_released ApiToCheck 122 123 Current ApiToCheck 124 125 Api_lint struct { 126 Enabled *bool 127 128 // If set, performs api_lint on any new APIs not found in the given signature file 129 New_since *string `android:"path"` 130 131 // If not blank, path to the baseline txt file for approved API lint violations. 132 Baseline_file *string `android:"path"` 133 } 134 } 135 136 // user can specify the version of previous released API file in order to do compatibility check. 137 Previous_api *string `android:"path"` 138 139 // is set to true, Metalava will allow framework SDK to contain annotations. 140 Annotations_enabled *bool 141 142 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from. 143 Merge_annotations_dirs []string 144 145 // a list of top-level directories containing Java stub files to merge show/hide annotations from. 146 Merge_inclusion_annotations_dirs []string 147 148 // a file containing a list of classes to do nullability validation for. 149 Validate_nullability_from_list *string 150 151 // a file containing expected warnings produced by validation of nullability annotations. 152 Check_nullability_warnings *string 153 154 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false. 155 Create_doc_stubs *bool 156 157 // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false. 158 // Has no effect if create_doc_stubs: true. 159 Output_javadoc_comments *bool 160 161 // if set to false then do not write out stubs. Defaults to true. 162 // 163 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately. 164 Generate_stubs *bool 165 166 // if set to true, provides a hint to the build system that this rule uses a lot of memory, 167 // which can be used for scheduling purposes 168 High_mem *bool 169 170 // if set to true, Metalava will allow framework SDK to contain API levels annotations. 171 Api_levels_annotations_enabled *bool 172 173 // Apply the api levels database created by this module rather than generating one in this droidstubs. 174 Api_levels_module *string 175 176 // the dirs which Metalava extracts API levels annotations from. 177 Api_levels_annotations_dirs []string 178 179 // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public. 180 Api_levels_sdk_type *string 181 182 // the filename which Metalava extracts API levels annotations from. Defaults to android.jar. 183 Api_levels_jar_filename *string 184 185 // if set to true, collect the values used by the Dev tools and 186 // write them in files packaged with the SDK. Defaults to false. 187 Write_sdk_values *bool 188 189 // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and 190 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info 191 Extensions_info_file *string `android:"path"` 192 193 // API surface of this module. If set, the module contributes to an API surface. 194 // For the full list of available API surfaces, refer to soong/android/sdk_version.go 195 Api_surface *string 196 197 // a list of aconfig_declarations module names that the stubs generated in this module 198 // depend on. 199 Aconfig_declarations []string 200 201 // List of hard coded filegroups containing Metalava config files that are passed to every 202 // Metalava invocation that this module performs. See addMetalavaConfigFilesToCmd. 203 ConfigFiles []string `android:"path" blueprint:"mutated"` 204} 205 206// Used by xsd_config 207type ApiFilePath interface { 208 ApiFilePath(StubsType) (android.Path, error) 209} 210 211type ApiStubsSrcProvider interface { 212 StubsSrcJar(StubsType) (android.Path, error) 213} 214 215// Provider of information about API stubs, used by java_sdk_library. 216type ApiStubsProvider interface { 217 AnnotationsZip(StubsType) (android.Path, error) 218 ApiFilePath 219 RemovedApiFilePath(StubsType) (android.Path, error) 220 221 ApiStubsSrcProvider 222} 223 224type currentApiTimestampProvider interface { 225 CurrentApiTimestamp() android.Path 226} 227 228type annotationFlagsParams struct { 229 migratingNullability bool 230 validatingNullability bool 231 nullabilityWarningsFile android.WritablePath 232 annotationsZip android.WritablePath 233} 234type stubsCommandParams struct { 235 srcJarDir android.ModuleOutPath 236 stubsDir android.OptionalPath 237 stubsSrcJar android.WritablePath 238 metadataZip android.WritablePath 239 metadataDir android.WritablePath 240 apiVersionsXml android.WritablePath 241 nullabilityWarningsFile android.WritablePath 242 annotationsZip android.WritablePath 243 stubConfig stubsCommandConfigParams 244} 245type stubsCommandConfigParams struct { 246 stubsType StubsType 247 javaVersion javaVersion 248 deps deps 249 checkApi bool 250 generateStubs bool 251 doApiLint bool 252 doCheckReleased bool 253 writeSdkValues bool 254 migratingNullability bool 255 validatingNullability bool 256} 257 258// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be 259// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to 260// a droiddoc module to generate documentation. 261func DroidstubsFactory() android.Module { 262 module := &Droidstubs{} 263 264 module.AddProperties(&module.properties, 265 &module.Javadoc.properties) 266 module.properties.ConfigFiles = getMetalavaConfigFilegroupReference() 267 module.initModuleAndImport(module) 268 269 InitDroiddocModule(module, android.HostAndDeviceSupported) 270 271 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { 272 module.createApiContribution(ctx) 273 }) 274 return module 275} 276 277// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API 278// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be 279// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs 280// module when symbols needed by the source files are provided by java_library_host modules. 281func DroidstubsHostFactory() android.Module { 282 module := &Droidstubs{} 283 284 module.AddProperties(&module.properties, 285 &module.Javadoc.properties) 286 287 module.properties.ConfigFiles = getMetalavaConfigFilegroupReference() 288 InitDroiddocModule(module, android.HostSupported) 289 return module 290} 291 292func (d *Droidstubs) AnnotationsZip(stubsType StubsType) (ret android.Path, err error) { 293 switch stubsType { 294 case Everything: 295 ret, err = d.everythingArtifacts.annotationsZip, nil 296 case Exportable: 297 ret, err = d.exportableArtifacts.annotationsZip, nil 298 default: 299 ret, err = nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String()) 300 } 301 return ret, err 302} 303 304func (d *Droidstubs) ApiFilePath(stubsType StubsType) (ret android.Path, err error) { 305 switch stubsType { 306 case Everything: 307 ret, err = d.apiFile, nil 308 case Exportable: 309 ret, err = d.exportableApiFile, nil 310 default: 311 ret, err = nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String()) 312 } 313 if ret == nil && err == nil { 314 err = fmt.Errorf("api file is null for the stub type %s", stubsType.String()) 315 } 316 return ret, err 317} 318 319func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (ret android.Path, err error) { 320 switch stubsType { 321 case Everything: 322 ret, err = d.everythingArtifacts.apiVersionsXml, nil 323 case Exportable: 324 ret, err = d.exportableArtifacts.apiVersionsXml, nil 325 default: 326 ret, err = nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String()) 327 } 328 if ret == nil && err == nil { 329 err = fmt.Errorf("api versions xml file is null for the stub type %s", stubsType.String()) 330 } 331 return ret, err 332} 333 334func (d *Droidstubs) DocZip(stubsType StubsType) (ret android.Path, err error) { 335 switch stubsType { 336 case Everything: 337 ret, err = d.docZip, nil 338 default: 339 ret, err = nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String()) 340 } 341 if ret == nil && err == nil { 342 err = fmt.Errorf("docs zip is null for the stub type %s", stubsType.String()) 343 } 344 return ret, err 345} 346 347func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (ret android.Path, err error) { 348 switch stubsType { 349 case Everything: 350 ret, err = d.removedApiFile, nil 351 case Exportable: 352 ret, err = d.exportableRemovedApiFile, nil 353 default: 354 ret, err = nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String()) 355 } 356 if ret == nil && err == nil { 357 err = fmt.Errorf("removed api file is null for the stub type %s", stubsType.String()) 358 } 359 return ret, err 360} 361 362func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (ret android.Path, err error) { 363 switch stubsType { 364 case Everything: 365 ret, err = d.stubsSrcJar, nil 366 case Exportable: 367 ret, err = d.exportableStubsSrcJar, nil 368 default: 369 ret, err = nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String()) 370 } 371 if ret == nil && err == nil { 372 err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String()) 373 } 374 return ret, err 375} 376 377func (d *Droidstubs) CurrentApiTimestamp() android.Path { 378 return d.checkCurrentApiTimestamp 379} 380 381var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"} 382var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"} 383var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"} 384var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"} 385var metalavaCurrentApiTimestampTag = dependencyTag{name: "metalava-current-api-timestamp-tag"} 386 387func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) { 388 d.Javadoc.addDeps(ctx) 389 390 if len(d.properties.Merge_annotations_dirs) != 0 { 391 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs { 392 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir) 393 } 394 } 395 396 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 { 397 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs { 398 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir) 399 } 400 } 401 402 if len(d.properties.Api_levels_annotations_dirs) != 0 { 403 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs { 404 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir) 405 } 406 } 407 408 if len(d.properties.Aconfig_declarations) != 0 { 409 for _, aconfigDeclarationModuleName := range d.properties.Aconfig_declarations { 410 ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationModuleName) 411 } 412 } 413 414 if d.properties.Api_levels_module != nil { 415 ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module)) 416 } 417} 418 419func (d *Droidstubs) sdkValuesFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, metadataDir android.WritablePath) { 420 cmd.FlagWithArg("--sdk-values ", metadataDir.String()) 421} 422 423func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath, stubsType StubsType, checkApi bool) { 424 425 apiFileName := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt") 426 uncheckedApiFile := android.PathForModuleOut(ctx, stubsType.String(), apiFileName) 427 cmd.FlagWithOutput("--api ", uncheckedApiFile) 428 if checkApi || String(d.properties.Api_filename) != "" { 429 if stubsType == Everything { 430 d.apiFile = uncheckedApiFile 431 } else if stubsType == Exportable { 432 d.exportableApiFile = uncheckedApiFile 433 } 434 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" { 435 if stubsType == Everything { 436 // If check api is disabled then make the source file available for export. 437 d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile) 438 } else if stubsType == Exportable { 439 d.exportableApiFile = uncheckedApiFile 440 } 441 } 442 443 removedApiFileName := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt") 444 uncheckedRemovedFile := android.PathForModuleOut(ctx, stubsType.String(), removedApiFileName) 445 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile) 446 if checkApi || String(d.properties.Removed_api_filename) != "" { 447 if stubsType == Everything { 448 d.removedApiFile = uncheckedRemovedFile 449 } else if stubsType == Exportable { 450 d.exportableRemovedApiFile = uncheckedRemovedFile 451 } 452 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" { 453 if stubsType == Everything { 454 // If check api is disabled then make the source removed api file available for export. 455 d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile) 456 } else if stubsType == Exportable { 457 d.exportableRemovedApiFile = uncheckedRemovedFile 458 } 459 } 460 461 if stubsDir.Valid() { 462 if Bool(d.properties.Create_doc_stubs) { 463 cmd.FlagWithArg("--doc-stubs ", stubsDir.String()) 464 } else { 465 cmd.FlagWithArg("--stubs ", stubsDir.String()) 466 if !Bool(d.properties.Output_javadoc_comments) { 467 cmd.Flag("--exclude-documentation-from-stubs") 468 } 469 } 470 } 471} 472 473func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, params annotationFlagsParams) { 474 if Bool(d.properties.Annotations_enabled) { 475 cmd.Flag(config.MetalavaAnnotationsFlags) 476 477 if params.migratingNullability { 478 previousApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Previous_api)}) 479 cmd.FlagForEachInput("--migrate-nullness ", previousApiFiles) 480 } 481 482 if s := String(d.properties.Validate_nullability_from_list); s != "" { 483 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s)) 484 } 485 486 if params.validatingNullability { 487 cmd.FlagWithOutput("--nullability-warnings-txt ", params.nullabilityWarningsFile) 488 } 489 490 cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip) 491 492 if len(d.properties.Merge_annotations_dirs) != 0 { 493 d.mergeAnnoDirFlags(ctx, cmd) 494 } 495 496 cmd.Flag(config.MetalavaAnnotationsWarningsFlags) 497 } 498} 499 500func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 501 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) { 502 if t, ok := m.(*ExportedDroiddocDir); ok { 503 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps) 504 } else { 505 ctx.PropertyErrorf("merge_annotations_dirs", 506 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) 507 } 508 }) 509} 510 511func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 512 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) { 513 if t, ok := m.(*ExportedDroiddocDir); ok { 514 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps) 515 } else { 516 ctx.PropertyErrorf("merge_inclusion_annotations_dirs", 517 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) 518 } 519 }) 520} 521 522func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) { 523 var apiVersions android.Path 524 if proptools.Bool(d.properties.Api_levels_annotations_enabled) { 525 d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml) 526 apiVersions = apiVersionsXml 527 } else { 528 ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) { 529 if s, ok := m.(*Droidstubs); ok { 530 if stubsType == Everything { 531 apiVersions = s.everythingArtifacts.apiVersionsXml 532 } else if stubsType == Exportable { 533 apiVersions = s.exportableArtifacts.apiVersionsXml 534 } else { 535 ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String()) 536 } 537 } else { 538 ctx.PropertyErrorf("api_levels_module", 539 "module %q is not a droidstubs module", ctx.OtherModuleName(m)) 540 } 541 }) 542 } 543 if apiVersions != nil { 544 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String()) 545 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) 546 cmd.FlagWithInput("--apply-api-levels ", apiVersions) 547 } 548} 549 550// AndroidPlusUpdatableJar is the name of some extra jars added into `module-lib` and 551// `system-server` directories that contain all the APIs provided by the platform and updatable 552// modules because the `android.jar` files do not. See b/337836752. 553const AndroidPlusUpdatableJar = "android-plus-updatable.jar" 554 555func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) { 556 if len(d.properties.Api_levels_annotations_dirs) == 0 { 557 ctx.PropertyErrorf("api_levels_annotations_dirs", 558 "has to be non-empty if api levels annotations was enabled!") 559 } 560 561 cmd.FlagWithOutput("--generate-api-levels ", apiVersionsXml) 562 563 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") 564 565 // TODO: Avoid the duplication of API surfaces, reuse apiScope. 566 // Add all relevant --android-jar-pattern patterns for Metalava. 567 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines 568 // an actual file present on disk (in the order the patterns were passed). For system APIs for 569 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs 570 // for older releases. Similarly, module-lib falls back to system API. 571 var sdkDirs []string 572 apiLevelsSdkType := proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") 573 switch apiLevelsSdkType { 574 case "system-server": 575 sdkDirs = []string{"system-server", "module-lib", "system", "public"} 576 case "module-lib": 577 sdkDirs = []string{"module-lib", "system", "public"} 578 case "system": 579 sdkDirs = []string{"system", "public"} 580 case "public": 581 sdkDirs = []string{"public"} 582 default: 583 ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes) 584 return 585 } 586 587 // Construct a pattern to match the appropriate extensions that should be included in the 588 // generated api-versions.xml file. 589 // 590 // Use the first item in the sdkDirs array as that is the sdk type for the target API levels 591 // being generated but has the advantage over `Api_levels_sdk_type` as it has been validated. 592 // The exception is for system-server which needs to include module-lib and system-server. That 593 // is because while system-server extends module-lib the system-server extension directory only 594 // contains service-* modules which provide system-server APIs it does not list the modules which 595 // only provide a module-lib, so they have to be included separately. 596 extensionSurfacesPattern := sdkDirs[0] 597 if apiLevelsSdkType == "system-server" { 598 // Take the first two items in sdkDirs, which are system-server and module-lib, and construct 599 // a pattern that will match either. 600 extensionSurfacesPattern = strings.Join(sdkDirs[0:2], "|") 601 } 602 extensionsPattern := fmt.Sprintf(`/extensions/[0-9]+/(%s)/.*\.jar`, extensionSurfacesPattern) 603 604 var dirs []string 605 var extensions_dir string 606 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { 607 if t, ok := m.(*ExportedDroiddocDir); ok { 608 extRegex := regexp.MustCompile(t.dir.String() + extensionsPattern) 609 610 // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps; 611 // ideally this should be read from prebuiltApis.properties.Extensions_* 612 for _, dep := range t.deps { 613 // Check to see if it matches an extension first. 614 depBase := dep.Base() 615 if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil { 616 if extensions_dir == "" { 617 extensions_dir = t.dir.String() + "/extensions" 618 } 619 cmd.Implicit(dep) 620 } else if depBase == filename { 621 // Check to see if it matches a dessert release for an SDK, e.g. Android, Car, Wear, etc.. 622 cmd.Implicit(dep) 623 } else if depBase == AndroidPlusUpdatableJar && d.properties.Extensions_info_file != nil { 624 // The output api-versions.xml has been requested to include information on SDK 625 // extensions. That means it also needs to include 626 // so 627 // The module-lib and system-server directories should use `android-plus-updatable.jar` 628 // instead of `android.jar`. See AndroidPlusUpdatableJar for more information. 629 cmd.Implicit(dep) 630 } else if filename != "android.jar" && depBase == "android.jar" { 631 // Metalava implicitly searches these patterns: 632 // prebuilts/tools/common/api-versions/android-%/android.jar 633 // prebuilts/sdk/%/public/android.jar 634 // Add android.jar files from the api_levels_annotations_dirs directories to try 635 // to satisfy these patterns. If Metalava can't find a match for an API level 636 // between 1 and 28 in at least one pattern it will fail. 637 cmd.Implicit(dep) 638 } 639 } 640 641 dirs = append(dirs, t.dir.String()) 642 } else { 643 ctx.PropertyErrorf("api_levels_annotations_dirs", 644 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) 645 } 646 }) 647 648 // Generate the list of --android-jar-pattern options. The order matters so the first one which 649 // matches will be the one that is used for a specific api level.. 650 for _, sdkDir := range sdkDirs { 651 for _, dir := range dirs { 652 addPattern := func(jarFilename string) { 653 cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, jarFilename)) 654 } 655 656 if sdkDir == "module-lib" || sdkDir == "system-server" { 657 // The module-lib and system-server android.jars do not include the updatable modules (as 658 // doing so in the source would introduce dependency cycles and the prebuilts have to 659 // match the sources). So, instead an additional `android-plus-updatable.jar` will be used 660 // that does include the updatable modules and this pattern will match that. This pattern 661 // is added in addition to the following pattern to decouple this change from the change 662 // to add the `android-plus-updatable.jar`. 663 addPattern(AndroidPlusUpdatableJar) 664 } 665 666 addPattern(filename) 667 } 668 } 669 670 if d.properties.Extensions_info_file != nil { 671 if extensions_dir == "" { 672 ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found") 673 } 674 info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file) 675 cmd.Implicit(info_file) 676 cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir) 677 cmd.FlagWithArg("--sdk-extensions-info ", info_file.String()) 678 } 679} 680 681func (d *Droidstubs) apiCompatibilityFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType) { 682 if len(d.Javadoc.properties.Out) > 0 { 683 ctx.PropertyErrorf("out", "out property may not be combined with check_api") 684 } 685 686 apiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Api_file)}) 687 removedApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Removed_api_file)}) 688 689 cmd.FlagForEachInput("--check-compatibility:api:released ", apiFiles) 690 cmd.FlagForEachInput("--check-compatibility:removed:released ", removedApiFiles) 691 692 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file) 693 if baselineFile.Valid() { 694 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path()) 695 } 696} 697 698func metalavaUseRbe(ctx android.ModuleContext) bool { 699 return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") 700} 701 702func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, 703 srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams, configFiles android.Paths) *android.RuleBuilderCommand { 704 rule.Command().Text("rm -rf").Flag(homeDir.String()) 705 rule.Command().Text("mkdir -p").Flag(homeDir.String()) 706 707 cmd := rule.Command() 708 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String()) 709 710 if metalavaUseRbe(ctx) { 711 rule.Remoteable(android.RemoteRuleSupports{RBE: true}) 712 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy) 713 compare := ctx.Config().IsEnvTrue("RBE_METALAVA_COMPARE") 714 remoteUpdateCache := !ctx.Config().IsEnvFalse("RBE_METALAVA_REMOTE_UPDATE_CACHE") 715 labels := map[string]string{"type": "tool", "name": "metalava"} 716 // TODO: metalava pool rejects these jobs 717 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16") 718 rule.Rewrapper(&remoteexec.REParams{ 719 Labels: labels, 720 ExecStrategy: execStrategy, 721 ToolchainInputs: []string{config.JavaCmd(ctx).String()}, 722 Platform: map[string]string{remoteexec.PoolKey: pool}, 723 Compare: compare, 724 NumLocalRuns: 1, 725 NumRemoteRuns: 1, 726 NoRemoteUpdateCache: !remoteUpdateCache, 727 }) 728 } 729 730 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")). 731 Flag(config.JavacVmFlags). 732 Flag(config.MetalavaAddOpens). 733 FlagWithArg("--java-source ", params.javaVersion.String()). 734 FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, fmt.Sprintf("%s.metalava.rsp", params.stubsType.String())), srcs). 735 FlagWithInput("@", srcJarList) 736 737 // Metalava does not differentiate between bootclasspath and classpath and has not done so for 738 // years, so it is unlikely to change any time soon. 739 combinedPaths := append(([]android.Path)(nil), params.deps.bootClasspath.Paths()...) 740 combinedPaths = append(combinedPaths, params.deps.classpath.Paths()...) 741 if len(combinedPaths) > 0 { 742 cmd.FlagWithInputList("--classpath ", combinedPaths, ":") 743 } 744 745 cmd.Flag(config.MetalavaFlags) 746 747 addMetalavaConfigFilesToCmd(cmd, configFiles) 748 749 return cmd 750} 751 752// MetalavaConfigFilegroup is the name of the filegroup in build/soong/java/metalava that lists 753// the configuration files to pass to Metalava. 754const MetalavaConfigFilegroup = "metalava-config-files" 755 756// Get a reference to the MetalavaConfigFilegroup suitable for use in a property. 757func getMetalavaConfigFilegroupReference() []string { 758 return []string{":" + MetalavaConfigFilegroup} 759} 760 761// addMetalavaConfigFilesToCmd adds --config-file options to use the config files list in the 762// MetalavaConfigFilegroup filegroup. 763func addMetalavaConfigFilesToCmd(cmd *android.RuleBuilderCommand, configFiles android.Paths) { 764 cmd.FlagForEachInput("--config-file ", configFiles) 765} 766 767// Pass flagged apis related flags to metalava. When aconfig_declarations property is not 768// defined for a module, simply revert all flagged apis annotations. If aconfig_declarations 769// property is defined, apply transformations and only revert the flagged apis that are not 770// enabled via release configurations and are not specified in aconfig_declarations 771func generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) { 772 var filterArgs string 773 switch stubsType { 774 // No flagged apis specific flags need to be passed to metalava when generating 775 // everything stubs 776 case Everything: 777 return 778 779 case Runtime: 780 filterArgs = "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'" 781 782 case Exportable: 783 // When the build flag RELEASE_EXPORT_RUNTIME_APIS is set to true, apis marked with 784 // the flagged apis that have read_write permissions are exposed on top of the enabled 785 // and read_only apis. This is to support local override of flag values at runtime. 786 if ctx.Config().ReleaseExportRuntimeApis() { 787 filterArgs = "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'" 788 } else { 789 filterArgs = "--filter='state:ENABLED+permission:READ_ONLY'" 790 } 791 } 792 793 if len(aconfigFlagsPaths) == 0 { 794 // This argument should not be added for "everything" stubs 795 cmd.Flag("--revert-annotation android.annotation.FlaggedApi") 796 return 797 } 798 799 releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String())) 800 revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String())) 801 802 ctx.Build(pctx, android.BuildParams{ 803 Rule: gatherReleasedFlaggedApisRule, 804 Inputs: aconfigFlagsPaths, 805 Output: releasedFlaggedApisFile, 806 Description: fmt.Sprintf("%s gather aconfig flags", stubsType), 807 Args: map[string]string{ 808 "flags_path": android.JoinPathsWithPrefix(aconfigFlagsPaths, "--cache "), 809 "filter_args": filterArgs, 810 }, 811 }) 812 813 ctx.Build(pctx, android.BuildParams{ 814 Rule: generateMetalavaRevertAnnotationsRule, 815 Input: releasedFlaggedApisFile, 816 Output: revertAnnotationsFile, 817 Description: fmt.Sprintf("%s revert annotations", stubsType), 818 }) 819 820 cmd.FlagWithInput("@", revertAnnotationsFile) 821} 822 823func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, 824 params stubsCommandParams) *android.RuleBuilderCommand { 825 if BoolDefault(d.properties.High_mem, false) { 826 // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel. 827 rule.HighMem() 828 } 829 830 if params.stubConfig.generateStubs { 831 rule.Command().Text("rm -rf").Text(params.stubsDir.String()) 832 rule.Command().Text("mkdir -p").Text(params.stubsDir.String()) 833 } 834 835 srcJarList := zipSyncCmd(ctx, rule, params.srcJarDir, d.Javadoc.srcJars) 836 837 homeDir := android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "home") 838 839 configFiles := android.PathsForModuleSrc(ctx, d.properties.ConfigFiles) 840 841 cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig, configFiles) 842 cmd.Implicits(d.Javadoc.implicits) 843 844 d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi) 845 846 if params.stubConfig.writeSdkValues { 847 d.sdkValuesFlags(ctx, cmd, params.metadataDir) 848 } 849 850 annotationParams := annotationFlagsParams{ 851 migratingNullability: params.stubConfig.migratingNullability, 852 validatingNullability: params.stubConfig.validatingNullability, 853 nullabilityWarningsFile: params.nullabilityWarningsFile, 854 annotationsZip: params.annotationsZip, 855 } 856 857 d.annotationsFlags(ctx, cmd, annotationParams) 858 d.inclusionAnnotationsFlags(ctx, cmd) 859 d.apiLevelsAnnotationsFlags(ctx, cmd, params.stubConfig.stubsType, params.apiVersionsXml) 860 861 if params.stubConfig.doCheckReleased { 862 d.apiCompatibilityFlags(ctx, cmd, params.stubConfig.stubsType) 863 } 864 865 d.expandArgs(ctx, cmd) 866 867 for _, o := range d.Javadoc.properties.Out { 868 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) 869 } 870 871 return cmd 872} 873 874// Sandbox rule for generating the everything stubs and other artifacts 875func (d *Droidstubs) everythingStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) { 876 srcJarDir := android.PathForModuleOut(ctx, Everything.String(), "srcjars") 877 rule := android.NewRuleBuilder(pctx, ctx) 878 rule.Sbox(android.PathForModuleOut(ctx, Everything.String()), 879 android.PathForModuleOut(ctx, "metalava.sbox.textproto")). 880 SandboxInputs() 881 882 var stubsDir android.OptionalPath 883 if params.generateStubs { 884 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, Everything.String(), "stubsDir")) 885 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-"+"stubs.srcjar") 886 } 887 888 if params.writeSdkValues { 889 d.everythingArtifacts.metadataDir = android.PathForModuleOut(ctx, Everything.String(), "metadata") 890 d.everythingArtifacts.metadataZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-metadata.zip") 891 } 892 893 if Bool(d.properties.Annotations_enabled) { 894 if params.validatingNullability { 895 d.everythingArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_nullability_warnings.txt") 896 } 897 d.everythingArtifacts.annotationsZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_annotations.zip") 898 } 899 if Bool(d.properties.Api_levels_annotations_enabled) { 900 d.everythingArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, Everything.String(), "api-versions.xml") 901 } 902 903 commonCmdParams := stubsCommandParams{ 904 srcJarDir: srcJarDir, 905 stubsDir: stubsDir, 906 stubsSrcJar: d.Javadoc.stubsSrcJar, 907 metadataDir: d.everythingArtifacts.metadataDir, 908 apiVersionsXml: d.everythingArtifacts.apiVersionsXml, 909 nullabilityWarningsFile: d.everythingArtifacts.nullabilityWarningsFile, 910 annotationsZip: d.everythingArtifacts.annotationsZip, 911 stubConfig: params, 912 } 913 914 cmd := d.commonMetalavaStubCmd(ctx, rule, commonCmdParams) 915 916 d.everythingOptionalCmd(ctx, cmd, params.doApiLint, params.doCheckReleased) 917 918 if params.generateStubs { 919 rule.Command(). 920 BuiltTool("soong_zip"). 921 Flag("-write_if_changed"). 922 Flag("-jar"). 923 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar). 924 FlagWithArg("-C ", stubsDir.String()). 925 FlagWithArg("-D ", stubsDir.String()) 926 } 927 928 if params.writeSdkValues { 929 rule.Command(). 930 BuiltTool("soong_zip"). 931 Flag("-write_if_changed"). 932 Flag("-d"). 933 FlagWithOutput("-o ", d.everythingArtifacts.metadataZip). 934 FlagWithArg("-C ", d.everythingArtifacts.metadataDir.String()). 935 FlagWithArg("-D ", d.everythingArtifacts.metadataDir.String()) 936 } 937 938 // TODO: We don't really need two separate API files, but this is a reminiscence of how 939 // we used to run metalava separately for API lint and the "last_released" check. Unify them. 940 if params.doApiLint { 941 rule.Command().Text("touch").Output(d.apiLintTimestamp) 942 } 943 if params.doCheckReleased { 944 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp) 945 } 946 947 // TODO(b/183630617): rewrapper doesn't support restat rules 948 if !metalavaUseRbe(ctx) { 949 rule.Restat() 950 } 951 952 zipSyncCleanupCmd(rule, srcJarDir) 953 954 rule.Build("metalava", "metalava merged") 955} 956 957// Sandbox rule for generating the everything artifacts that are not run by 958// default but only run based on the module configurations 959func (d *Droidstubs) everythingOptionalCmd(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, doApiLint bool, doCheckReleased bool) { 960 961 // Add API lint options. 962 treatDocumentationIssuesAsErrors := false 963 if doApiLint { 964 var newSince android.Paths 965 if d.properties.Check_api.Api_lint.New_since != nil { 966 newSince = android.PathsForModuleSrc(ctx, []string{proptools.String(d.properties.Check_api.Api_lint.New_since)}) 967 } 968 cmd.Flag("--api-lint") 969 cmd.FlagForEachInput("--api-lint-previous-api ", newSince) 970 d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt") 971 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint" 972 973 // If UnflaggedApi issues have not already been configured then make sure that existing 974 // UnflaggedApi issues are reported as warnings but issues in new/changed code are treated as 975 // errors by the Build Warnings Aye Aye Analyzer in Gerrit. 976 // Once existing issues have been fixed this will be changed to error. 977 // TODO(b/362771529): Switch to --error 978 if !strings.Contains(cmd.String(), " UnflaggedApi ") { 979 cmd.Flag("--error-when-new UnflaggedApi") 980 } 981 982 // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released. 983 if d.Name() != "android.car-system-stubs-docs" && 984 d.Name() != "android.car-stubs-docs" { 985 treatDocumentationIssuesAsErrors = true 986 cmd.Flag("--warnings-as-errors") // Most lints are actually warnings. 987 } 988 989 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file) 990 updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "api_lint_baseline.txt") 991 d.apiLintTimestamp = android.PathForModuleOut(ctx, Everything.String(), "api_lint.timestamp") 992 993 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s. 994 // 995 // TODO: metalava also has a slightly different message hardcoded. Should we unify this 996 // message and metalava's one? 997 msg := `$'` + // Enclose with $' ... ' 998 `************************************************************\n` + 999 `Your API changes are triggering API Lint warnings or errors.\n` + 1000 `\n` + 1001 `To make the failures go away:\n` + 1002 `\n` + 1003 `1. REQUIRED: Read the messages carefully and address them by` + 1004 ` fixing the API if appropriate.\n` + 1005 `2. If the failure is a false positive, you can suppress it with:\n` + 1006 ` @SuppressLint("<id>")\n` + 1007 ` where the <id> is given in brackets in the error message above.\n` 1008 1009 if baselineFile.Valid() { 1010 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path()) 1011 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput) 1012 1013 msg += fmt.Sprintf(``+ 1014 `3. FOR LSC ONLY: You can update the baseline by executing\n`+ 1015 ` the following command:\n`+ 1016 ` (cd $ANDROID_BUILD_TOP && cp \\\n`+ 1017 ` "%s" \\\n`+ 1018 ` "%s")\n`+ 1019 ` To submit the revised baseline.txt to the main Android\n`+ 1020 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path()) 1021 } else { 1022 msg += fmt.Sprintf(``+ 1023 `3. FOR LSC ONLY: You can add a baseline file of existing lint failures\n`+ 1024 ` to the build rule of %s.\n`, d.Name()) 1025 } 1026 // Note the message ends with a ' (single quote), to close the $' ... ' . 1027 msg += `************************************************************\n'` 1028 1029 cmd.FlagWithArg("--error-message:api-lint ", msg) 1030 } 1031 1032 if !treatDocumentationIssuesAsErrors { 1033 treatDocumentationIssuesAsWarningErrorWhenNew(cmd) 1034 } 1035 1036 // Add "check released" options. (Detect incompatible API changes from the last public release) 1037 if doCheckReleased { 1038 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file) 1039 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_last_released_api.timestamp") 1040 if baselineFile.Valid() { 1041 updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "last_released_baseline.txt") 1042 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput) 1043 } 1044 // Note this string includes quote ($' ... '), which decodes the "\n"s. 1045 msg := `$'\n******************************\n` + 1046 `You have tried to change the API from what has been previously released in\n` + 1047 `an SDK. Please fix the errors listed above.\n` + 1048 `******************************\n'` 1049 1050 cmd.FlagWithArg("--error-message:compatibility:released ", msg) 1051 } 1052 1053 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { 1054 // Pass the current API file into metalava so it can use it as the basis for determining how to 1055 // generate the output signature files (both api and removed). 1056 currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) 1057 cmd.FlagWithInput("--use-same-format-as ", currentApiFile) 1058 } 1059} 1060 1061// HIDDEN_DOCUMENTATION_ISSUES is the set of documentation related issues that should always be 1062// hidden as they are very noisy and provide little value. 1063var HIDDEN_DOCUMENTATION_ISSUES = []string{ 1064 "Deprecated", 1065 "IntDef", 1066 "Nullable", 1067} 1068 1069func treatDocumentationIssuesAsWarningErrorWhenNew(cmd *android.RuleBuilderCommand) { 1070 // Treat documentation issues as warnings, but error when new. 1071 cmd.Flag("--error-when-new-category").Flag("Documentation") 1072 1073 // Hide some documentation issues that generated a lot of noise for little benefit. 1074 cmd.FlagForEachArg("--hide ", HIDDEN_DOCUMENTATION_ISSUES) 1075} 1076 1077// Sandbox rule for generating exportable stubs and other artifacts 1078func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) { 1079 optionalCmdParams := stubsCommandParams{ 1080 stubConfig: params, 1081 } 1082 1083 if params.generateStubs { 1084 d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar") 1085 optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar 1086 } 1087 1088 if params.writeSdkValues { 1089 d.exportableArtifacts.metadataZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-metadata.zip") 1090 d.exportableArtifacts.metadataDir = android.PathForModuleOut(ctx, params.stubsType.String(), "metadata") 1091 optionalCmdParams.metadataZip = d.exportableArtifacts.metadataZip 1092 optionalCmdParams.metadataDir = d.exportableArtifacts.metadataDir 1093 } 1094 1095 if Bool(d.properties.Annotations_enabled) { 1096 if params.validatingNullability { 1097 d.exportableArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_nullability_warnings.txt") 1098 optionalCmdParams.nullabilityWarningsFile = d.exportableArtifacts.nullabilityWarningsFile 1099 } 1100 d.exportableArtifacts.annotationsZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_annotations.zip") 1101 optionalCmdParams.annotationsZip = d.exportableArtifacts.annotationsZip 1102 } 1103 if Bool(d.properties.Api_levels_annotations_enabled) { 1104 d.exportableArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, params.stubsType.String(), "api-versions.xml") 1105 optionalCmdParams.apiVersionsXml = d.exportableArtifacts.apiVersionsXml 1106 } 1107 1108 if params.checkApi || String(d.properties.Api_filename) != "" { 1109 filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt") 1110 d.exportableApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename) 1111 } 1112 1113 if params.checkApi || String(d.properties.Removed_api_filename) != "" { 1114 filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_api.txt") 1115 d.exportableRemovedApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename) 1116 } 1117 1118 d.optionalStubCmd(ctx, optionalCmdParams) 1119} 1120 1121func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsCommandParams) { 1122 1123 params.srcJarDir = android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "srcjars") 1124 rule := android.NewRuleBuilder(pctx, ctx) 1125 rule.Sbox(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String()), 1126 android.PathForModuleOut(ctx, fmt.Sprintf("metalava_%s.sbox.textproto", params.stubConfig.stubsType.String()))). 1127 SandboxInputs() 1128 1129 if params.stubConfig.generateStubs { 1130 params.stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "stubsDir")) 1131 } 1132 1133 cmd := d.commonMetalavaStubCmd(ctx, rule, params) 1134 1135 generateRevertAnnotationArgs(ctx, cmd, params.stubConfig.stubsType, params.stubConfig.deps.aconfigProtoFiles) 1136 1137 if params.stubConfig.doApiLint { 1138 // Pass the lint baseline file as an input to resolve the lint errors. 1139 // The exportable stubs generation does not update the lint baseline file. 1140 // Lint baseline file update is handled by the everything stubs 1141 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file) 1142 if baselineFile.Valid() { 1143 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path()) 1144 } 1145 } 1146 1147 // Treat documentation issues as warnings, but error when new. 1148 treatDocumentationIssuesAsWarningErrorWhenNew(cmd) 1149 1150 if params.stubConfig.generateStubs { 1151 rule.Command(). 1152 BuiltTool("soong_zip"). 1153 Flag("-write_if_changed"). 1154 Flag("-jar"). 1155 FlagWithOutput("-o ", params.stubsSrcJar). 1156 FlagWithArg("-C ", params.stubsDir.String()). 1157 FlagWithArg("-D ", params.stubsDir.String()) 1158 } 1159 1160 if params.stubConfig.writeSdkValues { 1161 rule.Command(). 1162 BuiltTool("soong_zip"). 1163 Flag("-write_if_changed"). 1164 Flag("-d"). 1165 FlagWithOutput("-o ", params.metadataZip). 1166 FlagWithArg("-C ", params.metadataDir.String()). 1167 FlagWithArg("-D ", params.metadataDir.String()) 1168 } 1169 1170 // TODO(b/183630617): rewrapper doesn't support restat rules 1171 if !metalavaUseRbe(ctx) { 1172 rule.Restat() 1173 } 1174 1175 zipSyncCleanupCmd(rule, params.srcJarDir) 1176 1177 rule.Build(fmt.Sprintf("metalava_%s", params.stubConfig.stubsType.String()), "metalava merged") 1178} 1179 1180func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1181 deps := d.Javadoc.collectDeps(ctx) 1182 1183 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d)) 1184 generateStubs := BoolDefault(d.properties.Generate_stubs, true) 1185 1186 // Add options for the other optional tasks: API-lint and check-released. 1187 // We generate separate timestamp files for them. 1188 doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) 1189 doCheckReleased := apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") 1190 1191 writeSdkValues := Bool(d.properties.Write_sdk_values) 1192 1193 annotationsEnabled := Bool(d.properties.Annotations_enabled) 1194 1195 migratingNullability := annotationsEnabled && String(d.properties.Previous_api) != "" 1196 validatingNullability := annotationsEnabled && (strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") || 1197 String(d.properties.Validate_nullability_from_list) != "") 1198 1199 checkApi := apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || 1200 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") 1201 1202 stubCmdParams := stubsCommandConfigParams{ 1203 javaVersion: javaVersion, 1204 deps: deps, 1205 checkApi: checkApi, 1206 generateStubs: generateStubs, 1207 doApiLint: doApiLint, 1208 doCheckReleased: doCheckReleased, 1209 writeSdkValues: writeSdkValues, 1210 migratingNullability: migratingNullability, 1211 validatingNullability: validatingNullability, 1212 } 1213 stubCmdParams.stubsType = Everything 1214 // Create default (i.e. "everything" stubs) rule for metalava 1215 d.everythingStubCmd(ctx, stubCmdParams) 1216 1217 // The module generates "exportable" (and "runtime" eventually) stubs regardless of whether 1218 // aconfig_declarations property is defined or not. If the property is not defined, the module simply 1219 // strips all flagged apis to generate the "exportable" stubs 1220 stubCmdParams.stubsType = Exportable 1221 d.exportableStubCmd(ctx, stubCmdParams) 1222 1223 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { 1224 1225 if len(d.Javadoc.properties.Out) > 0 { 1226 ctx.PropertyErrorf("out", "out property may not be combined with check_api") 1227 } 1228 1229 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) 1230 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) 1231 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file) 1232 1233 if baselineFile.Valid() { 1234 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName()) 1235 } 1236 1237 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_current_api.timestamp") 1238 1239 rule := android.NewRuleBuilder(pctx, ctx) 1240 1241 // Diff command line. 1242 // -F matches the closest "opening" line, such as "package android {" 1243 // and " public class Intent {". 1244 diff := `diff -u -F '{ *$'` 1245 1246 rule.Command().Text("( true") 1247 rule.Command(). 1248 Text(diff). 1249 Input(apiFile).Input(d.apiFile) 1250 1251 rule.Command(). 1252 Text(diff). 1253 Input(removedApiFile).Input(d.removedApiFile) 1254 1255 msg := fmt.Sprintf(`\n******************************\n`+ 1256 `You have tried to change the API from what has been previously approved.\n\n`+ 1257 `To make these errors go away, you have two choices:\n`+ 1258 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+ 1259 ` to the new methods, etc. shown in the above diff.\n\n`+ 1260 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+ 1261 ` m %s-update-current-api\n\n`+ 1262 ` To submit the revised current.txt to the main Android repository,\n`+ 1263 ` you will need approval.\n`+ 1264 `If your build failed due to stub validation, you can resolve the errors with\n`+ 1265 `either of the two choices above and try re-building the target.\n`+ 1266 `If the mismatch between the stubs and the current.txt is intended,\n`+ 1267 `you can try re-building the target by executing the following command:\n`+ 1268 `m DISABLE_STUB_VALIDATION=true <your build target>.\n`+ 1269 `Note that DISABLE_STUB_VALIDATION=true does not bypass checkapi.\n`+ 1270 `******************************\n`, ctx.ModuleName()) 1271 1272 rule.Command(). 1273 Text("touch").Output(d.checkCurrentApiTimestamp). 1274 Text(") || ("). 1275 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1276 Text("; exit 38"). 1277 Text(")") 1278 1279 rule.Build("metalavaCurrentApiCheck", "check current API") 1280 1281 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "update_current_api.timestamp") 1282 1283 // update API rule 1284 rule = android.NewRuleBuilder(pctx, ctx) 1285 1286 rule.Command().Text("( true") 1287 1288 rule.Command(). 1289 Text("cp").Flag("-f"). 1290 Input(d.apiFile).Flag(apiFile.String()) 1291 1292 rule.Command(). 1293 Text("cp").Flag("-f"). 1294 Input(d.removedApiFile).Flag(removedApiFile.String()) 1295 1296 msg = "failed to update public API" 1297 1298 rule.Command(). 1299 Text("touch").Output(d.updateCurrentApiTimestamp). 1300 Text(") || ("). 1301 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1302 Text("; exit 38"). 1303 Text(")") 1304 1305 rule.Build("metalavaCurrentApiUpdate", "update current API") 1306 } 1307 1308 if String(d.properties.Check_nullability_warnings) != "" { 1309 if d.everythingArtifacts.nullabilityWarningsFile == nil { 1310 ctx.PropertyErrorf("check_nullability_warnings", 1311 "Cannot specify check_nullability_warnings unless validating nullability") 1312 } 1313 1314 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings)) 1315 1316 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp") 1317 1318 msg := fmt.Sprintf(`\n******************************\n`+ 1319 `The warnings encountered during nullability annotation validation did\n`+ 1320 `not match the checked in file of expected warnings. The diffs are shown\n`+ 1321 `above. You have two options:\n`+ 1322 ` 1. Resolve the differences by editing the nullability annotations.\n`+ 1323 ` 2. Update the file of expected warnings by running:\n`+ 1324 ` cp %s %s\n`+ 1325 ` and submitting the updated file as part of your change.`, 1326 d.everythingArtifacts.nullabilityWarningsFile, checkNullabilityWarnings) 1327 1328 rule := android.NewRuleBuilder(pctx, ctx) 1329 1330 rule.Command(). 1331 Text("("). 1332 Text("diff").Input(checkNullabilityWarnings).Input(d.everythingArtifacts.nullabilityWarningsFile). 1333 Text("&&"). 1334 Text("touch").Output(d.checkNullabilityWarningsTimestamp). 1335 Text(") || ("). 1336 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1337 Text("; exit 38"). 1338 Text(")") 1339 1340 rule.Build("nullabilityWarningsCheck", "nullability warnings check") 1341 } 1342 1343 d.setOutputFiles(ctx) 1344} 1345 1346// This method sets the outputFiles property, which is used to set the 1347// OutputFilesProvider later. 1348// Droidstubs' tag supports specifying with the stubs type. 1349// While supporting the pre-existing tags, it also supports tags with 1350// the stubs type prefix. Some examples are shown below: 1351// {.annotations.zip} - pre-existing behavior. Returns the path to the 1352// annotation zip. 1353// {.exportable} - Returns the path to the exportable stubs src jar. 1354// {.exportable.annotations.zip} - Returns the path to the exportable 1355// annotations zip file. 1356// {.runtime.api_versions.xml} - Runtime stubs does not generate api versions 1357// xml file. For unsupported combinations, the default everything output file 1358// is returned. 1359func (d *Droidstubs) setOutputFiles(ctx android.ModuleContext) { 1360 tagToOutputFileFunc := map[string]func(StubsType) (android.Path, error){ 1361 "": d.StubsSrcJar, 1362 ".docs.zip": d.DocZip, 1363 ".api.txt": d.ApiFilePath, 1364 android.DefaultDistTag: d.ApiFilePath, 1365 ".removed-api.txt": d.RemovedApiFilePath, 1366 ".annotations.zip": d.AnnotationsZip, 1367 ".api_versions.xml": d.ApiVersionsXmlFilePath, 1368 } 1369 stubsTypeToPrefix := map[StubsType]string{ 1370 Everything: "", 1371 Exportable: ".exportable", 1372 } 1373 for _, tag := range android.SortedKeys(tagToOutputFileFunc) { 1374 for _, stubType := range android.SortedKeys(stubsTypeToPrefix) { 1375 tagWithPrefix := stubsTypeToPrefix[stubType] + tag 1376 outputFile, err := tagToOutputFileFunc[tag](stubType) 1377 if err == nil && outputFile != nil { 1378 ctx.SetOutputFiles(android.Paths{outputFile}, tagWithPrefix) 1379 } 1380 } 1381 } 1382} 1383 1384func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) { 1385 api_file := d.properties.Check_api.Current.Api_file 1386 api_surface := d.properties.Api_surface 1387 1388 props := struct { 1389 Name *string 1390 Api_surface *string 1391 Api_file *string 1392 Visibility []string 1393 }{} 1394 1395 props.Name = proptools.StringPtr(d.Name() + ".api.contribution") 1396 props.Api_surface = api_surface 1397 props.Api_file = api_file 1398 props.Visibility = []string{"//visibility:override", "//visibility:public"} 1399 1400 ctx.CreateModule(ApiContributionFactory, &props) 1401} 1402 1403// TODO (b/262014796): Export the API contributions of CorePlatformApi 1404// A map to populate the api surface of a droidstub from a substring appearing in its name 1405// This map assumes that droidstubs (either checked-in or created by java_sdk_library) 1406// use a strict naming convention 1407var ( 1408 droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{ 1409 // public is commented out since the core libraries use public in their java_sdk_library names 1410 "intracore": android.SdkIntraCore, 1411 "intra.core": android.SdkIntraCore, 1412 "system_server": android.SdkSystemServer, 1413 "system-server": android.SdkSystemServer, 1414 "system": android.SdkSystem, 1415 "module_lib": android.SdkModule, 1416 "module-lib": android.SdkModule, 1417 "platform.api": android.SdkCorePlatform, 1418 "test": android.SdkTest, 1419 "toolchain": android.SdkToolchain, 1420 } 1421) 1422 1423func StubsDefaultsFactory() android.Module { 1424 module := &DocDefaults{} 1425 1426 module.AddProperties( 1427 &JavadocProperties{}, 1428 &DroidstubsProperties{}, 1429 ) 1430 1431 android.InitDefaultsModule(module) 1432 1433 return module 1434} 1435 1436var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil) 1437 1438type PrebuiltStubsSourcesProperties struct { 1439 Srcs []string `android:"path"` 1440 1441 // Name of the source soong module that gets shadowed by this prebuilt 1442 // If unspecified, follows the naming convention that the source module of 1443 // the prebuilt is Name() without "prebuilt_" prefix 1444 Source_module_name *string 1445 1446 // Non-nil if this prebuilt stub srcs module was dynamically created by a java_sdk_library_import 1447 // The name is the undecorated name of the java_sdk_library as it appears in the blueprint file 1448 // (without any prebuilt_ prefix) 1449 Created_by_java_sdk_library_name *string `blueprint:"mutated"` 1450} 1451 1452func (j *PrebuiltStubsSources) BaseModuleName() string { 1453 return proptools.StringDefault(j.properties.Source_module_name, j.ModuleBase.Name()) 1454} 1455 1456func (j *PrebuiltStubsSources) CreatedByJavaSdkLibraryName() *string { 1457 return j.properties.Created_by_java_sdk_library_name 1458} 1459 1460type PrebuiltStubsSources struct { 1461 android.ModuleBase 1462 android.DefaultableModuleBase 1463 embeddableInModuleAndImport 1464 1465 prebuilt android.Prebuilt 1466 1467 properties PrebuiltStubsSourcesProperties 1468 1469 stubsSrcJar android.Path 1470} 1471 1472func (d *PrebuiltStubsSources) StubsSrcJar(_ StubsType) (android.Path, error) { 1473 return d.stubsSrcJar, nil 1474} 1475 1476func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1477 if len(p.properties.Srcs) != 1 { 1478 ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs)) 1479 return 1480 } 1481 1482 src := p.properties.Srcs[0] 1483 if filepath.Ext(src) == ".srcjar" { 1484 // This is a srcjar. We can use it directly. 1485 p.stubsSrcJar = android.PathForModuleSrc(ctx, src) 1486 } else { 1487 outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") 1488 1489 // This is a directory. Glob the contents just in case the directory does not exist. 1490 srcGlob := src + "/**/*" 1491 srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob}) 1492 1493 // Although PathForModuleSrc can return nil if either the path doesn't exist or 1494 // the path components are invalid it won't in this case because no components 1495 // are specified and the module directory must exist in order to get this far. 1496 srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src) 1497 1498 rule := android.NewRuleBuilder(pctx, ctx) 1499 rule.Command(). 1500 BuiltTool("soong_zip"). 1501 Flag("-write_if_changed"). 1502 Flag("-jar"). 1503 FlagWithOutput("-o ", outPath). 1504 FlagWithArg("-C ", srcDir.String()). 1505 FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths) 1506 rule.Restat() 1507 rule.Build("zip src", "Create srcjar from prebuilt source") 1508 p.stubsSrcJar = outPath 1509 } 1510 1511 ctx.SetOutputFiles(android.Paths{p.stubsSrcJar}, "") 1512 // prebuilt droidstubs does not output "exportable" stubs. 1513 // Output the "everything" stubs srcjar file if the tag is ".exportable". 1514 ctx.SetOutputFiles(android.Paths{p.stubsSrcJar}, ".exportable") 1515} 1516 1517func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt { 1518 return &p.prebuilt 1519} 1520 1521func (p *PrebuiltStubsSources) Name() string { 1522 return p.prebuilt.Name(p.ModuleBase.Name()) 1523} 1524 1525// prebuilt_stubs_sources imports a set of java source files as if they were 1526// generated by droidstubs. 1527// 1528// By default, a prebuilt_stubs_sources has a single variant that expects a 1529// set of `.java` files generated by droidstubs. 1530// 1531// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one 1532// for host modules. 1533// 1534// Intended only for use by sdk snapshots. 1535func PrebuiltStubsSourcesFactory() android.Module { 1536 module := &PrebuiltStubsSources{} 1537 1538 module.AddProperties(&module.properties) 1539 module.initModuleAndImport(module) 1540 1541 android.InitPrebuiltModule(module, &module.properties.Srcs) 1542 InitDroiddocModule(module, android.HostAndDeviceSupported) 1543 return module 1544} 1545