blob: 32005f64938f8b8f8cc0cedc1d62d4a8b89ebfa6 [file] [log] [blame]
<html><head><meta charset="utf-8" lang="kotlin">
</head><body style="visibility: visible;" id="md"><meta charset="UTF-8"><meta http-equiv="content-type" content="text/html;charset=UTF-8"><meta name="viewport" content="width=600, initial-scale=1"><style>body{max-width:680px;margin:auto;padding:20px;text-align:justify;line-height:140%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased;color:#222;font-family:Palatino,Georgia,"Times New Roman",serif}</style><style>@media print{*{-webkit-print-color-adjust:exact;text-shadow:none !important}}body{counter-reset: h1 paragraph line item list-item}@page{margin:0;size:auto}#mdContextMenu{position:absolute;background:#383838;cursor:default;border:1px solid #999;color:#fff;padding:4px 0px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,"Helvetica Neue",sans-serif;font-size:85%;font-weight:600;border-radius:4px;box-shadow:0px 3px 10px rgba(0,0,0,35%)}#mdContextMenu div{padding:0px 20px}#mdContextMenu div:hover{background:#1659d1}.md code,.md pre{font-family:Menlo,Consolas,monospace;font-size:85%;text-align:left;line-height:140%}.md .mediumToc code,.md longToc code,.md .shortToc code,.md h1 code,.md h2 code,.md h3 code,.md h4 code,.md h5 code,.md h6 code{font-size:unset}.md div.title{font-size:26px;font-weight:800;line-height:120%;text-align:center}.md div.afterTitles{height:10px}.md div.subtitle{text-align:center}.md iframe.textinsert, .md object.textinsert,.md iframe:not(.markdeep){display:block;margin-top:10px;margin-bottom:10px;width:100%;height:75vh;border:1px solid #000;border-radius:4px;background:#f5f5f4}.md .image{display:inline-block}.md img{max-width:100%;page-break-inside:avoid}.md li{text-align:left;text-indent:0}.md pre.listing {width:100%;tab-size:4;-moz-tab-size:4;-o-tab-size:4;counter-reset:line;overflow-x:auto;resize:horizontal}.md pre.listing .linenumbers span.line:before{width:30px;margin-left:-28px;font-size:80%;text-align:right;counter-increment:line;content:counter(line);display:inline-block;padding-right:13px;margin-right:8px;color:#ccc}.md div.tilde{margin:20px 0 -10px;text-align:center}.md .imagecaption,.md .tablecaption,.md .listingcaption{display:inline-block;margin:7px 5px 12px;text-align:justify;font-style:italic}.md img.pixel{image-rendering:-moz-crisp-edges;image-rendering:pixelated}.md blockquote.fancyquote{margin:25px 0 25px;text-align:left;line-height:160%}.md blockquote.fancyquote::before{content:"“";color:#DDD;font-family:Times New Roman;font-size:45px;line-height:0;margin-right:6px;vertical-align:-0.3em}.md span.fancyquote{font-size:118%;color:#777;font-style:italic}.md span.fancyquote::after{content:"”";font-style:normal;color:#DDD;font-family:Times New Roman;font-size:45px;line-height:0;margin-left:6px;vertical-align:-0.3em}.md blockquote.fancyquote .author{width:100%;margin-top:10px;display:inline-block;text-align:right}.md small{font-size:60%}.md big{font-size:150%}.md div.title,contents,.md .tocHeader,.md h1,.md h2,.md h3,.md h4,.md h5,.md h6,.md .shortTOC,.md .mediumTOC,.nonumberh1,.nonumberh2,.nonumberh3,.nonumberh4,.nonumberh5,.nonumberh6{font-family:Verdana,Helvetica,Arial,sans-serif;margin:13.4px 0 13.4px;padding:15px 0 3px;border-top:none;clear:both}.md .tocTop {display:none}.md h1,.md h2,.md h3,.md h4,.md h5,.md h6,.md .nonumberh1,.md .nonumberh2,.md .nonumberh3,.md .nonumberh4,.md .nonumberh5,.md .nonumberh6{page-break-after:avoid;break-after:avoid}.md svg.diagram{display:block;font-family:Menlo,Consolas,monospace;font-size:85%;text-align:center;stroke-linecap:round;stroke-width:2px;page-break-inside:avoid;stroke:#000;fill:#000}.md svg.diagram .opendot{fill:#fff}.md svg.diagram .shadeddot{fill:#CCC}.md svg.diagram .dotteddot{stroke:#000;stroke-dasharray:4;fill:none}.md svg.diagram text{stroke:none}@media print{@page{margin:1in 5mm;transform: scale(150%)}}@media print{.md .pagebreak{page-break-after:always;visibility:hidden}}.md a{font-family:Georgia,Palatino,'Times New Roman'}.md h1,.md .tocHeader,.md .nonumberh1{border-bottom:3px solid;font-size:20px;font-weight:bold;}.md h1,.md .nonumberh1{counter-reset:h2 h3 h4 h5 h6}.md h2,.md .nonumberh2{counter-reset:h3 h4 h5 h6;border-bottom:2px solid #999;color:#555;font-weight:bold;font-size:18px;}.md h3,.md h4,.md h5,.md h6,.md .nonumberh3,.md .nonumberh4,.md .nonumberh5,.md .nonumberh6{font-family:Verdana,Helvetica,Arial,sans-serif;color:#555;font-size:16px;}.md h3{counter-reset:h4 h5 h6}.md h4{counter-reset:h5 h6}.md h5{counter-reset:h6}.md div.table{margin:16px 0 16px 0}.md table{border-collapse:collapse;line-height:140%;page-break-inside:avoid}.md table.table{margin:auto}.md table.calendar{width:100%;margin:auto;font-size:11px;font-family:Verdana,Helvetica,Arial,sans-serif}.md table.calendar th{font-size:16px}.md .today{background:#ECF8FA}.md .calendar .parenthesized{color:#999;font-style:italic}.md table.table th{color:#FFF;background-color:#AAA;border:1px solid #888;padding:8px 15px 8px 15px}.md table.table td{padding:5px 15px 5px 15px;border:1px solid #888}.md table.table tr:nth-child(even){background:#EEE}.md pre.tilde{border-top: 1px solid #CCC;border-bottom: 1px solid #CCC;padding: 5px 0 5px 20px;margin:0 0 0 0;background:#FCFCFC;page-break-inside:avoid}.md a.target{width:0px;height:0px;visibility:hidden;font-size:0px;display:inline-block}.md a:link, .md a:visited{color:#38A;text-decoration:none}.md a:link:hover{text-decoration:underline}.md dt{font-weight:700}.md dl>dd{margin-top:-8px; margin-bottom:8px}.md dl>table{margin:35px 0 30px}.md code{page-break-inside:avoid;} @media print{.md .listing code{white-space:pre-wrap}}.md .endnote{font-size:13px;line-height:15px;padding-left:10px;text-indent:-10px}.md .bib{padding-left:80px;text-indent:-80px;text-align:left}.markdeepFooter{font-size:9px;text-align:right;padding-top:80px;color:#999}.md .mediumTOC{float:right;font-size:12px;line-height:15px;border-left:1px solid #CCC;padding-left:15px;margin:15px 0px 15px 25px}.md .mediumTOC .level1{font-weight:600}.md .longTOC .level1{font-weight:600;display:block;padding-top:12px;margin:0 0 -20px}.md .shortTOC{text-align:center;font-weight:bold;margin-top:15px;font-size:14px}.md .admonition{position:relative;margin:1em 0;padding:.4rem 1rem;border-radius:.2rem;border-left:2.5rem solid rgba(68,138,255,.4);background-color:rgba(68,138,255,.15);}.md .admonition-title{font-weight:bold;border-bottom:solid 1px rgba(68,138,255,.4);padding-bottom:4px;margin-bottom:4px;margin-left: -1rem;padding-left:1rem;margin-right:-1rem;border-color:rgba(68,138,255,.4)}.md .admonition.tip{border-left:2.5rem solid rgba(50,255,90,.4);background-color:rgba(50,255,90,.15)}.md .admonition.tip::before{content:"\24d8";font-weight:bold;font-size:150%;position:relative;top:3px;color:rgba(26,128,46,.8);left:-2.95rem;display:block;width:0;height:0}.md .admonition.tip>.admonition-title{border-color:rgba(50,255,90,.4)}.md .admonition.warn,.md .admonition.warning{border-left:2.5rem solid rgba(255,145,0,.4);background-color:rgba(255,145,0,.15)}.md .admonition.warn::before,.md .admonition.warning::before{content:"\26A0";font-weight:bold;font-size:150%;position:relative;top:2px;color:rgba(128,73,0,.8);left:-2.95rem;display:block;width:0;height:0}.md .admonition.warn>.admonition-title,.md .admonition.warning>.admonition-title{border-color:rgba(255,145,0,.4)}.md .admonition.error{border-left: 2.5rem solid rgba(255,23,68,.4);background-color:rgba(255,23,68,.15)}.md .admonition.error>.admonition-title{border-color:rgba(255,23,68,.4)}.md .admonition.error::before{content: "\2612";font-family:"Arial";font-size:200%;position:relative;color:rgba(128,12,34,.8);top:-2px;left:-3rem;display:block;width:0;height:0}.md .admonition p:last-child{margin-bottom:0}.md li.checked,.md li.unchecked{list-style:none;overflow:visible;text-indent:-1.2em}.md li.checked:before,.md li.unchecked:before{content:"\2611";display:block;float:left;width:1em;font-size:120%}.md li.unchecked:before{content:"\2610"}</style><style>.md h1::before {
content:counter(h1) " ";
counter-increment: h1;margin-right:10px}
.md h2::before {
content:counter(h1) "."counter(h2) " ";
counter-increment: h2;margin-right:10px}
.md h3::before {
content:counter(h1) "."counter(h2) "."counter(h3) " ";
counter-increment: h3;margin-right:10px}
.md h4::before {
content:counter(h1) "."counter(h2) "."counter(h3) "."counter(h4) " ";
counter-increment: h4;margin-right:10px}
.md h5::before {
content:counter(h1) "."counter(h2) "."counter(h3) "."counter(h4) "."counter(h5) " ";
counter-increment: h5;margin-right:10px}
.md h6::before {
content:counter(h1) "."counter(h2) "."counter(h3) "."counter(h4) "."counter(h5) "."counter(h6) " ";
counter-increment: h6;margin-right:10px}
</style><style>.hljs{display:block;overflow-x:auto;padding:0.5em;background:#fff;color:#000;-webkit-text-size-adjust:none}.hljs-comment{color:#006a00}.hljs-keyword{color:#02E}.hljs-literal,.nginx .hljs-title{color:#aa0d91}.method,.hljs-list .hljs-title,.hljs-tag .hljs-title,.setting .hljs-value,.hljs-winutils,.tex .hljs-command,.http .hljs-title,.hljs-request,.hljs-status,.hljs-name{color:#008}.hljs-envvar,.tex .hljs-special{color:#660}.hljs-string{color:#c41a16}.hljs-tag .hljs-value,.hljs-cdata,.hljs-filter .hljs-argument,.hljs-attr_selector,.apache .hljs-cbracket,.hljs-date,.hljs-regexp{color:#080}.hljs-sub .hljs-identifier,.hljs-pi,.hljs-tag,.hljs-tag .hljs-keyword,.hljs-decorator,.ini .hljs-title,.hljs-shebang,.hljs-prompt,.hljs-hexcolor,.hljs-rule .hljs-value,.hljs-symbol,.hljs-symbol .hljs-string,.hljs-number,.css .hljs-function,.hljs-function .hljs-title,.coffeescript .hljs-attribute{color:#A0C}.hljs-function .hljs-title{font-weight:bold;color:#000}.hljs-class .hljs-title,.smalltalk .hljs-class,.hljs-type,.hljs-typename,.hljs-tag .hljs-attribute,.hljs-doctype,.hljs-class .hljs-id,.hljs-built_in,.setting,.hljs-params,.clojure .hljs-attribute{color:#5c2699}.hljs-variable{color:#3f6e74}.css .hljs-tag,.hljs-rule .hljs-property,.hljs-pseudo,.hljs-subst{color:#000}.css .hljs-class,.css .hljs-id{color:#9b703f}.hljs-value .hljs-important{color:#ff7700;font-weight:bold}.hljs-rule .hljs-keyword{color:#c5af75}.hljs-annotation,.apache .hljs-sqbracket,.nginx .hljs-built_in{color:#9b859d}.hljs-preprocessor,.hljs-preprocessor *,.hljs-pragma{color:#643820}.tex .hljs-formula{background-color:#eee;font-style:italic}.diff .hljs-header,.hljs-chunk{color:#808080;font-weight:bold}.diff .hljs-change{background-color:#bccff9}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-comment .hljs-doctag{font-weight:bold}.method .hljs-id{color:#000}</style><style>div.title { padding-top: 40px; } div.afterTitles { height: 15px; }</style><meta charset="utf-8" lang="kotlin">
<span class="md"><p><title>Android User Guide</title></p><div class="title"> Android User Guide </div>
<div class="afterTitles"></div><div class="mediumTOC"><center><b>Contents</b></center><p><a href="#" class="tocTop">(Top)</a><br>
<a href="#baselines" class="level1"><span class="tocNumber">1&nbsp; </span>Baselines</a><br>
<a href="#creatingabaseline" class="level1"><span class="tocNumber">2&nbsp; </span>Creating a Baseline</a><br>
&nbsp;&nbsp;<a href="#creatingabaseline/customizethebaseline" class="level2"><span class="tocNumber">2.1&nbsp; </span>Customize the baseline</a><br>
&nbsp;&nbsp;<a href="#creatingabaseline/baselinewarning" class="level2"><span class="tocNumber">2.2&nbsp; </span>Baseline warning</a><br>
<a href="#performancetuning" class="level1"><span class="tocNumber">3&nbsp; </span>Performance Tuning</a><br>
&nbsp;&nbsp;<a href="#performancetuning/use7.0andincrementallint" class="level2"><span class="tocNumber">3.1&nbsp; </span>Use 7.0 and Incremental Lint</a><br>
&nbsp;&nbsp;<a href="#performancetuning/usethelintdebugtarget,notlint" class="level2"><span class="tocNumber">3.2&nbsp; </span>Use the <code>lintDebug</code> target, not <code>lint</code></a><br>
&nbsp;&nbsp;<a href="#performancetuning/onlyanalyzeapp/leafmodules" class="level2"><span class="tocNumber">3.3&nbsp; </span>Only analyze app/leaf modules</a><br>
&nbsp;&nbsp;<a href="#performancetuning/don'tanalyzetestsources" class="level2"><span class="tocNumber">3.4&nbsp; </span>Don't analyze test sources</a><br>
&nbsp;&nbsp;<a href="#performancetuning/don'tusecheckallwarnings" class="level2"><span class="tocNumber">3.5&nbsp; </span>Don't use checkAllWarnings</a><br>
&nbsp;&nbsp;<a href="#performancetuning/uselatestversion" class="level2"><span class="tocNumber">3.6&nbsp; </span>Use latest version</a><br>
&nbsp;&nbsp;<a href="#performancetuning/givelintalotofram" class="level2"><span class="tocNumber">3.7&nbsp; </span>Give lint a lot of RAM</a><br>
&nbsp;&nbsp;<a href="#performancetuning/findingslowlintchecks" class="level2"><span class="tocNumber">3.8&nbsp; </span>Finding Slow Lint Checks</a><br>
<a href="#suppressinglintchecks" class="level1"><span class="tocNumber">4&nbsp; </span>Suppressing Lint Checks</a><br>
<a href="#configuringusinglint.xmlfiles" class="level1"><span class="tocNumber">5&nbsp; </span>Configuring Using lint.xml Files</a><br>
&nbsp;&nbsp;<a href="#configuringusinglint.xmlfiles/xmlsyntax" class="level2"><span class="tocNumber">5.1&nbsp; </span>XML Syntax</a><br>
&nbsp;&nbsp;<a href="#configuringusinglint.xmlfiles/nesting&amp;precedence" class="level2"><span class="tocNumber">5.2&nbsp; </span>Nesting &amp; Precedence</a><br>
&nbsp;&nbsp;<a href="#configuringusinglint.xmlfiles/samplelint.xmlfile" class="level2"><span class="tocNumber">5.3&nbsp; </span>Sample lint.xml file</a><br>
<a href="#appendix:recentchanges" class="level1"><span class="tocNumber">6&nbsp; </span>Appendix: Recent Changes</a><br>
<a href="#appendix:environmentvariablesandsystemproperties" class="level1"><span class="tocNumber">7&nbsp; </span>Appendix: Environment Variables and System Properties</a><br>
&nbsp;&nbsp;<a href="#appendix:environmentvariablesandsystemproperties/environmentvariables" class="level2"><span class="tocNumber">7.1&nbsp; </span>Environment Variables</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#appendix:environmentvariablesandsystemproperties/environmentvariables/detectorconfigurationvariables" class="level3"><span class="tocNumber">7.1.1&nbsp; </span>Detector Configuration Variables</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#appendix:environmentvariablesandsystemproperties/environmentvariables/lintconfigurationvariables" class="level3"><span class="tocNumber">7.1.2&nbsp; </span>Lint Configuration Variables</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#appendix:environmentvariablesandsystemproperties/environmentvariables/lintdevelopmentvariables" class="level3"><span class="tocNumber">7.1.3&nbsp; </span>Lint Development Variables</a><br>
&nbsp;&nbsp;<a href="#appendix:environmentvariablesandsystemproperties/systemproperties" class="level2"><span class="tocNumber">7.2&nbsp; </span>System Properties</a><br>
</p></div>
<p></p><p>
This chapter inlines all the usage information into a single
long book, suitable for printing or reading on a tablet.
</p><p>
<strong class="asterisk">Recent Changes</strong>
</p><p>
This chapter lists recent changes to lint that affect users of lint.
For information about internal improvements and API changes affecting
lint check authors, see the API Guide.
</p><p>
<strong class="asterisk">7.0</strong>
</p><p>
</p><ul>
<li class="asterisk">New built-in lint checks:</li></ul>
<p></p><p>
</p><div class="table"><table class="table"><tbody><tr><th style="text-align:left"> Issue ID </th><th style="text-align:left"> Summary </th></tr>
<tr><td style="text-align:left"> <code>AnnotateVersionCheck</code> </td><td style="text-align:left"> Annotate SDK_INT checks </td></tr>
<tr><td style="text-align:left"> <code>CoarseFineLocation</code> </td><td style="text-align:left"> Cannot use <code>ACCESS_FINE_LOCATION</code> without <code>ACCESS_COARSE_LOCATION</code> </td></tr>
<tr><td style="text-align:left"> <code>CustomSplashScreen</code> </td><td style="text-align:left"> Application-defined Launch Screen </td></tr>
<tr><td style="text-align:left"> <code>CustomX509TrustManager</code> </td><td style="text-align:left"> Implements custom TLS trust manager </td></tr>
<tr><td style="text-align:left"> <code>HighSamplingRate</code> </td><td style="text-align:left"> High sensor sampling rate </td></tr>
<tr><td style="text-align:left"> <code>IntentFilterExportedReceiver</code> </td><td style="text-align:left"> Unspecified <code>android:exported</code> in manifest </td></tr>
<tr><td style="text-align:left"> <code>LaunchActivityFromNotification</code> </td><td style="text-align:left"> Notification Launches Services or BroadcastReceivers </td></tr>
<tr><td style="text-align:left"> <code>LeanbackUsesWifi</code> </td><td style="text-align:left"> Using android.hardware.wifi on TV </td></tr>
<tr><td style="text-align:left"> <code>MediaCapabilities</code> </td><td style="text-align:left"> Media Capabilities property not specified </td></tr>
<tr><td style="text-align:left"> <code>NotificationTrampoline</code> </td><td style="text-align:left"> Notification Trampolines </td></tr>
<tr><td style="text-align:left"> <code>NotifyDataSetChanged</code> </td><td style="text-align:left"> Invalidating All RecyclerView Data </td></tr>
<tr><td style="text-align:left"> <code>TileProviderPermissions</code> </td><td style="text-align:left"> TileProvider does not set permission </td></tr>
<tr><td style="text-align:left"> <code>TrustAllX509TrustManager</code> </td><td style="text-align:left"> Insecure TLS/SSL trust manager </td></tr>
<tr><td style="text-align:left"> <code>UnspecifiedImmutableFlag</code> </td><td style="text-align:left"> Missing <code>PendingIntent</code> mutability flag </td></tr>
<tr><td style="text-align:left"> <code>WatchFaceEditor</code> </td><td style="text-align:left"> Watch face editor must use launchMode=“standard” </td></tr>
</tbody></table></div>
<p></p><p>
</p><ul>
<li class="asterisk">Lint checks now include information for reported incidents where the
lint check came from, such as which library artifact provided it.
This should make it easier to request enhancements or file bugs
around false positives or false negatives.
<p></p><p>
</p></li>
<li class="asterisk">Lint “partial analysis” mode is now integrated in lint. It is
enabled by default, but you can disable it by modifying
<code>gradle.properties</code> to include
<p></p><p>
<code>android.enableParallelLint=false</code>
</p><p>
</p></li>
<li class="asterisk">The API check now also looks up operator overloading functions.</li></ul>
<p></p><p>
<strong class="asterisk">4.2</strong>
</p><p>
</p><ul>
<li class="asterisk">Improved support for lint.xml configuration files. You can now
specify lint.xml files in project source folders, where the settings
will apply recursively within just that folder. You can also specify
options for detectors, and enable or disable checks for specific
clients (such as just in Gradle, or just in the IDE, and so on.)
<p></p><p>
</p></li>
<li class="asterisk">Support for SARIF reports; a static analysis report file format
supported by for example GitHub, allowing the results to be
visualized in a unified way on CI servers.</li></ul>
<p></p>
<a class="target" name="baselines">&nbsp;</a><a class="target" name="baselines">&nbsp;</a><a class="target" name="toc1">&nbsp;</a><h1>Baselines</h1>
<a class="target" name="creatingabaseline">&nbsp;</a><a class="target" name="creatingabaseline">&nbsp;</a><a class="target" name="toc2">&nbsp;</a><h1>Creating a Baseline</h1>
<p>
You can take a snapshot of your project's current set of warnings,
and then use the snapshot as a baseline for future inspection runs
so that only new issues are reported. The baseline snapshot lets you
start using lint to fail the build without having to go back and
address all existing issues first.
</p><p>
To create a baseline snapshot, modify your project's <code>build.gradle</code>``
file as follows.
</p><pre class="listing tilde"><code><span class="line">android {</span>
<span class="line"> lintOptions {</span>
<span class="line"> baseline file(<span class="hljs-string">"lint-baseline.xml"</span>)</span>
<span class="line"> }</span>
<span class="line">}</span></code></pre><p>
When you first add this line, the <code>lint-baseline.xml</code> file is
created to establish your baseline. From then on, the tools only
read the file to determine the baseline. If you want to create a new
baseline, manually delete the file and run lint again to recreate it.
</p><p>
Then, run lint from the IDE (<strong class="asterisk">Analyze &gt; Inspect Code</strong>) or from
the command line as follows. The output prints the location of the
lint-baseline.xml file. The file location for your setup might be
different from what is shown here.
</p><pre class="listing backtick"><code><span class="line"> $ ./gradlew lintDebug</span>
<span class="line"> ...</span>
<span class="line"> Wrote XML report to file:///app/lint-baseline.xml</span>
<span class="line"> Created baseline file /app/lint-baseline.xml</span></code></pre><p>
Running lint records all of the current issues in the
<code>lint-baseline.xml</code> file. The set of current issues is called the
baseline, and you can check the lint-baseline.xml file into version
control if you want to share it with others.
</p>
<a class="target" name="customizethebaseline">&nbsp;</a><a class="target" name="creatingabaseline/customizethebaseline">&nbsp;</a><a class="target" name="toc2.1">&nbsp;</a><h2>Customize the baseline</h2>
<p>
If you want to add some issue types to the baseline, but not all of
them, you can specify the issues to add by editing your project's
build.gradle, as follows.
</p><pre class="listing tilde"><code><span class="line">android {</span>
<span class="line"> lintOptions {</span>
<span class="line"> check <span class="hljs-string">'NewApi'</span>, <span class="hljs-string">'HandlerLeak'</span></span>
<span class="line"> baseline file(<span class="hljs-string">"lint-baseline.xml"</span>)</span>
<span class="line"> }</span>
<span class="line">}</span></code></pre><p>
After you create the baseline, if you add any new warnings to the
codebase, lint lists only the newly introduced bugs.
</p>
<a class="target" name="baselinewarning">&nbsp;</a><a class="target" name="creatingabaseline/baselinewarning">&nbsp;</a><a class="target" name="toc2.2">&nbsp;</a><h2>Baseline warning</h2>
<p>
When baselines are in effect, you get an informational warning that
tells you that one or more issues were filtered out because they
were already listed in the baseline. The reason for this warning is
to help you remember that you have configured a baseline, because
ideally, you would want to fix all of the issues at some point.
</p><p>
This informational warning does not only tell you the exact number of
errors and warnings that were filtered out, it also keeps track of
issues that are not reported anymore. This information lets you know
if you have actually fixed issues, so you can optionally re-create
the baseline to prevent the error from coming back undetected.
</p><p>
</p><div class="admonition note"><div class="admonition-title"> Baselines are enabled when you run inspections in batch</div>
<p></p><p>
mode in the IDE, but they are ignored for the in-editor checks that
run in the background when you are editing a file. The reason is that
baselines are intended for the case where a codebase has a massive
number of existing warnings, but you do want to fix issues locally
while you touch the code.</p></div>
<p></p><p>
<a href="https://developer.android.com/studio/write/lint#snapshot">Official documentation</a>
</p>
<a class="target" name="performancetuning">&nbsp;</a><a class="target" name="performancetuning">&nbsp;</a><a class="target" name="toc3">&nbsp;</a><h1>Performance Tuning</h1>
<p>
Lint tends to get slower for every release. There's a reason for that:
It keeps checking more and more things (as of 7.0 canary we're up to
around 400 separate issues), and existing issues are often made more
complex as well, doing deeper flow and data analysis, and occasionally
there are new features which also add costs, such as baselines, Kotlin
analysis, etc. And this is all compounded by the codebases lint is
getting run on also growing bigger and bigger, and being broken up into
more and more modules.
</p><p>
This chapter provides some tips on how to improve the performance of
lint on CI servers.
</p><p>
</p><div class="admonition tip">Some of these suggestions are not true in all cases, so you might
want to time before and after to verify that for your project each
change is an improvement.</div>
<p></p>
<a class="target" name="use7.0andincrementallint">&nbsp;</a><a class="target" name="performancetuning/use7.0andincrementallint">&nbsp;</a><a class="target" name="toc3.1">&nbsp;</a><h2>Use 7.0 and Incremental Lint</h2>
<p>
In 7.0, lint will finally be capable of running incrementally across
modules, meaning that if you change code in just one module, lint will
only have to rerun analysis on modules downstream from that module.
With large projects with many modules, this should be a significant
improvement.
</p><p>
To use this:
</p><p>
</p><ol start="1">
<li class="number">Update to the latest 7.0 canary 12 or later.
<p></p><p>
</p></li>
<li class="number">Update your CI configuration such that it does not clean the working
directories between each build.</li></ol>
<p></p><p>
We are working on making the state files used by this mechanism path
relative such that this facility will also work for Gradle's remote
cache; once that's done, this will work for clean builds as well.
</p>
<a class="target" name="usethelintdebugtarget,notlint">&nbsp;</a><a class="target" name="performancetuning/usethelintdebugtarget,notlint">&nbsp;</a><a class="target" name="toc3.2">&nbsp;</a><h2>Use the <code>lintDebug</code> target, not <code>lint</code></h2>
<p>
If you run “./gradlew tasks” you'll see that there's a <code>lint</code> task, and
you may be tempted to run it. But lint also adds specific tasks for
each variant. For example, if you only have “debug” and “release”
variants (e.g. you haven't defined any product flavors or additional
build types), lint will create 3 targets:
</p><p>
</p><ul>
<li class="asterisk"><code>lint</code>
</li>
<li class="asterisk"><code>lintDebug</code>
</li>
<li class="asterisk"><code>lintRelease</code></li></ul>
<p></p><p>
If you have defined additional build types or product flavors, you can
end up with many more of these — <code>lintFreeDebug</code>, <code>lintProDebug</code>,
<code>lintFreeBeta</code>, <code>lintProBeta</code>, etc.
</p><p>
<strong class="asterisk">Don't configure your CI job to run the <code>lint</code> task; pick a specific
variant instead, such as <code>lintDebug</code></strong>. The reason this is so
important, is that what the <code>lint</code> task really does is run lint over
and over again, for <em class="asterisk">each</em> variant, and then it collates the results in
the end! It combines all the errors it found, and shows which specific
variants every error applies to, unless it applies to all (which is
nearly always the case).
</p><p>
The rationale for this behavior is that you could have a
variant-specific issue; for example, you may have a resource file which
is only present in a variant-specific source set (such as
<code>src/debug/res/values</code>), so the general lint target checks everything.
Of course, you're probably only shipping your release variant, so you
could limit yourself to just running <code>lintRelease</code> and you're not going
to miss much.
</p><p>
</p><div class="admonition note">You're probably shipping your release variant, not your debug
variant, so instead of running <code>lintDebug</code> it's probably more
accurate to run <code>lintRelease</code>. However, unless you're doing anything
variant specific, it's unlikely that this matters, and running
<code>lintRelease</code> can take significantly longer since it performs more
build time optimizations.</div>
<p></p><p>
If you have lots of variants this makes a huge difference; with 7
variants, <code>lint</code> will take ~7x longer than <code>lintDebug</code> !! (modulo some
minor caching)
</p><p>
</p><div class="admonition tip">In 7.0 and Arctic Fox we're changing the behavior of the <code>lint</code>
target such that it is just an alias for <code>lintDebug</code>, so once you
update to 7.0 this is no longer a problem.</div>
<p></p>
<a class="target" name="onlyanalyzeapp/leafmodules">&nbsp;</a><a class="target" name="performancetuning/onlyanalyzeapp/leafmodules">&nbsp;</a><a class="target" name="toc3.3">&nbsp;</a><h2>Only analyze app/leaf modules</h2>
<p>
If you have divided your project into many smaller modules - a number
of libraries and just a couple of app modules, it's much better to
</p><p>
</p><ol start="1">
<li class="number">Turn on checkDependencies mode, and
<p></p><p>
</p></li>
<li class="number">Only run lint on the app modules, instead of recursively running
lint on each module.</li></ol>
<p></p><p>
To do this, first add this to your app module's build.gradle file:
</p><pre class="listing backtick"><code><span class="line"><span class="hljs-string">android</span> {</span>
<span class="line"> <span class="hljs-string">...</span></span>
<span class="line"> <span class="hljs-string">lintOptions</span> {</span>
<span class="line"> <span class="hljs-string">...</span></span>
<span class="line"> <span class="hljs-string">checkDependencies</span> <span class="hljs-literal">true</span></span>
<span class="line"> <span class="hljs-string">...</span></span>
<span class="line"> }</span>
<span class="line">}</span></code></pre><p>
Then instead of running <code>./gradlew lintDebug</code>, run <code>./gradlew
:app:lintDebug</code>.
</p><p>
Since you've turned on check-dependencies mode, running lint on the app
module will also run it on all the dependent modules the app depends on
— e.g. all the libraries. But this should also make things run a lot
faster, since it's a single lint invocation, where lint shares a lot
more computation (such as symbol resolution in the SDK and various
shared libraries, etc).
</p><p>
</p><div class="admonition note">Note that <code>checkDependencies true</code> will also cause lint to analyze
Kotlin-only or Java-only modules, which the normal <code>./gradlew
lintDebug</code> approach will not do, since that just invokes lint on
modules that apply the Android plugins. This is actually a good
thing since that code does get included in your Android app and lint
has a number of checks that are relevant for that code. But note
that this analysis isn't free, so it's technically possible that in
some cases (if you have a lot of these modules relative to the
number of Android modules) lint will not actually run faster with
<code>checkDependencies true</code>. However, for this scenario it's probably a
change you want to make anyway.</div>
<p></p><p>
This isn't just a good idea from a performance perspective; you'll also
get more accurate results. For example, the unused resource analysis
will now correctly know whether a resource defined in a library is
consumed by the app module; that doesn't happen when you run lint first
on the library, and later on just the app, which is what happens when
you run <code>./gradlew lintDebug</code>. As a bonus you'll also get a single HTML
report containing all the results from your codebase, instead of having
to hunt around the tree for all the various reports and look at each
one separately.
</p><p>
</p><div class="admonition note">This mode used to be on by default, since it has better usability.
We had to turn it off for performance reasons, because many users
were running redundant targets. But in 7.0 we've added a new
mechanism (partial analysis) which solves these performance
problems, so we will most likely turn this mode back on by default.</div>
<p></p>
<a class="target" name="don'tanalyzetestsources">&nbsp;</a><a class="target" name="performancetuning/don'tanalyzetestsources">&nbsp;</a><a class="target" name="toc3.4">&nbsp;</a><h2>Don't analyze test sources</h2>
<p>
Lint has two flags controlling what to do about test sources:
<code>checkTestSources</code> and <code>ignoreTestSources</code>. These mean different things.
</p><p>
The <code>checkTestSources</code> option controls whether lint should run all the
normal checks on the test sources. This is already off by default, so
there's really no performance reason to tweak it. The only reason you'd
turn this on is if you really want to make sure your test sources are
pristine as well. The <code>ignoreTestSources</code> option on the other hand
controls whether lint should really ignore all test sources. Even if
lint doesn't run normal checks on the test sources, it still has to
include them in analysis for some of the regular lint checks for
production code. For example, what if you have a resource which is only
referenced from a test; do you then want to flag this as unused when
the test is still referencing it?
</p><p>
Add the following to your app module's <code>build.gradle</code> file to tell lint
to completely ignore your test sources, which should help lint run
faster since (for well tested code) this can help skip a lot of code
analysis and type resolution:
</p><pre class="listing backtick"><code><span class="line"><span class="hljs-string">android</span> {</span>
<span class="line"> <span class="hljs-string">...</span></span>
<span class="line"> <span class="hljs-string">lintOptions</span> {</span>
<span class="line"> <span class="hljs-string">...</span></span>
<span class="line"> <span class="hljs-string">ignoreTestSources</span> <span class="hljs-literal">true</span></span>
<span class="line"> <span class="hljs-string">...</span></span>
<span class="line"> }</span>
<span class="line">}</span></code></pre>
<a class="target" name="don'tusecheckallwarnings">&nbsp;</a><a class="target" name="performancetuning/don'tusecheckallwarnings">&nbsp;</a><a class="target" name="toc3.5">&nbsp;</a><h2>Don't use checkAllWarnings</h2>
<p>
Lint has a <code>checkAllWarnings</code> option you can use to turn on checking of
all warnings, including those that are off by default. This flag is off
by default, but some developers turn it on (<em class="asterisk">“because I want all the
tips I can get”</em> is what I heard from one developer).
</p><p>
Be careful doing that, because some of the disabled checks are slow,
and some have a lot of false positives which is why they're off by
default but available if you really want to audit for one specific
problem. (In older versions this would also turn on the
<code>WrongThreadInterprocedural</code> check, which is particularly expensive,
though in recent versions we've specifically exempted this check from
<code>checkAllWarnings</code>.)
</p>
<a class="target" name="uselatestversion">&nbsp;</a><a class="target" name="performancetuning/uselatestversion">&nbsp;</a><a class="target" name="toc3.6">&nbsp;</a><h2>Use latest version</h2>
<p>
Try using the latest versions of lint (the Android Gradle plugin), as
well as of Gradle — even if that means using a canary version. Yes, by
all means, for your production builds use a stable version of the
Gradle plugin to build your release APK/bundle, but for your CI server,
consider running the latest preview version of lint, since generally
those versions will have the most up to date fixes. (Yes, regressions
happen and canaries go through less testing, but in general lint has
really good coverage so regressions do not happen very often.)
</p>
<a class="target" name="givelintalotofram">&nbsp;</a><a class="target" name="performancetuning/givelintalotofram">&nbsp;</a><a class="target" name="toc3.7">&nbsp;</a><h2>Give lint a lot of RAM</h2>
<p>
This one is kind of obvious, but lint (especially the code analysis
part) is really memory hungry; it does a lot of the same work as a
compiler, except that it also hangs on to a lot more data (e.g. the
full ASTs with whitespace and comments etc). Explore bumping up the
memory given to the Gradle daemon significantly to see if it helps
bring down the overall analysis time.
</p><p>
This is <em class="asterisk">especially</em> important if you happen to run many lint jobs in
parallel! If you follow the advice above (where you're running a single
lint job with recursive dependencies on the app module) this is less
likely to happen, but I've seen various thread dumps from users asking
about performance where there was 16-20 concurrent separate lint jobs
running in the Gradle daemon, and each one requires a lot of memory;
these separate lint job threads are not sharing data.
</p><p>
One user reported this result:
</p><blockquote>
I have a very large project (with over 2000 classes) and giving lint
more memory had a huge effect:
<p></p><p>
<code>./gradlew -Dorg.gradle.jvmargs=-Xmx2g app:lintDebug</code> takes 25m 18s
</p><p>
<code>./gradlew -Dorg.gradle.jvmargs=-Xmx8g app:lintDebug</code> takes 8m 57s!</p></blockquote>
<p></p>
<a class="target" name="findingslowlintchecks">&nbsp;</a><a class="target" name="performancetuning/findingslowlintchecks">&nbsp;</a><a class="target" name="toc3.8">&nbsp;</a><h2>Finding Slow Lint Checks</h2>
<p>
We have a tool we use to try to attribute the time spent during
analysis to individual lint checks. When analysis is taking longer
than expected, we run this tool to see if any of the lint checks
are misbehaving. Here's some sample output:
</p><pre class="listing backtick"><code><span class="line"><span class="hljs-string">$</span> <span class="hljs-string">./gradlew</span> <span class="hljs-string">lintDebug</span> <span class="hljs-string">-no-daemon</span> <span class="hljs-string">-Dorg.gradle.jvmargs="..."</span></span>
<span class="line"></span>
<span class="line"><span class="hljs-string">BUILD</span> <span class="hljs-string">SUCCESSFUL</span> <span class="hljs-string">in</span> <span class="hljs-string">10s</span></span>
<span class="line"><span class="hljs-attr">15 actionable tasks:</span> <span class="hljs-number">1</span> <span class="hljs-string">executed,</span> <span class="hljs-number">14</span> <span class="hljs-string">up-to-date</span></span>
<span class="line"></span>
<span class="line"><span class="hljs-attr">Lint detector performance stats:</span></span>
<span class="line"> <span class="hljs-string">total</span> <span class="hljs-string">self</span> <span class="hljs-string">calls</span></span>
<span class="line"> <span class="hljs-string">LintDriver</span> <span class="hljs-number">3709 </span><span class="hljs-string">ms</span> <span class="hljs-number">1302 </span><span class="hljs-string">ms</span> <span class="hljs-number">2821</span></span>
<span class="line"><span class="hljs-string">TopDownAnalyzerFacadeForJVM</span> <span class="hljs-number">2121 </span><span class="hljs-string">ms</span> <span class="hljs-number">2121 </span><span class="hljs-string">ms</span> <span class="hljs-number">6</span></span>
<span class="line"> <span class="hljs-string">IconDetector</span> <span class="hljs-number">81</span> <span class="hljs-string">ms</span> <span class="hljs-number">81</span> <span class="hljs-string">ms</span> <span class="hljs-number">257</span></span>
<span class="line"> <span class="hljs-string">OverdrawDetector</span> <span class="hljs-number">51</span> <span class="hljs-string">ms</span> <span class="hljs-number">51</span> <span class="hljs-string">ms</span> <span class="hljs-number">36</span></span>
<span class="line"> <span class="hljs-string">InvalidPackageDetector</span> <span class="hljs-number">34</span> <span class="hljs-string">ms</span> <span class="hljs-number">34</span> <span class="hljs-string">ms</span> <span class="hljs-number">51744</span></span>
<span class="line"> <span class="hljs-string">GradleDetector</span> <span class="hljs-number">20</span> <span class="hljs-string">ms</span> <span class="hljs-number">20</span> <span class="hljs-string">ms</span> <span class="hljs-number">94</span></span>
<span class="line"> <span class="hljs-string">LocaleFolderDetector</span> <span class="hljs-number">11</span> <span class="hljs-string">ms</span> <span class="hljs-number">11</span> <span class="hljs-string">ms</span> <span class="hljs-number">986</span></span>
<span class="line"> <span class="hljs-string">RestrictToDetector</span> <span class="hljs-number">11</span> <span class="hljs-string">ms</span> <span class="hljs-number">11</span> <span class="hljs-string">ms</span> <span class="hljs-number">19</span></span>
<span class="line"> <span class="hljs-string">ApiDetector</span> <span class="hljs-number">11</span> <span class="hljs-string">ms</span> <span class="hljs-number">11</span> <span class="hljs-string">ms</span> <span class="hljs-number">1255</span></span>
<span class="line"> <span class="hljs-string">PrivateResourceDetector</span> <span class="hljs-number">10</span> <span class="hljs-string">ms</span> <span class="hljs-number">10</span> <span class="hljs-string">ms</span> <span class="hljs-number">422</span></span>
<span class="line"> [<span class="hljs-string">...</span>]</span></code></pre><p>
Here you can see that <code>InvalidPackageDetector</code> is taking up an
unreasonable amount of time. And this is actually real output from an
earlier version of lint where we tracked down a real problem in that
detector.
</p><p>
You can read more about this tool in <a href="https://groups.google.com/g/lint-dev/c/mwpTCaQPXYU/m/YKc4EcMYAgAJ">this
post</a>.
</p><p>
If you see a suspicious check, you can try to disable its issues
(unless you find their value is worth the cost; after all, real world
bugs are typically more expensive than server compute cycles.) But
don't forget to also report the bug to the lint check author!
</p><p>
</p><div class="admonition warning">One thing to be aware of is that the “blame” is not entirely fair.
There are a number of expensive operations in lint, and especially
symbol resolution, which is cached. That means that the first
unlucky detector that comes along has to perform the computation,
and subsequent detectors just get to reuse the result. Because of
this, it's not always the case that a particular detector is a
performance culprit, and as soon as you disable it, a new detector
moves to the top of the list paying the same initialization costs.
The main use for this tool is to find extreme or unusual performance
behaviors.</div>
<p></p>
<a class="target" name="suppressinglintchecks">&nbsp;</a><a class="target" name="suppressinglintchecks">&nbsp;</a><a class="target" name="toc4">&nbsp;</a><h1>Suppressing Lint Checks</h1>
<p>
Lint errors can be suppressed in a variety of ways:
</p><p>
</p><ol start="1">
<li class="number">With a <code>@SuppressLint</code> annotation in the Java code
</li>
<li class="number">With a <code>tools:ignore</code> attribute in the XML file
</li>
<li class="number">With a //noinspection comment in the source code
</li>
<li class="number">With ignore flags specified in the <code>build.gradle</code> file,
as explained below
</li>
<li class="number">With a <code>lint.xml</code> configuration file in the project
</li>
<li class="number">With a <code>lint.xml</code> configuration file passed to lint
via the —config flag
</li>
<li class="number">With the —ignoreflag passed to lint
</li>
<li class="number">With a <a href="#baselines">baseline</a></li></ol>
<p></p><p>
To suppress a lint warning with an annotation, add
a <code>@SuppressLint("id")</code> annotation on the class, method
or variable declaration closest to the warning instance
you want to disable. The id can be one or more issue
id's, such as <code>"UnusedResources"</code> or <code>{"UnusedResources",
"UnusedIds"}</code>, or it can be <code>"all"</code> to suppress all lint
warnings in the given scope.
</p><p>
You can also use <code>@Suppress</code> in Kotlin or <code>@SuppressWarnings</code>
in Java.
</p><p>
To suppress a lint warning with a comment, add
a <code>//noinspection id</code> comment on the line before the statement
with the error.
</p><p>
To suppress a lint warning in an XML file, add a
<code>tools:ignore="id"</code> attribute on the element containing
the error, or one of its surrounding elements. You also
need to define the namespace for the tools prefix on the
root element in your document, next to the <code>xmlns:android</code>
declaration:
<code>xmlns:tools="http://schemas.android.com/tools"</code>
</p><p>
To suppress a lint warning in a <code>build.gradle</code> file, add a
section like this:
</p><pre class="listing backtick"><code><span class="line">android {</span>
<span class="line"> lintOptions {</span>
<span class="line"> disable 'TypographyFractions','TypographyQuotes'</span>
<span class="line"> }</span>
<span class="line">}</span></code></pre><p>
Here we specify a comma separated list of issue id's after the
disable command. You can also use <code>warning</code> or <code>error</code> instead
of <code>disable</code> to change the severity of issues.
</p><p>
To suppress lint warnings with a configuration XML file,
create a file named <code>lint.xml</code>. See the
<a href="#configuringusinglintxmlfiles">lint.xml configuration</a> document
for more details.
</p><p>
To suppress lint checks from the command line, pass the
<code>--ignore</code> flag with a comma separated list of ids to be suppressed, such as:
</p><pre class="listing backtick"><code><span class="line"><span class="hljs-meta">$</span><span class="bash"> lint --ignore UnusedResources,UselessLeaf /my/project/path</span></span></code></pre><p>
For more information, see
<a href="https://developer.android.com/studio/write/lint.html#config" class="url">https://developer.android.com/studio/write/lint.html#config</a>
</p>
<a class="target" name="configuringusinglint.xmlfiles">&nbsp;</a><a class="target" name="configuringusinglint.xmlfiles">&nbsp;</a><a class="target" name="toc5">&nbsp;</a><h1>Configuring Using lint.xml Files</h1>
<p>
In addition to configuring lint with command line flags or Gradle DSL
options, you can also create XML files named <code>lint.xml</code>, which lint
will look for automatically.
</p><p>
Like <code>.gitignore</code> files, these can be nested, so you can for example
create a <code>lint.xml</code> file which sets the severity of an issue to error,
but then in a specific subfolder change the severity to be just a
warning.
</p><p>
This chapter describes the syntax of <code>lint.xml</code> files.
</p>
<a class="target" name="xmlsyntax">&nbsp;</a><a class="target" name="configuringusinglint.xmlfiles/xmlsyntax">&nbsp;</a><a class="target" name="toc5.1">&nbsp;</a><h2>XML Syntax</h2>
<p>
The root tag is always <code>&lt;lint&gt;</code>, and it can contain one or more
<code>&lt;issue&gt;</code> elements. Each <issue> can specify the following
attributes: <code>id</code>: The issue id the following configuration applies
to. Note that this can be a comma separated list of multiple id's, in
which case the configuration applies to all of them. It can also be
the special value “all”, which will match all issue id's. And when
configuring severity, the id is also allowed to be a category, such
as “Security”.
</issue></p><p>
<code>in</code>: Specifies that this configuration only applies when lint
runs in the given hosts. There are predefined names for various
integrations of lint; “gradle” refers to lint running in the Gradle
plugin; “studio” refers to lint running in the IDE, “cli” refers to
lint running from the command line tools “lint” binary, etc. Like
with id's, this can be a comma separated list, which makes the rule
match if the lint host is any of the listed hosts. Finally, note that
you can also add a “!” in front of each host to negate the check. For
example, to enable a check anywhere except when running in Studio,
use <code>in="!studio"</code>.
</p><p>
In addition, the <issue> element can specify one or more children:
</issue></p><p>
<code>&lt;ignore path="..."&gt;</code>: Specifies a path to ignore. Can contain the
globbing character “*” to match any substring in the path. <code>&lt;ignore regexp="..."&gt;</code>: Specifies either a regular expression to ignore. The
regular expression is matched against both the location of the error
and the error message itself. <code>&lt;option name="..." value="..."&gt;</code>:
Specifies an option value. This can be used to configure some lint
checks with options.
</p><p>
Finally, on the root <lint> element you can specify a number of
attributes, such as <code>lintJars</code> (a list of jar files containing custom
lint checks, separated by a semicolon as a path separator), and
flags like warningsAsErrors, checkTestSources, etc (matching most
of the flags offered via the lintOptions block in Gradle files.)
</lint></p>
<a class="target" name="nesting&amp;precedence">&nbsp;</a><a class="target" name="configuringusinglint.xmlfiles/nesting&amp;precedence">&nbsp;</a><a class="target" name="toc5.2">&nbsp;</a><h2>Nesting &amp; Precedence</h2>
<p>
You can specify configurations for “all”, but these will be
matched after an exact match has been done. E.g. if we have
both <code>&lt;issue id="all" severity="ignore"&gt;</code> and <code>&lt;issue id="MyId" severity="error"&gt;</code>, the severity for <code>MyId</code> will be “error”“ since
that's a more exact match.
</p><p>
The lint.xml files can be nested in a directory structure, and when
lint reports an error, it looks up the closest lint.xml file, and
if no configuration is found there, continues searching upwards in
the directory tree. This means that the configuration closest to the
report location takes precedence. Note however, that this has higher
priority than the above all versus id match, so if there is an <code>all</code>
match in a <code>lint.xml</code> file and an exact match in a more distant
parent <code>lint.xml</code> file, the closest <code>lint.xml</code> all match will be
used.
</p><p>
When there are configurations which specify a host, lint will search
in this order:
</p><p>
</p><ol start="1">
<li class="number">An exact host match. E.g. if you're running in Studio and there is
an <code>&lt;issue&gt;</code> configuration which specifies
<code>in="studio"</code>, then that configuration will be used.
</li>
<li class="number">A match which does not specify a host. Usually <code>&lt;issue&gt;</code>
configurations do not specify a host,
and these will be consulted next.
</li>
<li class="number">A match which specifies other hosts. For example, if you're
running in Studio and a configuration specifies
”!gradle“, this will match after the other attempts.</li></ol>
<p></p>
<a class="target" name="samplelint.xmlfile">&nbsp;</a><a class="target" name="configuringusinglint.xmlfiles/samplelint.xmlfile">&nbsp;</a><a class="target" name="toc5.3">&nbsp;</a><h2>Sample lint.xml file</h2>
<p>
Typically lint.xml files are pretty short and simple, but here's
one which uses most of the available features. (Note: the
HTML version of this isn't properly handling empty elements,
so if you're going to copy/paste go to the source file.)
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-comment">&lt;!--?xml version="1.0" encoding="UTF-8"?--&gt;</span></span>
<span class="line"><span class="hljs-tag">&lt;<span class="hljs-name">lint</span> <span class="hljs-attr">lintjars</span>=<span class="hljs-string">"../checks/local.jar;../checks/custom.jar"</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- The special id "all" matches all issues but is only consulted</span>
<span class="line"> if there is no specific match --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"all"</span> <span class="hljs-attr">severity</span>=<span class="hljs-string">"ignore"</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- Possible severities: ignore, information, warning, error, fatal --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"ValidActionsXml"</span> <span class="hljs-attr">severity</span>=<span class="hljs-string">"error"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"ObsoleteLayoutParam"</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- The &lt;ignore&gt; tag has two possible attributes: path and regexp (see below) --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">ignore</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"res/layout-xlarge/activation.xml"</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- You can use globbing patterns in the path strings --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">ignore</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"**/layout-x*/onclick.xml"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">ignore</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"res/**/activation.xml"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;/<span class="hljs-name">ignore</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ignore</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ignore</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"NewApi"</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- You can also ignore via a regular expression, this is not only</span>
<span class="line"> matched against the path but also the error message --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">ignore</span> <span class="hljs-attr">regexp</span>=<span class="hljs-string">"st.*gs"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;/<span class="hljs-name">ignore</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- The "in" attribute lets you specify that the element only</span>
<span class="line"> applies in a particular tools, such as gradle, studio, etc; this</span>
<span class="line"> can be a comma separated list --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">in</span>=<span class="hljs-string">"studio"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"NewerVersionAvailable"</span> <span class="hljs-attr">severity</span>=<span class="hljs-string">"error"</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- You can also use ! to specify that it does not apply in a tool --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">in</span>=<span class="hljs-string">"!gradle"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"TrulyRandom"</span> <span class="hljs-attr">severity</span>=<span class="hljs-string">"error"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"UnknownNullness"</span>&gt;</span></span>
<span class="line"> <span class="hljs-comment">&lt;!-- For detectors that support it, you can also specify option values --&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ignore-deprecated"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"true"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">issue</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"TooManyViews"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"maxCount"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"20"</span>&gt;</span></span>
<span class="line"> <span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span></span>
<span class="line"><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">issue</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">lint</span>&gt;</span></span></code></pre><p>
</p>
<a class="target" name="appendix:recentchanges">&nbsp;</a><a class="target" name="appendix:recentchanges">&nbsp;</a><a class="target" name="toc6">&nbsp;</a><h1>Appendix: Recent Changes</h1>
<p>
<strong class="asterisk">Recent Changes</strong>
</p><p>
This chapter lists recent changes to lint that affect users of lint.
For information about internal improvements and API changes affecting
lint check authors, see the API Guide.
</p><p>
<strong class="asterisk">7.0</strong>
</p><p>
</p><ul>
<li class="asterisk">New built-in lint checks:</li></ul>
<p></p><p>
</p><div class="table"><table class="table"><tbody><tr><th style="text-align:left"> Issue ID </th><th style="text-align:left"> Summary </th></tr>
<tr><td style="text-align:left"> <code>AnnotateVersionCheck</code> </td><td style="text-align:left"> Annotate SDK_INT checks </td></tr>
<tr><td style="text-align:left"> <code>CoarseFineLocation</code> </td><td style="text-align:left"> Cannot use <code>ACCESS_FINE_LOCATION</code> without <code>ACCESS_COARSE_LOCATION</code> </td></tr>
<tr><td style="text-align:left"> <code>CustomSplashScreen</code> </td><td style="text-align:left"> Application-defined Launch Screen </td></tr>
<tr><td style="text-align:left"> <code>CustomX509TrustManager</code> </td><td style="text-align:left"> Implements custom TLS trust manager </td></tr>
<tr><td style="text-align:left"> <code>HighSamplingRate</code> </td><td style="text-align:left"> High sensor sampling rate </td></tr>
<tr><td style="text-align:left"> <code>IntentFilterExportedReceiver</code> </td><td style="text-align:left"> Unspecified <code>android:exported</code> in manifest </td></tr>
<tr><td style="text-align:left"> <code>LaunchActivityFromNotification</code> </td><td style="text-align:left"> Notification Launches Services or BroadcastReceivers </td></tr>
<tr><td style="text-align:left"> <code>LeanbackUsesWifi</code> </td><td style="text-align:left"> Using android.hardware.wifi on TV </td></tr>
<tr><td style="text-align:left"> <code>MediaCapabilities</code> </td><td style="text-align:left"> Media Capabilities property not specified </td></tr>
<tr><td style="text-align:left"> <code>NotificationTrampoline</code> </td><td style="text-align:left"> Notification Trampolines </td></tr>
<tr><td style="text-align:left"> <code>NotifyDataSetChanged</code> </td><td style="text-align:left"> Invalidating All RecyclerView Data </td></tr>
<tr><td style="text-align:left"> <code>TileProviderPermissions</code> </td><td style="text-align:left"> TileProvider does not set permission </td></tr>
<tr><td style="text-align:left"> <code>TrustAllX509TrustManager</code> </td><td style="text-align:left"> Insecure TLS/SSL trust manager </td></tr>
<tr><td style="text-align:left"> <code>UnspecifiedImmutableFlag</code> </td><td style="text-align:left"> Missing <code>PendingIntent</code> mutability flag </td></tr>
<tr><td style="text-align:left"> <code>WatchFaceEditor</code> </td><td style="text-align:left"> Watch face editor must use launchMode=“standard” </td></tr>
</tbody></table></div>
<p></p><p>
</p><ul>
<li class="asterisk">Lint checks now include information for reported incidents where the
lint check came from, such as which library artifact provided it.
This should make it easier to request enhancements or file bugs
around false positives or false negatives.
<p></p><p>
</p></li>
<li class="asterisk">Lint “partial analysis” mode is now integrated in lint. It is
enabled by default, but you can disable it by modifying
<code>gradle.properties</code> to include
<p></p><p>
<code>android.enableParallelLint=false</code>
</p><p>
</p></li>
<li class="asterisk">The API check now also looks up operator overloading functions.</li></ul>
<p></p><p>
<strong class="asterisk">4.2</strong>
</p><p>
</p><ul>
<li class="asterisk">Improved support for lint.xml configuration files. You can now
specify lint.xml files in project source folders, where the settings
will apply recursively within just that folder. You can also specify
options for detectors, and enable or disable checks for specific
clients (such as just in Gradle, or just in the IDE, and so on.)
<p></p><p>
</p></li>
<li class="asterisk">Support for SARIF reports; a static analysis report file format
supported by for example GitHub, allowing the results to be
visualized in a unified way on CI servers.</li></ul>
<p></p>
<a class="target" name="appendix:environmentvariablesandsystemproperties">&nbsp;</a><a class="target" name="appendix:environmentvariablesandsystemproperties">&nbsp;</a><a class="target" name="toc7">&nbsp;</a><h1>Appendix: Environment Variables and System Properties</h1>
<p>
This chapter lists the various environment variables and system
properties that Lint will look at. None of these are really intended to
be used or guaranteed to be supported in the future, but documenting
what they are seems useful.
</p>
<a class="target" name="environmentvariables">&nbsp;</a><a class="target" name="appendix:environmentvariablesandsystemproperties/environmentvariables">&nbsp;</a><a class="target" name="toc7.1">&nbsp;</a><h2>Environment Variables</h2>
<a class="target" name="detectorconfigurationvariables">&nbsp;</a><a class="target" name="appendix:environmentvariablesandsystemproperties/environmentvariables/detectorconfigurationvariables">&nbsp;</a><a class="target" name="toc7.1.1">&nbsp;</a><h3>Detector Configuration Variables</h3>
<p>
</p><dl><dt><code>ANDROID_LINT_INCLUDE_LDPI</code></dt><dd><p> Lint's icon checks normally ignore the <code>ldpi</code> density since it's not
commonly used any more, but you can turn this back on with this
environment variable set to <code>true</code>.
</p></dd><dt><code>ANDROID_LINT_MAX_VIEW_COUNT</code></dt><dd><p> Lint's <code>TooManyViews</code> check makes sure that a single layout does not
have more than 80 views. You can set this environment variable to a
different number to change the limit.
</p></dd><dt><code>ANDROID_LINT_MAX_DEPTH</code></dt><dd><p> Lint's <code>TooManyViews</code> check makes sure that a single layout does not
have a deeper layout hierarchy than 10 levels.You can set this
environment variable to a different number to change the limit.
</p></dd><dt><code>ANDROID_LINT_NULLNESS_IGNORE_DEPRECATED</code></dt><dd><p> Lint's <code>UnknownNullness</code> which flags any API element which is not
explicitly annotated with nullness annotations, normally skips
deprecated elements. Set this environment variable to true to include
these as well.
</p><p>
Corresponding system property: <code>lint.nullness.ignore-deprecated</code>
</p></dd></dl><p></p>
<a class="target" name="lintconfigurationvariables">&nbsp;</a><a class="target" name="appendix:environmentvariablesandsystemproperties/environmentvariables/lintconfigurationvariables">&nbsp;</a><a class="target" name="toc7.1.2">&nbsp;</a><h3>Lint Configuration Variables</h3>
<p>
</p><dl><dt><code>ANDROID_SDK_ROOT</code></dt><dd><p> Locates the Android SDK root
</p></dd><dt><code>ANDROID_HOME</code></dt><dd><p> Locates the Android SDK root, if <code>$ANDROID_SDK_ROOT</code> has not been set
</p></dd><dt><code>JAVA_HOME</code></dt><dd><p> Locates the JDK when lint is analyzing JDK (not Android) projects
</p></dd><dt><code>LINT_XML_ROOT</code></dt><dd><p> Normally the search for <code>lint.xml</code> files proceeds upwards in the
directory hierarchy. In the Gradle integration, the search will stop
at the root Gradle project, but in other build systems, it can
continue up to the root directory. This environment variable sets a
path where the search should stop.
</p></dd><dt><code>ANDROID_LINT_JARS</code></dt><dd><p> A path of jar files (using the path separator — semicolon on
Windows, colon elsewhere) for lint to load extra lint checks from
</p></dd><dt><code>ANDROID_SDK_CACHE_DIR</code></dt><dd><p> Sets the directory where lint should read and write its cache files.
Lint has a number of databases that it caches between invocations,
such as its binary representation of the SDK API database, used to
look up API levels quickly. In the Gradle integration of lint, this
cache directory is set to the root <code>build/</code> directory, but elsewhere
the cache directory is located in a <code>lint</code> subfolder of the normal
Android tooling cache directory, such as <code>~/.android</code>.
</p></dd><dt><code>LINT_OVERRIDE_CONFIGURATION</code></dt><dd><p> Path to a lint XML file which should override any local <code>lint.xml</code>
files closer to reported issues. This provides a way to globally
change configuration.
</p><p>
Corresponding system property: <code>lint.configuration.override</code>
</p></dd><dt><code>LINT_DO_NOT_REUSE_UAST_ENV</code></dt><dd><p> Set to <code>true</code> to enable a workaround (if affected) for
<a href="https://issuetracker.google.com/159733104">bug 159733104</a>
until 7.0 is released.
</p><p>
Corresponding system property: <code>lint.do.not.reuse.uast.env</code>
</p></dd><dt><code>LINT_API_DATABASE</code></dt><dd><p> Point lint to an alternative API database XML file instead of the
normally used <code>$SDK/platforms/android-?/data/api-versions.xml</code> file.
</p></dd></dl><p></p>
<a class="target" name="lintdevelopmentvariables">&nbsp;</a><a class="target" name="appendix:environmentvariablesandsystemproperties/environmentvariables/lintdevelopmentvariables">&nbsp;</a><a class="target" name="toc7.1.3">&nbsp;</a><h3>Lint Development Variables</h3>
<p>
</p><dl><dt><code>LINT_PRINT_STACKTRACE</code></dt><dd><p> If set to true, lint will print the full stack traces of any internal
exceptions encountered during analysis. This is useful for authors of
lint checks, or for power users who can reproduce a bug and want to
report it with more details.
</p><p>
Corresponding system property: <code>lint.print-stacktrace</code>
</p></dd><dt><code>LINT_TEST_KOTLINC</code></dt><dd><p> When writing a lint check unit test, when creating a <code>compiled</code> or
<code>bytecode</code> test file, lint can generate the .class file binary
content automatically if it is pointed to the <code>kotlinc</code> compiler.
</p></dd><dt><code>LINT_TEST_JAVAC</code></dt><dd><p> When writing a lint check unit test, when creating a <code>compiled</code> or
<code>bytecode</code> test file, lint can generate the .class file binary
content automatically if it is pointed to the <code>javac</code> compiler.
</p></dd><dt><code>INCLUDE_EXPENSIVE_LINT_TESTS</code></dt><dd><p> When working on lint itself, set this environment variable to <code>true</code>
some really, really expensive tests that we don't want run on the CI
server or by the rest of the development team.
</p></dd></dl><p></p>
<a class="target" name="systemproperties">&nbsp;</a><a class="target" name="appendix:environmentvariablesandsystemproperties/systemproperties">&nbsp;</a><a class="target" name="toc7.2">&nbsp;</a><h2>System Properties</h2>
<p>
</p><div class="admonition tip">To set system properties when running lint via Gradle, try for
example <code>./gradlew lintDebug -Dlint.baselines.continue=true</code></div>
<p></p><p>
</p><dl><dt><code>lint.baselines.continue</code></dt><dd><p> When you configure a new baseline, lint normally fails the build
after creating the baseline. You can set this system property to true
to force lint to continue.
</p></dd><dt><code>lint.autofix</code></dt><dd><p> Turns on auto-fixing (applying safe quickfixes) by default. This is a
shortcut for invoking the <code>lintFix</code> targets or running the <code>lint</code>
command with <code>--apply-suggestions</code>.
</p></dd><dt><code>lint.html.prefs</code></dt><dd><p> This property allows you to customize lint's HTML reports. It
consists of a comma separated list of property assignments, e.g.
<code>./gradlew :app:lintDebug -Dlint.html.prefs=theme=darcula,window=5</code>
</p></dd></dl><div class="table"><table class="table"><tbody><tr><th style="text-align:left"> Property </th><th style="text-align:left"> Explanation and Values </th><th style="text-align:left"> Default </th></tr>
<tr><td style="text-align:left"> <code>theme</code> </td><td style="text-align:left"> <code>light</code>, <code>darcula</code>, <code>solarized</code> </td><td style="text-align:left"> <code>light</code> </td></tr>
<tr><td style="text-align:left"> <code>window</code> </td><td style="text-align:left"> Number of lines around problem </td><td style="text-align:left"> 3 </td></tr>
<tr><td style="text-align:left"> <code>maxIncidents</code> </td><td style="text-align:left"> Maximum incidents shown per issue type </td><td style="text-align:left"> 50 </td></tr>
<tr><td style="text-align:left"> <code>splitLimit</code> </td><td style="text-align:left"> Issue count before “More...” button </td><td style="text-align:left"> 8 </td></tr>
<tr><td style="text-align:left"> <code>maxPerIssue</code> </td><td style="text-align:left"> Name of split limit prior to 7.0 </td><td style="text-align:left"> 8 </td></tr>
<tr><td style="text-align:left"> <code>underlineErrors</code> </td><td style="text-align:left"> If true, wavy underlines, else highlight </td><td style="text-align:left"> <code>true</code> </td></tr>
</tbody></table></div>
<p></p><p>
</p><dl><table><tbody><tr valign="top"><td><dt><code>lint.unused-resources.exclude-tests</code></dt></td><td><dd><p> Whether the unused resource check should exclude test sources as
referenced resources.
</p></dd></td></tr><tr valign="top"><td><dt><code>lint.configuration.override</code></dt></td><td><dd><p> Alias for <code>$LINT_OVERRIDE_CONFIGURATION</code>
</p></dd></td></tr><tr valign="top"><td><dt><code>lint.print-stacktrace</code></dt></td><td><dd><p> Alias for <code>$LINT_PRINT_STACKTRACE</code>
</p></dd></td></tr><tr valign="top"><td><dt><code>lint.do.not.reuse.uast.env</code></dt></td><td><dd><p> Alias for <code>$LINT_DO_NOT_REUSE_UAST_ENV</code>
</p></dd></td></tr><tr valign="top"><td><dt><code>android.lint.log-jar-problems</code></dt></td><td><dd><p> Controls whether lint will complain about custom check lint jar
loading problems. By default, true.
</p></dd></td></tr></tbody></table></dl><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility=&ldquo;visible&rdquo;)</script>
<p></p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.13&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);"></div></div></body></html>