Merge changes from topic "fdtrack" am: bd2ac8d335 am: 31e9511fe1

Change-Id: Ie53f6dbad108faa4cb447f8d4184e1aa38761150
diff --git a/libc/Android.bp b/libc/Android.bp
index ef1bbe8..0f8ed3e 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1085,7 +1085,7 @@
         "bionic/clone.cpp",
         "bionic/ctype.cpp",
         "bionic/dirent.cpp",
-        "bionic/dup2.cpp",
+        "bionic/dup.cpp",
         "bionic/environ.cpp",
         "bionic/error.cpp",
         "bionic/eventfd_read.cpp",
@@ -1094,7 +1094,9 @@
         "bionic/faccessat.cpp",
         "bionic/fchmod.cpp",
         "bionic/fchmodat.cpp",
+        "bionic/fcntl.cpp",
         "bionic/fdsan.cpp",
+        "bionic/fdtrack.cpp",
         "bionic/ffs.cpp",
         "bionic/fgetxattr.cpp",
         "bionic/flistxattr.cpp",
@@ -1163,6 +1165,7 @@
         "bionic/realpath.cpp",
         "bionic/reboot.cpp",
         "bionic/recv.cpp",
+        "bionic/recvmsg.cpp",
         "bionic/rename.cpp",
         "bionic/rmdir.cpp",
         "bionic/scandir.cpp",
@@ -1797,7 +1800,7 @@
     name: "bionic_libc_platform_headers",
     visibility: [
         "//art:__subpackages__",
-        "//bionic/libc:__subpackages__",
+        "//bionic:__subpackages__",
         "//frameworks:__subpackages__",
         "//external/perfetto:__subpackages__",
         "//external/scudo:__subpackages__",
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 517d5f9..1343e4e 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -123,12 +123,12 @@
 ssize_t     readv(int, const struct iovec*, int)   all
 ssize_t     writev(int, const struct iovec*, int)  all
 int         __fcntl64:fcntl64(int, int, void*)  lp32
-int         fcntl(int, int, void*)  lp64
+int         __fcntl:fcntl(int, int, void*)  lp64
 int         flock(int, int)   all
 int         __fchmod:fchmod(int, mode_t)  all
-int         dup(int)  all
 int         pipe2(int*, int) all
-int         dup3(int, int, int)   all
+int         __dup:dup(int)  all
+int         __dup3:dup3(int, int, int)   all
 int         fsync(int)  all
 int         fdatasync(int) all
 int         fchown:fchown32(int, uid_t, gid_t)  arm,x86
@@ -254,9 +254,9 @@
 int           shutdown(int, int)  arm,arm64,mips,mips64,x86_64
 int           setsockopt(int, int, int, const void*, socklen_t)  arm,arm64,mips,mips64,x86_64
 int           getsockopt(int, int, int, void*, socklen_t*)    arm,arm64,mips,mips64,x86_64
-ssize_t       recvmsg(int, struct msghdr*, unsigned int)   arm,arm64,mips,mips64,x86_64
+ssize_t       __recvmsg:recvmsg(int, struct msghdr*, unsigned int)   arm,arm64,mips,mips64,x86_64
 ssize_t       __sendmsg:sendmsg(int, const struct msghdr*, unsigned int)  arm,arm64,mips,mips64,x86_64
-int           recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*)   arm,arm64,mips,mips64,x86_64
+int           __recvmmsg:recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*)   arm,arm64,mips,mips64,x86_64
 int           __sendmmsg:sendmmsg(int, struct mmsghdr*, unsigned int, int)   arm,arm64,mips,mips64,x86_64
 
 # sockets for x86. These are done as an "indexed" call to socketcall syscall.
@@ -273,9 +273,9 @@
 int           setsockopt:socketcall:14(int, int, int, const void*, socklen_t)  x86
 int           getsockopt:socketcall:15(int, int, int, void*, socklen_t*)    x86
 int           __sendmsg:socketcall:16(int, const struct msghdr*, unsigned int)  x86
-int           recvmsg:socketcall:17(int, struct msghdr*, unsigned int)   x86
+int           __recvmsg:socketcall:17(int, struct msghdr*, unsigned int)   x86
 int           __accept4:socketcall:18(int, struct sockaddr*, socklen_t*, int)  x86
-int           recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*)   x86
+int           __recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*)   x86
 int           __sendmmsg:socketcall:20(int, struct mmsghdr*, unsigned int, int)   x86
 
 # scheduler & real-time
diff --git a/libc/bionic/NetdClientDispatch.cpp b/libc/bionic/NetdClientDispatch.cpp
index 463ef36..e6f4a97 100644
--- a/libc/bionic/NetdClientDispatch.cpp
+++ b/libc/bionic/NetdClientDispatch.cpp
@@ -18,6 +18,8 @@
 
 #include <sys/socket.h>
 
+#include "private/bionic_fdtrack.h"
+
 #ifdef __i386__
 #define __socketcall __attribute__((__cdecl__))
 #else
@@ -53,7 +55,7 @@
 };
 
 int accept4(int fd, sockaddr* addr, socklen_t* addr_length, int flags) {
-    return __netdClientDispatch.accept4(fd, addr, addr_length, flags);
+  return FDTRACK_CREATE(__netdClientDispatch.accept4(fd, addr, addr_length, flags));
 }
 
 int connect(int fd, const sockaddr* addr, socklen_t addr_length) {
@@ -74,5 +76,5 @@
 }
 
 int socket(int domain, int type, int protocol) {
-    return __netdClientDispatch.socket(domain, type, protocol);
+  return FDTRACK_CREATE(__netdClientDispatch.socket(domain, type, protocol));
 }
diff --git a/libc/bionic/dup2.cpp b/libc/bionic/dup.cpp
similarity index 83%
rename from libc/bionic/dup2.cpp
rename to libc/bionic/dup.cpp
index 98c5646..d9e89a5 100644
--- a/libc/bionic/dup2.cpp
+++ b/libc/bionic/dup.cpp
@@ -29,6 +29,15 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#include "private/bionic_fdtrack.h"
+
+extern "C" int __dup(int old_fd);
+extern "C" int __dup3(int old_fd, int new_fd, int flags);
+
+int dup(int old_fd) {
+  return FDTRACK_CREATE(__dup(old_fd));
+}
+
 int dup2(int old_fd, int new_fd) {
   // If old_fd is equal to new_fd and a valid file descriptor, dup2 returns
   // old_fd without closing it. This is not true of dup3, so we have to
@@ -40,5 +49,9 @@
     return old_fd;
   }
 
-  return dup3(old_fd, new_fd, 0);
+  return FDTRACK_CREATE(__dup3(old_fd, new_fd, 0));
+}
+
+int dup3(int old_fd, int new_fd, int flags) {
+  return FDTRACK_CREATE(__dup3(old_fd, new_fd, flags));
 }
