1// Copyright 2020 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 "sort" 20 "strings" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25 "android/soong/java/config" 26 "android/soong/remoteexec" 27) 28 29// lint checks automatically enforced for modules that have different min_sdk_version than 30// sdk_version 31var updatabilityChecks = []string{"NewApi"} 32 33type LintProperties struct { 34 // Controls for running Android Lint on the module. 35 Lint struct { 36 37 // If true, run Android Lint on the module. Defaults to true. 38 Enabled *bool 39 40 // Flags to pass to the Android Lint tool. 41 Flags []string 42 43 // Checks that should be treated as fatal. 44 Fatal_checks []string 45 46 // Checks that should be treated as errors. 47 Error_checks []string 48 49 // Checks that should be treated as warnings. 50 Warning_checks []string 51 52 // Checks that should be skipped. 53 Disabled_checks []string 54 55 // Modules that provide extra lint checks 56 Extra_check_modules []string 57 58 // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml". 59 Baseline_filename *string 60 61 // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false. 62 Strict_updatability_linting *bool 63 } 64} 65 66type linter struct { 67 name string 68 manifest android.Path 69 mergedManifest android.Path 70 srcs android.Paths 71 srcJars android.Paths 72 resources android.Paths 73 classpath android.Paths 74 classes android.Path 75 extraLintCheckJars android.Paths 76 test bool 77 library bool 78 minSdkVersion android.ApiLevel 79 targetSdkVersion android.ApiLevel 80 compileSdkVersion android.ApiLevel 81 compileSdkKind android.SdkKind 82 javaLanguageLevel string 83 kotlinLanguageLevel string 84 outputs lintOutputs 85 properties LintProperties 86 extraMainlineLintErrors []string 87 88 reports android.Paths 89 90 buildModuleReportZip bool 91} 92 93type lintOutputs struct { 94 html android.Path 95 text android.Path 96 xml android.Path 97 98 depSets LintDepSets 99} 100 101type lintOutputsIntf interface { 102 lintOutputs() *lintOutputs 103} 104 105type LintDepSetsIntf interface { 106 LintDepSets() LintDepSets 107 108 // Methods used to propagate strict_updatability_linting values. 109 GetStrictUpdatabilityLinting() bool 110 SetStrictUpdatabilityLinting(bool) 111} 112 113type LintDepSets struct { 114 HTML, Text, XML *android.DepSet 115} 116 117type LintDepSetsBuilder struct { 118 HTML, Text, XML *android.DepSetBuilder 119} 120 121func NewLintDepSetBuilder() LintDepSetsBuilder { 122 return LintDepSetsBuilder{ 123 HTML: android.NewDepSetBuilder(android.POSTORDER), 124 Text: android.NewDepSetBuilder(android.POSTORDER), 125 XML: android.NewDepSetBuilder(android.POSTORDER), 126 } 127} 128 129func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder { 130 l.HTML.Direct(html) 131 l.Text.Direct(text) 132 l.XML.Direct(xml) 133 return l 134} 135 136func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder { 137 if depSets.HTML != nil { 138 l.HTML.Transitive(depSets.HTML) 139 } 140 if depSets.Text != nil { 141 l.Text.Transitive(depSets.Text) 142 } 143 if depSets.XML != nil { 144 l.XML.Transitive(depSets.XML) 145 } 146 return l 147} 148 149func (l LintDepSetsBuilder) Build() LintDepSets { 150 return LintDepSets{ 151 HTML: l.HTML.Build(), 152 Text: l.Text.Build(), 153 XML: l.XML.Build(), 154 } 155} 156 157func (l *linter) LintDepSets() LintDepSets { 158 return l.outputs.depSets 159} 160 161func (l *linter) GetStrictUpdatabilityLinting() bool { 162 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false) 163} 164 165func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) { 166 l.properties.Lint.Strict_updatability_linting = &strictLinting 167} 168 169var _ LintDepSetsIntf = (*linter)(nil) 170 171var _ lintOutputsIntf = (*linter)(nil) 172 173func (l *linter) lintOutputs() *lintOutputs { 174 return &l.outputs 175} 176 177func (l *linter) enabled() bool { 178 return BoolDefault(l.properties.Lint.Enabled, true) 179} 180 181func (l *linter) deps(ctx android.BottomUpMutatorContext) { 182 if !l.enabled() { 183 return 184 } 185 186 extraCheckModules := l.properties.Lint.Extra_check_modules 187 188 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" { 189 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" { 190 extraCheckModules = strings.Split(checkOnlyModules, ",") 191 } 192 } 193 194 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), 195 extraLintCheckTag, extraCheckModules...) 196} 197 198// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them 199// around. 200type lintPaths struct { 201 projectXML android.WritablePath 202 configXML android.WritablePath 203 cacheDir android.WritablePath 204 homeDir android.WritablePath 205 srcjarDir android.WritablePath 206} 207 208func lintRBEExecStrategy(ctx android.ModuleContext) string { 209 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy) 210} 211 212func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths { 213 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml") 214 // Lint looks for a lint.xml file next to the project.xml file, give it one. 215 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml") 216 cacheDir := android.PathForModuleOut(ctx, "lint", "cache") 217 homeDir := android.PathForModuleOut(ctx, "lint", "home") 218 219 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars") 220 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars) 221 222 cmd := rule.Command(). 223 BuiltTool("lint_project_xml"). 224 FlagWithOutput("--project_out ", projectXMLPath). 225 FlagWithOutput("--config_out ", configXMLPath). 226 FlagWithArg("--name ", ctx.ModuleName()) 227 228 if l.library { 229 cmd.Flag("--library") 230 } 231 if l.test { 232 cmd.Flag("--test") 233 } 234 if l.manifest != nil { 235 cmd.FlagWithInput("--manifest ", l.manifest) 236 } 237 if l.mergedManifest != nil { 238 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest) 239 } 240 241 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to 242 // lint separately. 243 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list") 244 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs) 245 246 cmd.FlagWithInput("--generated_srcs ", srcJarList) 247 248 if len(l.resources) > 0 { 249 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list") 250 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources) 251 } 252 253 if l.classes != nil { 254 cmd.FlagWithInput("--classes ", l.classes) 255 } 256 257 cmd.FlagForEachInput("--classpath ", l.classpath) 258 259 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars) 260 261 cmd.FlagWithArg("--root_dir ", "$PWD") 262 263 // The cache tag in project.xml is relative to the root dir, or the project.xml file if 264 // the root dir is not set. 265 cmd.FlagWithArg("--cache_dir ", cacheDir.String()) 266 267 cmd.FlagWithInput("@", 268 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt")) 269 270 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors) 271 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks) 272 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks) 273 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks) 274 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks) 275 276 if l.GetStrictUpdatabilityLinting() { 277 // Verify the module does not baseline issues that endanger safe updatability. 278 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() { 279 cmd.FlagWithInput("--baseline ", baselinePath.Path()) 280 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks) 281 } 282 } 283 284 return lintPaths{ 285 projectXML: projectXMLPath, 286 configXML: configXMLPath, 287 cacheDir: cacheDir, 288 homeDir: homeDir, 289 } 290 291} 292 293// generateManifest adds a command to the rule to write a simple manifest that contains the 294// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest. 295func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath { 296 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml") 297 298 rule.Command().Text("("). 299 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`). 300 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`). 301 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`). 302 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`, 303 l.minSdkVersion.String(), l.targetSdkVersion.String()). 304 Text(`echo "</manifest>"`). 305 Text(") >").Output(manifestPath) 306 307 return manifestPath 308} 309 310func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath { 311 var lintBaseline android.OptionalPath 312 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" { 313 if String(l.properties.Lint.Baseline_filename) != "" { 314 // if manually specified, we require the file to exist 315 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename)) 316 } else { 317 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename) 318 } 319 } 320 return lintBaseline 321} 322 323func (l *linter) lint(ctx android.ModuleContext) { 324 if !l.enabled() { 325 return 326 } 327 328 if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 { 329 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...) 330 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks) 331 if len(filtered) != 0 { 332 ctx.PropertyErrorf("lint.warning_checks", 333 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered) 334 } 335 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks) 336 if len(filtered) != 0 { 337 ctx.PropertyErrorf("lint.disabled_checks", 338 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered) 339 } 340 } 341 342 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) 343 for _, extraLintCheckModule := range extraLintCheckModules { 344 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) { 345 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo) 346 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...) 347 } else { 348 ctx.PropertyErrorf("lint.extra_check_modules", 349 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule)) 350 } 351 } 352 353 rule := android.NewRuleBuilder(pctx, ctx). 354 Sbox(android.PathForModuleOut(ctx, "lint"), 355 android.PathForModuleOut(ctx, "lint.sbox.textproto")). 356 SandboxInputs() 357 358 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") { 359 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16") 360 rule.Remoteable(android.RemoteRuleSupports{RBE: true}) 361 rule.Rewrapper(&remoteexec.REParams{ 362 Labels: map[string]string{"type": "tool", "name": "lint"}, 363 ExecStrategy: lintRBEExecStrategy(ctx), 364 ToolchainInputs: []string{config.JavaCmd(ctx).String()}, 365 Platform: map[string]string{remoteexec.PoolKey: pool}, 366 }) 367 } 368 369 if l.manifest == nil { 370 manifest := l.generateManifest(ctx, rule) 371 l.manifest = manifest 372 rule.Temporary(manifest) 373 } 374 375 lintPaths := l.writeLintProjectXML(ctx, rule) 376 377 html := android.PathForModuleOut(ctx, "lint", "lint-report.html") 378 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt") 379 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml") 380 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml") 381 382 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml) 383 384 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { 385 if depLint, ok := dep.(LintDepSetsIntf); ok { 386 depSetsBuilder.Transitive(depLint.LintDepSets()) 387 } 388 }) 389 390 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) 391 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) 392 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml) 393 394 var apiVersionsName, apiVersionsPrebuilt string 395 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer { 396 // When compiling an SDK module (or system server) we use the filtered 397 // database because otherwise lint's 398 // NewApi check produces too many false positives; This database excludes information 399 // about classes created in mainline modules hence removing those false positives. 400 apiVersionsName = "api_versions_public_filtered.xml" 401 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml" 402 } else { 403 apiVersionsName = "api_versions.xml" 404 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml" 405 } 406 407 var annotationsZipPath, apiVersionsXMLPath android.Path 408 if ctx.Config().AlwaysUsePrebuiltSdks() { 409 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip") 410 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt) 411 } else { 412 annotationsZipPath = copiedAnnotationsZipPath(ctx) 413 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName) 414 } 415 416 cmd := rule.Command() 417 418 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`). 419 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()). 420 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath). 421 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath) 422 423 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")). 424 Flag("--quiet"). 425 FlagWithInput("--project ", lintPaths.projectXML). 426 FlagWithInput("--config ", lintPaths.configXML). 427 FlagWithOutput("--html ", html). 428 FlagWithOutput("--text ", text). 429 FlagWithOutput("--xml ", xml). 430 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()). 431 FlagWithArg("--java-language-level ", l.javaLanguageLevel). 432 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel). 433 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())). 434 Flag("--exitcode"). 435 Flags(l.properties.Lint.Flags). 436 Implicit(annotationsZipPath). 437 Implicit(apiVersionsXMLPath) 438 439 rule.Temporary(lintPaths.projectXML) 440 rule.Temporary(lintPaths.configXML) 441 442 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" { 443 cmd.FlagWithArg("--check ", checkOnly) 444 } 445 446 lintBaseline := l.getBaselineFilepath(ctx) 447 if lintBaseline.Valid() { 448 cmd.FlagWithInput("--baseline ", lintBaseline.Path()) 449 } 450 451 cmd.FlagWithOutput("--write-reference-baseline ", baseline) 452 453 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)") 454 455 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) 456 457 // The HTML output contains a date, remove it to make the output deterministic. 458 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html) 459 460 rule.Build("lint", "lint") 461 462 l.outputs = lintOutputs{ 463 html: html, 464 text: text, 465 xml: xml, 466 467 depSets: depSetsBuilder.Build(), 468 } 469 470 if l.buildModuleReportZip { 471 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets()) 472 } 473} 474 475func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths { 476 htmlList := depSets.HTML.ToSortedList() 477 textList := depSets.Text.ToSortedList() 478 xmlList := depSets.XML.ToSortedList() 479 480 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 { 481 return nil 482 } 483 484 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip") 485 lintZip(ctx, htmlList, htmlZip) 486 487 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip") 488 lintZip(ctx, textList, textZip) 489 490 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") 491 lintZip(ctx, xmlList, xmlZip) 492 493 return android.Paths{htmlZip, textZip, xmlZip} 494} 495 496type lintSingleton struct { 497 htmlZip android.WritablePath 498 textZip android.WritablePath 499 xmlZip android.WritablePath 500} 501 502func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) { 503 l.generateLintReportZips(ctx) 504 l.copyLintDependencies(ctx) 505} 506 507func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module { 508 var res android.Module 509 ctx.VisitAllModules(func(m android.Module) { 510 if ctx.ModuleName(m) == moduleName { 511 if res == nil { 512 res = m 513 } else { 514 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName, 515 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res)) 516 } 517 } 518 }) 519 return res 520} 521 522func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) { 523 if ctx.Config().AlwaysUsePrebuiltSdks() { 524 return 525 } 526 527 frameworkDocStubs := findModuleOrErr(ctx, "framework-doc-stubs") 528 if frameworkDocStubs == nil { 529 if !ctx.Config().AllowMissingDependencies() { 530 ctx.Errorf("lint: missing framework-doc-stubs") 531 } 532 return 533 } 534 535 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered") 536 if filteredDb == nil { 537 if !ctx.Config().AllowMissingDependencies() { 538 ctx.Errorf("lint: missing api-versions-xml-public-filtered") 539 } 540 return 541 } 542 543 ctx.Build(pctx, android.BuildParams{ 544 Rule: android.CpIfChanged, 545 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"), 546 Output: copiedAnnotationsZipPath(ctx), 547 }) 548 549 ctx.Build(pctx, android.BuildParams{ 550 Rule: android.CpIfChanged, 551 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"), 552 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"), 553 }) 554 555 ctx.Build(pctx, android.BuildParams{ 556 Rule: android.CpIfChanged, 557 Input: android.OutputFileForModule(ctx, filteredDb, ""), 558 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"), 559 }) 560} 561 562func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath { 563 return android.PathForOutput(ctx, "lint", "annotations.zip") 564} 565 566func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath { 567 return android.PathForOutput(ctx, "lint", name) 568} 569 570func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { 571 if ctx.Config().UnbundledBuild() { 572 return 573 } 574 575 var outputs []*lintOutputs 576 var dirs []string 577 ctx.VisitAllModules(func(m android.Module) { 578 if ctx.Config().KatiEnabled() && !m.ExportedToMake() { 579 return 580 } 581 582 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() { 583 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo) 584 if apexInfo.IsForPlatform() { 585 // There are stray platform variants of modules in apexes that are not available for 586 // the platform, and they sometimes can't be built. Don't depend on them. 587 return 588 } 589 } 590 591 if l, ok := m.(lintOutputsIntf); ok { 592 outputs = append(outputs, l.lintOutputs()) 593 } 594 }) 595 596 dirs = android.SortedUniqueStrings(dirs) 597 598 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) { 599 var paths android.Paths 600 601 for _, output := range outputs { 602 if p := get(output); p != nil { 603 paths = append(paths, p) 604 } 605 } 606 607 lintZip(ctx, paths, outputPath) 608 } 609 610 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip") 611 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html }) 612 613 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip") 614 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text }) 615 616 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip") 617 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml }) 618 619 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip) 620} 621 622func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) { 623 if !ctx.Config().UnbundledBuild() { 624 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip) 625 } 626} 627 628var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil) 629 630func init() { 631 android.RegisterSingletonType("lint", 632 func() android.Singleton { return &lintSingleton{} }) 633 634 registerLintBuildComponents(android.InitRegistrationContext) 635} 636 637func registerLintBuildComponents(ctx android.RegistrationContext) { 638 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { 639 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel() 640 }) 641} 642 643func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) { 644 paths = android.SortedUniquePaths(android.CopyOfPaths(paths)) 645 646 sort.Slice(paths, func(i, j int) bool { 647 return paths[i].String() < paths[j].String() 648 }) 649 650 rule := android.NewRuleBuilder(pctx, ctx) 651 652 rule.Command().BuiltTool("soong_zip"). 653 FlagWithOutput("-o ", outputPath). 654 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). 655 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths) 656 657 rule.Build(outputPath.Base(), outputPath.Base()) 658} 659 660// Enforce the strict updatability linting to all applicable transitive dependencies. 661func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) { 662 m := ctx.Module() 663 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() { 664 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) { 665 if a, ok := d.(LintDepSetsIntf); ok { 666 a.SetStrictUpdatabilityLinting(true) 667 } 668 }) 669 } 670} 671