1// Copyright 2018 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 "strings" 21 22 "github.com/google/blueprint" 23 "github.com/google/blueprint/proptools" 24 25 "android/soong/android" 26 "android/soong/java/config" 27 "android/soong/remoteexec" 28) 29 30func init() { 31 RegisterDocsBuildComponents(android.InitRegistrationContext) 32 RegisterStubsBuildComponents(android.InitRegistrationContext) 33 34 // Register sdk member type. 35 android.RegisterSdkMemberType(&droidStubsSdkMemberType{ 36 SdkMemberTypeBase: android.SdkMemberTypeBase{ 37 PropertyName: "stubs_sources", 38 // stubs_sources can be used with sdk to provide the source stubs for APIs provided by 39 // the APEX. 40 SupportsSdk: true, 41 }, 42 }) 43} 44 45func RegisterDocsBuildComponents(ctx android.RegistrationContext) { 46 ctx.RegisterModuleType("doc_defaults", DocDefaultsFactory) 47 48 ctx.RegisterModuleType("droiddoc", DroiddocFactory) 49 ctx.RegisterModuleType("droiddoc_host", DroiddocHostFactory) 50 ctx.RegisterModuleType("droiddoc_exported_dir", ExportedDroiddocDirFactory) 51 ctx.RegisterModuleType("javadoc", JavadocFactory) 52 ctx.RegisterModuleType("javadoc_host", JavadocHostFactory) 53} 54 55func RegisterStubsBuildComponents(ctx android.RegistrationContext) { 56 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory) 57 58 ctx.RegisterModuleType("droidstubs", DroidstubsFactory) 59 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory) 60 61 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory) 62} 63 64var ( 65 srcsLibTag = dependencyTag{name: "sources from javalib"} 66) 67 68type JavadocProperties struct { 69 // list of source files used to compile the Java module. May be .java, .logtags, .proto, 70 // or .aidl files. 71 Srcs []string `android:"path,arch_variant"` 72 73 // list of directories rooted at the Android.bp file that will 74 // be added to the search paths for finding source files when passing package names. 75 Local_sourcepaths []string 76 77 // list of source files that should not be used to build the Java module. 78 // This is most useful in the arch/multilib variants to remove non-common files 79 // filegroup or genrule can be included within this property. 80 Exclude_srcs []string `android:"path,arch_variant"` 81 82 // list of package names that should actually be used. If this property is left unspecified, 83 // all the sources from the srcs property is used. 84 Filter_packages []string 85 86 // list of java libraries that will be in the classpath. 87 Libs []string `android:"arch_variant"` 88 89 // If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true. 90 Installable *bool 91 92 // if not blank, set to the version of the sdk to compile against. 93 // Defaults to compiling against the current platform. 94 Sdk_version *string `android:"arch_variant"` 95 96 // When targeting 1.9 and above, override the modules to use with --system, 97 // otherwise provides defaults libraries to add to the bootclasspath. 98 // Defaults to "none" 99 System_modules *string 100 101 Aidl struct { 102 // Top level directories to pass to aidl tool 103 Include_dirs []string 104 105 // Directories rooted at the Android.bp file to pass to aidl tool 106 Local_include_dirs []string 107 } 108 109 // If not blank, set the java version passed to javadoc as -source 110 Java_version *string 111 112 // local files that are used within user customized droiddoc options. 113 Arg_files []string `android:"path"` 114 115 // user customized droiddoc args. Deprecated, use flags instead. 116 // Available variables for substitution: 117 // 118 // $(location <label>): the path to the arg_files with name <label> 119 // $$: a literal $ 120 Args *string 121 122 // user customized droiddoc args. Not compatible with property args. 123 // Available variables for substitution: 124 // 125 // $(location <label>): the path to the arg_files with name <label> 126 // $$: a literal $ 127 Flags []string 128 129 // names of the output files used in args that will be generated 130 Out []string 131 132 // If set, metalava is sandboxed to only read files explicitly specified on the command 133 // line. Defaults to false. 134 Sandbox *bool 135} 136 137type ApiToCheck struct { 138 // path to the API txt file that the new API extracted from source code is checked 139 // against. The path can be local to the module or from other module (via :module syntax). 140 Api_file *string `android:"path"` 141 142 // path to the API txt file that the new @removed API extractd from source code is 143 // checked against. The path can be local to the module or from other module (via 144 // :module syntax). 145 Removed_api_file *string `android:"path"` 146 147 // If not blank, path to the baseline txt file for approved API check violations. 148 Baseline_file *string `android:"path"` 149 150 // Arguments to the apicheck tool. 151 Args *string 152} 153 154type DroiddocProperties struct { 155 // directory relative to top of the source tree that contains doc templates files. 156 Custom_template *string 157 158 // directories under current module source which contains html/jd files. 159 Html_dirs []string 160 161 // set a value in the Clearsilver hdf namespace. 162 Hdf []string 163 164 // proofread file contains all of the text content of the javadocs concatenated into one file, 165 // suitable for spell-checking and other goodness. 166 Proofread_file *string 167 168 // a todo file lists the program elements that are missing documentation. 169 // At some point, this might be improved to show more warnings. 170 Todo_file *string `android:"path"` 171 172 // directory under current module source that provide additional resources (images). 173 Resourcesdir *string 174 175 // resources output directory under out/soong/.intermediates. 176 Resourcesoutdir *string 177 178 // if set to true, collect the values used by the Dev tools and 179 // write them in files packaged with the SDK. Defaults to false. 180 Write_sdk_values *bool 181 182 // index.html under current module will be copied to docs out dir, if not null. 183 Static_doc_index_redirect *string `android:"path"` 184 185 // source.properties under current module will be copied to docs out dir, if not null. 186 Static_doc_properties *string `android:"path"` 187 188 // a list of files under current module source dir which contains known tags in Java sources. 189 // filegroup or genrule can be included within this property. 190 Knowntags []string `android:"path"` 191 192 // the generated public API filename by Doclava. 193 Api_filename *string 194 195 // the generated removed API filename by Doclava. 196 Removed_api_filename *string 197 198 // the generated removed Dex API filename by Doclava. 199 Removed_dex_api_filename *string 200 201 // if set to false, don't allow droiddoc to generate stubs source files. Defaults to false. 202 Create_stubs *bool 203 204 Check_api struct { 205 Last_released ApiToCheck 206 207 Current ApiToCheck 208 209 // do not perform API check against Last_released, in the case that both two specified API 210 // files by Last_released are modules which don't exist. 211 Ignore_missing_latest_api *bool `blueprint:"mutated"` 212 } 213 214 // if set to true, generate docs through Dokka instead of Doclava. 215 Dokka_enabled *bool 216 217 // Compat config XML. Generates compat change documentation if set. 218 Compat_config *string `android:"path"` 219} 220 221type DroidstubsProperties struct { 222 // the generated public API filename by Metalava. 223 Api_filename *string 224 225 // the generated removed API filename by Metalava. 226 Removed_api_filename *string 227 228 // the generated removed Dex API filename by Metalava. 229 Removed_dex_api_filename *string 230 231 Check_api struct { 232 Last_released ApiToCheck 233 234 Current ApiToCheck 235 236 // The java_sdk_library module generates references to modules (i.e. filegroups) 237 // from which information about the latest API version can be obtained. As those 238 // modules may not exist (e.g. because a previous version has not been released) it 239 // sets ignore_missing_latest_api=true on the droidstubs modules it creates so 240 // that droidstubs can ignore those references if the modules do not yet exist. 241 // 242 // If true then this will ignore module references for modules that do not exist 243 // in properties that supply the previous version of the API. 244 // 245 // There are two sets of those: 246 // * Api_file, Removed_api_file in check_api.last_released 247 // * New_since in check_api.api_lint.new_since 248 // 249 // The first two must be set as a pair, so either they should both exist or neither 250 // should exist - in which case when this property is true they are ignored. If one 251 // exists and the other does not then it is an error. 252 Ignore_missing_latest_api *bool `blueprint:"mutated"` 253 254 Api_lint struct { 255 Enabled *bool 256 257 // If set, performs api_lint on any new APIs not found in the given signature file 258 New_since *string `android:"path"` 259 260 // If not blank, path to the baseline txt file for approved API lint violations. 261 Baseline_file *string `android:"path"` 262 } 263 } 264 265 // user can specify the version of previous released API file in order to do compatibility check. 266 Previous_api *string `android:"path"` 267 268 // is set to true, Metalava will allow framework SDK to contain annotations. 269 Annotations_enabled *bool 270 271 // a list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from. 272 Merge_annotations_dirs []string 273 274 // a list of top-level directories containing Java stub files to merge show/hide annotations from. 275 Merge_inclusion_annotations_dirs []string 276 277 // a file containing a list of classes to do nullability validation for. 278 Validate_nullability_from_list *string 279 280 // a file containing expected warnings produced by validation of nullability annotations. 281 Check_nullability_warnings *string 282 283 // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false. 284 Create_doc_stubs *bool 285 286 // if set to false then do not write out stubs. Defaults to true. 287 // 288 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately. 289 Generate_stubs *bool 290 291 // is set to true, Metalava will allow framework SDK to contain API levels annotations. 292 Api_levels_annotations_enabled *bool 293 294 // the dirs which Metalava extracts API levels annotations from. 295 Api_levels_annotations_dirs []string 296 297 // if set to true, collect the values used by the Dev tools and 298 // write them in files packaged with the SDK. Defaults to false. 299 Write_sdk_values *bool 300 301 // If set to true, .xml based public API file will be also generated, and 302 // JDiff tool will be invoked to genreate javadoc files. Defaults to false. 303 Jdiff_enabled *bool 304} 305 306// 307// Common flags passed down to build rule 308// 309type droiddocBuilderFlags struct { 310 bootClasspathArgs string 311 classpathArgs string 312 sourcepathArgs string 313 dokkaClasspathArgs string 314 aidlFlags string 315 aidlDeps android.Paths 316 317 doclavaStubsFlags string 318 doclavaDocsFlags string 319 postDoclavaCmds string 320} 321 322func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) { 323 android.InitAndroidArchModule(module, hod, android.MultilibCommon) 324 android.InitDefaultableModule(module) 325} 326 327func apiCheckEnabled(ctx android.ModuleContext, apiToCheck ApiToCheck, apiVersionTag string) bool { 328 if ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") { 329 return false 330 } else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" { 331 return true 332 } else if String(apiToCheck.Api_file) != "" { 333 panic("for " + apiVersionTag + " removed_api_file has to be non-empty!") 334 } else if String(apiToCheck.Removed_api_file) != "" { 335 panic("for " + apiVersionTag + " api_file has to be non-empty!") 336 } 337 338 return false 339} 340 341func ignoreMissingModules(ctx android.BottomUpMutatorContext, apiToCheck *ApiToCheck) { 342 api_file := String(apiToCheck.Api_file) 343 removed_api_file := String(apiToCheck.Removed_api_file) 344 345 api_module := android.SrcIsModule(api_file) 346 removed_api_module := android.SrcIsModule(removed_api_file) 347 348 if api_module == "" || removed_api_module == "" { 349 return 350 } 351 352 if ctx.OtherModuleExists(api_module) || ctx.OtherModuleExists(removed_api_module) { 353 return 354 } 355 356 apiToCheck.Api_file = nil 357 apiToCheck.Removed_api_file = nil 358} 359 360// Used by xsd_config 361type ApiFilePath interface { 362 ApiFilePath() android.Path 363} 364 365type ApiStubsSrcProvider interface { 366 StubsSrcJar() android.Path 367} 368 369// Provider of information about API stubs, used by java_sdk_library. 370type ApiStubsProvider interface { 371 ApiFilePath 372 RemovedApiFilePath() android.Path 373 374 ApiStubsSrcProvider 375} 376 377// 378// Javadoc 379// 380type Javadoc struct { 381 android.ModuleBase 382 android.DefaultableModuleBase 383 384 properties JavadocProperties 385 386 srcJars android.Paths 387 srcFiles android.Paths 388 sourcepaths android.Paths 389 argFiles android.Paths 390 implicits android.Paths 391 392 args []string 393 394 docZip android.WritablePath 395 stubsSrcJar android.WritablePath 396} 397 398func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) { 399 switch tag { 400 case "": 401 return android.Paths{j.stubsSrcJar}, nil 402 case ".docs.zip": 403 return android.Paths{j.docZip}, nil 404 default: 405 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 406 } 407} 408 409// javadoc converts .java source files to documentation using javadoc. 410func JavadocFactory() android.Module { 411 module := &Javadoc{} 412 413 module.AddProperties(&module.properties) 414 415 InitDroiddocModule(module, android.HostAndDeviceSupported) 416 return module 417} 418 419// javadoc_host converts .java source files to documentation using javadoc. 420func JavadocHostFactory() android.Module { 421 module := &Javadoc{} 422 423 module.AddProperties(&module.properties) 424 425 InitDroiddocModule(module, android.HostSupported) 426 return module 427} 428 429var _ android.OutputFileProducer = (*Javadoc)(nil) 430 431func (j *Javadoc) sdkVersion() sdkSpec { 432 return sdkSpecFrom(String(j.properties.Sdk_version)) 433} 434 435func (j *Javadoc) systemModules() string { 436 return proptools.String(j.properties.System_modules) 437} 438 439func (j *Javadoc) minSdkVersion() sdkSpec { 440 return j.sdkVersion() 441} 442 443func (j *Javadoc) targetSdkVersion() sdkSpec { 444 return j.sdkVersion() 445} 446 447func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) { 448 if ctx.Device() { 449 sdkDep := decodeSdkDep(ctx, sdkContext(j)) 450 if sdkDep.useModule { 451 ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) 452 ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) 453 ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) 454 ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) 455 } 456 } 457 458 ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) 459} 460 461func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags { 462 var flags droiddocBuilderFlags 463 464 flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs) 465 466 return flags 467} 468 469func (j *Javadoc) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath, 470 aidlIncludeDirs android.Paths) (string, android.Paths) { 471 472 aidlIncludes := android.PathsForModuleSrc(ctx, j.properties.Aidl.Local_include_dirs) 473 aidlIncludes = append(aidlIncludes, android.PathsForSource(ctx, j.properties.Aidl.Include_dirs)...) 474 475 var flags []string 476 var deps android.Paths 477 478 if aidlPreprocess.Valid() { 479 flags = append(flags, "-p"+aidlPreprocess.String()) 480 deps = append(deps, aidlPreprocess.Path()) 481 } else { 482 flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I")) 483 } 484 485 flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I")) 486 flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String()) 487 if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() { 488 flags = append(flags, "-I"+src.String()) 489 } 490 491 return strings.Join(flags, " "), deps 492} 493 494// TODO: remove the duplication between this and the one in gen.go 495func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths, 496 flags droiddocBuilderFlags) android.Paths { 497 498 outSrcFiles := make(android.Paths, 0, len(srcFiles)) 499 var aidlSrcs android.Paths 500 501 aidlIncludeFlags := genAidlIncludeFlags(srcFiles) 502 503 for _, srcFile := range srcFiles { 504 switch srcFile.Ext() { 505 case ".aidl": 506 aidlSrcs = append(aidlSrcs, srcFile) 507 case ".logtags": 508 javaFile := genLogtags(ctx, srcFile) 509 outSrcFiles = append(outSrcFiles, javaFile) 510 default: 511 outSrcFiles = append(outSrcFiles, srcFile) 512 } 513 } 514 515 // Process all aidl files together to support sharding them into one or more rules that produce srcjars. 516 if len(aidlSrcs) > 0 { 517 srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps) 518 outSrcFiles = append(outSrcFiles, srcJarFiles...) 519 } 520 521 return outSrcFiles 522} 523 524func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { 525 var deps deps 526 527 sdkDep := decodeSdkDep(ctx, sdkContext(j)) 528 if sdkDep.invalidVersion { 529 ctx.AddMissingDependencies(sdkDep.bootclasspath) 530 ctx.AddMissingDependencies(sdkDep.java9Classpath) 531 } else if sdkDep.useFiles { 532 deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...) 533 deps.aidlPreprocess = sdkDep.aidl 534 } else { 535 deps.aidlPreprocess = sdkDep.aidl 536 } 537 538 ctx.VisitDirectDeps(func(module android.Module) { 539 otherName := ctx.OtherModuleName(module) 540 tag := ctx.OtherModuleDependencyTag(module) 541 542 switch tag { 543 case bootClasspathTag: 544 if dep, ok := module.(Dependency); ok { 545 deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...) 546 } else if sm, ok := module.(SystemModulesProvider); ok { 547 // A system modules dependency has been added to the bootclasspath 548 // so add its libs to the bootclasspath. 549 deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...) 550 } else { 551 panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName())) 552 } 553 case libTag: 554 switch dep := module.(type) { 555 case SdkLibraryDependency: 556 deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) 557 case Dependency: 558 deps.classpath = append(deps.classpath, dep.HeaderJars()...) 559 deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) 560 case android.SourceFileProducer: 561 checkProducesJars(ctx, dep) 562 deps.classpath = append(deps.classpath, dep.Srcs()...) 563 default: 564 ctx.ModuleErrorf("depends on non-java module %q", otherName) 565 } 566 case java9LibTag: 567 switch dep := module.(type) { 568 case Dependency: 569 deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...) 570 default: 571 ctx.ModuleErrorf("depends on non-java module %q", otherName) 572 } 573 case systemModulesTag: 574 if deps.systemModules != nil { 575 panic("Found two system module dependencies") 576 } 577 sm := module.(SystemModulesProvider) 578 outputDir, outputDeps := sm.OutputDirAndDeps() 579 deps.systemModules = &systemModules{outputDir, outputDeps} 580 } 581 }) 582 // do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs 583 // may contain filegroup or genrule. 584 srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs) 585 j.implicits = append(j.implicits, srcFiles...) 586 587 filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path { 588 if filterPackages == nil { 589 return srcs 590 } 591 filtered := []android.Path{} 592 for _, src := range srcs { 593 if src.Ext() != ".java" { 594 // Don't filter-out non-Java (=generated sources) by package names. This is not ideal, 595 // but otherwise metalava emits stub sources having references to the generated AIDL classes 596 // in filtered-out pacages (e.g. com.android.internal.*). 597 // TODO(b/141149570) We need to fix this by introducing default private constructors or 598 // fixing metalava to not emit constructors having references to unknown classes. 599 filtered = append(filtered, src) 600 continue 601 } 602 packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".") 603 if android.HasAnyPrefix(packageName, filterPackages) { 604 filtered = append(filtered, src) 605 } 606 } 607 return filtered 608 } 609 srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages) 610 611 // While metalava needs package html files, it does not need them to be explicit on the command 612 // line. More importantly, the metalava rsp file is also used by the subsequent jdiff action if 613 // jdiff_enabled=true. javadoc complains if it receives html files on the command line. The filter 614 // below excludes html files from the rsp file for both metalava and jdiff. Note that the html 615 // files are still included as implicit inputs for successful remote execution and correct 616 // incremental builds. 617 filterHtml := func(srcs []android.Path) []android.Path { 618 filtered := []android.Path{} 619 for _, src := range srcs { 620 if src.Ext() == ".html" { 621 continue 622 } 623 filtered = append(filtered, src) 624 } 625 return filtered 626 } 627 srcFiles = filterHtml(srcFiles) 628 629 aidlFlags := j.collectAidlFlags(ctx, deps) 630 srcFiles = j.genSources(ctx, srcFiles, aidlFlags) 631 632 // srcs may depend on some genrule output. 633 j.srcJars = srcFiles.FilterByExt(".srcjar") 634 j.srcJars = append(j.srcJars, deps.srcJars...) 635 636 j.srcFiles = srcFiles.FilterOutByExt(".srcjar") 637 j.srcFiles = append(j.srcFiles, deps.srcs...) 638 639 if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 { 640 j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".") 641 } 642 j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths) 643 644 j.argFiles = android.PathsForModuleSrc(ctx, j.properties.Arg_files) 645 argFilesMap := map[string]string{} 646 argFileLabels := []string{} 647 648 for _, label := range j.properties.Arg_files { 649 var paths = android.PathsForModuleSrc(ctx, []string{label}) 650 if _, exists := argFilesMap[label]; !exists { 651 argFilesMap[label] = strings.Join(paths.Strings(), " ") 652 argFileLabels = append(argFileLabels, label) 653 } else { 654 ctx.ModuleErrorf("multiple arg_files for %q, %q and %q", 655 label, argFilesMap[label], paths) 656 } 657 } 658 659 var argsPropertyName string 660 flags := make([]string, 0) 661 if j.properties.Args != nil && j.properties.Flags != nil { 662 ctx.PropertyErrorf("args", "flags is set. Cannot set args") 663 } else if args := proptools.String(j.properties.Args); args != "" { 664 flags = append(flags, args) 665 argsPropertyName = "args" 666 } else { 667 flags = append(flags, j.properties.Flags...) 668 argsPropertyName = "flags" 669 } 670 671 for _, flag := range flags { 672 args, err := android.Expand(flag, func(name string) (string, error) { 673 if strings.HasPrefix(name, "location ") { 674 label := strings.TrimSpace(strings.TrimPrefix(name, "location ")) 675 if paths, ok := argFilesMap[label]; ok { 676 return paths, nil 677 } else { 678 return "", fmt.Errorf("unknown location label %q, expecting one of %q", 679 label, strings.Join(argFileLabels, ", ")) 680 } 681 } else if name == "genDir" { 682 return android.PathForModuleGen(ctx).String(), nil 683 } 684 return "", fmt.Errorf("unknown variable '$(%s)'", name) 685 }) 686 687 if err != nil { 688 ctx.PropertyErrorf(argsPropertyName, "%s", err.Error()) 689 } 690 j.args = append(j.args, args) 691 } 692 693 return deps 694} 695 696func (j *Javadoc) DepsMutator(ctx android.BottomUpMutatorContext) { 697 j.addDeps(ctx) 698} 699 700func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { 701 deps := j.collectDeps(ctx) 702 703 j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") 704 705 outDir := android.PathForModuleOut(ctx, "out") 706 srcJarDir := android.PathForModuleOut(ctx, "srcjars") 707 708 j.stubsSrcJar = nil 709 710 rule := android.NewRuleBuilder() 711 712 rule.Command().Text("rm -rf").Text(outDir.String()) 713 rule.Command().Text("mkdir -p").Text(outDir.String()) 714 715 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, j.srcJars) 716 717 javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j)) 718 719 cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList, 720 deps.systemModules, deps.classpath, j.sourcepaths) 721 722 cmd.FlagWithArg("-source ", javaVersion.String()). 723 Flag("-J-Xmx1024m"). 724 Flag("-XDignore.symbol.file"). 725 Flag("-Xdoclint:none") 726 727 rule.Command(). 728 BuiltTool(ctx, "soong_zip"). 729 Flag("-write_if_changed"). 730 Flag("-d"). 731 FlagWithOutput("-o ", j.docZip). 732 FlagWithArg("-C ", outDir.String()). 733 FlagWithArg("-D ", outDir.String()) 734 735 rule.Restat() 736 737 zipSyncCleanupCmd(rule, srcJarDir) 738 739 rule.Build(pctx, ctx, "javadoc", "javadoc") 740} 741 742// 743// Droiddoc 744// 745type Droiddoc struct { 746 Javadoc 747 748 properties DroiddocProperties 749 apiFile android.WritablePath 750 privateApiFile android.WritablePath 751 removedApiFile android.WritablePath 752 removedDexApiFile android.WritablePath 753 754 checkCurrentApiTimestamp android.WritablePath 755 updateCurrentApiTimestamp android.WritablePath 756 checkLastReleasedApiTimestamp android.WritablePath 757 758 apiFilePath android.Path 759} 760 761// droiddoc converts .java source files to documentation using doclava or dokka. 762func DroiddocFactory() android.Module { 763 module := &Droiddoc{} 764 765 module.AddProperties(&module.properties, 766 &module.Javadoc.properties) 767 768 InitDroiddocModule(module, android.HostAndDeviceSupported) 769 return module 770} 771 772// droiddoc_host converts .java source files to documentation using doclava or dokka. 773func DroiddocHostFactory() android.Module { 774 module := &Droiddoc{} 775 776 module.AddProperties(&module.properties, 777 &module.Javadoc.properties) 778 779 InitDroiddocModule(module, android.HostSupported) 780 return module 781} 782 783func (d *Droiddoc) ApiFilePath() android.Path { 784 return d.apiFilePath 785} 786 787func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) { 788 d.Javadoc.addDeps(ctx) 789 790 if Bool(d.properties.Check_api.Ignore_missing_latest_api) { 791 ignoreMissingModules(ctx, &d.properties.Check_api.Last_released) 792 } 793 794 if String(d.properties.Custom_template) != "" { 795 ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template)) 796 } 797} 798 799func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) { 800 buildNumberFile := ctx.Config().BuildNumberFile(ctx) 801 // Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources. For modules with 1.9 802 // sources, droiddoc will get sources produced by metalava which will have already stripped out the 803 // 1.9 language features. 804 cmd.FlagWithArg("-source ", "1.8"). 805 Flag("-J-Xmx1600m"). 806 Flag("-J-XX:-OmitStackTraceInFastThrow"). 807 Flag("-XDignore.symbol.file"). 808 FlagWithArg("-doclet ", "com.google.doclava.Doclava"). 809 FlagWithInputList("-docletpath ", docletPath.Paths(), ":"). 810 FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile). 811 FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `) 812 813 if String(d.properties.Custom_template) == "" { 814 // TODO: This is almost always droiddoc-templates-sdk 815 ctx.PropertyErrorf("custom_template", "must specify a template") 816 } 817 818 ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) { 819 if t, ok := m.(*ExportedDroiddocDir); ok { 820 cmd.FlagWithArg("-templatedir ", t.dir.String()).Implicits(t.deps) 821 } else { 822 ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_exported_dir", ctx.OtherModuleName(m)) 823 } 824 }) 825 826 if len(d.properties.Html_dirs) > 0 { 827 htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0]) 828 cmd.FlagWithArg("-htmldir ", htmlDir.String()). 829 Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")})) 830 } 831 832 if len(d.properties.Html_dirs) > 1 { 833 htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1]) 834 cmd.FlagWithArg("-htmldir2 ", htmlDir2.String()). 835 Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[1], "**/*")})) 836 } 837 838 if len(d.properties.Html_dirs) > 2 { 839 ctx.PropertyErrorf("html_dirs", "Droiddoc only supports up to 2 html dirs") 840 } 841 842 knownTags := android.PathsForModuleSrc(ctx, d.properties.Knowntags) 843 cmd.FlagForEachInput("-knowntags ", knownTags) 844 845 cmd.FlagForEachArg("-hdf ", d.properties.Hdf) 846 847 if String(d.properties.Proofread_file) != "" { 848 proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file)) 849 cmd.FlagWithOutput("-proofread ", proofreadFile) 850 } 851 852 if String(d.properties.Todo_file) != "" { 853 // tricky part: 854 // we should not compute full path for todo_file through PathForModuleOut(). 855 // the non-standard doclet will get the full path relative to "-o". 856 cmd.FlagWithArg("-todo ", String(d.properties.Todo_file)). 857 ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file))) 858 } 859 860 if String(d.properties.Resourcesdir) != "" { 861 // TODO: should we add files under resourcesDir to the implicits? It seems that 862 // resourcesDir is one sub dir of htmlDir 863 resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir)) 864 cmd.FlagWithArg("-resourcesdir ", resourcesDir.String()) 865 } 866 867 if String(d.properties.Resourcesoutdir) != "" { 868 // TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere. 869 cmd.FlagWithArg("-resourcesoutdir ", String(d.properties.Resourcesoutdir)) 870 } 871} 872 873func (d *Droiddoc) createStubs() bool { 874 return BoolDefault(d.properties.Create_stubs, false) 875} 876 877func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) { 878 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || 879 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || 880 String(d.properties.Api_filename) != "" { 881 882 d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt") 883 cmd.FlagWithOutput("-api ", d.apiFile) 884 d.apiFilePath = d.apiFile 885 } 886 887 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || 888 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || 889 String(d.properties.Removed_api_filename) != "" { 890 d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt") 891 cmd.FlagWithOutput("-removedApi ", d.removedApiFile) 892 } 893 894 if String(d.properties.Removed_dex_api_filename) != "" { 895 d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename)) 896 cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile) 897 } 898 899 if d.createStubs() { 900 cmd.FlagWithArg("-stubs ", stubsDir.String()) 901 } 902 903 if Bool(d.properties.Write_sdk_values) { 904 cmd.FlagWithArg("-sdkvalues ", android.PathForModuleOut(ctx, "out").String()) 905 } 906} 907 908func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) { 909 if String(d.properties.Static_doc_index_redirect) != "" { 910 staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect)) 911 rule.Command().Text("cp"). 912 Input(staticDocIndexRedirect). 913 Output(android.PathForModuleOut(ctx, "out", "index.html")) 914 } 915 916 if String(d.properties.Static_doc_properties) != "" { 917 staticDocProperties := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_properties)) 918 rule.Command().Text("cp"). 919 Input(staticDocProperties). 920 Output(android.PathForModuleOut(ctx, "out", "source.properties")) 921 } 922} 923 924func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, 925 outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand { 926 927 cmd := rule.Command(). 928 BuiltTool(ctx, "soong_javac_wrapper").Tool(config.JavadocCmd(ctx)). 929 Flag(config.JavacVmFlags). 930 FlagWithArg("-encoding ", "UTF-8"). 931 FlagWithRspFileInputList("@", srcs). 932 FlagWithInput("@", srcJarList) 933 934 // TODO(ccross): Remove this if- statement once we finish migration for all Doclava 935 // based stubs generation. 936 // In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar 937 // dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out 938 // the correct package name base path. 939 if len(sourcepaths) > 0 { 940 cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":") 941 } else { 942 cmd.FlagWithArg("-sourcepath ", srcJarDir.String()) 943 } 944 945 cmd.FlagWithArg("-d ", outDir.String()). 946 Flag("-quiet") 947 948 return cmd 949} 950 951func javadocSystemModulesCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, 952 outDir, srcJarDir, srcJarList android.Path, systemModules *systemModules, 953 classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand { 954 955 cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths) 956 957 flag, deps := systemModules.FormJavaSystemModulesPath(ctx.Device()) 958 cmd.Flag(flag).Implicits(deps) 959 960 cmd.FlagWithArg("--patch-module ", "java.base=.") 961 962 if len(classpath) > 0 { 963 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") 964 } 965 966 return cmd 967} 968 969func javadocBootclasspathCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, 970 outDir, srcJarDir, srcJarList android.Path, bootclasspath, classpath classpath, 971 sourcepaths android.Paths) *android.RuleBuilderCommand { 972 973 cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths) 974 975 if len(bootclasspath) == 0 && ctx.Device() { 976 // explicitly specify -bootclasspath "" if the bootclasspath is empty to 977 // ensure java does not fall back to the default bootclasspath. 978 cmd.FlagWithArg("-bootclasspath ", `""`) 979 } else if len(bootclasspath) > 0 { 980 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":") 981 } 982 983 if len(classpath) > 0 { 984 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") 985 } 986 987 return cmd 988} 989 990func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, 991 outDir, srcJarDir android.Path, bootclasspath, classpath classpath) *android.RuleBuilderCommand { 992 993 // Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka. 994 dokkaClasspath := append(bootclasspath.Paths(), classpath.Paths()...) 995 996 return rule.Command(). 997 BuiltTool(ctx, "dokka"). 998 Flag(config.JavacVmFlags). 999 Flag(srcJarDir.String()). 1000 FlagWithInputList("-classpath ", dokkaClasspath, ":"). 1001 FlagWithArg("-format ", "dac"). 1002 FlagWithArg("-dacRoot ", "/reference/kotlin"). 1003 FlagWithArg("-output ", outDir.String()) 1004} 1005 1006func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1007 deps := d.Javadoc.collectDeps(ctx) 1008 1009 d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") 1010 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") 1011 1012 jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar") 1013 doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar") 1014 java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME") 1015 checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")} 1016 1017 outDir := android.PathForModuleOut(ctx, "out") 1018 srcJarDir := android.PathForModuleOut(ctx, "srcjars") 1019 stubsDir := android.PathForModuleOut(ctx, "stubsDir") 1020 1021 rule := android.NewRuleBuilder() 1022 1023 rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String()) 1024 rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String()) 1025 1026 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) 1027 1028 var cmd *android.RuleBuilderCommand 1029 if Bool(d.properties.Dokka_enabled) { 1030 cmd = dokkaCmd(ctx, rule, outDir, srcJarDir, deps.bootClasspath, deps.classpath) 1031 } else { 1032 cmd = javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList, 1033 deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) 1034 } 1035 1036 d.stubsFlags(ctx, cmd, stubsDir) 1037 1038 cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles) 1039 1040 if d.properties.Compat_config != nil { 1041 compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config)) 1042 cmd.FlagWithInput("-compatconfig ", compatConfig) 1043 } 1044 1045 var desc string 1046 if Bool(d.properties.Dokka_enabled) { 1047 desc = "dokka" 1048 } else { 1049 d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava}) 1050 1051 for _, o := range d.Javadoc.properties.Out { 1052 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) 1053 } 1054 1055 d.postDoclavaCmds(ctx, rule) 1056 desc = "doclava" 1057 } 1058 1059 rule.Command(). 1060 BuiltTool(ctx, "soong_zip"). 1061 Flag("-write_if_changed"). 1062 Flag("-d"). 1063 FlagWithOutput("-o ", d.docZip). 1064 FlagWithArg("-C ", outDir.String()). 1065 FlagWithArg("-D ", outDir.String()) 1066 1067 rule.Command(). 1068 BuiltTool(ctx, "soong_zip"). 1069 Flag("-write_if_changed"). 1070 Flag("-jar"). 1071 FlagWithOutput("-o ", d.stubsSrcJar). 1072 FlagWithArg("-C ", stubsDir.String()). 1073 FlagWithArg("-D ", stubsDir.String()) 1074 1075 rule.Restat() 1076 1077 zipSyncCleanupCmd(rule, srcJarDir) 1078 1079 rule.Build(pctx, ctx, "javadoc", desc) 1080 1081 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") && 1082 !ctx.Config().IsPdkBuild() { 1083 1084 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) 1085 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) 1086 1087 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp") 1088 1089 rule := android.NewRuleBuilder() 1090 1091 rule.Command().Text("( true") 1092 1093 rule.Command(). 1094 BuiltTool(ctx, "apicheck"). 1095 Flag("-JXmx1024m"). 1096 FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":"). 1097 OptionalFlag(d.properties.Check_api.Current.Args). 1098 Input(apiFile). 1099 Input(d.apiFile). 1100 Input(removedApiFile). 1101 Input(d.removedApiFile) 1102 1103 msg := fmt.Sprintf(`\n******************************\n`+ 1104 `You have tried to change the API from what has been previously approved.\n\n`+ 1105 `To make these errors go away, you have two choices:\n`+ 1106 ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+ 1107 ` errors above.\n\n`+ 1108 ` 2. You can update current.txt by executing the following command:\n`+ 1109 ` make %s-update-current-api\n\n`+ 1110 ` To submit the revised current.txt to the main Android repository,\n`+ 1111 ` you will need approval.\n`+ 1112 `******************************\n`, ctx.ModuleName()) 1113 1114 rule.Command(). 1115 Text("touch").Output(d.checkCurrentApiTimestamp). 1116 Text(") || ("). 1117 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1118 Text("; exit 38"). 1119 Text(")") 1120 1121 rule.Build(pctx, ctx, "doclavaCurrentApiCheck", "check current API") 1122 1123 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp") 1124 1125 // update API rule 1126 rule = android.NewRuleBuilder() 1127 1128 rule.Command().Text("( true") 1129 1130 rule.Command(). 1131 Text("cp").Flag("-f"). 1132 Input(d.apiFile).Flag(apiFile.String()) 1133 1134 rule.Command(). 1135 Text("cp").Flag("-f"). 1136 Input(d.removedApiFile).Flag(removedApiFile.String()) 1137 1138 msg = "failed to update public API" 1139 1140 rule.Command(). 1141 Text("touch").Output(d.updateCurrentApiTimestamp). 1142 Text(") || ("). 1143 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1144 Text("; exit 38"). 1145 Text(")") 1146 1147 rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API") 1148 } 1149 1150 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") && 1151 !ctx.Config().IsPdkBuild() { 1152 1153 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) 1154 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) 1155 1156 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp") 1157 1158 rule := android.NewRuleBuilder() 1159 1160 rule.Command(). 1161 Text("("). 1162 BuiltTool(ctx, "apicheck"). 1163 Flag("-JXmx1024m"). 1164 FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":"). 1165 OptionalFlag(d.properties.Check_api.Last_released.Args). 1166 Input(apiFile). 1167 Input(d.apiFile). 1168 Input(removedApiFile). 1169 Input(d.removedApiFile) 1170 1171 msg := `\n******************************\n` + 1172 `You have tried to change the API from what has been previously released in\n` + 1173 `an SDK. Please fix the errors listed above.\n` + 1174 `******************************\n` 1175 1176 rule.Command(). 1177 Text("touch").Output(d.checkLastReleasedApiTimestamp). 1178 Text(") || ("). 1179 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1180 Text("; exit 38"). 1181 Text(")") 1182 1183 rule.Build(pctx, ctx, "doclavaLastApiCheck", "check last API") 1184 } 1185} 1186 1187// 1188// Droidstubs 1189// 1190type Droidstubs struct { 1191 Javadoc 1192 android.SdkBase 1193 1194 properties DroidstubsProperties 1195 apiFile android.WritablePath 1196 apiXmlFile android.WritablePath 1197 lastReleasedApiXmlFile android.WritablePath 1198 privateApiFile android.WritablePath 1199 removedApiFile android.WritablePath 1200 removedDexApiFile android.WritablePath 1201 nullabilityWarningsFile android.WritablePath 1202 1203 checkCurrentApiTimestamp android.WritablePath 1204 updateCurrentApiTimestamp android.WritablePath 1205 checkLastReleasedApiTimestamp android.WritablePath 1206 apiLintTimestamp android.WritablePath 1207 apiLintReport android.WritablePath 1208 1209 checkNullabilityWarningsTimestamp android.WritablePath 1210 1211 annotationsZip android.WritablePath 1212 apiVersionsXml android.WritablePath 1213 1214 apiFilePath android.Path 1215 1216 jdiffDocZip android.WritablePath 1217 jdiffStubsSrcJar android.WritablePath 1218 1219 metadataZip android.WritablePath 1220 metadataDir android.WritablePath 1221} 1222 1223// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be 1224// documented, filtering out hidden classes and methods. The resulting .java files are intended to be passed to 1225// a droiddoc module to generate documentation. 1226func DroidstubsFactory() android.Module { 1227 module := &Droidstubs{} 1228 1229 module.AddProperties(&module.properties, 1230 &module.Javadoc.properties) 1231 1232 InitDroiddocModule(module, android.HostAndDeviceSupported) 1233 android.InitSdkAwareModule(module) 1234 return module 1235} 1236 1237// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API 1238// to be documented, filtering out hidden classes and methods. The resulting .java files are intended to be 1239// passed to a droiddoc_host module to generate documentation. Use a droidstubs_host instead of a droidstubs 1240// module when symbols needed by the source files are provided by java_library_host modules. 1241func DroidstubsHostFactory() android.Module { 1242 module := &Droidstubs{} 1243 1244 module.AddProperties(&module.properties, 1245 &module.Javadoc.properties) 1246 1247 InitDroiddocModule(module, android.HostSupported) 1248 return module 1249} 1250 1251func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) { 1252 switch tag { 1253 case "": 1254 return android.Paths{d.stubsSrcJar}, nil 1255 case ".docs.zip": 1256 return android.Paths{d.docZip}, nil 1257 case ".annotations.zip": 1258 return android.Paths{d.annotationsZip}, nil 1259 case ".api_versions.xml": 1260 return android.Paths{d.apiVersionsXml}, nil 1261 default: 1262 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 1263 } 1264} 1265 1266func (d *Droidstubs) ApiFilePath() android.Path { 1267 return d.apiFilePath 1268} 1269 1270func (d *Droidstubs) RemovedApiFilePath() android.Path { 1271 return d.removedApiFile 1272} 1273 1274func (d *Droidstubs) StubsSrcJar() android.Path { 1275 return d.stubsSrcJar 1276} 1277 1278func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) { 1279 d.Javadoc.addDeps(ctx) 1280 1281 // If requested clear any properties that provide information about the latest version 1282 // of an API and which reference non-existent modules. 1283 if Bool(d.properties.Check_api.Ignore_missing_latest_api) { 1284 ignoreMissingModules(ctx, &d.properties.Check_api.Last_released) 1285 1286 // If the new_since references a module, e.g. :module-latest-api and the module 1287 // does not exist then clear it. 1288 newSinceSrc := d.properties.Check_api.Api_lint.New_since 1289 newSinceSrcModule := android.SrcIsModule(proptools.String(newSinceSrc)) 1290 if newSinceSrcModule != "" && !ctx.OtherModuleExists(newSinceSrcModule) { 1291 d.properties.Check_api.Api_lint.New_since = nil 1292 } 1293 } 1294 1295 if len(d.properties.Merge_annotations_dirs) != 0 { 1296 for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs { 1297 ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir) 1298 } 1299 } 1300 1301 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 { 1302 for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs { 1303 ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir) 1304 } 1305 } 1306 1307 if len(d.properties.Api_levels_annotations_dirs) != 0 { 1308 for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs { 1309 ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir) 1310 } 1311 } 1312} 1313 1314func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) { 1315 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || 1316 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || 1317 String(d.properties.Api_filename) != "" { 1318 d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt") 1319 cmd.FlagWithOutput("--api ", d.apiFile) 1320 d.apiFilePath = d.apiFile 1321 } 1322 1323 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || 1324 apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || 1325 String(d.properties.Removed_api_filename) != "" { 1326 d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt") 1327 cmd.FlagWithOutput("--removed-api ", d.removedApiFile) 1328 } 1329 1330 if String(d.properties.Removed_dex_api_filename) != "" { 1331 d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename)) 1332 cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile) 1333 } 1334 1335 if Bool(d.properties.Write_sdk_values) { 1336 d.metadataDir = android.PathForModuleOut(ctx, "metadata") 1337 cmd.FlagWithArg("--sdk-values ", d.metadataDir.String()) 1338 } 1339 1340 if stubsDir.Valid() { 1341 if Bool(d.properties.Create_doc_stubs) { 1342 cmd.FlagWithArg("--doc-stubs ", stubsDir.String()) 1343 } else { 1344 cmd.FlagWithArg("--stubs ", stubsDir.String()) 1345 cmd.Flag("--exclude-documentation-from-stubs") 1346 } 1347 } 1348} 1349 1350func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 1351 if Bool(d.properties.Annotations_enabled) { 1352 cmd.Flag("--include-annotations") 1353 1354 validatingNullability := 1355 android.InList("--validate-nullability-from-merged-stubs", d.Javadoc.args) || 1356 String(d.properties.Validate_nullability_from_list) != "" 1357 1358 migratingNullability := String(d.properties.Previous_api) != "" 1359 if migratingNullability { 1360 previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api)) 1361 cmd.FlagWithInput("--migrate-nullness ", previousApi) 1362 } 1363 1364 if s := String(d.properties.Validate_nullability_from_list); s != "" { 1365 cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s)) 1366 } 1367 1368 if validatingNullability { 1369 d.nullabilityWarningsFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_nullability_warnings.txt") 1370 cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile) 1371 } 1372 1373 d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip") 1374 cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip) 1375 1376 if len(d.properties.Merge_annotations_dirs) != 0 { 1377 d.mergeAnnoDirFlags(ctx, cmd) 1378 } 1379 1380 // TODO(tnorbye): find owners to fix these warnings when annotation was enabled. 1381 cmd.FlagWithArg("--hide ", "HiddenTypedefConstant"). 1382 FlagWithArg("--hide ", "SuperfluousPrefix"). 1383 FlagWithArg("--hide ", "AnnotationExtraction") 1384 } 1385} 1386 1387func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 1388 ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) { 1389 if t, ok := m.(*ExportedDroiddocDir); ok { 1390 cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps) 1391 } else { 1392 ctx.PropertyErrorf("merge_annotations_dirs", 1393 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) 1394 } 1395 }) 1396} 1397 1398func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 1399 ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) { 1400 if t, ok := m.(*ExportedDroiddocDir); ok { 1401 cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps) 1402 } else { 1403 ctx.PropertyErrorf("merge_inclusion_annotations_dirs", 1404 "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) 1405 } 1406 }) 1407} 1408 1409func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 1410 if Bool(d.properties.Api_levels_annotations_enabled) { 1411 d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml") 1412 1413 if len(d.properties.Api_levels_annotations_dirs) == 0 { 1414 ctx.PropertyErrorf("api_levels_annotations_dirs", 1415 "has to be non-empty if api levels annotations was enabled!") 1416 } 1417 1418 cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) 1419 cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml) 1420 cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion()) 1421 cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) 1422 1423 ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { 1424 if t, ok := m.(*ExportedDroiddocDir); ok { 1425 for _, dep := range t.deps { 1426 if strings.HasSuffix(dep.String(), "android.jar") { 1427 cmd.Implicit(dep) 1428 } 1429 } 1430 cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/android.jar") 1431 } else { 1432 ctx.PropertyErrorf("api_levels_annotations_dirs", 1433 "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) 1434 } 1435 }) 1436 1437 } 1438} 1439 1440func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { 1441 if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() && d.apiFile != nil { 1442 if d.apiFile.String() == "" { 1443 ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.") 1444 } 1445 1446 d.apiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.xml") 1447 cmd.FlagWithOutput("--api-xml ", d.apiXmlFile) 1448 1449 if String(d.properties.Check_api.Last_released.Api_file) == "" { 1450 ctx.PropertyErrorf("check_api.last_released.api_file", 1451 "has to be non-empty if jdiff was enabled!") 1452 } 1453 1454 lastReleasedApi := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) 1455 d.lastReleasedApiXmlFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_last_released_api.xml") 1456 cmd.FlagWithInput("--convert-to-jdiff ", lastReleasedApi).Output(d.lastReleasedApiXmlFile) 1457 } 1458} 1459 1460func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths, 1461 srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicitsRsp android.WritablePath, sandbox bool) *android.RuleBuilderCommand { 1462 // Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel. 1463 rule.HighMem() 1464 cmd := rule.Command() 1465 if ctx.Config().IsEnvTrue("RBE_METALAVA") { 1466 rule.Remoteable(android.RemoteRuleSupports{RBE: true}) 1467 pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava") 1468 execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy) 1469 labels := map[string]string{"type": "compile", "lang": "java", "compiler": "metalava"} 1470 if !sandbox { 1471 execStrategy = remoteexec.LocalExecStrategy 1472 labels["shallow"] = "true" 1473 } 1474 inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()} 1475 if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" { 1476 inputs = append(inputs, strings.Split(v, ",")...) 1477 } 1478 cmd.Text((&remoteexec.REParams{ 1479 Labels: labels, 1480 ExecStrategy: execStrategy, 1481 Inputs: inputs, 1482 RSPFile: implicitsRsp.String(), 1483 ToolchainInputs: []string{config.JavaCmd(ctx).String()}, 1484 Platform: map[string]string{remoteexec.PoolKey: pool}, 1485 }).NoVarTemplate(ctx.Config())) 1486 } 1487 1488 cmd.BuiltTool(ctx, "metalava"). 1489 Flag(config.JavacVmFlags). 1490 FlagWithArg("-encoding ", "UTF-8"). 1491 FlagWithArg("-source ", javaVersion.String()). 1492 FlagWithRspFileInputList("@", srcs). 1493 FlagWithInput("@", srcJarList) 1494 1495 if javaHome := ctx.Config().Getenv("ANDROID_JAVA_HOME"); javaHome != "" { 1496 cmd.Implicit(android.PathForSource(ctx, javaHome)) 1497 } 1498 1499 if sandbox { 1500 cmd.FlagWithOutput("--strict-input-files ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt")) 1501 } else { 1502 cmd.FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt")) 1503 } 1504 1505 if implicitsRsp != nil { 1506 cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String()) 1507 } 1508 1509 if len(bootclasspath) > 0 { 1510 cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":") 1511 } 1512 1513 if len(classpath) > 0 { 1514 cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") 1515 } 1516 1517 if len(sourcepaths) > 0 { 1518 cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":") 1519 } else { 1520 cmd.FlagWithArg("-sourcepath ", `""`) 1521 } 1522 1523 cmd.Flag("--no-banner"). 1524 Flag("--color"). 1525 Flag("--quiet"). 1526 Flag("--format=v2"). 1527 FlagWithArg("--repeat-errors-max ", "10"). 1528 FlagWithArg("--hide ", "UnresolvedImport") 1529 1530 return cmd 1531} 1532 1533func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1534 deps := d.Javadoc.collectDeps(ctx) 1535 1536 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d)) 1537 1538 // Create rule for metalava 1539 1540 srcJarDir := android.PathForModuleOut(ctx, "srcjars") 1541 1542 rule := android.NewRuleBuilder() 1543 1544 generateStubs := BoolDefault(d.properties.Generate_stubs, true) 1545 var stubsDir android.OptionalPath 1546 if generateStubs { 1547 d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") 1548 stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "stubsDir")) 1549 rule.Command().Text("rm -rf").Text(stubsDir.String()) 1550 rule.Command().Text("mkdir -p").Text(stubsDir.String()) 1551 } 1552 1553 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) 1554 1555 implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp") 1556 1557 cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList, 1558 deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, implicitsRsp, 1559 Bool(d.Javadoc.properties.Sandbox)) 1560 cmd.Implicits(d.Javadoc.implicits) 1561 1562 d.stubsFlags(ctx, cmd, stubsDir) 1563 1564 d.annotationsFlags(ctx, cmd) 1565 d.inclusionAnnotationsFlags(ctx, cmd) 1566 d.apiLevelsAnnotationsFlags(ctx, cmd) 1567 d.apiToXmlFlags(ctx, cmd) 1568 1569 if android.InList("--generate-documentation", d.Javadoc.args) { 1570 // Currently Metalava have the ability to invoke Javadoc in a seperate process. 1571 // Pass "-nodocs" to suppress the Javadoc invocation when Metalava receives 1572 // "--generate-documentation" arg. This is not needed when Metalava removes this feature. 1573 d.Javadoc.args = append(d.Javadoc.args, "-nodocs") 1574 } 1575 1576 cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles) 1577 for _, o := range d.Javadoc.properties.Out { 1578 cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) 1579 } 1580 1581 // Add options for the other optional tasks: API-lint and check-released. 1582 // We generate separate timestamp files for them. 1583 1584 doApiLint := false 1585 doCheckReleased := false 1586 1587 // Add API lint options. 1588 1589 if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().IsPdkBuild() { 1590 doApiLint = true 1591 1592 newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since) 1593 if newSince.Valid() { 1594 cmd.FlagWithInput("--api-lint ", newSince.Path()) 1595 } else { 1596 cmd.Flag("--api-lint") 1597 } 1598 d.apiLintReport = android.PathForModuleOut(ctx, "api_lint_report.txt") 1599 cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint" 1600 1601 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file) 1602 updatedBaselineOutput := android.PathForModuleOut(ctx, "api_lint_baseline.txt") 1603 d.apiLintTimestamp = android.PathForModuleOut(ctx, "api_lint.timestamp") 1604 1605 // Note this string includes a special shell quote $' ... ', which decodes the "\n"s. 1606 // However, because $' ... ' doesn't expand environmental variables, we can't just embed 1607 // $PWD, so we have to terminate $'...', use "$PWD", then start $' ... ' again, 1608 // which is why we have '"$PWD"$' in it. 1609 // 1610 // TODO: metalava also has a slightly different message hardcoded. Should we unify this 1611 // message and metalava's one? 1612 msg := `$'` + // Enclose with $' ... ' 1613 `************************************************************\n` + 1614 `Your API changes are triggering API Lint warnings or errors.\n` + 1615 `To make these errors go away, fix the code according to the\n` + 1616 `error and/or warning messages above.\n` + 1617 `\n` + 1618 `If it is not possible to do so, there are workarounds:\n` + 1619 `\n` + 1620 `1. You can suppress the errors with @SuppressLint("<id>")\n` 1621 1622 if baselineFile.Valid() { 1623 cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path()) 1624 cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput) 1625 1626 msg += fmt.Sprintf(``+ 1627 `2. You can update the baseline by executing the following\n`+ 1628 ` command:\n`+ 1629 ` cp \\\n`+ 1630 ` "'"$PWD"$'/%s" \\\n`+ 1631 ` "'"$PWD"$'/%s"\n`+ 1632 ` To submit the revised baseline.txt to the main Android\n`+ 1633 ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path()) 1634 } else { 1635 msg += fmt.Sprintf(``+ 1636 `2. You can add a baseline file of existing lint failures\n`+ 1637 ` to the build rule of %s.\n`, d.Name()) 1638 } 1639 // Note the message ends with a ' (single quote), to close the $' ... ' . 1640 msg += `************************************************************\n'` 1641 1642 cmd.FlagWithArg("--error-message:api-lint ", msg) 1643 } 1644 1645 // Add "check released" options. (Detect incompatible API changes from the last public release) 1646 1647 if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") && 1648 !ctx.Config().IsPdkBuild() { 1649 doCheckReleased = true 1650 1651 if len(d.Javadoc.properties.Out) > 0 { 1652 ctx.PropertyErrorf("out", "out property may not be combined with check_api") 1653 } 1654 1655 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) 1656 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) 1657 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file) 1658 updatedBaselineOutput := android.PathForModuleOut(ctx, "last_released_baseline.txt") 1659 1660 d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp") 1661 1662 cmd.FlagWithInput("--check-compatibility:api:released ", apiFile) 1663 cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile) 1664 1665 if baselineFile.Valid() { 1666 cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path()) 1667 cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput) 1668 } 1669 1670 // Note this string includes quote ($' ... '), which decodes the "\n"s. 1671 msg := `$'\n******************************\n` + 1672 `You have tried to change the API from what has been previously released in\n` + 1673 `an SDK. Please fix the errors listed above.\n` + 1674 `******************************\n'` 1675 1676 cmd.FlagWithArg("--error-message:compatibility:released ", msg) 1677 } 1678 1679 impRule := android.NewRuleBuilder() 1680 impCmd := impRule.Command() 1681 // An action that copies the ninja generated rsp file to a new location. This allows us to 1682 // add a large number of inputs to a file without exceeding bash command length limits (which 1683 // would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the 1684 // rsp file to be ${output}.rsp. 1685 impCmd.Text("cp").FlagWithRspFileInputList("", cmd.GetImplicits()).Output(implicitsRsp) 1686 impRule.Build(pctx, ctx, "implicitsGen", "implicits generation") 1687 cmd.Implicit(implicitsRsp) 1688 1689 if generateStubs { 1690 rule.Command(). 1691 BuiltTool(ctx, "soong_zip"). 1692 Flag("-write_if_changed"). 1693 Flag("-jar"). 1694 FlagWithOutput("-o ", d.Javadoc.stubsSrcJar). 1695 FlagWithArg("-C ", stubsDir.String()). 1696 FlagWithArg("-D ", stubsDir.String()) 1697 } 1698 1699 if Bool(d.properties.Write_sdk_values) { 1700 d.metadataZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-metadata.zip") 1701 rule.Command(). 1702 BuiltTool(ctx, "soong_zip"). 1703 Flag("-write_if_changed"). 1704 Flag("-d"). 1705 FlagWithOutput("-o ", d.metadataZip). 1706 FlagWithArg("-C ", d.metadataDir.String()). 1707 FlagWithArg("-D ", d.metadataDir.String()) 1708 } 1709 1710 // TODO: We don't really need two separate API files, but this is a reminiscence of how 1711 // we used to run metalava separately for API lint and the "last_released" check. Unify them. 1712 if doApiLint { 1713 rule.Command().Text("touch").Output(d.apiLintTimestamp) 1714 } 1715 if doCheckReleased { 1716 rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp) 1717 } 1718 1719 rule.Restat() 1720 1721 zipSyncCleanupCmd(rule, srcJarDir) 1722 1723 rule.Build(pctx, ctx, "metalava", "metalava merged") 1724 1725 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") && 1726 !ctx.Config().IsPdkBuild() { 1727 1728 if len(d.Javadoc.properties.Out) > 0 { 1729 ctx.PropertyErrorf("out", "out property may not be combined with check_api") 1730 } 1731 1732 apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) 1733 removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) 1734 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file) 1735 1736 if baselineFile.Valid() { 1737 ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName()) 1738 } 1739 1740 d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp") 1741 1742 rule := android.NewRuleBuilder() 1743 1744 // Diff command line. 1745 // -F matches the closest "opening" line, such as "package android {" 1746 // and " public class Intent {". 1747 diff := `diff -u -F '{ *$'` 1748 1749 rule.Command().Text("( true") 1750 rule.Command(). 1751 Text(diff). 1752 Input(apiFile).Input(d.apiFile) 1753 1754 rule.Command(). 1755 Text(diff). 1756 Input(removedApiFile).Input(d.removedApiFile) 1757 1758 msg := fmt.Sprintf(`\n******************************\n`+ 1759 `You have tried to change the API from what has been previously approved.\n\n`+ 1760 `To make these errors go away, you have two choices:\n`+ 1761 ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+ 1762 ` to the new methods, etc. shown in the above diff.\n\n`+ 1763 ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+ 1764 ` make %s-update-current-api\n\n`+ 1765 ` To submit the revised current.txt to the main Android repository,\n`+ 1766 ` you will need approval.\n`+ 1767 `******************************\n`, ctx.ModuleName()) 1768 1769 rule.Command(). 1770 Text("touch").Output(d.checkCurrentApiTimestamp). 1771 Text(") || ("). 1772 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1773 Text("; exit 38"). 1774 Text(")") 1775 1776 rule.Build(pctx, ctx, "metalavaCurrentApiCheck", "check current API") 1777 1778 d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp") 1779 1780 // update API rule 1781 rule = android.NewRuleBuilder() 1782 1783 rule.Command().Text("( true") 1784 1785 rule.Command(). 1786 Text("cp").Flag("-f"). 1787 Input(d.apiFile).Flag(apiFile.String()) 1788 1789 rule.Command(). 1790 Text("cp").Flag("-f"). 1791 Input(d.removedApiFile).Flag(removedApiFile.String()) 1792 1793 msg = "failed to update public API" 1794 1795 rule.Command(). 1796 Text("touch").Output(d.updateCurrentApiTimestamp). 1797 Text(") || ("). 1798 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1799 Text("; exit 38"). 1800 Text(")") 1801 1802 rule.Build(pctx, ctx, "metalavaCurrentApiUpdate", "update current API") 1803 } 1804 1805 if String(d.properties.Check_nullability_warnings) != "" { 1806 if d.nullabilityWarningsFile == nil { 1807 ctx.PropertyErrorf("check_nullability_warnings", 1808 "Cannot specify check_nullability_warnings unless validating nullability") 1809 } 1810 1811 checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings)) 1812 1813 d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "check_nullability_warnings.timestamp") 1814 1815 msg := fmt.Sprintf(`\n******************************\n`+ 1816 `The warnings encountered during nullability annotation validation did\n`+ 1817 `not match the checked in file of expected warnings. The diffs are shown\n`+ 1818 `above. You have two options:\n`+ 1819 ` 1. Resolve the differences by editing the nullability annotations.\n`+ 1820 ` 2. Update the file of expected warnings by running:\n`+ 1821 ` cp %s %s\n`+ 1822 ` and submitting the updated file as part of your change.`, 1823 d.nullabilityWarningsFile, checkNullabilityWarnings) 1824 1825 rule := android.NewRuleBuilder() 1826 1827 rule.Command(). 1828 Text("("). 1829 Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile). 1830 Text("&&"). 1831 Text("touch").Output(d.checkNullabilityWarningsTimestamp). 1832 Text(") || ("). 1833 Text("echo").Flag("-e").Flag(`"` + msg + `"`). 1834 Text("; exit 38"). 1835 Text(")") 1836 1837 rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check") 1838 } 1839 1840 if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() { 1841 if len(d.Javadoc.properties.Out) > 0 { 1842 ctx.PropertyErrorf("out", "out property may not be combined with jdiff") 1843 } 1844 1845 outDir := android.PathForModuleOut(ctx, "jdiff-out") 1846 srcJarDir := android.PathForModuleOut(ctx, "jdiff-srcjars") 1847 stubsDir := android.PathForModuleOut(ctx, "jdiff-stubsDir") 1848 1849 rule := android.NewRuleBuilder() 1850 1851 // Please sync with android-api-council@ before making any changes for the name of jdiffDocZip below 1852 // since there's cron job downstream that fetch this .zip file periodically. 1853 // See b/116221385 for reference. 1854 d.jdiffDocZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-docs.zip") 1855 d.jdiffStubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"jdiff-stubs.srcjar") 1856 1857 jdiff := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jdiff.jar") 1858 1859 rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String()) 1860 rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String()) 1861 1862 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) 1863 1864 cmd := javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList, 1865 deps.bootClasspath, deps.classpath, d.sourcepaths) 1866 1867 cmd.Flag("-J-Xmx1600m"). 1868 Flag("-XDignore.symbol.file"). 1869 FlagWithArg("-doclet ", "jdiff.JDiff"). 1870 FlagWithInput("-docletpath ", jdiff). 1871 Flag("-quiet") 1872 1873 if d.apiXmlFile != nil { 1874 cmd.FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())). 1875 FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())). 1876 Implicit(d.apiXmlFile) 1877 } 1878 1879 if d.lastReleasedApiXmlFile != nil { 1880 cmd.FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())). 1881 FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())). 1882 Implicit(d.lastReleasedApiXmlFile) 1883 } 1884 1885 rule.Command(). 1886 BuiltTool(ctx, "soong_zip"). 1887 Flag("-write_if_changed"). 1888 Flag("-d"). 1889 FlagWithOutput("-o ", d.jdiffDocZip). 1890 FlagWithArg("-C ", outDir.String()). 1891 FlagWithArg("-D ", outDir.String()) 1892 1893 rule.Command(). 1894 BuiltTool(ctx, "soong_zip"). 1895 Flag("-write_if_changed"). 1896 Flag("-jar"). 1897 FlagWithOutput("-o ", d.jdiffStubsSrcJar). 1898 FlagWithArg("-C ", stubsDir.String()). 1899 FlagWithArg("-D ", stubsDir.String()) 1900 1901 rule.Restat() 1902 1903 zipSyncCleanupCmd(rule, srcJarDir) 1904 1905 rule.Build(pctx, ctx, "jdiff", "jdiff") 1906 } 1907} 1908 1909// 1910// Exported Droiddoc Directory 1911// 1912var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"} 1913var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"} 1914var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"} 1915var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"} 1916 1917type ExportedDroiddocDirProperties struct { 1918 // path to the directory containing Droiddoc related files. 1919 Path *string 1920} 1921 1922type ExportedDroiddocDir struct { 1923 android.ModuleBase 1924 1925 properties ExportedDroiddocDirProperties 1926 1927 deps android.Paths 1928 dir android.Path 1929} 1930 1931// droiddoc_exported_dir exports a directory of html templates or nullability annotations for use by doclava. 1932func ExportedDroiddocDirFactory() android.Module { 1933 module := &ExportedDroiddocDir{} 1934 module.AddProperties(&module.properties) 1935 android.InitAndroidModule(module) 1936 return module 1937} 1938 1939func (d *ExportedDroiddocDir) DepsMutator(android.BottomUpMutatorContext) {} 1940 1941func (d *ExportedDroiddocDir) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1942 path := String(d.properties.Path) 1943 d.dir = android.PathForModuleSrc(ctx, path) 1944 d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")}) 1945} 1946 1947// 1948// Defaults 1949// 1950type DocDefaults struct { 1951 android.ModuleBase 1952 android.DefaultsModuleBase 1953} 1954 1955func DocDefaultsFactory() android.Module { 1956 module := &DocDefaults{} 1957 1958 module.AddProperties( 1959 &JavadocProperties{}, 1960 &DroiddocProperties{}, 1961 ) 1962 1963 android.InitDefaultsModule(module) 1964 1965 return module 1966} 1967 1968func StubsDefaultsFactory() android.Module { 1969 module := &DocDefaults{} 1970 1971 module.AddProperties( 1972 &JavadocProperties{}, 1973 &DroidstubsProperties{}, 1974 ) 1975 1976 android.InitDefaultsModule(module) 1977 1978 return module 1979} 1980 1981func zipSyncCmd(ctx android.ModuleContext, rule *android.RuleBuilder, 1982 srcJarDir android.ModuleOutPath, srcJars android.Paths) android.OutputPath { 1983 1984 rule.Command().Text("rm -rf").Text(srcJarDir.String()) 1985 rule.Command().Text("mkdir -p").Text(srcJarDir.String()) 1986 srcJarList := srcJarDir.Join(ctx, "list") 1987 1988 rule.Temporary(srcJarList) 1989 1990 rule.Command().BuiltTool(ctx, "zipsync"). 1991 FlagWithArg("-d ", srcJarDir.String()). 1992 FlagWithOutput("-l ", srcJarList). 1993 FlagWithArg("-f ", `"*.java"`). 1994 Inputs(srcJars) 1995 1996 return srcJarList 1997} 1998 1999func zipSyncCleanupCmd(rule *android.RuleBuilder, srcJarDir android.ModuleOutPath) { 2000 rule.Command().Text("rm -rf").Text(srcJarDir.String()) 2001} 2002 2003var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil) 2004 2005type PrebuiltStubsSourcesProperties struct { 2006 Srcs []string `android:"path"` 2007} 2008 2009type PrebuiltStubsSources struct { 2010 android.ModuleBase 2011 android.DefaultableModuleBase 2012 prebuilt android.Prebuilt 2013 android.SdkBase 2014 2015 properties PrebuiltStubsSourcesProperties 2016 2017 // The source directories containing stubs source files. 2018 srcDirs android.Paths 2019 stubsSrcJar android.ModuleOutPath 2020} 2021 2022func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) { 2023 switch tag { 2024 case "": 2025 return android.Paths{p.stubsSrcJar}, nil 2026 default: 2027 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 2028 } 2029} 2030 2031func (d *PrebuiltStubsSources) StubsSrcJar() android.Path { 2032 return d.stubsSrcJar 2033} 2034 2035func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { 2036 p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") 2037 2038 p.srcDirs = android.PathsForModuleSrc(ctx, p.properties.Srcs) 2039 2040 rule := android.NewRuleBuilder() 2041 command := rule.Command(). 2042 BuiltTool(ctx, "soong_zip"). 2043 Flag("-write_if_changed"). 2044 Flag("-jar"). 2045 FlagWithOutput("-o ", p.stubsSrcJar) 2046 2047 for _, d := range p.srcDirs { 2048 dir := d.String() 2049 command. 2050 FlagWithArg("-C ", dir). 2051 FlagWithInput("-D ", d) 2052 } 2053 2054 rule.Restat() 2055 2056 rule.Build(pctx, ctx, "zip src", "Create srcjar from prebuilt source") 2057} 2058 2059func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt { 2060 return &p.prebuilt 2061} 2062 2063func (p *PrebuiltStubsSources) Name() string { 2064 return p.prebuilt.Name(p.ModuleBase.Name()) 2065} 2066 2067// prebuilt_stubs_sources imports a set of java source files as if they were 2068// generated by droidstubs. 2069// 2070// By default, a prebuilt_stubs_sources has a single variant that expects a 2071// set of `.java` files generated by droidstubs. 2072// 2073// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one 2074// for host modules. 2075// 2076// Intended only for use by sdk snapshots. 2077func PrebuiltStubsSourcesFactory() android.Module { 2078 module := &PrebuiltStubsSources{} 2079 2080 module.AddProperties(&module.properties) 2081 2082 android.InitPrebuiltModule(module, &module.properties.Srcs) 2083 android.InitSdkAwareModule(module) 2084 InitDroiddocModule(module, android.HostAndDeviceSupported) 2085 return module 2086} 2087 2088type droidStubsSdkMemberType struct { 2089 android.SdkMemberTypeBase 2090} 2091 2092func (mt *droidStubsSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) { 2093 mctx.AddVariationDependencies(nil, dependencyTag, names...) 2094} 2095 2096func (mt *droidStubsSdkMemberType) IsInstance(module android.Module) bool { 2097 _, ok := module.(*Droidstubs) 2098 return ok 2099} 2100 2101func (mt *droidStubsSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { 2102 return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_stubs_sources") 2103} 2104 2105func (mt *droidStubsSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { 2106 return &droidStubsInfoProperties{} 2107} 2108 2109type droidStubsInfoProperties struct { 2110 android.SdkMemberPropertiesBase 2111 2112 StubsSrcJar android.Path 2113} 2114 2115func (p *droidStubsInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { 2116 droidstubs := variant.(*Droidstubs) 2117 p.StubsSrcJar = droidstubs.stubsSrcJar 2118} 2119 2120func (p *droidStubsInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { 2121 if p.StubsSrcJar != nil { 2122 builder := ctx.SnapshotBuilder() 2123 2124 snapshotRelativeDir := filepath.Join("java", ctx.Name()+"_stubs_sources") 2125 2126 builder.UnzipToSnapshot(p.StubsSrcJar, snapshotRelativeDir) 2127 2128 propertySet.AddProperty("srcs", []string{snapshotRelativeDir}) 2129 } 2130} 2131