diff --git a/libc/bionic/fcntl.cpp b/libc/bionic/fcntl.cpp
new file mode 100644
index 0000000..c508131
--- /dev/null
+++ b/libc/bionic/fcntl.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include <fcntl.h>
+
+#include "private/bionic_fdtrack.h"
+
+#if defined(__LP64__)
+
+extern "C" int __fcntl(int fd, int cmd, ...);
+
+int fcntl(int fd, int cmd, ...) {
+  va_list args;
+  va_start(args, cmd);
+
+  // This is a bit sketchy, especially because arg can be an int, but all of our
+  // supported 64-bit ABIs pass arg in a register.
+  void* arg = va_arg(args, void*);
+  va_end(args);
+
+  int rc = __fcntl(fd, cmd, arg);
+  if (cmd == F_DUPFD) {
+    return FDTRACK_CREATE_NAME("F_DUPFD", rc);
+  } else if (cmd == F_DUPFD_CLOEXEC) {
+    return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", rc);
+  }
+  return rc;
+}
+
+#else
+
+extern "C" int __fcntl64(int, int, ...);
+
+// For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
+int fcntl(int fd, int cmd, ...) {
+  va_list ap;
+
+  va_start(ap, cmd);
+  void* arg = va_arg(ap, void*);
+  va_end(ap);
+
+  if (cmd == F_DUPFD) {
+    return FDTRACK_CREATE_NAME("F_DUPFD", __fcntl64(fd, cmd, arg));
+  } else if (cmd == F_DUPFD_CLOEXEC) {
+    return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", __fcntl64(fd, cmd, arg));
+  }
+  return __fcntl64(fd, cmd, arg);
+}
+
+#endif
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index d4ac71c..ebc680f 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -43,6 +43,7 @@
 #include <platform/bionic/reserved_signals.h>
 #include <sys/system_properties.h>
 
+#include "private/bionic_fdtrack.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_inline_raise.h"
 #include "pthread_internal.h"
@@ -245,6 +246,7 @@
 }
 
 int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) {
+  FDTRACK_CLOSE(fd);
   FdEntry* fde = GetFdEntry(fd);
   if (!fde) {
     return __close(fd);
diff --git a/libc/bionic/fdtrack.cpp b/libc/bionic/fdtrack.cpp
new file mode 100644
index 0000000..1123512
--- /dev/null
+++ b/libc/bionic/fdtrack.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdatomic.h>
+
+#include <platform/bionic/fdtrack.h>
+#include <platform/bionic/reserved_signals.h>
+
+#include "private/bionic_fdtrack.h"
+#include "private/bionic_tls.h"
+#include "private/bionic_globals.h"
+
+_Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+
+bool android_fdtrack_get_enabled() {
+  return !__get_bionic_tls().fdtrack_disabled;
+}
+
+bool android_fdtrack_set_enabled(bool new_value) {
+  auto& tls = __get_bionic_tls();
+  bool prev = !tls.fdtrack_disabled;
+  tls.fdtrack_disabled = !new_value;
+  return prev;
+}
+
+bool android_fdtrack_compare_exchange_hook(android_fdtrack_hook_t* expected,
+                                           android_fdtrack_hook_t value) {
+  return atomic_compare_exchange_strong(&__android_fdtrack_hook, expected, value);
+}
+
+void __libc_init_fdtrack() {
+  // Register a no-op signal handler.
+  signal(BIONIC_SIGNAL_FDTRACK, [](int) {});
+}
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 2de1bc7..f08e582 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -37,27 +37,17 @@
 #include <sys/vfs.h>
 #include <unistd.h>
 
+#include "private/bionic_fdtrack.h"
+
 #if defined(__LP64__)
 #error This code is only needed on 32-bit systems!
 #endif
 
 // System calls we need.
-extern "C" int __fcntl64(int, int, void*);
 extern "C" int __llseek(int, unsigned long, unsigned long, off64_t*, int);
 extern "C" int __preadv64(int, const struct iovec*, int, long, long);
 extern "C" int __pwritev64(int, const struct iovec*, int, long, long);
 
-// For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
-int fcntl(int fd, int cmd, ...) {
-  va_list ap;
-
-  va_start(ap, cmd);
-  void* arg = va_arg(ap, void*);
-  va_end(ap);
-
-  return __fcntl64(fd, cmd, arg);
-}
-
 // For lseek64 we need to use the llseek system call which splits the off64_t in two and
 // returns the off64_t result via a pointer because 32-bit kernels can't return 64-bit results.
 off64_t lseek64(int fd, off64_t off, int whence) {
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index e4106e9..12628f7 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -104,6 +104,7 @@
 
   __system_properties_init(); // Requires 'environ'.
   __libc_init_fdsan(); // Requires system properties (for debug.fdsan).
+  __libc_init_fdtrack();
 
   SetDefaultHeapTaggingLevel();
 }
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 222e5d3..bd8685a 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include "private/bionic_fdtrack.h"
 #include "private/bionic_fortify.h"
 
 extern "C" int __openat(int, const char*, int, int);
@@ -62,13 +63,13 @@
     va_end(args);
   }
 
-  return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), mode);
+  return FDTRACK_CREATE(__openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), mode));
 }
 __strong_alias(open64, open);
 
 int __open_2(const char* pathname, int flags) {
   if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
-  return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0);
+  return FDTRACK_CREATE_NAME("open", __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0));
 }
 
 int openat(int fd, const char *pathname, int flags, ...) {
@@ -81,11 +82,11 @@
     va_end(args);
   }
 
-  return __openat(fd, pathname, force_O_LARGEFILE(flags), mode);
+  return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), mode));
 }
 __strong_alias(openat64, openat);
 
 int __openat_2(int fd, const char* pathname, int flags) {
   if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
-  return __openat(fd, pathname, force_O_LARGEFILE(flags), 0);
+  return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), 0));
 }
diff --git a/libc/bionic/recvmsg.cpp b/libc/bionic/recvmsg.cpp
new file mode 100644
index 0000000..003f43d
--- /dev/null
+++ b/libc/bionic/recvmsg.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <sys/socket.h>
+
+#include <async_safe/log.h>
+
+#include "private/bionic_fdtrack.h"
+
+extern "C" ssize_t __recvmsg(int __fd, struct msghdr* __msg, int __flags);
+extern "C" int __recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags,
+                          const struct timespec* __timeout);
+
+static inline __attribute__((artificial)) __attribute__((always_inline)) void track_fds(
+    struct msghdr* msg, const char* function_name) {
+  if (!__android_fdtrack_hook) {
+    return;
+  }
+
+  for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+    if (cmsg->cmsg_type != SCM_RIGHTS) {
+      continue;
+    }
+
+    if (cmsg->cmsg_len <= sizeof(struct cmsghdr)) {
+      continue;
+    }
+
+    size_t data_length = cmsg->cmsg_len - sizeof(struct cmsghdr);
+    if (data_length % sizeof(int) != 0) {
+      async_safe_fatal("invalid cmsg length: %zu", data_length);
+    }
+
+    for (size_t offset = 0; offset < data_length; offset += sizeof(int)) {
+      int fd;
+      memcpy(&fd, CMSG_DATA(cmsg) + offset, sizeof(int));
+      FDTRACK_CREATE_NAME(function_name, fd);
+    }
+  }
+}
+
+ssize_t recvmsg(int __fd, struct msghdr* __msg, int __flags) {
+  ssize_t rc = __recvmsg(__fd, __msg, __flags);
+  if (rc == -1) {
+    return -1;
+  }
+  track_fds(__msg, "recvmsg");
+  return rc;
+}
+
+int recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags,
+             const struct timespec* __timeout) {
+  int rc = __recvmmsg(__fd, __msgs, __msg_count, __flags, __timeout);
+  if (rc == -1) {
+    return -1;
+  }
+  for (int i = 0; i < rc; ++i) {
+    track_fds(&__msgs[i].msg_hdr, "recvmmsg");
+  }
+  return rc;
+}
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 2710fb2..2ca4b21 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1752,6 +1752,9 @@
     __system_property_set_filename;
     __system_property_update;
     android_fdsan_get_fd_table;
+    android_fdtrack_compare_exchange_hook; # llndk
+    android_fdtrack_get_enabled; # llndk
+    android_fdtrack_set_enabled; # llndk
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/platform/bionic/fdtrack.h b/libc/platform/bionic/fdtrack.h
new file mode 100644
index 0000000..6eb379b
--- /dev/null
+++ b/libc/platform/bionic/fdtrack.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+// Types of an android_fdtrack_event.
+enum android_fdtrack_event_type {
+  // File descriptor creation: create is the active member of android_fdtrack_event::data.
+  ANDROID_FDTRACK_EVENT_TYPE_CREATE,
+
+  // File descriptor closed.
+  ANDROID_FDTRACK_EVENT_TYPE_CLOSE,
+};
+
+struct android_fdtrack_event {
+  // File descriptor for which this event occurred.
+  int fd;
+
+  // Type of event: this is one of the enumerators of android_fdtrack_event_type.
+  uint8_t type;
+
+  // Data for the event.
+  union {
+    struct {
+      const char* function_name;
+    } create;
+  } data;
+};
+
+// Callback invoked upon file descriptor creation/closure.
+typedef void (*android_fdtrack_hook_t)(struct android_fdtrack_event*);
+
+// Register a hook which is called to track fd lifecycle events.
+bool android_fdtrack_compare_exchange_hook(android_fdtrack_hook_t* expected, android_fdtrack_hook_t value) __INTRODUCED_IN(30);
+
+// Enable/disable fdtrack *on the current thread*.
+// This is primarily useful when performing operations which you don't want to track
+// (e.g. when emitting already-recorded information).
+bool android_fdtrack_get_enabled() __INTRODUCED_IN(30);
+bool android_fdtrack_set_enabled(bool new_value) __INTRODUCED_IN(30);
+
+__END_DECLS
diff --git a/libc/platform/bionic/reserved_signals.h b/libc/platform/bionic/reserved_signals.h
index 7634b27..4ac6455 100644
--- a/libc/platform/bionic/reserved_signals.h
+++ b/libc/platform/bionic/reserved_signals.h
@@ -42,14 +42,16 @@
 //   36 (__SIGRTMIN + 4)        platform profilers (heapprofd, traced_perf)
 //   37 (__SIGRTMIN + 5)        coverage (libprofile-extras)
 //   38 (__SIGRTMIN + 6)        heapprofd ART managed heap dumps
+//   39 (__SIGRTMIN + 7)        fdtrack
 //
 // If you change this, also change __ndk_legacy___libc_current_sigrtmin
 // in <android/legacy_signal_inlines.h> to match.
 
 #define BIONIC_SIGNAL_DEBUGGER __SIGRTMIN + 3
 #define BIONIC_SIGNAL_PROFILER __SIGRTMIN + 4
+#define BIONIC_SIGNAL_FDTRACK __SIGRTMIN + 7
 
-#define __SIGRT_RESERVED 7
+#define __SIGRT_RESERVED 8
 static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset, int how) {
   int (*block)(sigset64_t*, int);
   int (*unblock)(sigset64_t*, int);
@@ -77,5 +79,6 @@
   unblock(&sigset, __SIGRTMIN + 4);
   unblock(&sigset, __SIGRTMIN + 5);
   unblock(&sigset, __SIGRTMIN + 6);
+  unblock(&sigset, __SIGRTMIN + 7);
   return sigset;
 }
diff --git a/libc/private/bionic_fdtrack.h b/libc/private/bionic_fdtrack.h
new file mode 100644
index 0000000..174ba1d
--- /dev/null
+++ b/libc/private/bionic_fdtrack.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <stdatomic.h>
+
+#include "platform/bionic/fdtrack.h"
+
+#include "bionic/pthread_internal.h"
+#include "private/bionic_tls.h"
+#include "private/ErrnoRestorer.h"
+
+extern "C" _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+
+// Macro to record file descriptor creation.
+// e.g.:
+//   int socket(int domain, int type, int protocol) {
+//     return FDTRACK_CREATE_NAME("socket", __socket(domain, type, protocol));
+//   }
+#define FDTRACK_CREATE_NAME(name, fd_value)                       \
+  ({                                                              \
+    int __fd = (fd_value);                                        \
+    if (__fd != -1 && __predict_false(__android_fdtrack_hook)) {  \
+      bionic_tls& tls = __get_bionic_tls();                       \
+      /* fdtrack_disabled is only true during reentrant calls. */ \
+      if (!__predict_false(tls.fdtrack_disabled)) {               \
+        ErrnoRestorer r;                                          \
+        tls.fdtrack_disabled = true;                              \
+        android_fdtrack_event event;                              \
+        event.fd = __fd;                                          \
+        event.type = ANDROID_FDTRACK_EVENT_TYPE_CREATE;           \
+        event.data.create.function_name = name;                   \
+        __android_fdtrack_hook(&event);                           \
+        tls.fdtrack_disabled = false;                             \
+      }                                                           \
+    }                                                             \
+    __fd;                                                         \
+  })
+
+// Macro to record file descriptor creation, with the current function's name.
+// e.g.:
+//   int socket(int domain, int type, int protocol) {
+//     return FDTRACK_CREATE_NAME(__socket(domain, type, protocol));
+//   }
+#define FDTRACK_CREATE(fd_value) FDTRACK_CREATE_NAME(__func__, (fd_value))
+
+// Macro to record file descriptor closure.
+// Note that this does not actually close the file descriptor.
+#define FDTRACK_CLOSE(fd_value)                                  \
+  ({                                                             \
+    int __fd = (fd_value);                                       \
+    if (__fd != -1 && __predict_false(__android_fdtrack_hook)) { \
+      bionic_tls& tls = __get_bionic_tls();                      \
+      if (!__predict_false(tls.fdtrack_disabled)) {              \
+        int saved_errno = errno;                                 \
+        tls.fdtrack_disabled = true;                             \
+        android_fdtrack_event event;                             \
+        event.fd = __fd;                                         \
+        event.type = ANDROID_FDTRACK_EVENT_TYPE_CLOSE;           \
+        __android_fdtrack_hook(&event);                          \
+        tls.fdtrack_disabled = false;                            \
+        errno = saved_errno;                                     \
+      }                                                          \
+    }                                                            \
+    __fd;                                                        \
+  })
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 8997ceb..4cc9bbe 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -100,6 +100,7 @@
 
 __LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals();
 __LIBC_HIDDEN__ void __libc_init_fdsan();
+__LIBC_HIDDEN__ void __libc_init_fdtrack();
 __LIBC_HIDDEN__ void __libc_init_profiling_handlers();
 
 __LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals);
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index bb5c67b..80d645a 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -128,6 +128,9 @@
   group_state_t group;
   passwd_state_t passwd;
 
