Add @Keep and @KeepForSubclassing annotations for public R8 API

Add simple src/main/keep.txt file specifying that public members of
types marked with @Keep and public/protected members of types marked
with @KeepForSubclassing should be kept.

Add tools/build_r8lib.py to build a minified r8lib.jar from r8.jar and
test that d8_api_usage_sample.jar works with the minified r8lib.jar.

Also move RT_JAR from minify_tool.py to utils.py since it is used in
build_r8lib.py as well.

Change-Id: Ie091895705bfd4637513876a93f35911e958c479
diff --git a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
index e17acd0..b3d59fb 100644
--- a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
@@ -35,6 +35,7 @@
  * <p>The descriptor index is built eagerly upon creating the provider and subsequent requests for
  * resources in the descriptor set will then force the read of zip entry contents.
  */
+@Keep
 public class ArchiveClassFileProvider implements ClassFileResourceProvider, Closeable {
   private final Origin origin;
   private final ZipFile zipFile;
diff --git a/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java b/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java
index b3a4bfb..baac9bc 100644
--- a/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/ArchiveProgramResourceProvider.java
@@ -29,8 +29,10 @@
 import java.util.zip.ZipFile;
 
 /** Provider for archives of program resources. */
+@KeepForSubclassing
 public class ArchiveProgramResourceProvider implements ProgramResourceProvider {
 
+  @KeepForSubclassing
   public interface ZipFileSupplier {
     ZipFile open() throws IOException;
   }
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java
index e050356..8828248 100644
--- a/src/main/java/com/android/tools/r8/BaseCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCommand.java
@@ -28,6 +28,7 @@
  * <p>For concrete builders, see for example {@link D8Command.Builder} and {@link
  * R8Command.Builder}.
  */
+@Keep
 public abstract class BaseCommand {
 
   private final boolean printHelp;
@@ -101,6 +102,7 @@
    * @param <B> Concrete builder extending this base, e.g., {@link R8Command.Builder} or {@link
    *     D8Command.Builder}.
    */
+  @Keep
   public abstract static class Builder<C extends BaseCommand, B extends Builder<C, B>> {
 
     private final Reporter reporter;
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index d724656..5980a0c 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -21,6 +21,7 @@
  * <p>For concrete builders, see for example {@link D8Command.Builder} and {@link
  * R8Command.Builder}.
  */
+@Keep
 public abstract class BaseCompilerCommand extends BaseCommand {
 
   private final CompilationMode mode;
@@ -104,6 +105,7 @@
    * @param <B> Concrete builder extending this base, e.g., {@link R8Command.Builder} or {@link
    *     D8Command.Builder}.
    */
+  @Keep
   public abstract static class Builder<C extends BaseCompilerCommand, B extends Builder<C, B>>
       extends BaseCommand.Builder<C, B> {
 
diff --git a/src/main/java/com/android/tools/r8/ClassFileConsumer.java b/src/main/java/com/android/tools/r8/ClassFileConsumer.java
index 6c9a286..3bab0ab 100644
--- a/src/main/java/com/android/tools/r8/ClassFileConsumer.java
+++ b/src/main/java/com/android/tools/r8/ClassFileConsumer.java
@@ -26,6 +26,7 @@
  *
  * <p>This consumer can only be provided to R8.
  */
+@KeepForSubclassing
 public interface ClassFileConsumer extends ProgramConsumer {
 
   /**
@@ -49,6 +50,7 @@
   }
 
   /** Forwarding consumer to delegate to an optional existing consumer. */
+  @Keep
   class ForwardingConsumer implements ClassFileConsumer {
 
     private static final ClassFileConsumer EMPTY_CONSUMER = new ForwardingConsumer(null);
@@ -80,6 +82,7 @@
   }
 
   /** Consumer to write program resources to an output. */
+  @Keep
   class ArchiveConsumer extends ForwardingConsumer
       implements DataResourceConsumer, InternalProgramOutputPathConsumer {
     private final OutputBuilder outputBuilder;
@@ -163,6 +166,7 @@
   }
 
   /** Directory consumer to write program resources to a directory. */
+  @Keep
   class DirectoryConsumer extends ForwardingConsumer implements InternalProgramOutputPathConsumer {
     private final OutputBuilder outputBuilder;
     protected final boolean consumeDataResouces;
diff --git a/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java b/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java
index 4c71d88..db0a9f8 100644
--- a/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/ClassFileResourceProvider.java
@@ -12,6 +12,7 @@
  * only created on-demand when they are needed by the compiler. If never needed, the resource will
  * never be loaded.
  */
+@KeepForSubclassing
 public interface ClassFileResourceProvider {
 
   /**
diff --git a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
index a6923ba..89a33c1 100644
--- a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
+++ b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
@@ -6,6 +6,8 @@
 
 import java.nio.file.Path;
 
+// This class is used by the Android Studio Gradle plugin and is thus part of the R8 API.
+@Keep
 public class CompatProguardCommandBuilder extends R8Command.Builder {
   public CompatProguardCommandBuilder() {
     this(true);
diff --git a/src/main/java/com/android/tools/r8/CompilationFailedException.java b/src/main/java/com/android/tools/r8/CompilationFailedException.java
index 561ad0c..bcc4ad1 100644
--- a/src/main/java/com/android/tools/r8/CompilationFailedException.java
+++ b/src/main/java/com/android/tools/r8/CompilationFailedException.java
@@ -7,6 +7,7 @@
  * Exception thrown when compilation failed to complete because of errors previously reported
  * through {@link com.android.tools.r8.DiagnosticsHandler}.
  */
+@Keep
 public class CompilationFailedException extends Exception {
 
   public CompilationFailedException() {
diff --git a/src/main/java/com/android/tools/r8/CompilationMode.java b/src/main/java/com/android/tools/r8/CompilationMode.java
index f7aa4f0..fb02504 100644
--- a/src/main/java/com/android/tools/r8/CompilationMode.java
+++ b/src/main/java/com/android/tools/r8/CompilationMode.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8;
 
 /** Compilation mode. */
+@Keep
 public enum CompilationMode {
   /** Preserves debugging information during compilation, eg, line-numbers and locals. */
   DEBUG,
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 06cf0bb..f4d378a 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -52,6 +52,7 @@
  * them to DEX bytecode (compiling from Java bytecode for such inputs and merging for DEX inputs),
  * and then writes the result to the directory or zip archive specified by {@code outputPath}.
  */
+@Keep
 public final class D8 {
 
   private D8() {}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 00d84bd..8c6c02b 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -26,7 +26,8 @@
  *     .build();
  * </pre>
  */
-public class D8Command extends BaseCompilerCommand {
+@Keep
+public final class D8Command extends BaseCompilerCommand {
 
   private static class ClasspathInputOrigin extends InputFileOrigin {
 
@@ -40,6 +41,7 @@
    *
    * <p>A builder is obtained by calling {@link D8Command#builder}.
    */
+  @Keep
   public static class Builder extends BaseCompilerCommand.Builder<D8Command, Builder> {
 
     private boolean intermediate = false;
diff --git a/src/main/java/com/android/tools/r8/DataDirectoryResource.java b/src/main/java/com/android/tools/r8/DataDirectoryResource.java
index 2f421f7..3e860e3 100644
--- a/src/main/java/com/android/tools/r8/DataDirectoryResource.java
+++ b/src/main/java/com/android/tools/r8/DataDirectoryResource.java
@@ -12,6 +12,7 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+@Keep
 public interface DataDirectoryResource extends DataResource {
 
   static DataDirectoryResource fromFile(Path dir, Path file) {
diff --git a/src/main/java/com/android/tools/r8/DataEntryResource.java b/src/main/java/com/android/tools/r8/DataEntryResource.java
index 189d5eb..aa9c73f 100644
--- a/src/main/java/com/android/tools/r8/DataEntryResource.java
+++ b/src/main/java/com/android/tools/r8/DataEntryResource.java
@@ -15,6 +15,7 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+@Keep
 public interface DataEntryResource extends DataResource {
 
   /** Get the bytes of the data entry resource. */
diff --git a/src/main/java/com/android/tools/r8/DataResource.java b/src/main/java/com/android/tools/r8/DataResource.java
index 4609c97..eac8b6c 100644
--- a/src/main/java/com/android/tools/r8/DataResource.java
+++ b/src/main/java/com/android/tools/r8/DataResource.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+@Keep
 public interface DataResource extends Resource {
   char SEPARATOR = '/';
 
diff --git a/src/main/java/com/android/tools/r8/DataResourceConsumer.java b/src/main/java/com/android/tools/r8/DataResourceConsumer.java
index 215ca59..e306b9b 100644
--- a/src/main/java/com/android/tools/r8/DataResourceConsumer.java
+++ b/src/main/java/com/android/tools/r8/DataResourceConsumer.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+@KeepForSubclassing
 public interface DataResourceConsumer {
 
   void accept(DataDirectoryResource directory, DiagnosticsHandler diagnosticsHandler);
diff --git a/src/main/java/com/android/tools/r8/DataResourceProvider.java b/src/main/java/com/android/tools/r8/DataResourceProvider.java
index e851f0f..5e0a24f 100644
--- a/src/main/java/com/android/tools/r8/DataResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/DataResourceProvider.java
@@ -3,8 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+@KeepForSubclassing
 public interface DataResourceProvider {
 
+  @KeepForSubclassing
   interface Visitor {
     void visit(DataDirectoryResource directory);
     void visit(DataEntryResource file);
diff --git a/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java b/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java
index f1c0fac..311a3dd 100644
--- a/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java
+++ b/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java
@@ -29,6 +29,7 @@
  *
  * <p>This consumer receives DEX file content for each Java class-file input.
  */
+@KeepForSubclassing
 public interface DexFilePerClassFileConsumer extends ProgramConsumer {
 
   /**
@@ -57,6 +58,7 @@
   }
 
   /** Forwarding consumer to delegate to an optional existing consumer. */
+  @Keep
   class ForwardingConsumer implements DexFilePerClassFileConsumer {
 
     private static final DexFilePerClassFileConsumer EMPTY_CONSUMER = new ForwardingConsumer(null);
@@ -92,6 +94,7 @@
   }
 
   /** Consumer to write program resources to an output. */
+  @Keep
   class ArchiveConsumer extends ForwardingConsumer
       implements DataResourceConsumer, InternalProgramOutputPathConsumer {
     private final OutputBuilder outputBuilder;
@@ -181,6 +184,7 @@
   }
 
   /** Directory consumer to write program resources to a directory. */
+  @Keep
   class DirectoryConsumer extends ForwardingConsumer
       implements DataResourceConsumer, InternalProgramOutputPathConsumer {
     private final OutputBuilder outputBuilder;
diff --git a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
index 3bbab64..e802103 100644
--- a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
+++ b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
@@ -31,6 +31,7 @@
  * <p>This consumer receives DEX file content using standard indexed-multidex for programs larger
  * than a single DEX file. This is the default consumer for DEX programs.
  */
+@KeepForSubclassing
 public interface DexIndexedConsumer extends ProgramConsumer {
 
   /**
@@ -58,6 +59,7 @@
   }
 
   /** Forwarding consumer to delegate to an optional existing consumer. */
+  @Keep
   class ForwardingConsumer implements DexIndexedConsumer {
 
     private static final DexIndexedConsumer EMPTY_CONSUMER = new ForwardingConsumer(null);
@@ -100,6 +102,7 @@
   }
 
   /** Consumer to write program resources to an output. */
+  @Keep
   class ArchiveConsumer extends ForwardingConsumer
       implements DataResourceConsumer, InternalProgramOutputPathConsumer {
     protected final OutputBuilder outputBuilder;
@@ -181,6 +184,7 @@
     }
   }
 
+  @Keep
   class DirectoryConsumer extends ForwardingConsumer
       implements DataResourceConsumer, InternalProgramOutputPathConsumer {
     private final Path directory;
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index 2d52ec9..3e299f2 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -31,7 +31,8 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
-public class DexSplitterHelper {
+@Keep
+public final class DexSplitterHelper {
 
   public static void run(
       D8Command command, FeatureClassMapping featureClassMapping, String output, String proguardMap)
diff --git a/src/main/java/com/android/tools/r8/Diagnostic.java b/src/main/java/com/android/tools/r8/Diagnostic.java
index 7896251..3184d54 100644
--- a/src/main/java/com/android/tools/r8/Diagnostic.java
+++ b/src/main/java/com/android/tools/r8/Diagnostic.java
@@ -9,6 +9,7 @@
 /**
  * Interface for all diagnostic message produced by D8 and R8.
  */
+@Keep
 public interface Diagnostic {
 
   /**
diff --git a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
index 8212835..74a9a96 100644
--- a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
+++ b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
@@ -10,6 +10,7 @@
  *
  * <p>During compilation the warning and info methods will be called.
  */
+@Keep
 public interface DiagnosticsHandler {
 
   /**
diff --git a/src/main/java/com/android/tools/r8/DirectoryClassFileProvider.java b/src/main/java/com/android/tools/r8/DirectoryClassFileProvider.java
index 5d5f751..50aff3f 100644
--- a/src/main/java/com/android/tools/r8/DirectoryClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/DirectoryClassFileProvider.java
@@ -19,6 +19,7 @@
  * Lazy resource provider returning class file resources based
  * on filesystem directory content.
  */
+@Keep
 public final class DirectoryClassFileProvider implements ClassFileResourceProvider {
   private final Path root;
 
diff --git a/src/main/java/com/android/tools/r8/Keep.java b/src/main/java/com/android/tools/r8/Keep.java
new file mode 100644
index 0000000..13ed8c1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/Keep.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8;
+
+@Keep
+public @interface Keep {
+
+}
diff --git a/src/main/java/com/android/tools/r8/KeepForSubclassing.java b/src/main/java/com/android/tools/r8/KeepForSubclassing.java
new file mode 100644
index 0000000..6e57114
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/KeepForSubclassing.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8;
+
+@Keep
+public @interface KeepForSubclassing {
+
+}
diff --git a/src/main/java/com/android/tools/r8/OutputMode.java b/src/main/java/com/android/tools/r8/OutputMode.java
index 0da34b7..bc8a8d8 100644
--- a/src/main/java/com/android/tools/r8/OutputMode.java
+++ b/src/main/java/com/android/tools/r8/OutputMode.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8;
 
 /** Enumeration of the possible output formats of compilation. */
+@Keep
 public enum OutputMode {
 
   /** Produce DEX files using standard indexed-multidex for programs larger that a single file. */
diff --git a/src/main/java/com/android/tools/r8/ProgramConsumer.java b/src/main/java/com/android/tools/r8/ProgramConsumer.java
index 08d7d7c..b3143a0 100644
--- a/src/main/java/com/android/tools/r8/ProgramConsumer.java
+++ b/src/main/java/com/android/tools/r8/ProgramConsumer.java
@@ -6,6 +6,7 @@
 /**
  * Base for all program consumers to allow abstracting which concrete consumer is provided to D8/R8.
  */
+@KeepForSubclassing
 public interface ProgramConsumer {
 
   /**
diff --git a/src/main/java/com/android/tools/r8/ProgramResource.java b/src/main/java/com/android/tools/r8/ProgramResource.java
index cabeabc..ffeb558 100644
--- a/src/main/java/com/android/tools/r8/ProgramResource.java
+++ b/src/main/java/com/android/tools/r8/ProgramResource.java
@@ -20,9 +20,11 @@
  * A resource may optionally include a set describing the class descriptors for each type that is
  * defined by the resource.
  */
+@KeepForSubclassing
 public interface ProgramResource extends Resource {
 
   /** Type of program-format kinds. */
+  @Keep
   enum Kind {
     /** Format-kind for Java class-file resources. */
     CF,
@@ -66,6 +68,7 @@
   Set<String> getClassDescriptors();
 
   /** File-based program resource. */
+  @Keep
   class FileResource implements ProgramResource {
     private final Origin origin;
     private final Kind kind;
@@ -105,6 +108,7 @@
   }
 
   /** Byte-content based program resource. */
+  @Keep
   class ByteResource implements ProgramResource {
     private final Origin origin;
     private final Kind kind;
diff --git a/src/main/java/com/android/tools/r8/ProgramResourceProvider.java b/src/main/java/com/android/tools/r8/ProgramResourceProvider.java
index 76d340c..d4b8a87 100644
--- a/src/main/java/com/android/tools/r8/ProgramResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/ProgramResourceProvider.java
@@ -6,6 +6,7 @@
 import java.util.Collection;
 
 /** Program resource provider. */
+@KeepForSubclassing
 public interface ProgramResourceProvider {
 
   Collection<ProgramResource> getProgramResources() throws ResourceException;
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5d29d90..077e220 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -103,6 +103,7 @@
  * them to DEX bytecode, using {@code androidJar} as the reference of the system runtime library,
  * and then writes the result to the directory or zip archive specified by {@code outputPath}.
  */
+@Keep
 public class R8 {
 
   private final Timing timing = new Timing("R8");
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index ad5c882..86ff5a5 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -45,13 +45,15 @@
  *     .build();
  * </pre>
  */
-public class R8Command extends BaseCompilerCommand {
+@Keep
+public final class R8Command extends BaseCompilerCommand {
 
   /**
    * Builder for constructing a R8Command.
    *
    * <p>A builder is obtained by calling {@link R8Command#builder}.
    */
+  @Keep
   public static class Builder extends BaseCompilerCommand.Builder<R8Command, Builder> {
 
     private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/Resource.java b/src/main/java/com/android/tools/r8/Resource.java
index b64fe01..50c50cc 100644
--- a/src/main/java/com/android/tools/r8/Resource.java
+++ b/src/main/java/com/android/tools/r8/Resource.java
@@ -19,6 +19,7 @@
  * The D8/R8 compilers uses default implementations for various file-system resources, but the
  * client is free to provide their own.
  */
+@KeepForSubclassing
 public interface Resource {
   /**
    * Get the origin of the resource.
diff --git a/src/main/java/com/android/tools/r8/ResourceException.java b/src/main/java/com/android/tools/r8/ResourceException.java
index 3af7efa..2726b92 100644
--- a/src/main/java/com/android/tools/r8/ResourceException.java
+++ b/src/main/java/com/android/tools/r8/ResourceException.java
@@ -11,6 +11,7 @@
  * For example, this is the expected exception that must be thrown if a resource fails to produce
  * its content. See {@link ProgramResource#getByteStream()} and {@link StringResource#getString()}.
  */
+@Keep
 public class ResourceException extends Exception {
 
   private final Origin origin;
diff --git a/src/main/java/com/android/tools/r8/origin/ArchiveEntryOrigin.java b/src/main/java/com/android/tools/r8/origin/ArchiveEntryOrigin.java
index 0a6c84a..37ae662 100644
--- a/src/main/java/com/android/tools/r8/origin/ArchiveEntryOrigin.java
+++ b/src/main/java/com/android/tools/r8/origin/ArchiveEntryOrigin.java
@@ -4,9 +4,12 @@
 
 package com.android.tools.r8.origin;
 
+import com.android.tools.r8.Keep;
+
 /**
  * Origin representing an entry in an archive.
  */
+@Keep
 public class ArchiveEntryOrigin extends Origin {
 
   final String entryName;
diff --git a/src/main/java/com/android/tools/r8/origin/Origin.java b/src/main/java/com/android/tools/r8/origin/Origin.java
index c0bc2ec..3a8aa97 100644
--- a/src/main/java/com/android/tools/r8/origin/Origin.java
+++ b/src/main/java/com/android/tools/r8/origin/Origin.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.origin;
 
+import com.android.tools.r8.KeepForSubclassing;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -22,6 +23,7 @@
  * Origin.unknown()}. The former is the parent of any file path, while the latter is an unknown
  * origin (e.g., for generated resources of raw bytes).
  */
+@KeepForSubclassing
 public abstract class Origin implements Comparable<Origin> {
 
   private static final Origin ROOT =
diff --git a/src/main/java/com/android/tools/r8/origin/PathOrigin.java b/src/main/java/com/android/tools/r8/origin/PathOrigin.java
index 95ee46f..0ff8080 100644
--- a/src/main/java/com/android/tools/r8/origin/PathOrigin.java
+++ b/src/main/java/com/android/tools/r8/origin/PathOrigin.java
@@ -4,11 +4,13 @@
 
 package com.android.tools.r8.origin;
 
+import com.android.tools.r8.Keep;
 import java.nio.file.Path;
 
 /**
  * Path component in an origin description.
  */
+@Keep
 public class PathOrigin extends Origin {
 
   private final Path path;
diff --git a/src/main/java/com/android/tools/r8/position/Position.java b/src/main/java/com/android/tools/r8/position/Position.java
index 902fad5..618fd51 100644
--- a/src/main/java/com/android/tools/r8/position/Position.java
+++ b/src/main/java/com/android/tools/r8/position/Position.java
@@ -4,10 +4,13 @@
 
 package com.android.tools.r8.position;
 
+import com.android.tools.r8.Keep;
+
 /**
  * Represent a position in a resource, it can for example be line in a text file of the byte offset
  * in a binary stream.
  */
+@Keep
 public interface Position {
 
   /**
diff --git a/src/main/java/com/android/tools/r8/position/TextPosition.java b/src/main/java/com/android/tools/r8/position/TextPosition.java
index 9136fa7..0dd4090 100644
--- a/src/main/java/com/android/tools/r8/position/TextPosition.java
+++ b/src/main/java/com/android/tools/r8/position/TextPosition.java
@@ -3,10 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.position;
 
+import com.android.tools.r8.Keep;
+
 /**
  * A {@link Position} in a text file determined by line and column.
  * Line and column numbers start at 1.
  */
+@Keep
 public class TextPosition implements Position {
 
   /**
diff --git a/src/main/java/com/android/tools/r8/position/TextRange.java b/src/main/java/com/android/tools/r8/position/TextRange.java
index 5f35aad..0e642d8 100644
--- a/src/main/java/com/android/tools/r8/position/TextRange.java
+++ b/src/main/java/com/android/tools/r8/position/TextRange.java
@@ -4,6 +4,9 @@
 
 package com.android.tools.r8.position;
 
+import com.android.tools.r8.Keep;
+
+@Keep
 public class TextRange implements Position {
   private final TextPosition start;
   private final TextPosition end;
diff --git a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
index 873013e..8e84935 100644
--- a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
+++ b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.utils;
 
 import com.android.tools.r8.ArchiveClassFileProvider;
+import com.android.tools.r8.Keep;
 import com.android.tools.r8.dexsplitter.DexSplitter;
 import com.android.tools.r8.dexsplitter.DexSplitter.FeatureJar;
 import com.android.tools.r8.origin.PathOrigin;
@@ -38,6 +39,7 @@
  * <p>Note that this format does not allow specifying inter-module dependencies, this is simply a
  * placement tool.
  */
+@Keep
 public class FeatureClassMapping {
 
   HashMap<String, String> parsedRules = new HashMap<>(); // Already parsed rules.
@@ -198,6 +200,7 @@
         "Invalid mappings specification: " + error + "\n in file " + mappingFile + ":" + line);
   }
 
+  @Keep
   public static class FeatureMappingException extends Exception {
     FeatureMappingException(String message) {
       super(message);
diff --git a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
index b7cd855..06ab8a9 100644
--- a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
@@ -4,9 +4,11 @@
 package com.android.tools.r8.utils;
 
 import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.Keep;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 
+@Keep
 public class StringDiagnostic implements Diagnostic {
 
   private final Origin origin;
diff --git a/src/main/keep.txt b/src/main/keep.txt
new file mode 100644
index 0000000..2d74e47
--- /dev/null
+++ b/src/main/keep.txt
@@ -0,0 +1,6 @@
+# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-keep @com.android.tools.r8.Keep class * { public *; }
+-keep @com.android.tools.r8.KeepForSubclassing class * { public *; protected *; }
diff --git a/tools/build_r8lib.py b/tools/build_r8lib.py
new file mode 100755
index 0000000..e08c141
--- /dev/null
+++ b/tools/build_r8lib.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+'''
+Build r8lib.jar using src/main/keep.txt and test that d8_api_usage_sample.jar
+works with the minified R8.
+'''
+
+import argparse
+import os
+import subprocess
+import toolhelper
+import utils
+
+parser = argparse.ArgumentParser(description=__doc__.strip(),
+                                 formatter_class=argparse.RawTextHelpFormatter)
+
+SAMPLE_JAR = os.path.join(utils.REPO_ROOT, 'tests/d8_api_usage_sample.jar')
+KEEP_RULES = os.path.join(utils.REPO_ROOT, 'src/main/keep.txt')
+R8LIB_JAR = os.path.join(utils.LIBS, 'r8lib.jar')
+R8LIB_MAP_FILE = os.path.join(utils.LIBS, 'r8lib-map.txt')
+
+API_LEVEL = 26
+ANDROID_JAR = 'third_party/android_jar/lib-v%s/android.jar' % API_LEVEL
+
+
+def build_r8lib():
+  toolhelper.run(
+      'r8',
+      ('--release',
+       '--classfile',
+       '--lib', utils.RT_JAR,
+       utils.R8_JAR,
+       '--output', R8LIB_JAR,
+       '--pg-conf', KEEP_RULES,
+       '--pg-map-output', R8LIB_MAP_FILE))
+
+
+def test_d8sample():
+  with utils.TempDir() as path:
+    args = ['java', '-cp', '%s:%s' % (R8LIB_JAR, SAMPLE_JAR),
+            'com.android.tools.apiusagesample.D8ApiUsageSample',
+            '--output', path,
+            '--min-api', str(API_LEVEL),
+            '--lib', ANDROID_JAR,
+            '--classpath', utils.R8_JAR,
+            '--main-dex-list', '/dev/null',
+            os.path.join(utils.BUILD, 'test/examples/hello.jar')]
+    utils.PrintCmd(args)
+    subprocess.check_call(args)
+
+
+def main():
+  # Handle --help
+  parser.parse_args()
+
+  build_r8lib()
+  test_d8sample()
+
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/minify_tool.py b/tools/minify_tool.py
index 787c1e1..8f440dd 100755
--- a/tools/minify_tool.py
+++ b/tools/minify_tool.py
@@ -27,7 +27,6 @@
 MANIFEST_PATH = 'META-INF/MANIFEST.MF'
 MANIFEST = 'Manifest-Version: 1.0\nMain-Class: %s\n\n'
 MANIFEST_PATTERN = r'Main-Class:\s*(\S+)'
-RT = os.path.join(utils.REPO_ROOT, 'third_party/openjdk/openjdk-rt-1.8/rt.jar')
 
 parser = argparse.ArgumentParser(description=__doc__.strip(),
                                  formatter_class=argparse.RawTextHelpFormatter)
@@ -38,7 +37,7 @@
     '-o', '--output-jar',
     help='Path to output JAR (default: build/libs/<MainClass>-min.jar)')
 parser.add_argument(
-    '-l', '--lib', default=RT,
+    '-l', '--lib', default=utils.RT_JAR,
     help='Path to rt.jar to use instead of OpenJDK 1.8')
 parser.add_argument(
     '-m', '--mainclass',
@@ -85,8 +84,8 @@
           'No --mainclass specified and no Main-Class in input JAR manifest.')
     return mo.group(1)
 
-def minify_tool(mainclass=None, input_jar=utils.R8_JAR, output_jar=None, lib=RT,
-                debug=True, build=True, benchmark_name=None):
+def minify_tool(mainclass=None, input_jar=utils.R8_JAR, output_jar=None,
+                lib=utils.RT_JAR, debug=True, build=True, benchmark_name=None):
   if output_jar is None:
     output_jar = generate_output_name(input_jar, mainclass)
   with utils.TempDir() as path:
diff --git a/tools/utils.py b/tools/utils.py
index 9f6959f..3aab572 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -35,6 +35,7 @@
 COMPATPROGUARD_JAR = os.path.join(LIBS, 'compatproguard.jar')
 MAVEN_ZIP = os.path.join(LIBS, 'r8.zip')
 GENERATED_LICENSE = os.path.join(GENERATED_LICENSE_DIR, 'LICENSE')
+RT_JAR = os.path.join(REPO_ROOT, 'third_party/openjdk/openjdk-rt-1.8/rt.jar')
 
 def PrintCmd(s):
   if type(s) is list: