Repository: square/leakcanary
File: leakcanary-android/src/main/java/com/squareup/leakcanary/AbstractAnalysisResultService.java (Java)

Code before:
    try {
      listenerServiceClass = Class.forName(listenerServiceClassName);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    }
    Intent intent = new Intent(context, listenerServiceClass);

    intent.putExtra(RESULT_FILE_PATH_EXTRA, result.getAbsolutePath());
    ContextCompat.startForegroundService(context, intent);
  }

  private final AnalysisResultAccessor accessor = new AnalysisResultAccessor();

  public AbstractAnalysisResultService() {
    super(AbstractAnalysisResultService.class.getName(),
        R.string.leak_canary_notification_reporting);
  }

  @Override
  protected final void onHandleIntentInForeground(@Nullable Intent intent) {
    String heapDump = intent.getStringExtra(RESULT_FILE_PATH_EXTRA);
    final Leak leak = accessor.loadLeak(new File(heapDump));
    if (leak != null) {
      onHeapAnalyzed(leak.heapDump, leak.result);
    } else {
      onHeapAnalyzed(null, null);
    }
  }

  /**
   * Called after a heap dump is analyzed, whether or not a leak was found.
   * Check {@link AnalysisResult#leakFound} and {@link AnalysisResult#excludedLeak} to see if there
   * was a leak and if it can be ignored.
   * <p>
   * This will be called from a background intent service thread.
   * <p>
   * It's OK to block here and wait for the heap dump to be uploaded.
   * <p>
   * The heap dump file will be deleted immediately after this callback returns.
   */
  protected abstract void onHeapAnalyzed(@NonNull HeapDump heapDump,
      @NonNull AnalysisResult result);
}


Review comment (bug):
I'm thinking we should treat this as an edge case, log to logcat, and just never call back with null (and remove `@Nullable`).

Code after:
    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    }
    Intent intent = new Intent(context, listenerServiceClass);

    File analyzedHeapFile = AnalyzedHeap.save(heapDump, result);
    if (analyzedHeapFile != null) {
      intent.putExtra(ANALYZED_HEAP_PATH_EXTRA, analyzedHeapFile.getAbsolutePath());
    }
    ContextCompat.startForegroundService(context, intent);
  }

  public AbstractAnalysisResultService() {
    super(AbstractAnalysisResultService.class.getName(),
        R.string.leak_canary_notification_reporting);
  }

  @Override protected final void onHandleIntentInForeground(@Nullable Intent intent) {
    if (intent == null) {
      CanaryLog.d("AbstractAnalysisResultService received a null intent, ignoring.");
      return;
    }
    if (!intent.hasExtra(ANALYZED_HEAP_PATH_EXTRA)) {
      onAnalysisResultFailure(getString(R.string.leak_canary_result_failure_no_disk_space));
      return;
    }
    File analyzedHeapFile = new File(intent.getStringExtra(ANALYZED_HEAP_PATH_EXTRA));
    AnalyzedHeap analyzedHeap = AnalyzedHeap.load(analyzedHeapFile);
    if (analyzedHeap == null) {
      onAnalysisResultFailure(getString(R.string.leak_canary_result_failure_no_file));
      return;
    }
    try {
      onHeapAnalyzed(analyzedHeap);
    } finally {
      //noinspection ResultOfMethodCallIgnored
      analyzedHeap.heapDump.heapDumpFile.delete();
      //noinspection ResultOfMethodCallIgnored
      analyzedHeap.selfFile.delete();
    }
  }

  /**
   * Called after a heap dump is analyzed, whether or not a leak was found.
   * In {@link AnalyzedHeap#result} check {@link AnalysisResult#leakFound} and {@link
   * AnalysisResult#excludedLeak} to see if there was a leak and if it can be ignored.
   * <p>
   * This will be called from a background intent service thread.
   * <p>
   * It's OK to block here and wait for the heap dump to be uploaded.
   * <p>