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