blob: 6ef109f976d080bbc9d9c377102c4950848fd259 [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...)
Orion Hodsonb8166522022-08-15 20:23:38 +0100331 // Skip lint warning checks for NewApi warnings for libcore where they come from source
332 // files that reference the API they are adding (b/208656169).
333 if ctx.ModuleDir() != "libcore" {
334 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
335
336 if len(filtered) != 0 {
337 ctx.PropertyErrorf("lint.warning_checks",
338 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
339 }
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700340 }
Orion Hodsonb8166522022-08-15 20:23:38 +0100341
342 _, filtered := android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700343 if len(filtered) != 0 {
344 ctx.PropertyErrorf("lint.disabled_checks",
345 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
346 }
Cole Faust3f646262022-06-29 14:58:03 -0700347
348 // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
349 if ctx.ModuleName() == "PermissionController" {
350 l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
351 return s != "NewApi"
352 })
353 l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
354 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000355 }
356
Colin Cross92e4b462020-06-18 15:56:48 -0700357 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
358 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800359 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
360 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
361 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700362 } else {
363 ctx.PropertyErrorf("lint.extra_check_modules",
364 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
365 }
366 }
367
Colin Cross1661aff2021-03-12 17:56:51 -0800368 rule := android.NewRuleBuilder(pctx, ctx).
369 Sbox(android.PathForModuleOut(ctx, "lint"),
370 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
371 SandboxInputs()
372
373 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
374 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
375 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
376 rule.Rewrapper(&remoteexec.REParams{
377 Labels: map[string]string{"type": "tool", "name": "lint"},
378 ExecStrategy: lintRBEExecStrategy(ctx),
379 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700380 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800381 })
382 }
Colin Cross014489c2020-06-02 20:09:13 -0700383
384 if l.manifest == nil {
385 manifest := l.generateManifest(ctx, rule)
386 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800387 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700388 }
389
Colin Cross31972dc2021-03-04 10:44:12 -0800390 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700391
Colin Cross1661aff2021-03-12 17:56:51 -0800392 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
393 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
394 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Cross6b76c152021-09-09 09:36:25 -0700395 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700396
Colin Cross08dca382020-07-21 20:31:17 -0700397 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700398
399 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000400 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700401 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700402 }
403 })
Colin Cross014489c2020-06-02 20:09:13 -0700404
Colin Cross31972dc2021-03-04 10:44:12 -0800405 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
406 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800407 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700408
Pedro Loureiro18233a22021-06-08 18:11:21 +0000409 var apiVersionsName, apiVersionsPrebuilt string
Pedro Loureiroffb643f2021-07-05 13:53:36 +0000410 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
411 // When compiling an SDK module (or system server) we use the filtered
412 // database because otherwise lint's
Pedro Loureiro18233a22021-06-08 18:11:21 +0000413 // NewApi check produces too many false positives; This database excludes information
414 // about classes created in mainline modules hence removing those false positives.
415 apiVersionsName = "api_versions_public_filtered.xml"
416 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
417 } else {
418 apiVersionsName = "api_versions.xml"
419 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
420 }
421
Colin Cross8a6ed372020-07-06 11:45:51 -0700422 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900423 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700424 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
Pedro Loureiro18233a22021-06-08 18:11:21 +0000425 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
Colin Cross8a6ed372020-07-06 11:45:51 -0700426 } else {
427 annotationsZipPath = copiedAnnotationsZipPath(ctx)
Pedro Loureiro18233a22021-06-08 18:11:21 +0000428 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700429 }
430
Colin Cross31972dc2021-03-04 10:44:12 -0800431 cmd := rule.Command()
432
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000433 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800434 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700435 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800436 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
437
Colin Cross1661aff2021-03-12 17:56:51 -0800438 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700439 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800440 FlagWithInput("--project ", lintPaths.projectXML).
441 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700442 FlagWithOutput("--html ", html).
443 FlagWithOutput("--text ", text).
444 FlagWithOutput("--xml ", xml).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000445 FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
Colin Cross014489c2020-06-02 20:09:13 -0700446 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
447 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
448 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
449 Flag("--exitcode").
450 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800451 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700452 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700453
Colin Cross1661aff2021-03-12 17:56:51 -0800454 rule.Temporary(lintPaths.projectXML)
455 rule.Temporary(lintPaths.configXML)
456
Colin Cross988dfcc2020-07-16 17:32:17 -0700457 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
458 cmd.FlagWithArg("--check ", checkOnly)
459 }
460
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700461 lintBaseline := l.getBaselineFilepath(ctx)
462 if lintBaseline.Valid() {
463 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000464 }
465
Colin Cross6b76c152021-09-09 09:36:25 -0700466 cmd.FlagWithOutput("--write-reference-baseline ", baseline)
467
Colin Cross31972dc2021-03-04 10:44:12 -0800468 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700469
Colin Cross31972dc2021-03-04 10:44:12 -0800470 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700471
Colin Crossee4a8b72021-04-05 18:38:05 -0700472 // The HTML output contains a date, remove it to make the output deterministic.
473 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
474
Colin Crossf1a035e2020-11-16 17:32:30 -0800475 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700476
Colin Crossc0efd1d2020-07-03 11:56:24 -0700477 l.outputs = lintOutputs{
478 html: html,
479 text: text,
480 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700481
Colin Cross08dca382020-07-21 20:31:17 -0700482 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700483 }
Colin Cross014489c2020-06-02 20:09:13 -0700484
Colin Crossc0efd1d2020-07-03 11:56:24 -0700485 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700486 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700487 }
488}
Colin Cross014489c2020-06-02 20:09:13 -0700489
Colin Cross08dca382020-07-21 20:31:17 -0700490func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
491 htmlList := depSets.HTML.ToSortedList()
492 textList := depSets.Text.ToSortedList()
493 xmlList := depSets.XML.ToSortedList()
494
495 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
496 return nil
497 }
498
499 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
500 lintZip(ctx, htmlList, htmlZip)
501
502 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
503 lintZip(ctx, textList, textZip)
504
505 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
506 lintZip(ctx, xmlList, xmlZip)
507
508 return android.Paths{htmlZip, textZip, xmlZip}
509}
510
Colin Cross014489c2020-06-02 20:09:13 -0700511type lintSingleton struct {
512 htmlZip android.WritablePath
513 textZip android.WritablePath
514 xmlZip android.WritablePath
515}
516
517func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
518 l.generateLintReportZips(ctx)
519 l.copyLintDependencies(ctx)
520}
521
Pedro Loureiro18233a22021-06-08 18:11:21 +0000522func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
523 var res android.Module
524 ctx.VisitAllModules(func(m android.Module) {
525 if ctx.ModuleName(m) == moduleName {
526 if res == nil {
527 res = m
528 } else {
529 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
530 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
531 }
532 }
533 })
534 return res
535}
536
Colin Cross014489c2020-06-02 20:09:13 -0700537func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900538 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700539 return
540 }
541
Anton Hansson67cf60e2022-05-09 09:36:22 +0000542 apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
543 if apiVersionsDb == nil {
Colin Cross014489c2020-06-02 20:09:13 -0700544 if !ctx.Config().AllowMissingDependencies() {
Anton Hansson67cf60e2022-05-09 09:36:22 +0000545 ctx.Errorf("lint: missing module api_versions_public")
Colin Cross014489c2020-06-02 20:09:13 -0700546 }
547 return
548 }
549
Anton Hanssonea17a452022-05-09 09:42:17 +0000550 sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
551 if sdkAnnotations == nil {
552 if !ctx.Config().AllowMissingDependencies() {
553 ctx.Errorf("lint: missing module sdk-annotations.zip")
554 }
555 return
556 }
557
Pedro Loureiro18233a22021-06-08 18:11:21 +0000558 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
559 if filteredDb == nil {
560 if !ctx.Config().AllowMissingDependencies() {
561 ctx.Errorf("lint: missing api-versions-xml-public-filtered")
562 }
563 return
564 }
565
Colin Cross014489c2020-06-02 20:09:13 -0700566 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800567 Rule: android.CpIfChanged,
Anton Hanssonea17a452022-05-09 09:42:17 +0000568 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
Colin Cross8a6ed372020-07-06 11:45:51 -0700569 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700570 })
571
572 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800573 Rule: android.CpIfChanged,
Anton Hansson67cf60e2022-05-09 09:36:22 +0000574 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
Pedro Loureiro18233a22021-06-08 18:11:21 +0000575 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
576 })
577
578 ctx.Build(pctx, android.BuildParams{
579 Rule: android.CpIfChanged,
580 Input: android.OutputFileForModule(ctx, filteredDb, ""),
581 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
Colin Cross014489c2020-06-02 20:09:13 -0700582 })
583}
584
Colin Cross8a6ed372020-07-06 11:45:51 -0700585func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700586 return android.PathForOutput(ctx, "lint", "annotations.zip")
587}
588
Pedro Loureiro18233a22021-06-08 18:11:21 +0000589func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
590 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700591}
592
593func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700594 if ctx.Config().UnbundledBuild() {
595 return
596 }
597
Colin Cross014489c2020-06-02 20:09:13 -0700598 var outputs []*lintOutputs
599 var dirs []string
600 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500601 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700602 return
603 }
604
Colin Cross56a83212020-09-15 18:30:11 -0700605 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
606 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
607 if apexInfo.IsForPlatform() {
608 // There are stray platform variants of modules in apexes that are not available for
609 // the platform, and they sometimes can't be built. Don't depend on them.
610 return
611 }
Colin Cross014489c2020-06-02 20:09:13 -0700612 }
613
Colin Cross08dca382020-07-21 20:31:17 -0700614 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700615 outputs = append(outputs, l.lintOutputs())
616 }
617 })
618
619 dirs = android.SortedUniqueStrings(dirs)
620
621 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
622 var paths android.Paths
623
624 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700625 if p := get(output); p != nil {
626 paths = append(paths, p)
627 }
Colin Cross014489c2020-06-02 20:09:13 -0700628 }
629
Colin Crossc0efd1d2020-07-03 11:56:24 -0700630 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700631 }
632
633 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
634 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
635
636 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
637 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
638
639 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
640 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
641
642 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
643}
644
645func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700646 if !ctx.Config().UnbundledBuild() {
647 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
648 }
Colin Cross014489c2020-06-02 20:09:13 -0700649}
650
651var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
652
653func init() {
654 android.RegisterSingletonType("lint",
655 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700656
657 registerLintBuildComponents(android.InitRegistrationContext)
658}
659
660func registerLintBuildComponents(ctx android.RegistrationContext) {
661 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
662 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
663 })
Colin Cross014489c2020-06-02 20:09:13 -0700664}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700665
666func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
667 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
668
669 sort.Slice(paths, func(i, j int) bool {
670 return paths[i].String() < paths[j].String()
671 })
672
Colin Crossf1a035e2020-11-16 17:32:30 -0800673 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700674
Colin Crossf1a035e2020-11-16 17:32:30 -0800675 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700676 FlagWithOutput("-o ", outputPath).
677 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800678 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700679
Colin Crossf1a035e2020-11-16 17:32:30 -0800680 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700681}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700682
683// Enforce the strict updatability linting to all applicable transitive dependencies.
684func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
685 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000686 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700687 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000688 if a, ok := d.(LintDepSetsIntf); ok {
689 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700690 }
691 })
692 }
693}