**Testing Development Builds** This document describes how to run your development version of lint against some large projects to look for false positives, false negatives and other issues after making nontrivial changes. ## Conventions In the following, `$SRC` refers to your checkout of the lint development branch, normally `studio-main`, and the lint source code is found in `$SRC/tools/base/lint/`. ## Testing against AndroidX To run a development version of lint against the AndroidX tree, first check out AndroidX into `$ANDROIDX`. For checkout instructions, see [their README](https://android.googlesource.com/platform/frameworks/support/+/a ndroidx-main/README.md). Then, build lint into AGP: ```ksh cd $SRC/tools ./gradlew pL ``` (`pL` is short for publishLocal; Gradle allows abbreviations. After making changes to lint only, you can run just `./gradlew pAGL` which is quite a bit faster because it skips some targets that have to be built once but aren't affected by lint-only changes.) We'll need to know the version number of AGP that was built; as of this writing it's 7.1.0-dev, but that will change multiple times a year so you can consult the actual version with something like this: ```ksh $ grep buildVersion $SRC/tools/buildSrc/base/version.properties buildVersion = 7.1.0-dev ``` We'll need to supply a number of override properties, so it's helpful to place this into a shell function: ```ksh runGradleForAndroidX() { CUSTOM_REPO=$ADT_SOURCE_TREE/out/repo \ GRADLE_PLUGIN_VERSION=8.0.0-dev \ LINT_VERSION=31.0.0-dev \ GRADLE_PLUGIN_REPO=$ADT_SOURCE_TREE/out/repo:$ADT_SOURCE_TREE/prebuilts/tools/common/m2/repository \ $ADT_SOURCE_TREE/tools/gradlew --parallel ${@} } alias gwx=runGradleForAndroidX ``` Now you can go to `$ANDROIDX` and run all the lint targets (one for each library): ```ksh gwx lint ``` If you want to debug a particular scenario, replace the `--parallel` flag with `--no-daemon -Dorg.gradle.debug=true`, run the build, and create a Remote configuration in IntelliJ and use it to attach. You can also run `gwx updateLintBaseline` to have lint successfully run all targets and update the baselines and then inspect the diffs if you've added/updated lint checks and don't want it to stop after the first new (and correct) failure. ## Testing against Android Platform Lint is run as part of the Android platform builds, including a number of custom lint checks specific to the platform. The following will refer to the directory containing the Android platform source code as `$ANDROID_SRC`. First, checkout the AOSP platform into `$ANDROID_SRC`: ```ksh mkdir $ANDROID_SRC && cd $ANDROID_SRC repo init -u https://android.googlesource.com/platform/manifest -b master ``` Then create a new branch for testing: ```ksh repo start testing123 . ``` Next, build a development version of lint packaged into a commandline tools component: ```ksh cd $SRC/tools/base export DIST_DIR=/tmp/dist && mkdir -p $DIST_DIR ../buildSrc/servers/build_tools.sh ``` After this step, we'll have `/tmp/dist/commandlinetools_linux.zip` which we now need to insert into the Android platform, with some tweaks: ```ksh cd $ANDROID_SRC/prebuilts/cmdline-tools/ git rm -rf tools unzip $DIST_DIR/commandlinetools_linux.zip mv cmdline-tools tools git add tools ``` There is one deliberate change to the tools for platform usage that we need to preserve, so back out any changes to `tools/bin/lint`: ```ksh cd tools/bin && git reset lint && git restore lint ``` That's it. If you don't have a full Android build environment up and running (or enough diskspace!) you can upload this to gerrit and have the presubmit machinery do a test run: git commit, repo upload, and then mark the CL Presubmit-Ready. Here's an example of a trial balloon CL: [](https://android-review.googlesource.com/c/platform/prebuilts/cmdline-tools/+/1769725) And here's a sample CL of a real lint upgrade which shows some of the other CLs in the topic that were necessary -- updating baselines etc: [](https://android-review.googlesource.com/c/platform/prebuilts/cmdline-tools/+/1746780) If you **do** have an Android build environment, which is helpful if you actually need to debug to figure out why something is going on, run the following target to check lint: ```ksh m lint-check ``` As usual you'll want to run `. build/envsetup.sh` and `lunch sdk-eng` first. If there's a failure, you can look at `out/error.log` where you'll find something like this: ``` ... The failing command was run inside an sbox sandbox in temporary directory out/soong/.temp/sbox/aaa65d9ed8eca15675a35eeb74818d9864690068 The failing command line was: rm -rf ./out/srcjars && mkdir -p ./out/srcjars && ./tools/out/bin/zipsync -d ./out/srcjars -l ./out/srcjars/list -f "*.java" ./out/.intermediates/packages/modules/Permission/PermissionController/PermissionController/android_common_GooglePermissionController_apex30/gen/proto/proto0.srcjar ./out/.intermediates/packages/modules/Permission/PermissionController/PermissionController/android_common_GooglePermissionController_apex30/gen/android/R.srcjar ./out/.intermediates/packages/modules/Permission/PermissionController/PermissionController/android_common_GooglePermissionController_apex30/kapt/kapt-sources.jar ...truncated... ``` Note that the real lint command is prefixed by a few other commands on the same line so search forwards through `&&` until you get to the line which starts with `JAVA_OPTS=` (and lop off the rest after the next `&&` or '||'). Here's a typical invocation that we're left with: ``` JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED" ANDROID_SDK_HOME=out/soong/.intermediates/packages/modules/Permission/Pe rmissionController/PermissionController/android_common/lint/home SDK_ANNOTATIONS=./out/lint/annotations.zip LINT_OPTS=-DLINT_API_DATABASE=./out/lint/api_versions.xml ./tools/out/bin/lint --quiet --project ./out/project.xml --config ./out/lint.xml --html ./out/lint-report.html --text ./out/lint-report.txt --xml ./out/lint-report.xml --compile-sdk-version T --java-language-level 1.9 --kotlin-language-level 1.3 --url .=.,out/soong=out --exitcode ``` This means that you can `cd` to the sandbox directory and rerun the given command to repeat just the failing lint invocation, adding some debugging flags and attaching with a debugger as necessary. You can also convert this to a runconfig in IntelliJ for running the lint Main class with the right pwd, environment variables and arguments inside the IDE. ### New Check Fails The platform obviously isn't a real Android app, and some of the checks which apply for apps (such as flagging an import of `android.R` as suspicious) do not apply in platform code. If you've added a new lint check and it's finding false positives in the platform, you may consider just adding it to the exclude list in `build/soong/java/lint_defaults.txt`. ## Other Projects For other projects built with Gradle, you can add a property in your root `gradle.properties` to redirect AGP to use your custom version of lint instead. This is described in more detail in [](../usage/newer-lint.md.html).