+  char fdtrack_disabled;
+  char padding[3];
+
   // Initialize the main thread's final object using its bootstrap object.
   void copy_from_bootstrap(const bionic_tls* boot __attribute__((unused))) {
     // Nothing in bionic_tls needs to be preserved in the transition to the
diff --git a/libfdtrack/.clang-format b/libfdtrack/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libfdtrack/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libfdtrack/Android.bp b/libfdtrack/Android.bp
new file mode 100644
index 0000000..fd13512
--- /dev/null
+++ b/libfdtrack/Android.bp
@@ -0,0 +1,18 @@
+cc_library_shared {
+    name: "libfdtrack",
+    srcs: ["fdtrack.cpp"],
+    stl: "libc++_static",
+
+    header_libs: ["bionic_libc_platform_headers"],
+    static_libs: [
+        "libasync_safe",
+        "libbase",
+        "libunwindstack",
+        "liblzma",
+        "liblog",
+    ],
+    version_script: "libfdtrack.map.txt",
+
+    allow_undefined_symbols: true,
+    recovery_available: true,
+}
diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp
new file mode 100644
index 0000000..831a50d
--- /dev/null
+++ b/libfdtrack/fdtrack.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+
+#include <array>
+#include <mutex>
+#include <vector>
+
+#include <android/fdsan.h>
+#include <bionic/fdtrack.h>
+
+#include <android-base/no_destructor.h>
+#include <android-base/thread_annotations.h>
+#include <async_safe/log.h>
+#include <bionic/reserved_signals.h>
+#include <unwindstack/LocalUnwinder.h>
+
+struct FdEntry {
+  std::mutex mutex;
+  std::vector<unwindstack::LocalFrameData> backtrace GUARDED_BY(mutex);
+};
+
+extern "C" void fdtrack_dump();
+static void fd_hook(android_fdtrack_event* event);
+
+// Backtraces for the first 4k file descriptors ought to be enough to diagnose an fd leak.
+static constexpr size_t kFdTableSize = 4096;
+static constexpr size_t kStackDepth = 10;
+
+static bool installed = false;
+static std::array<FdEntry, kFdTableSize> stack_traces;
+static unwindstack::LocalUnwinder& Unwinder() {
+  static android::base::NoDestructor<unwindstack::LocalUnwinder> unwinder;
+  return *unwinder.get();
+}
+
+__attribute__((constructor)) static void ctor() {
+  signal(BIONIC_SIGNAL_FDTRACK, [](int) { fdtrack_dump(); });
+  if (Unwinder().Init()) {
+    android_fdtrack_hook_t expected = nullptr;
+    installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
+  }
+}
+
+__attribute__((destructor)) static void dtor() {
+  if (installed) {
+    android_fdtrack_hook_t expected = &fd_hook;
+    android_fdtrack_compare_exchange_hook(&expected, nullptr);
+  }
+}
+
+FdEntry* GetFdEntry(int fd) {
+  if (fd >= 0 && fd < static_cast<int>(kFdTableSize)) {
+    return &stack_traces[fd];
+  }
+  return nullptr;
+}
+
+static void fd_hook(android_fdtrack_event* event) {
+  if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CREATE) {
+    if (FdEntry* entry = GetFdEntry(event->fd); entry) {
+      std::lock_guard<std::mutex> lock(entry->mutex);
+      entry->backtrace.clear();
+      Unwinder().Unwind(&entry->backtrace, kStackDepth);
+    }
+  } else if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CLOSE) {
+    if (FdEntry* entry = GetFdEntry(event->fd); entry) {
+      std::lock_guard<std::mutex> lock(entry->mutex);
+      entry->backtrace.clear();
+    }
+  }
+}
+
+void fdtrack_dump() {
+  if (!installed) {
+    async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack not installed");
+  } else {
+    async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack dumping...");
+  }
+
+  bool prev = android_fdtrack_set_enabled(false);
+  for (int fd = 0; fd < static_cast<int>(stack_traces.size()); ++fd) {
+    FdEntry* entry = GetFdEntry(fd);
+    if (!entry) {
+      continue;
+    }
+
+    if (!entry->mutex.try_lock()) {
+      async_safe_format_log(ANDROID_LOG_WARN, "fdtrack", "fd %d locked, skipping", fd);
+      continue;
+    }
+
+    if (entry->backtrace.empty()) {
+      continue;
+    }
+
+    uint64_t fdsan_owner = android_fdsan_get_owner_tag(fd);
+
+    if (fdsan_owner != 0) {
+      async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (owner = %#" PRIx64 ")", fd,
+                            fdsan_owner);
+    } else {
+      async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (unowned)", fd);
+    }
+
+    const size_t frame_skip = 2;
+    for (size_t i = frame_skip; i < entry->backtrace.size(); ++i) {
+      auto& frame = entry->backtrace[i];
+      async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "  %zu: %s+%" PRIu64, i - frame_skip,
+                            frame.function_name.c_str(), frame.function_offset);
+    }
+
+    entry->mutex.unlock();
+  }
+  android_fdtrack_set_enabled(prev);
+}
diff --git a/libfdtrack/libfdtrack.map.txt b/libfdtrack/libfdtrack.map.txt
new file mode 100644
index 0000000..7a54c35
--- /dev/null
+++ b/libfdtrack/libfdtrack.map.txt
@@ -0,0 +1,6 @@
+LIBFDTRACK {
+  global:
+    fdtrack_dump;
+  local:
+    *;
+};
diff --git a/tests/Android.bp b/tests/Android.bp
index 7219fc5..1ef7b0e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -91,6 +91,7 @@
         "eventfd_test.cpp",
         "fcntl_test.cpp",
         "fdsan_test.cpp",
