blob: 34720e51de10ff2c7edb1040162458216c9ab87f [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
Cole Faustd57e8b22022-08-11 11:59:04 -070064
65 // Treat the code in this module as test code for @VisibleForTesting enforcement.
66 // This will be true by default for test module types, false otherwise.
67 // If soong gets support for testonly, this flag should be replaced with that.
68 Test *bool
ThiƩbaud Weksteen9c0dff92023-09-29 10:21:56 +100069
70 // Whether to ignore the exit code of Android lint. This is the --exit_code
71 // option. Defaults to false.
72 Suppress_exit_code *bool
Colin Cross014489c2020-06-02 20:09:13 -070073 }
74}
75
76type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000077 name string
78 manifest android.Path
79 mergedManifest android.Path
80 srcs android.Paths
81 srcJars android.Paths
82 resources android.Paths
83 classpath android.Paths
84 classes android.Path
85 extraLintCheckJars android.Paths
Pedro Loureirof4a88b12021-02-25 16:23:22 +000086 library bool
Cole Fauste5bf3fb2022-07-01 19:39:14 +000087 minSdkVersion int
88 targetSdkVersion int
89 compileSdkVersion int
Pedro Loureiro18233a22021-06-08 18:11:21 +000090 compileSdkKind android.SdkKind
Pedro Loureirof4a88b12021-02-25 16:23:22 +000091 javaLanguageLevel string
92 kotlinLanguageLevel string
93 outputs lintOutputs
94 properties LintProperties
95 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070096
Colin Cross08dca382020-07-21 20:31:17 -070097 reports android.Paths
98
Colin Crossc0efd1d2020-07-03 11:56:24 -070099 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -0700100}
101
102type lintOutputs struct {
Cole Faustdf38f7a2023-03-02 16:43:15 -0800103 html android.Path
104 text android.Path
105 xml android.Path
106 referenceBaseline android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -0700107
Colin Cross08dca382020-07-21 20:31:17 -0700108 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -0700109}
110
Colin Cross08dca382020-07-21 20:31:17 -0700111type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -0700112 lintOutputs() *lintOutputs
113}
114
Spandan Das17854f52022-01-14 21:19:14 +0000115type LintDepSetsIntf interface {
Colin Cross08dca382020-07-21 20:31:17 -0700116 LintDepSets() LintDepSets
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700117
118 // Methods used to propagate strict_updatability_linting values.
Spandan Das17854f52022-01-14 21:19:14 +0000119 GetStrictUpdatabilityLinting() bool
120 SetStrictUpdatabilityLinting(bool)
Colin Cross08dca382020-07-21 20:31:17 -0700121}
122
123type LintDepSets struct {
Colin Crossc85750b2022-04-21 12:50:51 -0700124 HTML, Text, XML *android.DepSet[android.Path]
Colin Cross08dca382020-07-21 20:31:17 -0700125}
126
127type LintDepSetsBuilder struct {
Colin Crossc85750b2022-04-21 12:50:51 -0700128 HTML, Text, XML *android.DepSetBuilder[android.Path]
Colin Cross08dca382020-07-21 20:31:17 -0700129}
130
131func NewLintDepSetBuilder() LintDepSetsBuilder {
132 return LintDepSetsBuilder{
Colin Crossc85750b2022-04-21 12:50:51 -0700133 HTML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
134 Text: android.NewDepSetBuilder[android.Path](android.POSTORDER),
135 XML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
Colin Cross08dca382020-07-21 20:31:17 -0700136 }
137}
138
139func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
140 l.HTML.Direct(html)
141 l.Text.Direct(text)
142 l.XML.Direct(xml)
143 return l
144}
145
146func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
147 if depSets.HTML != nil {
148 l.HTML.Transitive(depSets.HTML)
149 }
150 if depSets.Text != nil {
151 l.Text.Transitive(depSets.Text)
152 }
153 if depSets.XML != nil {
154 l.XML.Transitive(depSets.XML)
155 }
156 return l
157}
158
159func (l LintDepSetsBuilder) Build() LintDepSets {
160 return LintDepSets{
161 HTML: l.HTML.Build(),
162 Text: l.Text.Build(),
163 XML: l.XML.Build(),
164 }
165}
166
Cole Faust69861aa2023-01-31 15:49:07 -0800167type lintDatabaseFiles struct {
168 apiVersionsModule string
169 apiVersionsCopiedName string
170 apiVersionsPrebuiltPath string
171 annotationsModule string
172 annotationCopiedName string
173 annotationPrebuiltpath string
174}
175
176var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{
177 android.SdkPublic: {
178 apiVersionsModule: "api_versions_public",
179 apiVersionsCopiedName: "api_versions_public.xml",
180 apiVersionsPrebuiltPath: "prebuilts/sdk/current/public/data/api-versions.xml",
181 annotationsModule: "sdk-annotations.zip",
182 annotationCopiedName: "annotations-public.zip",
183 annotationPrebuiltpath: "prebuilts/sdk/current/public/data/annotations.zip",
184 },
185 android.SdkSystem: {
186 apiVersionsModule: "api_versions_system",
187 apiVersionsCopiedName: "api_versions_system.xml",
188 apiVersionsPrebuiltPath: "prebuilts/sdk/current/system/data/api-versions.xml",
189 annotationsModule: "sdk-annotations-system.zip",
190 annotationCopiedName: "annotations-system.zip",
191 annotationPrebuiltpath: "prebuilts/sdk/current/system/data/annotations.zip",
192 },
193 android.SdkModule: {
194 apiVersionsModule: "api_versions_module_lib",
195 apiVersionsCopiedName: "api_versions_module_lib.xml",
196 apiVersionsPrebuiltPath: "prebuilts/sdk/current/module-lib/data/api-versions.xml",
197 annotationsModule: "sdk-annotations-module-lib.zip",
198 annotationCopiedName: "annotations-module-lib.zip",
199 annotationPrebuiltpath: "prebuilts/sdk/current/module-lib/data/annotations.zip",
200 },
201 android.SdkSystemServer: {
202 apiVersionsModule: "api_versions_system_server",
203 apiVersionsCopiedName: "api_versions_system_server.xml",
204 apiVersionsPrebuiltPath: "prebuilts/sdk/current/system-server/data/api-versions.xml",
205 annotationsModule: "sdk-annotations-system-server.zip",
206 annotationCopiedName: "annotations-system-server.zip",
207 annotationPrebuiltpath: "prebuilts/sdk/current/system-server/data/annotations.zip",
208 },
209}
210
Colin Cross08dca382020-07-21 20:31:17 -0700211func (l *linter) LintDepSets() LintDepSets {
212 return l.outputs.depSets
213}
214
Spandan Das17854f52022-01-14 21:19:14 +0000215func (l *linter) GetStrictUpdatabilityLinting() bool {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700216 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
217}
218
Spandan Das17854f52022-01-14 21:19:14 +0000219func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700220 l.properties.Lint.Strict_updatability_linting = &strictLinting
221}
222
Spandan Das17854f52022-01-14 21:19:14 +0000223var _ LintDepSetsIntf = (*linter)(nil)
Colin Cross08dca382020-07-21 20:31:17 -0700224
225var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700226
227func (l *linter) lintOutputs() *lintOutputs {
228 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700229}
230
231func (l *linter) enabled() bool {
232 return BoolDefault(l.properties.Lint.Enabled, true)
233}
234
Colin Cross92e4b462020-06-18 15:56:48 -0700235func (l *linter) deps(ctx android.BottomUpMutatorContext) {
236 if !l.enabled() {
237 return
238 }
239
Colin Cross988dfcc2020-07-16 17:32:17 -0700240 extraCheckModules := l.properties.Lint.Extra_check_modules
241
mattgilbridee17645f2022-11-18 18:20:20 +0000242 if extraCheckModulesEnv := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); extraCheckModulesEnv != "" {
243 extraCheckModules = append(extraCheckModules, strings.Split(extraCheckModulesEnv, ",")...)
Colin Cross988dfcc2020-07-16 17:32:17 -0700244 }
245
246 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
247 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700248}
249
Colin Crossad22bc22021-03-10 09:45:40 -0800250// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
251// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800252type lintPaths struct {
253 projectXML android.WritablePath
254 configXML android.WritablePath
255 cacheDir android.WritablePath
256 homeDir android.WritablePath
257 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800258}
259
Colin Cross9b93af42021-03-10 10:40:58 -0800260func lintRBEExecStrategy(ctx android.ModuleContext) string {
261 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
262}
263
Colin Cross62695b92022-08-12 16:09:24 -0700264func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800265 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700266 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800267 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
268 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
269 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700270
Colin Cross1661aff2021-03-12 17:56:51 -0800271 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700272 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
273
274 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700275 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700276 FlagWithOutput("--project_out ", projectXMLPath).
277 FlagWithOutput("--config_out ", configXMLPath).
278 FlagWithArg("--name ", ctx.ModuleName())
279
280 if l.library {
281 cmd.Flag("--library")
282 }
Cole Faustd57e8b22022-08-11 11:59:04 -0700283 if proptools.BoolDefault(l.properties.Lint.Test, false) {
Colin Cross014489c2020-06-02 20:09:13 -0700284 cmd.Flag("--test")
285 }
286 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700287 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700288 }
289 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700290 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700291 }
292
Colin Cross5bedfa22021-03-23 17:07:14 -0700293 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
294 // lint separately.
Colin Cross62695b92022-08-12 16:09:24 -0700295 cmd.FlagWithInput("--srcs ", srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700296
297 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700298
Colin Cross5bedfa22021-03-23 17:07:14 -0700299 if len(l.resources) > 0 {
300 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
301 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700302 }
303
304 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700305 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700306 }
307
Colin Cross5bedfa22021-03-23 17:07:14 -0700308 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700309
Colin Cross5bedfa22021-03-23 17:07:14 -0700310 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700311
Colin Cross1661aff2021-03-12 17:56:51 -0800312 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700313
314 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
315 // the root dir is not set.
316 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700317
318 cmd.FlagWithInput("@",
319 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
320
Cole Faust69861aa2023-01-31 15:49:07 -0800321 if l.compileSdkKind == android.SdkPublic {
322 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
323 } else {
324 // TODO(b/268261262): Remove this branch. We're demoting NewApi to a warning due to pre-existing issues that need to be fixed.
325 cmd.FlagForEachArg("--warning_check ", l.extraMainlineLintErrors)
326 }
Colin Cross014489c2020-06-02 20:09:13 -0700327 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
328 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
329 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
330 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
331
Cole Faust1021ccd2023-02-26 21:15:25 -0800332 // TODO(b/193460475): Re-enable strict updatability linting
333 //if l.GetStrictUpdatabilityLinting() {
334 // // Verify the module does not baseline issues that endanger safe updatability.
335 // if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
336 // cmd.FlagWithInput("--baseline ", baselinePath.Path())
337 // cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
338 // }
339 //}
Jaewoong Jung48de8832021-04-21 16:17:25 -0700340
Colin Cross31972dc2021-03-04 10:44:12 -0800341 return lintPaths{
342 projectXML: projectXMLPath,
343 configXML: configXMLPath,
344 cacheDir: cacheDir,
345 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800346 }
347
Colin Cross014489c2020-06-02 20:09:13 -0700348}
349
Liz Kammer20ebfb42020-07-28 11:32:07 -0700350// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700351// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800352func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700353 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
354
355 rule.Command().Text("(").
356 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
357 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
358 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000359 Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
360 l.minSdkVersion, l.targetSdkVersion).
Colin Cross014489c2020-06-02 20:09:13 -0700361 Text(`echo "</manifest>"`).
362 Text(") >").Output(manifestPath)
363
364 return manifestPath
365}
366
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700367func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
368 var lintBaseline android.OptionalPath
369 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
370 if String(l.properties.Lint.Baseline_filename) != "" {
371 // if manually specified, we require the file to exist
372 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
373 } else {
374 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
375 }
376 }
377 return lintBaseline
378}
379
Colin Cross014489c2020-06-02 20:09:13 -0700380func (l *linter) lint(ctx android.ModuleContext) {
381 if !l.enabled() {
382 return
383 }
384
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000385 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700386 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
Orion Hodsonb8166522022-08-15 20:23:38 +0100387 // Skip lint warning checks for NewApi warnings for libcore where they come from source
388 // files that reference the API they are adding (b/208656169).
Orion Hodsonb2d3c8c2022-10-25 16:45:14 +0100389 if !strings.HasPrefix(ctx.ModuleDir(), "libcore") {
Orion Hodsonb8166522022-08-15 20:23:38 +0100390 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
391
392 if len(filtered) != 0 {
393 ctx.PropertyErrorf("lint.warning_checks",
394 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
395 }
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700396 }
Orion Hodsonb8166522022-08-15 20:23:38 +0100397
398 _, filtered := android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700399 if len(filtered) != 0 {
400 ctx.PropertyErrorf("lint.disabled_checks",
401 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
402 }
Cole Faust3f646262022-06-29 14:58:03 -0700403
404 // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
405 if ctx.ModuleName() == "PermissionController" {
406 l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
407 return s != "NewApi"
408 })
409 l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
410 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000411 }
412
Colin Cross92e4b462020-06-18 15:56:48 -0700413 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
414 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800415 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
416 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
417 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700418 } else {
419 ctx.PropertyErrorf("lint.extra_check_modules",
420 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
421 }
422 }
423
mattgilbride5aecabe2022-11-29 20:16:36 +0000424 l.extraLintCheckJars = append(l.extraLintCheckJars, android.PathForSource(ctx,
425 "prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar"))
426
Colin Cross1661aff2021-03-12 17:56:51 -0800427 rule := android.NewRuleBuilder(pctx, ctx).
428 Sbox(android.PathForModuleOut(ctx, "lint"),
429 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
430 SandboxInputs()
431
432 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
433 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
434 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
435 rule.Rewrapper(&remoteexec.REParams{
436 Labels: map[string]string{"type": "tool", "name": "lint"},
437 ExecStrategy: lintRBEExecStrategy(ctx),
438 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700439 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800440 })
441 }
Colin Cross014489c2020-06-02 20:09:13 -0700442
443 if l.manifest == nil {
444 manifest := l.generateManifest(ctx, rule)
445 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800446 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700447 }
448
Colin Cross62695b92022-08-12 16:09:24 -0700449 srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
450 srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
451 rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList)
452
453 lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700454
Colin Cross1661aff2021-03-12 17:56:51 -0800455 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
456 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
457 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Cole Faustdf38f7a2023-03-02 16:43:15 -0800458 referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700459
Colin Cross08dca382020-07-21 20:31:17 -0700460 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700461
462 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000463 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700464 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700465 }
466 })
Colin Cross014489c2020-06-02 20:09:13 -0700467
Colin Cross31972dc2021-03-04 10:44:12 -0800468 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
469 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800470 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700471
Cole Faust69861aa2023-01-31 15:49:07 -0800472 files, ok := allLintDatabasefiles[l.compileSdkKind]
473 if !ok {
474 files = allLintDatabasefiles[android.SdkPublic]
Pedro Loureiro18233a22021-06-08 18:11:21 +0000475 }
Colin Cross8a6ed372020-07-06 11:45:51 -0700476 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900477 if ctx.Config().AlwaysUsePrebuiltSdks() {
Cole Faust69861aa2023-01-31 15:49:07 -0800478 annotationsZipPath = android.PathForSource(ctx, files.annotationPrebuiltpath)
479 apiVersionsXMLPath = android.PathForSource(ctx, files.apiVersionsPrebuiltPath)
Colin Cross8a6ed372020-07-06 11:45:51 -0700480 } else {
Cole Faust69861aa2023-01-31 15:49:07 -0800481 annotationsZipPath = copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName)
482 apiVersionsXMLPath = copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700483 }
484
Colin Cross31972dc2021-03-04 10:44:12 -0800485 cmd := rule.Command()
486
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000487 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800488 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700489 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800490 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
491
Colin Cross1661aff2021-03-12 17:56:51 -0800492 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700493 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800494 FlagWithInput("--project ", lintPaths.projectXML).
495 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700496 FlagWithOutput("--html ", html).
497 FlagWithOutput("--text ", text).
498 FlagWithOutput("--xml ", xml).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000499 FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
Colin Cross014489c2020-06-02 20:09:13 -0700500 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
501 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
502 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
Colin Cross62695b92022-08-12 16:09:24 -0700503 Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
Colin Cross014489c2020-06-02 20:09:13 -0700504 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800505 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700506 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700507
Colin Cross1661aff2021-03-12 17:56:51 -0800508 rule.Temporary(lintPaths.projectXML)
509 rule.Temporary(lintPaths.configXML)
510
ThiƩbaud Weksteen9c0dff92023-09-29 10:21:56 +1000511 suppressExitCode := BoolDefault(l.properties.Lint.Suppress_exit_code, false)
512 if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" && !suppressExitCode {
mattgilbrideb597abd2023-03-22 17:44:18 +0000513 cmd.Flag("--exitcode")
514 }
515
Colin Cross988dfcc2020-07-16 17:32:17 -0700516 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
517 cmd.FlagWithArg("--check ", checkOnly)
518 }
519
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700520 lintBaseline := l.getBaselineFilepath(ctx)
521 if lintBaseline.Valid() {
522 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000523 }
524
Cole Faustdf38f7a2023-03-02 16:43:15 -0800525 cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
Colin Cross6b76c152021-09-09 09:36:25 -0700526
Colin Cross1b9e6832022-10-11 11:22:24 -0700527 cmd.Text("; EXITCODE=$?; ")
528
529 // The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
530 // export them out of the sandbox. Do this before exiting so that the suggestions exit even after
531 // a fatal error.
532 cmd.BuiltTool("soong_zip").
533 FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
534 FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
535 FlagWithInput("-r ", srcsList)
536
537 cmd.Text("; if [ $EXITCODE != 0 ]; then if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit $EXITCODE; fi")
Colin Cross014489c2020-06-02 20:09:13 -0700538
Colin Cross31972dc2021-03-04 10:44:12 -0800539 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700540
Colin Crossee4a8b72021-04-05 18:38:05 -0700541 // The HTML output contains a date, remove it to make the output deterministic.
542 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
543
Colin Crossf1a035e2020-11-16 17:32:30 -0800544 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700545
Colin Crossc0efd1d2020-07-03 11:56:24 -0700546 l.outputs = lintOutputs{
Cole Faustdf38f7a2023-03-02 16:43:15 -0800547 html: html,
548 text: text,
549 xml: xml,
550 referenceBaseline: referenceBaseline,
Colin Cross014489c2020-06-02 20:09:13 -0700551
Colin Cross08dca382020-07-21 20:31:17 -0700552 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700553 }
Colin Cross014489c2020-06-02 20:09:13 -0700554
Colin Crossc0efd1d2020-07-03 11:56:24 -0700555 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700556 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700557 }
558}
Colin Cross014489c2020-06-02 20:09:13 -0700559
Colin Cross08dca382020-07-21 20:31:17 -0700560func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
Colin Crossc85750b2022-04-21 12:50:51 -0700561 htmlList := android.SortedUniquePaths(depSets.HTML.ToList())
562 textList := android.SortedUniquePaths(depSets.Text.ToList())
563 xmlList := android.SortedUniquePaths(depSets.XML.ToList())
Colin Cross08dca382020-07-21 20:31:17 -0700564
565 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
566 return nil
567 }
568
569 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
570 lintZip(ctx, htmlList, htmlZip)
571
572 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
573 lintZip(ctx, textList, textZip)
574
575 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
576 lintZip(ctx, xmlList, xmlZip)
577
578 return android.Paths{htmlZip, textZip, xmlZip}
579}
580
Colin Cross014489c2020-06-02 20:09:13 -0700581type lintSingleton struct {
Cole Faustdf38f7a2023-03-02 16:43:15 -0800582 htmlZip android.WritablePath
583 textZip android.WritablePath
584 xmlZip android.WritablePath
585 referenceBaselineZip android.WritablePath
Colin Cross014489c2020-06-02 20:09:13 -0700586}
587
588func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
589 l.generateLintReportZips(ctx)
590 l.copyLintDependencies(ctx)
591}
592
Pedro Loureiro18233a22021-06-08 18:11:21 +0000593func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
594 var res android.Module
595 ctx.VisitAllModules(func(m android.Module) {
596 if ctx.ModuleName(m) == moduleName {
597 if res == nil {
598 res = m
599 } else {
600 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
601 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
602 }
603 }
604 })
605 return res
606}
607
Colin Cross014489c2020-06-02 20:09:13 -0700608func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900609 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700610 return
611 }
612
Cole Faust69861aa2023-01-31 15:49:07 -0800613 for _, sdk := range android.SortedKeys(allLintDatabasefiles) {
614 files := allLintDatabasefiles[sdk]
615 apiVersionsDb := findModuleOrErr(ctx, files.apiVersionsModule)
616 if apiVersionsDb == nil {
617 if !ctx.Config().AllowMissingDependencies() {
618 ctx.Errorf("lint: missing module api_versions_public")
619 }
620 return
Colin Cross014489c2020-06-02 20:09:13 -0700621 }
Colin Cross014489c2020-06-02 20:09:13 -0700622
Cole Faust69861aa2023-01-31 15:49:07 -0800623 sdkAnnotations := findModuleOrErr(ctx, files.annotationsModule)
624 if sdkAnnotations == nil {
625 if !ctx.Config().AllowMissingDependencies() {
626 ctx.Errorf("lint: missing module sdk-annotations.zip")
627 }
628 return
Anton Hanssonea17a452022-05-09 09:42:17 +0000629 }
Cole Faust69861aa2023-01-31 15:49:07 -0800630
631 ctx.Build(pctx, android.BuildParams{
632 Rule: android.CpIfChanged,
633 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
634 Output: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
635 })
636
637 ctx.Build(pctx, android.BuildParams{
638 Rule: android.CpIfChanged,
639 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
640 Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
641 })
Anton Hanssonea17a452022-05-09 09:42:17 +0000642 }
Colin Cross014489c2020-06-02 20:09:13 -0700643}
644
Cole Faust69861aa2023-01-31 15:49:07 -0800645func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.WritablePath {
Pedro Loureiro18233a22021-06-08 18:11:21 +0000646 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700647}
648
649func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700650 if ctx.Config().UnbundledBuild() {
651 return
652 }
653
Colin Cross014489c2020-06-02 20:09:13 -0700654 var outputs []*lintOutputs
655 var dirs []string
656 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500657 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700658 return
659 }
660
Colin Cross56a83212020-09-15 18:30:11 -0700661 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
662 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
663 if apexInfo.IsForPlatform() {
664 // There are stray platform variants of modules in apexes that are not available for
665 // the platform, and they sometimes can't be built. Don't depend on them.
666 return
667 }
Colin Cross014489c2020-06-02 20:09:13 -0700668 }
669
Colin Cross08dca382020-07-21 20:31:17 -0700670 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700671 outputs = append(outputs, l.lintOutputs())
672 }
673 })
674
675 dirs = android.SortedUniqueStrings(dirs)
676
677 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
678 var paths android.Paths
679
680 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700681 if p := get(output); p != nil {
682 paths = append(paths, p)
683 }
Colin Cross014489c2020-06-02 20:09:13 -0700684 }
685
Colin Crossc0efd1d2020-07-03 11:56:24 -0700686 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700687 }
688
689 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
690 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
691
692 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
693 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
694
695 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
696 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
697
Cole Faustdf38f7a2023-03-02 16:43:15 -0800698 l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip")
699 zip(l.referenceBaselineZip, func(l *lintOutputs) android.Path { return l.referenceBaseline })
700
701 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
Colin Cross014489c2020-06-02 20:09:13 -0700702}
703
704func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700705 if !ctx.Config().UnbundledBuild() {
Cole Faustdf38f7a2023-03-02 16:43:15 -0800706 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
Colin Cross8a6ed372020-07-06 11:45:51 -0700707 }
Colin Cross014489c2020-06-02 20:09:13 -0700708}
709
710var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
711
712func init() {
LaMont Jones0c10e4d2023-05-16 00:58:37 +0000713 android.RegisterParallelSingletonType("lint",
Colin Cross014489c2020-06-02 20:09:13 -0700714 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700715
716 registerLintBuildComponents(android.InitRegistrationContext)
717}
718
719func registerLintBuildComponents(ctx android.RegistrationContext) {
720 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
721 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
722 })
Colin Cross014489c2020-06-02 20:09:13 -0700723}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700724
725func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
726 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
727
728 sort.Slice(paths, func(i, j int) bool {
729 return paths[i].String() < paths[j].String()
730 })
731
Colin Crossf1a035e2020-11-16 17:32:30 -0800732 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700733
Colin Crossf1a035e2020-11-16 17:32:30 -0800734 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700735 FlagWithOutput("-o ", outputPath).
736 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800737 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700738
Colin Crossf1a035e2020-11-16 17:32:30 -0800739 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700740}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700741
742// Enforce the strict updatability linting to all applicable transitive dependencies.
743func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
744 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000745 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700746 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000747 if a, ok := d.(LintDepSetsIntf); ok {
748 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700749 }
750 })
751 }
752}