blob: c27ca9821394b8ec28d970950b0b016d5b7bce63 [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 }
Cole Faust3f646262022-06-29 14:58:03 -0700341
342 // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
343 if ctx.ModuleName() == "PermissionController" {
344 l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
345 return s != "NewApi"
346 })
347 l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
348 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000349 }
350
Colin Cross92e4b462020-06-18 15:56:48 -0700351 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
352 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800353 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
354 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
355 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700356 } else {
357 ctx.PropertyErrorf("lint.extra_check_modules",
358 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
359 }
360 }
361
Colin Cross1661aff2021-03-12 17:56:51 -0800362 rule := android.NewRuleBuilder(pctx, ctx).
363 Sbox(android.PathForModuleOut(ctx, "lint"),
364 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
365 SandboxInputs()
366
367 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
368 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
369 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
370 rule.Rewrapper(&remoteexec.REParams{
371 Labels: map[string]string{"type": "tool", "name": "lint"},
372 ExecStrategy: lintRBEExecStrategy(ctx),
373 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700374 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800375 })
376 }
Colin Cross014489c2020-06-02 20:09:13 -0700377
378 if l.manifest == nil {
379 manifest := l.generateManifest(ctx, rule)
380 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800381 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700382 }
383
Colin Cross31972dc2021-03-04 10:44:12 -0800384 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700385
Colin Cross1661aff2021-03-12 17:56:51 -0800386 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
387 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
388 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Cross6b76c152021-09-09 09:36:25 -0700389 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700390
Colin Cross08dca382020-07-21 20:31:17 -0700391 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700392
393 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000394 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700395 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700396 }
397 })
Colin Cross014489c2020-06-02 20:09:13 -0700398
Colin Cross31972dc2021-03-04 10:44:12 -0800399 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
400 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800401 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700402
Pedro Loureiro18233a22021-06-08 18:11:21 +0000403 var apiVersionsName, apiVersionsPrebuilt string
Pedro Loureiroffb643f2021-07-05 13:53:36 +0000404 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
405 // When compiling an SDK module (or system server) we use the filtered
406 // database because otherwise lint's
Pedro Loureiro18233a22021-06-08 18:11:21 +0000407 // NewApi check produces too many false positives; This database excludes information
408 // about classes created in mainline modules hence removing those false positives.
409 apiVersionsName = "api_versions_public_filtered.xml"
410 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
411 } else {
412 apiVersionsName = "api_versions.xml"
413 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
414 }
415
Colin Cross8a6ed372020-07-06 11:45:51 -0700416 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900417 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700418 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
Pedro Loureiro18233a22021-06-08 18:11:21 +0000419 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
Colin Cross8a6ed372020-07-06 11:45:51 -0700420 } else {
421 annotationsZipPath = copiedAnnotationsZipPath(ctx)
Pedro Loureiro18233a22021-06-08 18:11:21 +0000422 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700423 }
424
Colin Cross31972dc2021-03-04 10:44:12 -0800425 cmd := rule.Command()
426
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000427 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800428 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700429 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800430 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
431
Colin Cross1661aff2021-03-12 17:56:51 -0800432 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700433 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800434 FlagWithInput("--project ", lintPaths.projectXML).
435 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700436 FlagWithOutput("--html ", html).
437 FlagWithOutput("--text ", text).
438 FlagWithOutput("--xml ", xml).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000439 FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
Colin Cross014489c2020-06-02 20:09:13 -0700440 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
441 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
442 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
443 Flag("--exitcode").
444 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800445 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700446 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700447
Colin Cross1661aff2021-03-12 17:56:51 -0800448 rule.Temporary(lintPaths.projectXML)
449 rule.Temporary(lintPaths.configXML)
450
Colin Cross988dfcc2020-07-16 17:32:17 -0700451 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
452 cmd.FlagWithArg("--check ", checkOnly)
453 }
454
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700455 lintBaseline := l.getBaselineFilepath(ctx)
456 if lintBaseline.Valid() {
457 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000458 }
459
Colin Cross6b76c152021-09-09 09:36:25 -0700460 cmd.FlagWithOutput("--write-reference-baseline ", baseline)
461
Colin Cross31972dc2021-03-04 10:44:12 -0800462 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700463
Colin Cross31972dc2021-03-04 10:44:12 -0800464 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700465
Colin Crossee4a8b72021-04-05 18:38:05 -0700466 // The HTML output contains a date, remove it to make the output deterministic.
467 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
468
Colin Crossf1a035e2020-11-16 17:32:30 -0800469 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700470
Colin Crossc0efd1d2020-07-03 11:56:24 -0700471 l.outputs = lintOutputs{
472 html: html,
473 text: text,
474 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700475
Colin Cross08dca382020-07-21 20:31:17 -0700476 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700477 }
Colin Cross014489c2020-06-02 20:09:13 -0700478
Colin Crossc0efd1d2020-07-03 11:56:24 -0700479 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700480 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700481 }
482}
Colin Cross014489c2020-06-02 20:09:13 -0700483
Colin Cross08dca382020-07-21 20:31:17 -0700484func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
485 htmlList := depSets.HTML.ToSortedList()
486 textList := depSets.Text.ToSortedList()
487 xmlList := depSets.XML.ToSortedList()
488
489 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
490 return nil
491 }
492
493 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
494 lintZip(ctx, htmlList, htmlZip)
495
496 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
497 lintZip(ctx, textList, textZip)
498
499 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
500 lintZip(ctx, xmlList, xmlZip)
501
502 return android.Paths{htmlZip, textZip, xmlZip}
503}
504
Colin Cross014489c2020-06-02 20:09:13 -0700505type lintSingleton struct {
506 htmlZip android.WritablePath
507 textZip android.WritablePath
508 xmlZip android.WritablePath
509}
510
511func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
512 l.generateLintReportZips(ctx)
513 l.copyLintDependencies(ctx)
514}
515
Pedro Loureiro18233a22021-06-08 18:11:21 +0000516func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
517 var res android.Module
518 ctx.VisitAllModules(func(m android.Module) {
519 if ctx.ModuleName(m) == moduleName {
520 if res == nil {
521 res = m
522 } else {
523 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
524 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
525 }
526 }
527 })
528 return res
529}
530
Colin Cross014489c2020-06-02 20:09:13 -0700531func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900532 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700533 return
534 }
535
Anton Hansson67cf60e2022-05-09 09:36:22 +0000536 apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
537 if apiVersionsDb == nil {
Colin Cross014489c2020-06-02 20:09:13 -0700538 if !ctx.Config().AllowMissingDependencies() {
Anton Hansson67cf60e2022-05-09 09:36:22 +0000539 ctx.Errorf("lint: missing module api_versions_public")
Colin Cross014489c2020-06-02 20:09:13 -0700540 }
541 return
542 }
543
Anton Hanssonea17a452022-05-09 09:42:17 +0000544 sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
545 if sdkAnnotations == nil {
546 if !ctx.Config().AllowMissingDependencies() {
547 ctx.Errorf("lint: missing module sdk-annotations.zip")
548 }
549 return
550 }
551
Pedro Loureiro18233a22021-06-08 18:11:21 +0000552 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
553 if filteredDb == nil {
554 if !ctx.Config().AllowMissingDependencies() {
555 ctx.Errorf("lint: missing api-versions-xml-public-filtered")
556 }
557 return
558 }
559
Colin Cross014489c2020-06-02 20:09:13 -0700560 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800561 Rule: android.CpIfChanged,
Anton Hanssonea17a452022-05-09 09:42:17 +0000562 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
Colin Cross8a6ed372020-07-06 11:45:51 -0700563 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700564 })
565
566 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800567 Rule: android.CpIfChanged,
Anton Hansson67cf60e2022-05-09 09:36:22 +0000568 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
Pedro Loureiro18233a22021-06-08 18:11:21 +0000569 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
570 })
571
572 ctx.Build(pctx, android.BuildParams{
573 Rule: android.CpIfChanged,
574 Input: android.OutputFileForModule(ctx, filteredDb, ""),
575 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
Colin Cross014489c2020-06-02 20:09:13 -0700576 })
577}
578
Colin Cross8a6ed372020-07-06 11:45:51 -0700579func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700580 return android.PathForOutput(ctx, "lint", "annotations.zip")
581}
582
Pedro Loureiro18233a22021-06-08 18:11:21 +0000583func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
584 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700585}
586
587func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700588 if ctx.Config().UnbundledBuild() {
589 return
590 }
591
Colin Cross014489c2020-06-02 20:09:13 -0700592 var outputs []*lintOutputs
593 var dirs []string
594 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500595 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700596 return
597 }
598
Colin Cross56a83212020-09-15 18:30:11 -0700599 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
600 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
601 if apexInfo.IsForPlatform() {
602 // There are stray platform variants of modules in apexes that are not available for
603 // the platform, and they sometimes can't be built. Don't depend on them.
604 return
605 }
Colin Cross014489c2020-06-02 20:09:13 -0700606 }
607
Colin Cross08dca382020-07-21 20:31:17 -0700608 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700609 outputs = append(outputs, l.lintOutputs())
610 }
611 })
612
613 dirs = android.SortedUniqueStrings(dirs)
614
615 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
616 var paths android.Paths
617
618 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700619 if p := get(output); p != nil {
620 paths = append(paths, p)
621 }
Colin Cross014489c2020-06-02 20:09:13 -0700622 }
623
Colin Crossc0efd1d2020-07-03 11:56:24 -0700624 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700625 }
626
627 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
628 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
629
630 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
631 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
632
633 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
634 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
635
636 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
637}
638
639func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700640 if !ctx.Config().UnbundledBuild() {
641 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
642 }
Colin Cross014489c2020-06-02 20:09:13 -0700643}
644
645var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
646
647func init() {
648 android.RegisterSingletonType("lint",
649 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700650
651 registerLintBuildComponents(android.InitRegistrationContext)
652}
653
654func registerLintBuildComponents(ctx android.RegistrationContext) {
655 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
656 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
657 })
Colin Cross014489c2020-06-02 20:09:13 -0700658}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700659
660func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
661 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
662
663 sort.Slice(paths, func(i, j int) bool {
664 return paths[i].String() < paths[j].String()
665 })
666
Colin Crossf1a035e2020-11-16 17:32:30 -0800667 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700668
Colin Crossf1a035e2020-11-16 17:32:30 -0800669 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700670 FlagWithOutput("-o ", outputPath).
671 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800672 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700673
Colin Crossf1a035e2020-11-16 17:32:30 -0800674 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700675}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700676
677// Enforce the strict updatability linting to all applicable transitive dependencies.
678func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
679 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000680 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700681 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000682 if a, ok := d.(LintDepSetsIntf); ok {
683 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700684 }
685 })
686 }
687}