[assistant] add option to use json logger

Change-Id: I371ce6e5dc806ff3c74cc5947858b7915d94dbbb
diff --git a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationJsonLogger.java b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationJsonLogger.java
index 57e3cdf..97c98db 100644
--- a/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationJsonLogger.java
+++ b/src/assistant/java/com/android/tools/r8/assistant/runtime/ReflectiveOperationJsonLogger.java
@@ -36,6 +36,7 @@
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.lang.reflect.InvocationHandler;
 
 // This logs the information in JSON-like format,
@@ -46,15 +47,33 @@
   private final FileWriter output;
 
   public ReflectiveOperationJsonLogger() throws IOException {
-    String property = System.getProperty("com.android.tools.r8.reflectiveJsonLogger", "log.txt");
-    File file = new File(property);
-    file.createNewFile();
+    String outputFileName = System.getProperty("com.android.tools.r8.reflectiveJsonLogger");
+    File file;
+    if (outputFileName == null) {
+      String tmpDir = System.getProperty("java.io.tmpdir");
+      if (tmpDir == null) {
+        throw new IllegalStateException(
+            "System property 'java.io.tmpdir' is null, cannot create log file.");
+      }
+      file = new File(tmpDir, "log.txt");
+    } else {
+      file = new File(outputFileName);
+    }
     this.output = new FileWriter(file);
     output.write("[");
+    Runtime.getRuntime().addShutdownHook(new Thread(this::onShutdown));
+  }
+
+  private void onShutdown() {
+    try {
+      finished();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
   }
 
   public void finished() throws IOException {
-    output.write("{}]");
+    output.write("]");
     output.close();
   }
 
@@ -225,7 +244,11 @@
 
   @Override
   public void onClassIsInstance(Stack stack, Class<?> holder, Object object) {
-    output(CLASS_IS_INSTANCE, stack, printClass(holder), printClass(object.getClass()));
+    output(
+        CLASS_IS_INSTANCE,
+        stack,
+        printClass(holder),
+        printClass(object != null ? object.getClass() : null));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/R8AssistantCommand.java b/src/main/java/com/android/tools/r8/R8AssistantCommand.java
index ffc4828..e47fdc4 100644
--- a/src/main/java/com/android/tools/r8/R8AssistantCommand.java
+++ b/src/main/java/com/android/tools/r8/R8AssistantCommand.java
@@ -133,6 +133,10 @@
       return self();
     }
 
+    public Builder setReflectiveReceiverClass(Class<?> clazz) {
+      return setReflectiveReceiverClassDescriptor(DescriptorUtils.javaClassToDescriptor(clazz));
+    }
+
     @Override
     CompilationMode defaultCompilationMode() {
       return CompilationMode.RELEASE;
diff --git a/src/main/java/com/android/tools/r8/utils/CompileDumpR8Assistant.java b/src/main/java/com/android/tools/r8/utils/CompileDumpR8Assistant.java
index 91a4d03..a534771 100644
--- a/src/main/java/com/android/tools/r8/utils/CompileDumpR8Assistant.java
+++ b/src/main/java/com/android/tools/r8/utils/CompileDumpR8Assistant.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.R8Assistant;
 import com.android.tools.r8.R8AssistantCommand;
+import com.android.tools.r8.assistant.runtime.ReflectiveOperationJsonLogger;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -24,6 +25,8 @@
  */
 public class CompileDumpR8Assistant extends CompileDumpBase {
 
+  private static final List<String> VALID_OPTIONS = Arrays.asList("--reflective-usage-json-output");
+
   private static final List<String> VALID_OPTIONS_WITH_SINGLE_OPERAND =
       Arrays.asList("--output", "--lib", "--classpath", "--min-api", "--threads");
 
@@ -35,9 +38,19 @@
     List<Path> classpath = new ArrayList<>();
     int minApi = 1;
     int threads = -1;
+    BooleanBox reflectiveUsageAsJson = new BooleanBox(false);
+
     for (int i = 0; i < args.length; i++) {
       String option = args[i];
-      if (VALID_OPTIONS_WITH_SINGLE_OPERAND.contains(option)) {
+      if (VALID_OPTIONS.contains(option)) {
+        switch (option) {
+          case "--reflective-usage-json-output":
+            reflectiveUsageAsJson.set(true);
+            break;
+          default:
+            throw new IllegalArgumentException("Unimplemented option: " + option);
+        }
+      } else if (VALID_OPTIONS_WITH_SINGLE_OPERAND.contains(option)) {
         String operand = args[++i];
         switch (option) {
           case "--output":
@@ -72,15 +85,18 @@
         program.add(Paths.get(option));
       }
     }
-    R8AssistantCommand command =
+    R8AssistantCommand.Builder commandBuilder =
         R8AssistantCommand.builder()
             .addProgramFiles(program)
             .addLibraryFiles(library)
             .addClasspathFiles(classpath)
             .setOutput(outputPath, OutputMode.DexIndexed)
             .setMode(compilationMode)
-            .setMinApiLevel(minApi)
-            .build();
+            .setMinApiLevel(minApi);
+    if (reflectiveUsageAsJson.value) {
+      commandBuilder.setReflectiveReceiverClass(ReflectiveOperationJsonLogger.class);
+    }
+    R8AssistantCommand command = commandBuilder.build();
     if (threads != -1) {
       ExecutorService executor = Executors.newWorkStealingPool(threads);
       try {
diff --git a/tools/assistant/instrument_with_assistant_and_run_test.py b/tools/assistant/instrument_with_assistant_and_run_test.py
index f08e94c..aa7016c 100755
--- a/tools/assistant/instrument_with_assistant_and_run_test.py
+++ b/tools/assistant/instrument_with_assistant_and_run_test.py
@@ -39,9 +39,11 @@
     instrumented_dex = os.path.join(temp_dir, 'out.jar')
 
     with utils.TempDir() as compiledump_temp_dir:
+        otherargs = ['--output', instrumented_dex]
+        if options.json_output:
+            otherargs.append('--reflective-usage-json-output')
         compile_result = compiledump.run1(compiledump_temp_dir,
-                                          compiledump_args,
-                                          ['--output', instrumented_dex])
+                                          compiledump_args, otherargs)
         if compile_result != 0:
             raise Exception('Failed to run R8 assistant')
 
@@ -79,6 +81,11 @@
     result.add_argument('--id', help='The id of the app')
     result.add_argument('--id-test', help='The id of the test')
     result.add_argument('--device', help='The device to run on')
+    result.add_argument('--json-output',
+                        help='Use json for reflective use'
+                        '(default disabled)',
+                        default=False,
+                        action='store_true')
     result.add_argument('--debug-agent',
                         help='Enable Java debug agent and suspend compilation ',
                         default=False,