diff --git a/src/main/java/com/android/tools/metalava/Driver.kt b/src/main/java/com/android/tools/metalava/Driver.kt
index a1c3bf27aa42a79a5c4d5ec6af8aa9e270b4674e..19d6749c035e37a7ab9d52ce535bf36430d7ec4b 100644
--- a/src/main/java/com/android/tools/metalava/Driver.kt
+++ b/src/main/java/com/android/tools/metalava/Driver.kt
@@ -17,9 +17,10 @@
 
 package com.android.tools.metalava
 
-import com.android.SdkConstants
+import com.android.SdkConstants.DOT_JAR
 import com.android.SdkConstants.DOT_JAVA
 import com.android.SdkConstants.DOT_KT
+import com.android.SdkConstants.DOT_TXT
 import com.android.ide.common.process.CachedProcessOutputHandler
 import com.android.ide.common.process.DefaultProcessExecutor
 import com.android.ide.common.process.ProcessInfoBuilder
@@ -37,6 +38,7 @@ import com.android.tools.metalava.doclava1.ApiPredicate
 import com.android.tools.metalava.doclava1.Errors
 import com.android.tools.metalava.doclava1.FilterPredicate
 import com.android.tools.metalava.doclava1.TextCodebase
+import com.android.tools.metalava.model.ClassItem
 import com.android.tools.metalava.model.Codebase
 import com.android.tools.metalava.model.Item
 import com.android.tools.metalava.model.PackageDocs
