Google is committed to advancing racial equity for Black communities. See how.

RFC-0074: Expose Process Start Time

RFC-0074: Expose Process Start Time
StatusAccepted
Areas
  • Zircon
Description

Make process start time queryable from userspace.

Issues
Gerrit change
Authors
Reviewers
Date submitted (year-month-day)2021-02-19
Date reviewed (year-month-day)2021-03-11

Summary

We refactor ZX_INFO_PROCESS to expose a process's start time and also to clean up the flags describing its runtime. We say a process has a valid start time when a ZX_INFO_PROCESS_FLAG_STARTED flag is present and define it to be the monotonic time at which zx_process_start() was called, when valid.

Motivation

First filed at crbug.com/726484 and then fxbug.dev/30751, Chromium requested the feature in order to give a base time for trace events, extending a platform-agnostic interface already supporting Linux, macOS, and Windows. Further, fxbug.dev/43108 was filed to leverage this same feature in order to include uptime in crash reports.

Design

In a small, straightforward extension of ProcessDispatcher, we would record the time in ProcessDispatcher::AddInitializedThread() for the initial thread and then pass it along in ProcessDispatcher::GetInfo(); the former method is the main "starting" routine of zx_process_start(), while the latter is that of zx_get_object_info() for a process handle with ZX_INFO_PROCESS.

As for the struct populated by zx_object_get_info(), currently we have typedef struct zx_info_process { // The process's return code; only valid if |exited| is true. // If the process was killed, it will be one of the ZX_TASK_RETCODE values. int64_t return_code; // True if the process has ever left the initial creation state, // even if it has exited as well. bool started; // If true, the process has exited and |return_code| is valid. bool exited; // True if a debugger is attached to the process. bool debugger_attached; uint8_t padding1[5]; } zx_info_process_t; We would evolve it to be typedef struct zx_info_process { // The process's return code; only valid if the // |ZX_PROCESS_INFO_FLAG_EXITED| flag is set. If the process was killed, it // will be one of the |ZX_TASK_RETCODE| values. int64_t return_code; // The monotonic time at which `zx_process_start()` was called, only valid // if the |ZX_INFO_PROCESS_FLAG_STARTED| flag is set. zx_time_t start_time; // Bitwise OR of ZX_INFO_PROCESS_FLAG_* values. uint32_t flags; uint8_t padding1[4]; } zx_info_process_t; for which the following flag values would be introduced: ``// Whether the process has started.zx_process_info_t::start_time` is only // valid if this flag is set.

define ZX_INFO_PROCESS_FLAG_STARTED (1u << 0)

// Whether the process has exited.

define ZX_INFO_PROCESS_FLAG_EXITED (1u << 1)

// Whether a debugger is attached to the process.

define ZX_INFO_PROCESS_FLAG_DEBUGGER_ATTACHED (1u << 2)

The boolean-to-flag refactor is not strictly necessary, but it would bring
`zx_info_process_t` in line with current syscall struct policy, save a byte
on padding, and would not increase the amount of work needed to carry out this
proposal (and also would save the next engineer from a fair amount of hassle).

## Implementation

1. Rename the old struct to `zx_info_process_v1_t` and create an alias to refer
to it by its old name (`zx_info_process_t` -> `zx_info_process_v1_t`). Rename
the topic `ZX_INFO_PROCESS` to `ZX_INFO_PROCESS_V1` and create an alias to the
old name (`ZX_INFO_PROCESS` -> `ZX_INFO_PROCESS_V1`).

2. Add the new struct (`zx_info_process_v2_t`) and topic
(`ZX_INFO_PROCESS_V2`). Change the kernel to track process start time and
recognize the new topic and struct.

3. Update all code (in-tree and out-of-tree) to use `ZX_INFO_PROCESS_V2`.

4. Change the `ZX_INFO_PROCESS` and `zx_info_process_t` alias to refer to the
v2 topic and struct.

5. Wait until the previous change has been fully rolled out.

6. Update all code (in-tree and out-of-tree) to use `ZX_INFO_PROCESS` again.

7. Remove the v1 topic and struct, as well as the v2 alias.

The Rust and Go versions of these types will be similarly updated.

## Performance

The added logic should incur a negligible runtime cost, especially as it would
be amortized over the lifetime of an individual process.

## Security considerations

If a program already has a handle to a process, it can do and glean much more
than the time at which that process started. Moreover, start time is already
exposed - without seeming concern - in a number of [other operating systems](#prior-art-and-references).

## Privacy considerations

See [Security considerations](#security-considerations) above.

## Testing

Zircon's process-related core tests will be extended to assert, for example,
that time samples taken before and after a `zx_process_start()` do indeed
sandwich the recorded start time, and that a not-yet-started process has
`ZX_INFO_PROCESS_FLAG_STARTED` unset.

## Documentation

`ZX_INFO_PROCESS` documentation will be updated accordingly.

## Drawbacks, alternatives, and unknowns

Also considered was exposing the "start" time as a more general, task-level
concept (exposed under, say, `ZX_INFO_TASK_RUNTIME`). For threads, things
extend indentically: a thread's start time is the point at which
`zx_thread_start()` is called. For a job, it would then be most natural to say
that it "starts" when its first child starts. Since jobs can be nested,
however, this would introduce walking task subtrees, which is relatively more
complicated logic than dealing with the other two task types. Ultimately the
extensions were decided against, as they would not meet a current need and
would allow us to sidestep the need for task hierarchy walking.

## Prior art and references

Linux:  [`/proc/[pid]/stat`](https://man7.org/linux/man-pages/man5/procfs.5.html) exposes `starttime`.
FreeBSD: [`/proc/[pid]/status`](https://www.freebsd.org/cgi/man.cgi?query=procfs) exposes start time in a space-separated list of statistics.
macOS: The `proc_pidinfo()` syscalls seems to expose this.
...

<!-- The footer below is automatically added to this file. Do not modify anything below this line. -->
<div class="align-right">
<a href="https://bugs.fuchsia.dev/p/fuchsia/issues/entry?template=Fuchsia.dev%20Documentation&description=Issue%20on%20page:%20https://ci.android.com/edit?repo=fuchsia/fuchsia/main%26file=docs/contribute/governance/rfcs/0074_expose_process_start_time.md" title="Report a bug or suggest improvements on this page"><span class="material-icons" style="font-size: 18px">bug_report</span></a>
<a href="https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/contribute/governance/rfcs/0074_expose_process_start_time.md" title="View the source code of this page"><span class="material-icons" style="font-size: 18px">code</span></a>
<a href="https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/contribute/governance/rfcs/0074_expose_process_start_time.md" title="Edit the source code of this page"><span class="material-icons" style="font-size: 18px">edit</span></a>
</div>