Improve CompatDexBuilder worker compatibility

Improving worker compatibility some by returning exit codes instead of calling `System#exit`. This PR doesn't actually bring in worker compatibility but I can open a PR with that once this merges.

Closes #14430.

PiperOrigin-RevId: 420744753
diff --git a/src/test/java/com/google/devtools/build/android/r8/BUILD b/src/test/java/com/google/devtools/build/android/r8/BUILD
index 2fef22f..49d1f1f 100644
--- a/src/test/java/com/google/devtools/build/android/r8/BUILD
+++ b/src/test/java/com/google/devtools/build/android/r8/BUILD
@@ -31,6 +31,7 @@
     }),
     deps = [
         "//src/test/java/com/google/devtools/build/lib/testutil:TestSuite",
+        "//src/main/java/com/google/devtools/common/options:options_internal",
         "//src/tools/android/java/com/google/devtools/build/android/r8",
         "//third_party:guava",
         "//third_party:junit4",
diff --git a/src/test/java/com/google/devtools/build/android/r8/CompatDexBuilderTest.java b/src/test/java/com/google/devtools/build/android/r8/CompatDexBuilderTest.java
index 24e3655..158200b 100644
--- a/src/test/java/com/google/devtools/build/android/r8/CompatDexBuilderTest.java
+++ b/src/test/java/com/google/devtools/build/android/r8/CompatDexBuilderTest.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.D8Command;
 import com.android.tools.r8.OutputMode;
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.common.options.OptionsParsingException;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -40,7 +41,8 @@
   @Rule public TemporaryFolder temp = new TemporaryFolder();
 
   @Test
-  public void compileManyClasses() throws IOException, InterruptedException, ExecutionException {
+  public void compileManyClasses()
+      throws IOException, InterruptedException, ExecutionException, OptionsParsingException {
     // Random set of classes from the R8 example test directory naming001.
     final String inputJar = System.getProperty("CompatDexBuilderTests.naming001");
     final List<String> classNames =
diff --git a/src/tools/android/java/com/google/devtools/build/android/r8/CompatDexBuilder.java b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDexBuilder.java
index 58c1c06..6aecd25 100644
--- a/src/tools/android/java/com/google/devtools/build/android/r8/CompatDexBuilder.java
+++ b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDexBuilder.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.origin.ArchiveEntryOrigin;
 import com.android.tools.r8.origin.PathOrigin;
 import com.google.common.io.ByteStreams;
+import com.google.devtools.common.options.OptionsParsingException;
 import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -73,19 +74,20 @@
     }
   }
 
-  private String input;
-  private String output;
-  private int numberOfThreads = min(8, Runtime.getRuntime().availableProcessors());
-  private boolean noLocals;
-
   public static void main(String[] args)
-      throws IOException, InterruptedException, ExecutionException {
-    new CompatDexBuilder().run(args);
+      throws IOException, InterruptedException, ExecutionException, OptionsParsingException {
+    CompatDexBuilder compatDexBuilder = new CompatDexBuilder();
+    compatDexBuilder.processRequest(args);
   }
 
   @SuppressWarnings("JdkObsolete")
-  private void run(String[] args) throws IOException, InterruptedException, ExecutionException {
+  private void processRequest(String[] args)
+      throws IOException, InterruptedException, ExecutionException, OptionsParsingException {
     List<String> flags = new ArrayList<>();
+    String input = null;
+    String output = null;
+    int numberOfThreads = min(8, Runtime.getRuntime().availableProcessors());
+    boolean noLocals = false;
 
     for (String arg : args) {
       if (arg.startsWith("@")) {
@@ -127,19 +129,16 @@
           noLocals = true;
           break;
         default:
-          System.err.println("Unsupported option: " + flag);
-          System.exit(1);
+          throw new OptionsParsingException("Unsupported option: " + flag);
       }
     }
 
     if (input == null) {
-      System.err.println("No input jar specified");
-      System.exit(1);
+      throw new OptionsParsingException("No input jar specified");
     }
 
     if (output == null) {
-      System.err.println("No output jar specified");
-      System.exit(1);
+      throw new OptionsParsingException("No output jar specified");
     }
 
     ExecutorService executor = Executors.newWorkStealingPool(numberOfThreads);
@@ -149,6 +148,8 @@
       List<ZipEntry> toDex = new ArrayList<>();
 
       try (ZipFile zipFile = new ZipFile(input, UTF_8)) {
+        final CompilationMode compilationMode =
+            noLocals ? CompilationMode.RELEASE : CompilationMode.DEBUG;
         final Enumeration<? extends ZipEntry> entries = zipFile.entries();
         while (entries.hasMoreElements()) {
           ZipEntry entry = entries.nextElement();
@@ -163,7 +164,8 @@
 
         List<Future<DexConsumer>> futures = new ArrayList<>(toDex.size());
         for (ZipEntry classEntry : toDex) {
-          futures.add(executor.submit(() -> dexEntry(zipFile, classEntry, executor)));
+          futures.add(
+              executor.submit(() -> dexEntry(zipFile, classEntry, compilationMode, executor)));
         }
         for (int i = 0; i < futures.size(); i++) {
           ZipEntry entry = toDex.get(i);
@@ -176,13 +178,14 @@
     }
   }
 
-  private DexConsumer dexEntry(ZipFile zipFile, ZipEntry classEntry, ExecutorService executor)
+  private DexConsumer dexEntry(
+      ZipFile zipFile, ZipEntry classEntry, CompilationMode mode, ExecutorService executor)
       throws IOException, CompilationFailedException {
     DexConsumer consumer = new DexConsumer();
     D8Command.Builder builder = D8Command.builder();
     builder
         .setProgramConsumer(consumer)
-        .setMode(noLocals ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+        .setMode(mode)
         .setMinApiLevel(13) // H_MR2.
         .setDisableDesugaring(true)
         .setIntermediate(true);