@@ -207,14 +209,14 @@ private fun processFlags() {
     processNonCodebaseFlags()
 
     val codebase =
-        if (options.sources.size == 1 && options.sources[0].path.endsWith(SdkConstants.DOT_TXT)) {
+        if (options.sources.size == 1 && options.sources[0].path.endsWith(DOT_TXT)) {
             SignatureFileLoader.load(
                 file = options.sources[0],
                 kotlinStyleNulls = options.inputKotlinStyleNulls
             )
         } else if (options.apiJar != null) {
             loadFromJarFile(options.apiJar!!)
-        } else if (options.sources.size == 1 && options.sources[0].path.endsWith(SdkConstants.DOT_JAR)) {
+        } else if (options.sources.size == 1 && options.sources[0].path.endsWith(DOT_JAR)) {
             loadFromJarFile(options.sources[0])
         } else if (options.sources.isNotEmpty() || options.sourcePath.isNotEmpty()) {
             loadFromSources()
@@ -227,6 +229,10 @@ private fun processFlags() {
         options.stdout.println("\n$PROGRAM_NAME analyzed API in ${stopwatch.elapsed(TimeUnit.SECONDS)} seconds")
     }
 
+    options.subtractApi?.let {
+        subtractApi(codebase, it)
+    }
+
     val androidApiLevelXml = options.generateApiLevelXml
     val apiLevelJars = options.apiLevelJars
     if (androidApiLevelXml != null && apiLevelJars != null) {
@@ -372,7 +378,7 @@ private fun processFlags() {
     val previousApiFile = options.migrateNullsFrom
     if (previousApiFile != null) {
         val previous =
-            if (previousApiFile.path.endsWith(SdkConstants.DOT_JAR)) {
+            if (previousApiFile.path.endsWith(DOT_JAR)) {
                 loadFromJarFile(previousApiFile)
             } else {
                 SignatureFileLoader.load(
@@ -450,6 +456,23 @@ private fun processFlags() {
     invokeDocumentationTool()
 }
 
+fun subtractApi(codebase: Codebase, subtractApiFile: File) {
+    val path = subtractApiFile.path
+    val oldCodebase =
+        when {
+            path.endsWith(DOT_TXT) -> SignatureFileLoader.load(subtractApiFile)
+            path.endsWith(DOT_JAR) -> loadFromJarFile(subtractApiFile)
+            else -> throw DriverException("Unsupported $ARG_SUBTRACT_API format, expected .txt or .jar: ${subtractApiFile.name}")
+        }
+
+    CodebaseComparator().compare(object : ComparisonVisitor() {
+        override fun compare(old: ClassItem, new: ClassItem) {
+            new.included = false
+            new.emit = false
+        }
+    }, oldCodebase, codebase, ApiType.ALL.getReferenceFilter())
+}
+
 fun processNonCodebaseFlags() {
     // --copy-annotations?
     val privateAnnotationsSource = options.privateAnnotationsSource
@@ -554,7 +577,7 @@ fun checkCompatibility(
     val signatureFile = check.file
 
     val current =
-        if (signatureFile.path.endsWith(SdkConstants.DOT_JAR)) {
+        if (signatureFile.path.endsWith(DOT_JAR)) {
             loadFromJarFile(signatureFile)
         } else {
             SignatureFileLoader.load(
@@ -801,7 +824,7 @@ private fun loadFromSources(): Codebase {
         val previous =
             when {
                 previousApiFile == null -> null
-                previousApiFile.path.endsWith(SdkConstants.DOT_JAR) -> loadFromJarFile(previousApiFile)
+                previousApiFile.path.endsWith(DOT_JAR) -> loadFromJarFile(previousApiFile)
                 else -> SignatureFileLoader.load(
                     file = previousApiFile,
                     kotlinStyleNulls = options.inputKotlinStyleNulls
@@ -863,7 +886,7 @@ internal fun parseSources(
     // Create project environment with those paths
     projectEnvironment.registerPaths(joined)
 
-    val kotlinFiles = sources.filter { it.path.endsWith(SdkConstants.DOT_KT) }
+    val kotlinFiles = sources.filter { it.path.endsWith(DOT_KT) }
     val trace = KotlinLintAnalyzerFacade().analyze(kotlinFiles, joined, project)
 
     val rootDir = sourceRoots.firstOrNull() ?: sourcePath.firstOrNull() ?: File("").canonicalFile
diff --git a/src/main/java/com/android/tools/metalava/Options.kt b/src/main/java/com/android/tools/metalava/Options.kt
index 7b9698d7c5a9ca74dcee3da7e296a3ae2ac0e767..c2c354b720c71bf50b557c2b65154f298f43ca92 100644
--- a/src/main/java/com/android/tools/metalava/Options.kt
+++ b/src/main/java/com/android/tools/metalava/Options.kt
@@ -147,6 +147,7 @@ const val ARG_MERGE_BASELINE = "--merge-baseline"
 const val ARG_STUB_PACKAGES = "--stub-packages"
 const val ARG_STUB_IMPORT_PACKAGES = "--stub-import-packages"
 const val ARG_DELETE_EMPTY_BASELINES = "--delete-empty-baselines"
+const val ARG_SUBTRACT_API = "--subtract-api"
 
 class Options(
     private val args: Array<String>,
@@ -198,6 +199,9 @@ class Options(
      */
     var noDocs = false
 
+    /** API to subtract from signature and stub generation. Corresponds to [ARG_SUBTRACT_API]. */
+    var subtractApi: File? = null
+
     /**
      * Validator for nullability annotations, if validation is enabled.
      */
@@ -420,7 +424,7 @@ class Options(
     var removedDexApiFile: File? = null
 
     /** Whether output should be colorized */
-    var color = System.getenv("TERM")?.startsWith("xterm") ?: false
+    var color = System.getenv("TERM")?.startsWith("xterm") ?: System.getenv("COLORTERM") != null ?: false
 
     /** Whether to omit Java and Kotlin runtime library packages from annotation coverage stats */
     var omitRuntimePackageStats = false
@@ -645,6 +649,13 @@ class Options(
                     }
                 }
 
+                ARG_SUBTRACT_API -> {
+                    if (subtractApi != null) {
+                        throw DriverException(stderr = "Only one $ARG_SUBTRACT_API can be supplied")
+                    }
+                    subtractApi = stringToExistingFile(getValue(args, ++index))
+                }
+
                 // TODO: Remove the legacy --merge-annotations flag once it's no longer used to update P docs
                 ARG_MERGE_QUALIFIER_ANNOTATIONS, "--merge-zips", "--merge-annotations" -> mutableMergeQualifierAnnotations.addAll(
                     stringToExistingDirsOrFiles(
@@ -1901,11 +1912,14 @@ class Options(
                 "as hidden",
             ARG_SHOW_UNANNOTATED, "Include un-annotated public APIs in the signature file as well",
             "$ARG_JAVA_SOURCE <level>", "Sets the source level for Java source files; default is 1.8.",
-            "$ARG_STUB_PACKAGES <path>", "List of packages (separated by ${File.pathSeparator} which will be " +
-                "used to filter out irrelevant code. If specified, only code in these packages will be " +
+            "$ARG_STUB_PACKAGES <package-list>", "List of packages (separated by ${File.pathSeparator}) which will " +
+                "be used to filter out irrelevant code. If specified, only code in these packages will be " +
                 "included in signature files, stubs, etc. (This is not limited to just the stubs; the name " +
                 "is historical.) You can also use \".*\" at the end to match subpackages, so `foo.*` will " +
                 "match both `foo` and `foo.bar`.",
+            "$ARG_SUBTRACT_API <api file>", "Subtracts the API in the given signature or jar file from the " +
+                "current API being emitted via $ARG_API, $ARG_STUBS, $ARG_DOC_STUBS, etc. " +
+                "Note that the subtraction only applies to classes; it does not subtract members.",
 
             "", "\nDocumentation:",
             ARG_PUBLIC, "Only include elements that are public",
diff --git a/src/test/java/com/android/tools/metalava/DriverTest.kt b/src/test/java/com/android/tools/metalava/DriverTest.kt
index 2e790eaa07129141628fb4757f806adacd99809e..9c27ca41e0b8a2d8992f1f2b349857ba0d723e68 100644
--- a/src/test/java/com/android/tools/metalava/DriverTest.kt
+++ b/src/test/java/com/android/tools/metalava/DriverTest.kt
@@ -226,6 +226,9 @@ abstract class DriverTest {
         dexApi: String? = null,
         /** The DEX mapping API (corresponds to --dex-api-mapping) */
         dexApiMapping: String? = null,
+        /** The subtract api signature content (corresponds to --subtract-api) */
+        @Language("TEXT")
+        subtractApi: String? = null,
         /** Expected stubs (corresponds to --stubs) */
         @Language("JAVA") stubs: Array<String> = emptyArray(),
         /** Stub source file list generated */
@@ -773,6 +776,15 @@ abstract class DriverTest {
             emptyArray()
         }
 
+        var subtractApiFile: File? = null
+        val subtractApiArgs = if (subtractApi != null) {
+            subtractApiFile = temporaryFolder.newFile("subtract-api.txt")
+            subtractApiFile.writeText(subtractApi.trimIndent())
+            arrayOf(ARG_SUBTRACT_API, subtractApiFile.path)
+        } else {
+            emptyArray()
+        }
+
         val convertFiles = mutableListOf<Options.ConvertFile>()
         val convertArgs = if (convertToJDiff.isNotEmpty()) {
             val args = mutableListOf<String>()
@@ -998,6 +1010,7 @@ abstract class DriverTest {
             *dexApiArgs,
             *privateDexApiArgs,
             *dexApiMappingArgs,
+            *subtractApiArgs,
             *stubsArgs,
             *stubsSourceListArgs,
             "$ARG_COMPAT_OUTPUT=${if (compatibilityMode) "yes" else "no"}",
@@ -1276,7 +1289,10 @@ abstract class DriverTest {
                 "${stubsSourceListFile.path} does not exist even though --write-stubs-source-list was used",
                 stubsSourceListFile.exists()
             )
-            val actualText = readFile(stubsSourceListFile, stripBlankLines, trim)
+            val actualText = cleanupString(readFile(stubsSourceListFile, stripBlankLines, trim), project)
+                // To make golden files look better put one entry per line instead of a single
+                // space separated line
+                .replace(' ', '\n')
             assertEquals(stripComments(stubsSourceList, stripLineComments = false).trimIndent(), actualText)
         }
 
diff --git a/src/test/java/com/android/tools/metalava/OptionsTest.kt b/src/test/java/com/android/tools/metalava/OptionsTest.kt
index c405942eb5e2c475ea16dfe556dfa09c04471be5..d625725a9be67f692a8e360a1fa0e1ee76f89f53 100644
--- a/src/test/java/com/android/tools/metalava/OptionsTest.kt
+++ b/src/test/java/com/android/tools/metalava/OptionsTest.kt
@@ -108,7 +108,7 @@ API sources:
                                           signature file as well
 --java-source <level>                     Sets the source level for Java source files;
                                           default is 1.8.
---stub-packages <path>                    List of packages (separated by : which will be
+--stub-packages <package-list>            List of packages (separated by :) which will be
                                           used to filter out irrelevant code. If
                                           specified, only code in these packages will be
                                           included in signature files, stubs, etc. (This
@@ -116,6 +116,11 @@ API sources:
                                           historical.) You can also use ".*" at the end to
                                           match subpackages, so `foo.*` will match both
                                           `foo` and `foo.bar`.
+--subtract-api <api file>                 Subtracts the API in the given signature or jar
+                                          file from the current API being emitted via
+                                          --api, --stubs, --doc-stubs, etc. Note that the
+                                          subtraction only applies to classes; it does not
+                                          subtract members.
 
 Documentation:
 --public                                  Only include elements that are public
diff --git a/src/test/java/com/android/tools/metalava/StubsTest.kt b/src/test/java/com/android/tools/metalava/StubsTest.kt
index d0eb814955e9acf2dd4591a4d8998228bebc49f7..b8719ed7a0716911fdccb69ff84ec0b1ef4454cd 100644
--- a/src/test/java/com/android/tools/metalava/StubsTest.kt
+++ b/src/test/java/com/android/tools/metalava/StubsTest.kt
@@ -1995,7 +1995,13 @@ class StubsTest : DriverTest() {
                 public MySubClass2() { super(0); throw new RuntimeException("Stub!"); }
                 }
                 """
-            )
+            ),
+            stubsSourceList = """
+                TESTROOT/stubs/test/pkg/MyClass1.java
+                TESTROOT/stubs/test/pkg/MyClass2.java
+                TESTROOT/stubs/test/pkg/MySubClass1.java
+                TESTROOT/stubs/test/pkg/MySubClass2.java
+            """
         )
     }
 
diff --git a/src/test/java/com/android/tools/metalava/SubtractApiTest.kt b/src/test/java/com/android/tools/metalava/SubtractApiTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..02cb8dd92dd7114484dbf35aeb809760c719958e
--- /dev/null
+++ b/src/test/java/com/android/tools/metalava/SubtractApiTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("ALL")
+
+package com.android.tools.metalava
+
+import org.junit.Test
+
+class SubtractApiTest : DriverTest() {
+    @Test
+    fun `Subtract APIs`() {
+        check(
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class OnlyInNew {
+                        private OnlyInNew() { }
+                        public void method1() { }
+                        public void method5() { }
+                        public void method6() { }
+                    }
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg;
+                    public class InBoth {
+                        private InBoth() { }
+                        public void method1() { }
+                        public void method5() { }
+                        public void method9() { }
+                    }
+                    """
+                )
+            ),
+            subtractApi = """
+                package test.pkg {
+                  public class InBoth {
+                    method public void method1();
+                    method public void method5();
+                    method public void method9();
+                  }
+                  public class OnlyInOld {
+                    method public void method1();
+                    method public void method2();
+                    method public void method3();
+                  }
+                }
+                """,
+            api = """
+                package test.pkg {
+                  public class OnlyInNew {
+                    method public void method1();
+                    method public void method5();
+                    method public void method6();
+                  }
+                }
+                """,
+            stubs = arrayOf(
+                """
+                package test.pkg;
+                @SuppressWarnings({"unchecked", "deprecation", "all"})
+                public class OnlyInNew {
+                OnlyInNew() { throw new RuntimeException("Stub!"); }
+                public void method1() { throw new RuntimeException("Stub!"); }
+                public void method5() { throw new RuntimeException("Stub!"); }
+                public void method6() { throw new RuntimeException("Stub!"); }
+                }
+                """
+            ),
+            stubsSourceList = """
+                TESTROOT/stubs/test/pkg/OnlyInNew.java
+            """
+        )
+    }
+}