blob: e276345eb4d9cd32f964a8f9ec3b51026b58311f [file] [log] [blame]
Colin Cross014489c2020-06-02 20:09:13 -07001// 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"
Cole Fauste5bf3fb2022-07-01 19:39:14 +000020 "strconv"
Colin Cross988dfcc2020-07-16 17:32:17 -070021 "strings"
Colin Cross014489c2020-06-02 20:09:13 -070022
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000023 "github.com/google/blueprint/proptools"
24
Colin Cross014489c2020-06-02 20:09:13 -070025 "android/soong/android"
Colin Cross31972dc2021-03-04 10:44:12 -080026 "android/soong/java/config"
27 "android/soong/remoteexec"
Colin Cross014489c2020-06-02 20:09:13 -070028)
29
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -070030// lint checks automatically enforced for modules that have different min_sdk_version than
31// sdk_version
32var updatabilityChecks = []string{"NewApi"}
33
Colin Cross014489c2020-06-02 20:09:13 -070034type LintProperties struct {
35 // Controls for running Android Lint on the module.
36 Lint struct {
37
38 // If true, run Android Lint on the module. Defaults to true.
39 Enabled *bool
40
41 // Flags to pass to the Android Lint tool.
42 Flags []string
43
44 // Checks that should be treated as fatal.
45 Fatal_checks []string
46
47 // Checks that should be treated as errors.
48 Error_checks []string
49
50 // Checks that should be treated as warnings.
51 Warning_checks []string
52
53 // Checks that should be skipped.
54 Disabled_checks []string
Colin Cross92e4b462020-06-18 15:56:48 -070055
56 // Modules that provide extra lint checks
57 Extra_check_modules []string
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000058
59 // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
60 Baseline_filename *string
Jaewoong Jung48de8832021-04-21 16:17:25 -070061
62 // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
63 Strict_updatability_linting *bool
Colin Cross014489c2020-06-02 20:09:13 -070064 }
65}
66
67type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000068 name string
69 manifest android.Path
70 mergedManifest android.Path
71 srcs android.Paths
72 srcJars android.Paths
73 resources android.Paths
74 classpath android.Paths
75 classes android.Path
76 extraLintCheckJars android.Paths
77 test bool
78 library bool
Cole Fauste5bf3fb2022-07-01 19:39:14 +000079 minSdkVersion int
80 targetSdkVersion int
81 compileSdkVersion int
Pedro Loureiro18233a22021-06-08 18:11:21 +000082 compileSdkKind android.SdkKind
Pedro Loureirof4a88b12021-02-25 16:23:22 +000083 javaLanguageLevel string
84 kotlinLanguageLevel string
85 outputs lintOutputs
86 properties LintProperties
87 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070088
Colin Cross08dca382020-07-21 20:31:17 -070089 reports android.Paths
90
Colin Crossc0efd1d2020-07-03 11:56:24 -070091 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070092}
93
94type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070095 html android.Path
96 text android.Path
97 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070098
Colin Cross08dca382020-07-21 20:31:17 -070099 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -0700100}
101
Colin Cross08dca382020-07-21 20:31:17 -0700102type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -0700103 lintOutputs() *lintOutputs
104}
105
Spandan Das17854f52022-01-14 21:19:14 +0000106type LintDepSetsIntf interface {
Colin Cross08dca382020-07-21 20:31:17 -0700107 LintDepSets() LintDepSets
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700108
109 // Methods used to propagate strict_updatability_linting values.
Spandan Das17854f52022-01-14 21:19:14 +0000110 GetStrictUpdatabilityLinting() bool
111 SetStrictUpdatabilityLinting(bool)
Colin Cross08dca382020-07-21 20:31:17 -0700112}
113
114type LintDepSets struct {
115 HTML, Text, XML *android.DepSet
116}
117
118type LintDepSetsBuilder struct {
119 HTML, Text, XML *android.DepSetBuilder
120}
121
122func NewLintDepSetBuilder() LintDepSetsBuilder {
123 return LintDepSetsBuilder{
124 HTML: android.NewDepSetBuilder(android.POSTORDER),
125 Text: android.NewDepSetBuilder(android.POSTORDER),
126 XML: android.NewDepSetBuilder(android.POSTORDER),
127 }
128}
129
130func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
131 l.HTML.Direct(html)
132 l.Text.Direct(text)
133 l.XML.Direct(xml)
134 return l
135}
136
137func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
138 if depSets.HTML != nil {
139 l.HTML.Transitive(depSets.HTML)
140 }
141 if depSets.Text != nil {
142 l.Text.Transitive(depSets.Text)
143 }
144 if depSets.XML != nil {
145 l.XML.Transitive(depSets.XML)
146 }
147 return l
148}
149
150func (l LintDepSetsBuilder) Build() LintDepSets {
151 return LintDepSets{
152 HTML: l.HTML.Build(),
153 Text: l.Text.Build(),
154 XML: l.XML.Build(),
155 }
156}
157
158func (l *linter) LintDepSets() LintDepSets {
159 return l.outputs.depSets
160}
161
Spandan Das17854f52022-01-14 21:19:14 +0000162func (l *linter) GetStrictUpdatabilityLinting() bool {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700163 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
164}
165
Spandan Das17854f52022-01-14 21:19:14 +0000166func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700167 l.properties.Lint.Strict_updatability_linting = &strictLinting
168}
169
Spandan Das17854f52022-01-14 21:19:14 +0000170var _ LintDepSetsIntf = (*linter)(nil)
Colin Cross08dca382020-07-21 20:31:17 -0700171
172var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700173
174func (l *linter) lintOutputs() *lintOutputs {
175 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700176}
177
178func (l *linter) enabled() bool {
179 return BoolDefault(l.properties.Lint.Enabled, true)
180}
181
Colin Cross92e4b462020-06-18 15:56:48 -0700182func (l *linter) deps(ctx android.BottomUpMutatorContext) {
183 if !l.enabled() {
184 return
185 }
186
Colin Cross988dfcc2020-07-16 17:32:17 -0700187 extraCheckModules := l.properties.Lint.Extra_check_modules
188
189 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
190 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
191 extraCheckModules = strings.Split(checkOnlyModules, ",")
192 }
193 }
194
195 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
196 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700197}
198
Colin Crossad22bc22021-03-10 09:45:40 -0800199// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
200// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800201type lintPaths struct {
202 projectXML android.WritablePath
203 configXML android.WritablePath
204 cacheDir android.WritablePath
205 homeDir android.WritablePath
206 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800207}
208
Colin Cross9b93af42021-03-10 10:40:58 -0800209func lintRBEExecStrategy(ctx android.ModuleContext) string {
210 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
211}
212
Colin Cross31972dc2021-03-04 10:44:12 -0800213func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800214 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700215 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800216 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
217 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
218 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700219
Colin Cross1661aff2021-03-12 17:56:51 -0800220 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700221 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
222
223 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700224 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700225 FlagWithOutput("--project_out ", projectXMLPath).
226 FlagWithOutput("--config_out ", configXMLPath).
227 FlagWithArg("--name ", ctx.ModuleName())
228
229 if l.library {
230 cmd.Flag("--library")
231 }
232 if l.test {
233 cmd.Flag("--test")
234 }
235 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700236 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700237 }
238 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700239 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700240 }
241
Colin Cross5bedfa22021-03-23 17:07:14 -0700242 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
243 // lint separately.
244 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
245 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
Colin Cross014489c2020-06-02 20:09:13 -0700246
247 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700248
Colin Cross5bedfa22021-03-23 17:07:14 -0700249 if len(l.resources) > 0 {
250 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
251 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700252 }
253
254 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700255 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700256 }
257
Colin Cross5bedfa22021-03-23 17:07:14 -0700258 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700259
Colin Cross5bedfa22021-03-23 17:07:14 -0700260 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700261
Colin Cross1661aff2021-03-12 17:56:51 -0800262 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700263
264 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
265 // the root dir is not set.
266 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700267
268 cmd.FlagWithInput("@",
269 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
270
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000271 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700272 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
273 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
274 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
275 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
276
Spandan Das17854f52022-01-14 21:19:14 +0000277 if l.GetStrictUpdatabilityLinting() {
Jaewoong Jung3c87b1d2021-04-22 11:01:36 -0700278 // Verify the module does not baseline issues that endanger safe updatability.
Jaewoong Jung48de8832021-04-21 16:17:25 -0700279 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
280 cmd.FlagWithInput("--baseline ", baselinePath.Path())
281 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
282 }
283 }
284
Colin Cross31972dc2021-03-04 10:44:12 -0800285 return lintPaths{
286 projectXML: projectXMLPath,
287 configXML: configXMLPath,
288 cacheDir: cacheDir,
289 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800290 }
291
Colin Cross014489c2020-06-02 20:09:13 -0700292}
293
Liz Kammer20ebfb42020-07-28 11:32:07 -0700294// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700295// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800296func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700297 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
298
299 rule.Command().Text("(").
300 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
301 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
302 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000303 Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
304 l.minSdkVersion, l.targetSdkVersion).
Colin Cross014489c2020-06-02 20:09:13 -0700305 Text(`echo "</manifest>"`).
306 Text(") >").Output(manifestPath)
307
308 return manifestPath
309}
310
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700311func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
312 var lintBaseline android.OptionalPath
313 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
314 if String(l.properties.Lint.Baseline_filename) != "" {
315 // if manually specified, we require the file to exist
316 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
317 } else {
318 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
319 }
320 }
321 return lintBaseline
322}
323
Colin Cross014489c2020-06-02 20:09:13 -0700324func (l *linter) lint(ctx android.ModuleContext) {
325 if !l.enabled() {
326 return
327 }
328
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000329 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700330 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
331 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
332 if len(filtered) != 0 {
333 ctx.PropertyErrorf("lint.warning_checks",
334 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
335 }
336 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
337 if len(filtered) != 0 {
338 ctx.PropertyErrorf("lint.disabled_checks",
339 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
340 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000341 }
342
Colin Cross92e4b462020-06-18 15:56:48 -0700343 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
344 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800345 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
346 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
347 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700348 } else {
349 ctx.PropertyErrorf("lint.extra_check_modules",
350 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
351 }
352 }
353
Colin Cross1661aff2021-03-12 17:56:51 -0800354 rule := android.NewRuleBuilder(pctx, ctx).
355 Sbox(android.PathForModuleOut(ctx, "lint"),
356 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
357 SandboxInputs()
358
359 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
360 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
361 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
362 rule.Rewrapper(&remoteexec.REParams{
363 Labels: map[string]string{"type": "tool", "name": "lint"},
364 ExecStrategy: lintRBEExecStrategy(ctx),
365 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700366 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800367 })
368 }
Colin Cross014489c2020-06-02 20:09:13 -0700369
370 if l.manifest == nil {
371 manifest := l.generateManifest(ctx, rule)
372 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800373 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700374 }
375
Colin Cross31972dc2021-03-04 10:44:12 -0800376 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700377
Colin Cross1661aff2021-03-12 17:56:51 -0800378 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
379 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
380 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Cross6b76c152021-09-09 09:36:25 -0700381 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700382
Colin Cross08dca382020-07-21 20:31:17 -0700383 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700384
385 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000386 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700387 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700388 }
389 })
Colin Cross014489c2020-06-02 20:09:13 -0700390
Colin Cross31972dc2021-03-04 10:44:12 -0800391 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
392 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800393 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700394
Pedro Loureiro18233a22021-06-08 18:11:21 +0000395 var apiVersionsName, apiVersionsPrebuilt string
Pedro Loureiroffb643f2021-07-05 13:53:36 +0000396 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
397 // When compiling an SDK module (or system server) we use the filtered
398 // database because otherwise lint's
Pedro Loureiro18233a22021-06-08 18:11:21 +0000399 // NewApi check produces too many false positives; This database excludes information
400 // about classes created in mainline modules hence removing those false positives.
401 apiVersionsName = "api_versions_public_filtered.xml"
402 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
403 } else {
404 apiVersionsName = "api_versions.xml"
405 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
406 }
407
Colin Cross8a6ed372020-07-06 11:45:51 -0700408 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900409 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700410 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
Pedro Loureiro18233a22021-06-08 18:11:21 +0000411 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
Colin Cross8a6ed372020-07-06 11:45:51 -0700412 } else {
413 annotationsZipPath = copiedAnnotationsZipPath(ctx)
Pedro Loureiro18233a22021-06-08 18:11:21 +0000414 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700415 }
416
Colin Cross31972dc2021-03-04 10:44:12 -0800417 cmd := rule.Command()
418
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000419 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800420 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700421 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800422 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
423
Colin Cross1661aff2021-03-12 17:56:51 -0800424 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700425 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800426 FlagWithInput("--project ", lintPaths.projectXML).
427 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700428 FlagWithOutput("--html ", html).
429 FlagWithOutput("--text ", text).
430 FlagWithOutput("--xml ", xml).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000431 FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
Colin Cross014489c2020-06-02 20:09:13 -0700432 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
433 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
434 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
435 Flag("--exitcode").
436 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800437 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700438 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700439
Colin Cross1661aff2021-03-12 17:56:51 -0800440 rule.Temporary(lintPaths.projectXML)
441 rule.Temporary(lintPaths.configXML)
442
Colin Cross988dfcc2020-07-16 17:32:17 -0700443 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
444 cmd.FlagWithArg("--check ", checkOnly)
445 }
446
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700447 lintBaseline := l.getBaselineFilepath(ctx)
448 if lintBaseline.Valid() {
449 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000450 }
451
Colin Cross6b76c152021-09-09 09:36:25 -0700452 cmd.FlagWithOutput("--write-reference-baseline ", baseline)
453
Colin Cross31972dc2021-03-04 10:44:12 -0800454 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700455
Colin Cross31972dc2021-03-04 10:44:12 -0800456 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700457
Colin Crossee4a8b72021-04-05 18:38:05 -0700458 // The HTML output contains a date, remove it to make the output deterministic.
459 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
460
Colin Crossf1a035e2020-11-16 17:32:30 -0800461 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700462
Colin Crossc0efd1d2020-07-03 11:56:24 -0700463 l.outputs = lintOutputs{
464 html: html,
465 text: text,
466 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700467
Colin Cross08dca382020-07-21 20:31:17 -0700468 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700469 }
Colin Cross014489c2020-06-02 20:09:13 -0700470
Colin Crossc0efd1d2020-07-03 11:56:24 -0700471 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700472 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700473 }
474}
Colin Cross014489c2020-06-02 20:09:13 -0700475
Colin Cross08dca382020-07-21 20:31:17 -0700476func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
477 htmlList := depSets.HTML.ToSortedList()
478 textList := depSets.Text.ToSortedList()
479 xmlList := depSets.XML.ToSortedList()
480
481 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
482 return nil
483 }
484
485 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
486 lintZip(ctx, htmlList, htmlZip)
487
488 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
489 lintZip(ctx, textList, textZip)
490
491 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
492 lintZip(ctx, xmlList, xmlZip)
493
494 return android.Paths{htmlZip, textZip, xmlZip}
495}
496
Colin Cross014489c2020-06-02 20:09:13 -0700497type lintSingleton struct {
498 htmlZip android.WritablePath
499 textZip android.WritablePath
500 xmlZip android.WritablePath
501}
502
503func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
504 l.generateLintReportZips(ctx)
505 l.copyLintDependencies(ctx)
506}
507
Pedro Loureiro18233a22021-06-08 18:11:21 +0000508func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
509 var res android.Module
510 ctx.VisitAllModules(func(m android.Module) {
511 if ctx.ModuleName(m) == moduleName {
512 if res == nil {
513 res = m
514 } else {
515 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
516 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
517 }
518 }
519 })
520 return res
521}
522
Colin Cross014489c2020-06-02 20:09:13 -0700523func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900524 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700525 return
526 }
527
Anton Hansson67cf60e2022-05-09 09:36:22 +0000528 apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
529 if apiVersionsDb == nil {
Colin Cross014489c2020-06-02 20:09:13 -0700530 if !ctx.Config().AllowMissingDependencies() {
Anton Hansson67cf60e2022-05-09 09:36:22 +0000531 ctx.Errorf("lint: missing module api_versions_public")
Colin Cross014489c2020-06-02 20:09:13 -0700532 }
533 return
534 }
535
Anton Hanssonea17a452022-05-09 09:42:17 +0000536 sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
537 if sdkAnnotations == nil {
538 if !ctx.Config().AllowMissingDependencies() {
539 ctx.Errorf("lint: missing module sdk-annotations.zip")
540 }
541 return
542 }
543
Pedro Loureiro18233a22021-06-08 18:11:21 +0000544 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
545 if filteredDb == nil {
546 if !ctx.Config().AllowMissingDependencies() {
547 ctx.Errorf("lint: missing api-versions-xml-public-filtered")
548 }
549 return
550 }
551
Colin Cross014489c2020-06-02 20:09:13 -0700552 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800553 Rule: android.CpIfChanged,
Anton Hanssonea17a452022-05-09 09:42:17 +0000554 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
Colin Cross8a6ed372020-07-06 11:45:51 -0700555 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700556 })
557
558 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800559 Rule: android.CpIfChanged,
Anton Hansson67cf60e2022-05-09 09:36:22 +0000560 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
Pedro Loureiro18233a22021-06-08 18:11:21 +0000561 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
562 })
563
564 ctx.Build(pctx, android.BuildParams{
565 Rule: android.CpIfChanged,
566 Input: android.OutputFileForModule(ctx, filteredDb, ""),
567 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
Colin Cross014489c2020-06-02 20:09:13 -0700568 })
569}
570
Colin Cross8a6ed372020-07-06 11:45:51 -0700571func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700572 return android.PathForOutput(ctx, "lint", "annotations.zip")
573}
574
Pedro Loureiro18233a22021-06-08 18:11:21 +0000575func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
576 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700577}
578
579func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700580 if ctx.Config().UnbundledBuild() {
581 return
582 }
583
Colin Cross014489c2020-06-02 20:09:13 -0700584 var outputs []*lintOutputs
585 var dirs []string
586 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500587 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700588 return
589 }
590
Colin Cross56a83212020-09-15 18:30:11 -0700591 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
592 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
593 if apexInfo.IsForPlatform() {
594 // There are stray platform variants of modules in apexes that are not available for
595 // the platform, and they sometimes can't be built. Don't depend on them.
596 return
597 }
Colin Cross014489c2020-06-02 20:09:13 -0700598 }
599
Colin Cross08dca382020-07-21 20:31:17 -0700600 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700601 outputs = append(outputs, l.lintOutputs())
602 }
603 })
604
605 dirs = android.SortedUniqueStrings(dirs)
606
607 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
608 var paths android.Paths
609
610 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700611 if p := get(output); p != nil {
612 paths = append(paths, p)
613 }
Colin Cross014489c2020-06-02 20:09:13 -0700614 }
615
Colin Crossc0efd1d2020-07-03 11:56:24 -0700616 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700617 }
618
619 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
620 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
621
622 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
623 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
624
625 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
626 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
627
628 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
629}
630
631func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700632 if !ctx.Config().UnbundledBuild() {
633 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
634 }
Colin Cross014489c2020-06-02 20:09:13 -0700635}
636
637var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
638
639func init() {
640 android.RegisterSingletonType("lint",
641 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700642
643 registerLintBuildComponents(android.InitRegistrationContext)
644}
645
646func registerLintBuildComponents(ctx android.RegistrationContext) {
647 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
648 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
649 })
Colin Cross014489c2020-06-02 20:09:13 -0700650}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700651
652func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
653 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
654
655 sort.Slice(paths, func(i, j int) bool {
656 return paths[i].String() < paths[j].String()
657 })
658
Colin Crossf1a035e2020-11-16 17:32:30 -0800659 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700660
Colin Crossf1a035e2020-11-16 17:32:30 -0800661 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700662 FlagWithOutput("-o ", outputPath).
663 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800664 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700665
Colin Crossf1a035e2020-11-16 17:32:30 -0800666 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700667}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700668
669// Enforce the strict updatability linting to all applicable transitive dependencies.
670func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
671 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000672 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700673 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000674 if a, ok := d.(LintDepSetsIntf); ok {
675 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700676 }
677 })
678 }
679}