+        "fdtrack_test.cpp",
         "fenv_test.cpp",
         "_FILE_OFFSET_BITS_test.cpp",
         "float_test.cpp",
diff --git a/tests/fdtrack_test.cpp b/tests/fdtrack_test.cpp
new file mode 100644
index 0000000..fca92ce
--- /dev/null
+++ b/tests/fdtrack_test.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if defined(__BIONIC__)
+#include "platform/bionic/fdtrack.h"
+#endif
+
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+#if defined(__BIONIC__)
+std::vector<android_fdtrack_event> FdtrackRun(void (*func)()) {
+  // Each bionic test is run in separate process, so we can safely use a static here.
+  static std::vector<android_fdtrack_event> events;
+  events.clear();
+
+  android_fdtrack_hook_t previous = nullptr;
+  android_fdtrack_hook_t hook = [](android_fdtrack_event* event) {
+    events.push_back(*event);
+  };
+
+  if (!android_fdtrack_compare_exchange_hook(&previous, hook)) {
+    errx(1, "failed to exchange hook: previous hook was %p", previous);
+  }
+
+  if (previous) {
+    errx(1, "hook was already registered?");
+    abort();
+  }
+
+  func();
+
+  if (!android_fdtrack_compare_exchange_hook(&hook, nullptr)) {
+    errx(1, "failed to reset hook");
+  }
+
+  return std::move(events);
+}
+#endif
+
+TEST(fdtrack, open) {
+#if defined(__BIONIC__)
+  static int fd = -1;
+  auto events = FdtrackRun([]() { fd = open("/dev/null", O_WRONLY | O_CLOEXEC); });
+  ASSERT_NE(-1, fd);
+  ASSERT_EQ(1U, events.size());
+  ASSERT_EQ(fd, events[0].fd);
+  ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[0].type);
+  ASSERT_STREQ("open", events[0].data.create.function_name);
+#endif
+}
+
+TEST(fdtrack, close) {
+#if defined(__BIONIC__)
+  static int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
+  ASSERT_NE(-1, fd);
+
+  auto events = FdtrackRun([]() { close(fd); });
+  ASSERT_EQ(1U, events.size());
+  ASSERT_EQ(fd, events[0].fd);
+  ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CLOSE, events[0].type);
+#endif
+}
+
+TEST(fdtrack, enable_disable) {
+#if defined(__BIONIC__)
+  static int fd1 = -1;
+  static int fd2 = -1;
+  static int fd3 = -1;
+
+  auto events = FdtrackRun([]() {
+    if (!android_fdtrack_get_enabled()) {
+      errx(1, "fdtrack is disabled");
+    }
+    fd1 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+    android_fdtrack_set_enabled(false);
+    fd2 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+    android_fdtrack_set_enabled(true);
+    fd3 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+  });
+
+  if (fd1 == -1 || fd2 == -1 || fd3 == -1) {
+    errx(1, "failed to open /dev/null");
+  }
+
+  ASSERT_EQ(2U, events.size());
+
+  ASSERT_EQ(fd1, events[0].fd);
+  ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[0].type);
+  ASSERT_STREQ("open", events[0].data.create.function_name);
+
+  ASSERT_EQ(fd3, events[1].fd);
+  ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[1].type);
+  ASSERT_STREQ("open", events[1].data.create.function_name);
+#endif
+}