1## fdtrack 2 3[TOC] 4 5fdtrack is a file descriptor leak checker added to Android in API level 30. 6 7fdtrack consists of two parts: a set of hooks in bionic to register a callback 8that's invoked on file descriptor operations, and a library that implements a 9hook to perform and store backtraces for file descriptor creation. 10 11### bionic hooks 12bionic provides a header in the `bionic_libc_platform_headers` header_lib at <[bionic/fdtrack.h](https://android.googlesource.com/platform/bionic/+/refs/heads/main/libc/platform/bionic/fdtrack.h)>. 13Register a callback with `android_fdtrack_compare_exchange_hook` to receive 14callbacks upon file descriptor creation and destruction. This function can be 15called at any point in order to start capturing events, but be sure to properly 16handle unbalanced closes. This callback may be called from an async signal safe 17context, but not vfork (bionic tracks whether a thread is vforked, and chooses 18not to call callbacks when this is the case). 19 20### libfdtrack 21[libfdtrack](https://android.googlesource.com/platform/bionic/+/refs/heads/main/libfdtrack) 22implements a library that uses libunwindstack to unwind and store fd creation backtraces. 23 24 25#### Using libfdtrack 26libfdtrack registers its hook upon being loaded, so to start capturing 27backtraces, `dlopen("libfdtrack.so", RTLD_GLOBAL)` is all that's needed. To dump 28its output to logcat, either use `fdtrack_dump`, or send the signal 29`BIONIC_SIGNAL_FDTRACK` (available from `<bionic/reserved_signals.h>`) to the 30process. If you wish to iterate through the results programmatically, 31`fdtrack_iterate` can be used (warning: this interface is currently unstable, 32don't use it in code that can be used on multiple platform versions.) 33 34libfdtrack adds a significant amount of overhead, so for processes that are 35latency-critical like system_server, it's not feasible to always capture 36backtraces. Instead, if you can detect that an fd leak is ongoing, turning on 37backtraces for a while and then triggering a dump can be sufficient. 38system_server [implements this approach](https://android.googlesource.com/platform/frameworks/base/+/679f3e4242b8e018eb7df90ef433f81088a64fff%5E%21/), 39spawning a thread that regularly checks the count of fds in the process, turns 40on fdtrack when it hits a threshold, and then aborts after another threshold. 41This dumps the output to logcat, which will be available in both the tombstone 42and logcat from bugreports. 43 44#### Implementation details 45There are multiple methods to unwind in Android: 46 47 * libunwindstack 48 * Pros 49 * Primary method on the platform 50 * Able to unwind through ART 51 * Cons 52 * Uses malloc internally: unsafe unless a separate allocator is 53 statically-linked and steps are taken to prevent the unwind from being 54 interrupted by a signal 55 * Slow - infeasible to be used always in latency-sensitive processes 56 * `android_unsafe_frame_pointer_chase` 57 * Pros 58 * Definitely async signal safe 59 * Fast 60 * Cons 61 * Unable to unwind through ART because it doesn't maintain the frame pointer 62 * Requires -fno-omit-frame-pointer to be used on all code being unwound 63 through, which currently isn't the case on Android 64 * Frame layout is a mess on 32-bit ARM: the ARM standard, clang, and GCC 65 [all disagree](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172) 66 * Chasing the frame pointer will often result in multiple frames inside the 67 same function 68 69libfdtrack chooses to use libunwindstack for now, since unwinding through ART 70is critical to being useful for the initial user, system_server. 71