diff --git a/build.gradle b/build.gradle
index 1fb56b1b6507ea6b2384e4893c5240c44b04ade8..ad5e88029928872ad5b64e5718e7e519d90df19f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -109,7 +109,7 @@ configurations {
 }
 
 dependencies {
-    ktlint "com.github.shyiko:ktlint:0.29.0"
+    ktlint "com.github.shyiko:ktlint:0.30.0"
 }
 
 task ktlint(type: JavaExec, group: "verification") {
diff --git a/src/main/java/com/android/tools/metalava/Options.kt b/src/main/java/com/android/tools/metalava/Options.kt
index 8afb8cb5fd51ca34fb911a6fab223f35851b8f6f..7b9698d7c5a9ca74dcee3da7e296a3ae2ac0e767 100644
--- a/src/main/java/com/android/tools/metalava/Options.kt
+++ b/src/main/java/com/android/tools/metalava/Options.kt
@@ -136,7 +136,8 @@ const val ARG_INCLUDE_ANNOTATION_CLASSES = "--include-annotation-classes"
 const val ARG_REWRITE_ANNOTATIONS = "--rewrite-annotations"
 const val ARG_INCLUDE_SOURCE_RETENTION = "--include-source-retention"
 const val ARG_INCLUDE_SIG_VERSION = "--include-signature-version"
-const val ARG_UPDATE_API = "--update-api"
+const val ARG_UPDATE_API = "--only-update-api"
+const val ARG_CHECK_API = "--only-check-api"
 const val ARG_PASS_BASELINE_UPDATES = "--pass-baseline-updates"
 const val ARG_DEX_API_MAPPING = "--dex-api-mapping"
 const val ARG_GENERATE_DOCUMENTATION = "--generate-documentation"
@@ -241,7 +242,20 @@ class Options(
      * signature files. This avoids having duplicate metalava invocation logic where potentially newly
      * added flags are missing in one of the invocations etc.
      */
-    var updateApi = false
+    var onlyUpdateApi = false
+
+    /**
+     * Whether metalava is invoked as part of running the checkapi target. When this is true, metalava
+     * should *cancel* various other flags that are also being passed in, such as updating signature
+     * files.
+     *
+     * This is there to ease integration in the build system: for a given target, the build system will
+     * pass all the applicable flags (--stubs, --api, --check-compatibility, --generate-documentation, etc),
+     * and this integration is re-used for the checkapi facility where we *only* want to run compatibility
+     * checks. This avoids having duplicate metalava invocation logic where potentially newly
+     * added flags are missing in one of the invocations etc.
+     */
+    var onlyCheckApi = false
 
     /**
      * Whether signature files should emit in "compat" mode, preserving the various
@@ -420,7 +434,7 @@ class Options(
     var migrateNullsFrom: File? = null
 
     /** Private backing list for [compatibilityChecks]] */
-    private var mutableCompatibilityChecks: MutableList<CheckRequest> = mutableListOf()
+    private val mutableCompatibilityChecks: MutableList<CheckRequest> = mutableListOf()
 
     /** The list of compatibility checks to run */
     val compatibilityChecks: List<CheckRequest> = mutableCompatibilityChecks
@@ -986,7 +1000,8 @@ class Options(
 
                 ARG_NO_DOCS, "-nodocs" -> noDocs = true
 
-                ARG_UPDATE_API -> updateApi = true
+                ARG_UPDATE_API, "--update-api" -> onlyUpdateApi = true
+                ARG_CHECK_API -> onlyCheckApi = true
 
                 ARG_GENERATE_DOCUMENTATION -> {
                     // Digest all the remaining arguments.
@@ -1350,7 +1365,10 @@ class Options(
             generateAnnotations = false
         }
 
-        if (updateApi) {
+        if (onlyUpdateApi) {
+            if (onlyCheckApi) {
+                throw DriverException(stderr = "Cannot supply both $ARG_UPDATE_API and $ARG_CHECK_API at the same time")
+            }
             // We're running in update API mode: cancel other "action" flags; only signature file generation
             // flags count
             annotationCoverageClassReport = null
@@ -1373,6 +1391,46 @@ class Options(
             mutableCompatibilityChecks.clear()
             mutableAnnotationCoverageOf.clear()
             artifactRegistrations.clear()
+            mutableConvertToXmlFiles.clear()
+            nullabilityAnnotationsValidator = null
+            nullabilityWarningsTxt = null
+            validateNullabilityFromMergedStubs = false
+            validateNullabilityFromMergedStubs = false
+            validateNullabilityFromList = null
+        } else if (onlyCheckApi) {
+            annotationCoverageClassReport = null
+            annotationCoverageMemberReport = null
+            dumpAnnotationStatistics = false
+            apiLevelJars = null
+            generateApiLevelXml = null
+            applyApiLevelsXml = null
+            androidJarSignatureFiles = null
+            stubsDir = null
+            docStubsDir = null
+            stubsSourceList = null
+            docStubsSourceList = null
+            sdkValueDir = null
+            externalAnnotations = null
+            proguard = null
+            noDocs = true
+            invokeDocumentationToolArguments = emptyArray()
+            checkKotlinInterop = false
+            mutableAnnotationCoverageOf.clear()
+            artifactRegistrations.clear()
+            mutableConvertToXmlFiles.clear()
+            nullabilityAnnotationsValidator = null
+            nullabilityWarningsTxt = null
+            validateNullabilityFromMergedStubs = false
+            validateNullabilityFromMergedStubs = false
+            validateNullabilityFromList = null
+            apiFile = null
+            apiXmlFile = null
+            privateApiFile = null
+            dexApiFile = null
+            dexApiMappingFile = null
+            privateDexApiFile = null
+            removedApiFile = null
+            removedDexApiFile = null
         }
 
         if (baselineFile == null) {
@@ -1790,6 +1848,8 @@ class Options(
                 "to make it easier customize build system tasks.",
             ARG_UPDATE_API, "Cancel any other \"action\" flags other than generating signature files. This is here " +
                 "to make it easier customize build system tasks, particularly for the \"make update-api\" task.",
+            ARG_CHECK_API, "Cancel any other \"action\" flags other than checking signature files. This is here " +
+                "to make it easier customize build system tasks, particularly for the \"make checkapi\" task.",
 
             "", "\nAPI sources:",
             "$ARG_SOURCE_FILES <files>", "A comma separated list of source files to be parsed. Can also be " +
diff --git a/src/test/java/com/android/tools/metalava/OptionsTest.kt b/src/test/java/com/android/tools/metalava/OptionsTest.kt
index 36d02bf03f2735ac1277cb4e3293ab13f91f6a2f..c405942eb5e2c475ea16dfe556dfa09c04471be5 100644
--- a/src/test/java/com/android/tools/metalava/OptionsTest.kt
+++ b/src/test/java/com/android/tools/metalava/OptionsTest.kt
@@ -42,10 +42,14 @@ General:
 --no-docs                                 Cancel any other documentation flags supplied to
                                           metalava. This is here to make it easier
                                           customize build system tasks.
---update-api                              Cancel any other "action" flags other than
+--only-update-api                         Cancel any other "action" flags other than
                                           generating signature files. This is here to make
                                           it easier customize build system tasks,
                                           particularly for the "make update-api" task.
+--only-check-api                          Cancel any other "action" flags other than
+                                          checking signature files. This is here to make
+                                          it easier customize build system tasks,
+                                          particularly for the "make checkapi" task.
 
 API sources:
 --source-files <files>                    A comma separated list of source files to be
diff --git a/src/test/java/com/android/tools/metalava/StubsTest.kt b/src/test/java/com/android/tools/metalava/StubsTest.kt
index 3143036218d450022a35bf0d0422b7127c7df4c0..d0eb814955e9acf2dd4591a4d8998228bebc49f7 100644
--- a/src/test/java/com/android/tools/metalava/StubsTest.kt
+++ b/src/test/java/com/android/tools/metalava/StubsTest.kt
@@ -3715,6 +3715,41 @@ class StubsTest : DriverTest() {
         )
     }
 
+    @Test(expected = AssertionError::class)
+    fun `Test check-api should not generate stubs or API files`() {
+        check(
+            extraArguments = arrayOf(
+                ARG_CHECK_API,
+                ARG_EXCLUDE_ANNOTATIONS
+            ),
+            compatibilityMode = false,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class Foo {
+                        /**
+                         * @deprecated Use checkPermission instead.
+                         */
+                        @Deprecated
+                        protected boolean inClass(String name) {
+                            return false;
+                        }
+                    }
+                    """
+                )
+            ),
+            api = """
+            package test.pkg {
+              public class Foo {
+                ctor public Foo();
+                method @Deprecated protected boolean inClass(String);
+              }
+            }
+            """
+        )
+    }
+
     @Test
     fun `Include package private classes referenced from public API`() {
         // Real world example: android.net.http.Connection in apache-http referenced from RequestHandle