Running perfetto in detached mode

This document describes the --detach and --attach advanced operating modes of the perfetto cmdline client.

The use of --detach and --attach is highly discouraged because of the risk of leaking tracing sessions and accidentally leaving tracing on for arbitrarily long periods of time.

If what you are looking for is just a way to grab a trace in background (e.g., while the USB cable / adb is disconnected) from the adb shell simply use --background.

Use case

By default the tracing service traced keeps the lifetime of a tracing session attached to the lifetime of the perfetto cmdline client that started it. This means that a killall perfetto or kill $PID_OF_PERFETTO is sufficient to guarantee that the tracing session is stopped.
There are rare occasions when this is undesirable.

The use case this has been designed for is the Traceur app (on-device tracing UI for Android).
When required by the user, Traceur needs to enable tracing in the background, possibly for very long periods of time. Because Traceur is not a persistent service (and even if it was, it could be still low-memory-killed), it cannot just use --background. This is because the Android framework kills any other process in the same process group when tearing down an app/service, and this would including killing forked perfetto client obtained via --background.

Operation

--detach=key decouples the lifetime of the cmdline client from the lifetime of the tracing session.

The key argument is an arbitrary string passed by the client to later re-identify the session using --attach=key.

Once detached, the cmdline client will exit (without forking any bg process) and the traced service will keep the tracing session alive.
Because of the exit, a client that wants to use --detach needs to set the write_into_file flag in the trace config, which transfers the output trace file descriptor to the service (see the examples section).

A detached session will run until either:

  • The session is later re-attached and stopped.
  • The time limit specified by the duration_ms argument in the trace config is reached.

--attach=key re-couples the lifetime of a new cmdline client invocation with an existing tracing session identified by key. For security reasons the service allows a client to re-attach to a tracing session only if the Unix UID of the re-attaching client matches the UID of the client that originally started the session and detached.

Overall --attach=key makes the perfetto cmdline client behave as if it was never detached. This means that:

  • sending a SIGKILL (or Ctrl-C) to the client will gracefully stop the tracing session.
  • If the duration_ms time limit is hit, the client will be informed by the service and exit soon after.

When re-attaching it is possible to also specify a further --stop argument. --stop will gracefully terminate the tracing session immediately after re-attaching (This is to avoid a race where SIGKILL is sent too early, before the client gets a chance to attach or even register the signal handler).

No other cmdline argument other than --stop can be passed when using --attach.

--is_detached=key can be used to check whether a detached session is running. The cmdline client will return quickly after the invocation with the following exit code:

  • 0 if the session identified by key exists and can be re-attached.
  • 1 in case of a general error (e.g. wrong cmdline, cannot reach the service).
  • 2 if no detached session with the given key is found.

Examples

Capturing a long trace in detached mode

echo '
write_into_file: true
# Long tracing mode, periodically flush the trace buffer into the trace file.
file_write_period_ms: 5000

buffers {
  # This buffer needs to be big enough just to hold data between two consecutive
  # |file_write_period|s (5s in this examples).
  size_kb: 16384
}

data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      ftrace_events: "sched_switch"
    }
  }
}
' | perfetto -c - --txt --detach=session1 -o /data/misc/perfetto-traces/trace

sleep 60

perfetto --attach=session1 --stop
# At this point the trace file is fully flushed into
# /data/misc/perfetto-traces/trace.

Start in detached ring-buffer mode. Later stop and save the ring buffer

echo '
write_into_file: true

# Specify an arbitrarily long flush period. Practically this means: never flush
# unless trace is stopped.
# TODO(primiano): an explicit no_periodic_flushes argument would be nicer. Maybe
# we could repurpose the 0 value?
file_write_period_ms: 1000000000

buffers {
  # This will be the size of the final trace.
  size_kb: 16384
}

data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      ftrace_events: "sched_switch"
    }
  }
}
' | perfetto -c - --txt --detach=session2 -o /data/misc/perfetto-traces/trace

# Wait for user input, or some critical event to happen.

perfetto --attach=session2 --stop

# At this point the trace file is saved into
# /data/misc/perfetto-traces/trace.

Start tracing with a time limit. Later re-attach and wait for the end

echo '
duration_ms: 10000
write_into_file: true

buffers {
  size_kb: 16384
}

data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      ftrace_events: "sched_switch"
    }
  }
}
' | perfetto -c - --txt --detach=session3 -o /data/misc/perfetto-traces/trace

sleep 3
perfetto --attach=session3
# The cmdline client will stay up for 7 more seconds and then terminate.