class CpuProfilerStage extends StreamingStage implements CodeNavigator.Listener {

  public void startCapturing() {
    ProfilingConfiguration config = myProfilerConfigModel.getProfilingConfiguration();
    assert getStudioProfilers().getProcess() != null;
    Common.Process process = getStudioProfilers().getProcess();
    String traceFilePath = String.format("%s/%s-%d.trace", DAEMON_DEVICE_DIR_PATH, process.getName(), System.nanoTime());

    // Disable memory live allocation if config setting has the option set.
    if (config.isDisableLiveAllocation()) {
      getStudioProfilers().setMemoryLiveAllocationEnabled(false);
    }
    setCaptureState(CaptureState.STARTING);
    Cpu.CpuTraceConfiguration configuration = Cpu.CpuTraceConfiguration.newBuilder()
      .setAppName(process.getName())
      .setAbiCpuArch(process.getAbiCpuArch())
      .setInitiationType(TraceInitiationType.INITIATED_BY_UI)
      .setTempPath(traceFilePath) // TODO b/133321803 switch back to having daemon generates and provides the path.
      .setUserOptions(config.toProto())
      .addAllSymbolDirs(getStudioProfilers().getIdeServices().getNativeSymbolsDirectories())
      .build();

    if (getStudioProfilers().getIdeServices().getFeatureConfig().isUnifiedPipelineEnabled()) {
      Commands.Command startCommand = Commands.Command.newBuilder()
        .setStreamId(mySession.getStreamId())
        .setPid(mySession.getPid())
        .setType(Commands.Command.CommandType.START_CPU_TRACE)
        .setStartCpuTrace(Cpu.StartCpuTrace.newBuilder().setConfiguration(configuration).build())
        .build();

      Transport.ExecuteResponse response = getStudioProfilers().getClient().getTransportClient().execute(
        Transport.ExecuteRequest.newBuilder().setCommand(startCommand).build());
      TransportEventListener statusListener = new TransportEventListener(Common.Event.Kind.CPU_TRACE_STATUS,
                                                                         getStudioProfilers().getIdeServices().getMainExecutor(),
                                                                         event -> event.getCommandId() == response.getCommandId(),
                                                                         () -> mySession.getStreamId(),
                                                                         () -> mySession.getPid(),
                                                                         event -> {
                                                                           startCapturingCallback(
                                                                             event.getCpuTraceStatus().getTraceStartStatus());
                                                                           // unregisters the listener.
                                                                           return true;
                                                                         });
      getStudioProfilers().getTransportPoller().registerListener(statusListener);
    }
    else {
      CpuProfilingAppStartRequest request = CpuProfilingAppStartRequest.newBuilder()
        .setSession(mySession)
        .setConfiguration(configuration)
        .build();
      CompletableFuture.supplyAsync(
        () -> getCpuClient().startProfilingApp(request), getStudioProfilers().getIdeServices().getPoolExecutor())
        .thenAcceptAsync(response -> this.startCapturingCallback(response.getStatus()),
                         getStudioProfilers().getIdeServices().getMainExecutor());
    }

    getStudioProfilers().getIdeServices().getTemporaryProfilerPreferences().setBoolean(HAS_USED_CPU_CAPTURE, true);
    myInstructionsEaseOutModel.setCurrentPercentage(1);
  }

  public  CpuProfilerStage(@NotNull StudioProfilers profilers);
  public  CpuProfilerStage(@NotNull StudioProfilers profilers, @Nullable File importedTrace);
  @VisibleForTesting  CpuProfilerStage(@NotNull StudioProfilers profilers, @Nullable File importedTrace, @NotNull CpuCaptureParser captureParser);

}