Merge "Revert "Fix bug with double unload on unsuccessful dlopen""
diff --git a/docs/32-bit-abi.md b/docs/32-bit-abi.md
index 5e3ae45..607b5d2 100644
--- a/docs/32-bit-abi.md
+++ b/docs/32-bit-abi.md
@@ -1,8 +1,6 @@
-32-bit ABI bugs
-===============
+# 32-bit ABI bugs
 
-`off_t` is 32-bit
------------------
+## 32-bit `off_t` and `_FILE_OFFSET_BITS=64`
 
 On 32-bit Android, `off_t` is a signed 32-bit integer. This limits functions
 that use `off_t` to working on files no larger than 2GiB.
@@ -34,13 +32,19 @@
 increase your target API level, you'll have more and more of the functions
 available. API 12 adds some of the `<unistd.h>` functions, API 21 adds `mmap`,
 and by API 24 you have everything including `<stdio.h>`. See the
-[linker map](libc/libc.map.txt) for full details.
+[linker map](libc/libc.map.txt) for full details. Note also that in NDK r16 and
+later, we inline an mmap64 implementation in the headers when you target an API
+before 21 because it's an easy special case that's often needed. This means
+that code using `_FILE_OFFSET_BITS=64` and `mmap` will always compile.
+
+If your code stops compiling when you move to NDK r15 or later, removing any
+definition of `_FILE_OFFSET_BITS=64` will restore the behavior you used to have:
+you'll have a 32-bit `off_t` and use the 32-bit functions.
 
 In the 64-bit ABI, `off_t` is always 64-bit.
 
 
-`sigset_t` is too small for real-time signals
----------------------------------------------
+## `sigset_t` is too small for real-time signals
 
 On 32-bit Android, `sigset_t` is too small for ARM and x86 (but correct for
 MIPS). This means that there is no support for real-time signals in 32-bit
@@ -49,8 +53,7 @@
 In the 64-bit ABI, `sigset_t` is the correct size for every architecture.
 
 
-`time_t` is 32-bit
-------------------
+## `time_t` is 32-bit
 
 On 32-bit Android, `time_t` is 32-bit. The header `<time64.h>` and type
 `time64_t` exist as a workaround, but the kernel interfaces exposed on 32-bit
@@ -58,8 +61,7 @@
 
 In the 64-bit ABI, `time_t` is 64-bit.
 
-`pthread_mutex_t` is too small for large pids
----------------------------------------------
+## `pthread_mutex_t` is too small for large pids
 
 This doesn't generally affect Android devices, because on devices
 `/proc/sys/kernel/pid_max` is usually too small to hit the 16-bit limit,
diff --git a/docs/status.md b/docs/status.md
index 6467143..0aaa0b3 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -1,6 +1,69 @@
 Android bionic status
 =====================
 
+# Target API level behavioral differences
+
+Most bionic bug fixes and improvements have been made without checks for
+the app's `targetSdkVersion`. As of O there were exactly two exceptions,
+but there are likely to be more in future because of Project Treble.
+
+Invalid `pthread_t` handling (targetSdkVersion >= O)
+----------------------------------------------------
+
+As part of a long-term goal to remove the global thread list,
+and in an attempt to flush out racy code, we changed how an invalid
+`pthread_t` is handled. For `pthread_detach`, `pthread_getcpuclockid`,
+`pthread_getschedparam`/`pthread_setschedparam`, `pthread_join`, and
+`pthread_kill`, instead of returning ESRCH when passed an invalid
+`pthread_t`, if you're targeting O or above, they'll abort with the
+message "attempt to use invalid pthread\_t".
+
+Note that this doesn't change behavior as much as you might think: the
+old lookup only held the global thread list lock for the duration of
+the lookup, so there was still a race between that and the dereference
+in the caller, given that callers actually need the tid to pass to some
+syscall or other, and sometimes update fields in the `pthread_internal_t`
+struct too.
+
+We can't check a thread's tid against 0 to see whether a `pthread_t`
+is still valid because a dead thread gets its thread struct unmapped
+along with its stack, so the dereference isn't safe.
+
+To fix your code, taking the affected functions one by one:
+
+  * `pthread_getcpuclockid` and `pthread_getschedparam`/`pthread_setschedparam`
+    should be fine. Unsafe calls to those seem highly unlikely.
+
+  * Unsafe `pthread_detach` callers probably want to switch to
+    `pthread_attr_setdetachstate` instead, or use
+    `pthread_detach(pthread_self());` from the new thread's start routine
+    rather than calling detach in the parent.
+
+  * `pthread_join` calls should be safe anyway, because a joinable thread
+    won't actually exit and unmap until it's joined. If you're joining an
+    unjoinable thread, the fix is to stop marking it detached. If you're
+    joining an already-joined thread, you need to rethink your design!
+
+  * Unsafe `pthread_kill` calls aren't portably fixable. (And are obviously
+    inherently non-portable as-is.) The best alternative on Android is to
+    use `pthread_gettid_np` at some point that you know the thread to be
+    alive, and then call `kill`/`tgkill` with signal 0 (which checks
+    whether a process exists rather than actually sending a
+    signal). That's still not completely safe because if you're too late
+    the tid may have been reused, but your code is inherently unsafe without
+    a redesign anyway.
+
+Interruptable `sem_wait` (targetSdkVersion >= N)
+------------------------------------------------
+
+POSIX says that `sem_wait` can be interrupted by delivery of a
+signal. This wasn't historically true in Android, and when we fixed this
+bug we found that existing code relied on the old behavior. To preserve
+compatibility, `sem_wait` can only return EINTR on Android if the app
+targets N or later.
+
+# Bionic function availability
+
 libc
 ----
 
@@ -8,18 +71,19 @@
 
 New libc functions in P:
   * `__freading`/`__fwriting` (completing <stdio_ext.h>)
-  * `endhostent`/endnetent`/`endprotoent`/`getnetent`/`getprotoent`/`sethostent`/`setnetent`/`setprotoent` (completing <netdb.h>)
+  * `endhostent`/`endnetent`/`endprotoent`/`getnetent`/`getprotoent`/`sethostent`/`setnetent`/`setprotoent` (completing <netdb.h>)
   * `fexecve`
   * `fflush_unlocked`/`fgetc_unlocked`/`fgets_unlocked`/`fputc_unlocked`/`fputs_unlocked`/`fread_unlocked`/`fwrite_unlocked`
   * `getentropy`/`getrandom` (adding <sys/random.h>)
   * `getlogin_r`
   * `glob`/`globfree` (adding <glob.h>)
-  * `hcreate`/hcreate_r`/`hdestroy`/`hdestroy_r`/`hsearch`/`hsearch_r` (completing <search.h>)
+  * `hcreate`/`hcreate_r`/`hdestroy`/`hdestroy_r`/`hsearch`/`hsearch_r` (completing <search.h>)
   * `iconv`/`iconv_close`/`iconv_open` (adding <iconv.h>)
   * `pthread_attr_getinheritsched`/`pthread_attr_setinheritsched`/`pthread_setschedprio`
   * <spawn.h>
   * `swab`
   * `syncfs`
+  * %C and %S support in the printf family (previously only the wprintf family supported these).
 
 New libc functions in O:
   * `sendto` FORTIFY support
diff --git a/libc/Android.bp b/libc/Android.bp
index b88c987..3ec75ee 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -2037,6 +2037,22 @@
 }
 
 ndk_headers {
+    name: "libc_asm_mips",
+    from: "kernel/uapi/asm-mips",
+    to: "mipsel-linux-android",
+    srcs: ["kernel/uapi/asm-mips/**/*.h"],
+    license: "NOTICE",
+}
+
+ndk_headers {
+    name: "libc_asm_mips64",
+    from: "kernel/uapi/asm-mips",
+    to: "mips64el-linux-android",
+    srcs: ["kernel/uapi/asm-mips/**/*.h"],
+    license: "NOTICE",
+}
+
+ndk_headers {
     name: "libc_asm_x86",
     from: "kernel/uapi/asm-x86",
     to: "i686-linux-android",
diff --git a/libc/bionic/vdso.cpp b/libc/bionic/vdso.cpp
index 8cdb504..969c39f 100644
--- a/libc/bionic/vdso.cpp
+++ b/libc/bionic/vdso.cpp
@@ -26,11 +26,18 @@
 #include <unistd.h>
 #include "private/KernelArgumentBlock.h"
 
+static inline int vdso_return(int result) {
+  if (__predict_true(result == 0)) return 0;
+
+  errno = -result;
+  return -1;
+}
+
 int clock_gettime(int clock_id, timespec* tp) {
   auto vdso_clock_gettime = reinterpret_cast<decltype(&clock_gettime)>(
     __libc_globals->vdso[VDSO_CLOCK_GETTIME].fn);
   if (__predict_true(vdso_clock_gettime)) {
-    return vdso_clock_gettime(clock_id, tp);
+    return vdso_return(vdso_clock_gettime(clock_id, tp));
   }
   return __clock_gettime(clock_id, tp);
 }
@@ -39,17 +46,15 @@
   auto vdso_gettimeofday = reinterpret_cast<decltype(&gettimeofday)>(
     __libc_globals->vdso[VDSO_GETTIMEOFDAY].fn);
   if (__predict_true(vdso_gettimeofday)) {
-    return vdso_gettimeofday(tv, tz);
+    return vdso_return(vdso_gettimeofday(tv, tz));
   }
   return __gettimeofday(tv, tz);
 }
 
 void __libc_init_vdso(libc_globals* globals, KernelArgumentBlock& args) {
   auto&& vdso = globals->vdso;
-  vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL,
-                               reinterpret_cast<void*>(__clock_gettime) };
-  vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL,
-                              reinterpret_cast<void*>(__gettimeofday) };
+  vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, nullptr };
+  vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, nullptr };
 
   // Do we have a vdso?
   uintptr_t vdso_ehdr_addr = args.getauxval(AT_SYSINFO_EHDR);
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 2d45fc5..e02a371 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -173,6 +173,7 @@
 int fseek(FILE* __fp, long __offset, int __whence);
 long ftell(FILE* __fp);
 
+/* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
 #if defined(__USE_FILE_OFFSET64)
 int fgetpos(FILE* __fp, fpos_t* __pos) __RENAME(fgetpos64) __INTRODUCED_IN(24);
 int fsetpos(FILE* __fp, const fpos_t* __pos) __RENAME(fsetpos64) __INTRODUCED_IN(24);
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 833ced0..3cf6723 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -205,25 +205,28 @@
  * In our header files we test against __USE_BSD and __USE_GNU.
  */
 #if defined(_GNU_SOURCE)
-# define __USE_BSD 1
-# define __USE_GNU 1
+#  define __USE_BSD 1
+#  define __USE_GNU 1
 #endif
 
 #if defined(_BSD_SOURCE)
-# define __USE_BSD 1
+#  define __USE_BSD 1
 #endif
 
-/* _FILE_OFFSET_BITS 64 support. */
+/*
+ * _FILE_OFFSET_BITS 64 support.
+ * See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md
+ */
 #if !defined(__LP64__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
-#define __USE_FILE_OFFSET64 1
+#  define __USE_FILE_OFFSET64 1
 /*
  * Note that __RENAME_IF_FILE_OFFSET64 is only valid if the off_t and off64_t
  * functions were both added at the same API level because if you use this,
  * you only have one declaration to attach __INTRODUCED_IN to.
  */
-#define __RENAME_IF_FILE_OFFSET64(func) __RENAME(func)
+#  define __RENAME_IF_FILE_OFFSET64(func) __RENAME(func)
 #else
-#define __RENAME_IF_FILE_OFFSET64(func)
+#  define __RENAME_IF_FILE_OFFSET64(func)
 #endif
 
 /*
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
index 028b024..5a7e3c0 100644
--- a/libc/include/sys/mman.h
+++ b/libc/include/sys/mman.h
@@ -44,8 +44,9 @@
 #define MREMAP_MAYMOVE  1
 #define MREMAP_FIXED    2
 
-#if defined(__USE_FILE_OFFSET64)
 /*
+ * See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md
+ *
  * mmap64 wasn't really around until L, but we added an inline for it since it
  * allows a lot more code to compile with _FILE_OFFSET_BITS=64.
  *
@@ -54,17 +55,18 @@
  * mmap64 to every translation unit that includes this header. Instead, just
  * preserve the old behavior for GCC and emit a useful diagnostic.
  */
+#if defined(__USE_FILE_OFFSET64)
 void* mmap(void* __addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset)
-#if !defined(__clang__) && __ANDROID_API__ < __ANDROID_API_L__
-    __attribute__((error("mmap is not available with _FILE_OFFSET_BITS=64 when using GCC until "
-                         "android-21. Either raise your minSdkVersion, disable "
-                         "_FILE_OFFSET_BITS=64, or switch to Clang.")));
-#else
+#  if !defined(__clang__) && __ANDROID_API__ < __ANDROID_API_L__
+      __attribute__((error("mmap is not available with _FILE_OFFSET_BITS=64 when using GCC until "
+                           "android-21. Either raise your minSdkVersion, disable "
+                           "_FILE_OFFSET_BITS=64, or switch to Clang.")));
+#  else
     __RENAME(mmap64);
-#endif  /* defined(__clang__) */
+#  endif
 #else
 void* mmap(void* __addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset);
-#endif  /* defined(__USE_FILE_OFFSET64) */
+#endif
 
 #if __ANDROID_API__ >= __ANDROID_API_L__
 void* mmap64(void* __addr, size_t __size, int __prot, int __flags, int __fd, off64_t __offset) __INTRODUCED_IN(21);
diff --git a/libc/include/sys/sendfile.h b/libc/include/sys/sendfile.h
index ecdb76c..97432c0 100644
--- a/libc/include/sys/sendfile.h
+++ b/libc/include/sys/sendfile.h
@@ -34,6 +34,7 @@
 
 __BEGIN_DECLS
 
+/* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
 #if defined(__USE_FILE_OFFSET64)
 ssize_t sendfile(int __out_fd, int __in_fd, off_t* __offset, size_t __count) __RENAME(sendfile64) __INTRODUCED_IN(21);
 #else
diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h
index 26ad6a5..f07c8fd 100644
--- a/libc/include/sys/types.h
+++ b/libc/include/sys/types.h
@@ -95,12 +95,13 @@
 typedef __kernel_time_t __time_t;
 typedef __time_t time_t;
 
+/* This historical accident means that we had a 32-bit off_t on 32-bit architectures. */
+/* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
 #if defined(__USE_FILE_OFFSET64) || defined(__LP64__)
 typedef int64_t off_t;
 typedef off_t loff_t;
 typedef loff_t off64_t;
 #else
-/* This historical accident means that we had a 32-bit off_t on 32-bit architectures. */
 typedef __kernel_off_t off_t;
 typedef __kernel_loff_t loff_t;
 typedef loff_t off64_t;
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index c60cf80..ef75c84 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -168,16 +168,10 @@
 int fsync(int __fd);
 int fdatasync(int __fd) __INTRODUCED_IN(9);
 
-#if defined(__USE_FILE_OFFSET64)
-off_t lseek(int __fd, off_t __offset, int __whence) __RENAME(lseek64);
-#else
-off_t lseek(int __fd, off_t __offset, int __whence);
-#endif
-
-off64_t lseek64(int __fd, off64_t __offset, int __whence);
-
+/* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
 #if defined(__USE_FILE_OFFSET64)
 int truncate(const char* __path, off_t __length) __RENAME(truncate64) __INTRODUCED_IN(21);
+off_t lseek(int __fd, off_t __offset, int __whence) __RENAME(lseek64);
 ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset)
   __overloadable __RENAME(pread64) __INTRODUCED_IN(12);
 ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset)
@@ -185,6 +179,7 @@
 int ftruncate(int __fd, off_t __length) __RENAME(ftruncate64) __INTRODUCED_IN(12);
 #else
 int truncate(const char* __path, off_t __length);
+off_t lseek(int __fd, off_t __offset, int __whence);
 ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset)
     __overloadable __RENAME_CLANG(pread);
 ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset)
@@ -193,6 +188,7 @@
 #endif
 
 int truncate64(const char* __path, off64_t __length) __INTRODUCED_IN(21);
+off64_t lseek64(int __fd, off64_t __offset, int __whence);
 ssize_t pread64(int __fd, void* __buf, size_t __count, off64_t __offset)
     __INTRODUCED_IN(12) __overloadable __RENAME_CLANG(pread64);
 ssize_t pwrite64(int __fd, const void* __buf, size_t __count, off64_t __offset)
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index d7ba379..4e90668 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -1385,7 +1385,7 @@
     exit(0);
   }
   ASSERT_NE(-1, pid);
-  ASSERT_EQ(pid, waitpid(pid, nullptr, 0));
+  ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
 
   // Read all of the contents.
   std::string actual;
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 3f59a9c..33dbfd9 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -324,7 +324,7 @@
   }
 
   int status;
-  if (waitpid(pid, &status, 0) != pid) {
+  if (TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)) != pid) {
     perror("waitpid");
     return false;
   }
diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp
index 78fcf2b..d460dec 100644
--- a/tests/sys_ptrace_test.cpp
+++ b/tests/sys_ptrace_test.cpp
@@ -51,7 +51,7 @@
   ~ChildGuard() {
     kill(pid, SIGKILL);
     int status;
-    waitpid(pid, &status, 0);
+    TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
   }
 
  private:
@@ -184,7 +184,7 @@
   ChildGuard guard(child);
 
   int status;
-  ASSERT_EQ(child, waitpid(child, &status, __WALL)) << strerror(errno);
+  ASSERT_EQ(child, TEMP_FAILURE_RETRY(waitpid(child, &status, __WALL))) << strerror(errno);
   ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
   ASSERT_EQ(SIGSTOP, WSTOPSIG(status)) << "Status was: " << status;
 
@@ -196,7 +196,7 @@
   set_watchpoint(child, uintptr_t(&data) + offset, size);
 
   ASSERT_EQ(0, ptrace(PTRACE_CONT, child, nullptr, nullptr)) << strerror(errno);
-  ASSERT_EQ(child, waitpid(child, &status, __WALL)) << strerror(errno);
+  ASSERT_EQ(child, TEMP_FAILURE_RETRY(waitpid(child, &status, __WALL))) << strerror(errno);
   ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
   ASSERT_EQ(SIGTRAP, WSTOPSIG(status)) << "Status was: " << status;
 
@@ -364,7 +364,7 @@
   ChildGuard guard(child);
 
   int status;
-  ASSERT_EQ(child, waitpid(child, &status, __WALL)) << strerror(errno);
+  ASSERT_EQ(child, TEMP_FAILURE_RETRY(waitpid(child, &status, __WALL))) << strerror(errno);
   ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
   ASSERT_EQ(SIGSTOP, WSTOPSIG(status)) << "Status was: " << status;
 
@@ -376,7 +376,7 @@
   set_breakpoint(child);
 
   ASSERT_EQ(0, ptrace(PTRACE_CONT, child, nullptr, nullptr)) << strerror(errno);
-  ASSERT_EQ(child, waitpid(child, &status, __WALL)) << strerror(errno);
+  ASSERT_EQ(child, TEMP_FAILURE_RETRY(waitpid(child, &status, __WALL))) << strerror(errno);
   ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
   ASSERT_EQ(SIGTRAP, WSTOPSIG(status)) << "Status was: " << status;
 
@@ -436,7 +436,7 @@
     }
 
     int result;
-    pid_t rc = waitpid(tracer, &result, 0);
+    pid_t rc = TEMP_FAILURE_RETRY(waitpid(tracer, &result, 0));
     if (rc != tracer) {
       printf("waitpid returned %d (%s)\n", rc, strerror(errno));
       return false;
@@ -463,7 +463,7 @@
     }
 
     int result;
-    pid_t rc = waitpid(worker, &result, WNOHANG);
+    pid_t rc = TEMP_FAILURE_RETRY(waitpid(worker, &result, WNOHANG));
     if (rc != 0) {
       printf("worker exited prematurely\n");
       return false;
@@ -471,7 +471,7 @@
 
     worker_pipe_write.reset();
 
-    rc = waitpid(worker, &result, 0);
+    rc = TEMP_FAILURE_RETRY(waitpid(worker, &result, 0));
     if (rc != worker) {
       printf("waitpid for worker returned %d (%s)\n", rc, strerror(errno));
       return false;
@@ -517,9 +517,9 @@
   std::this_thread::sleep_for(250ms);
 
   int result;
-  ASSERT_EQ(0, waitpid(worker, &result, WNOHANG));
+  ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitpid(worker, &result, WNOHANG)));
   ASSERT_TRUE(WaitForTracer());
-  ASSERT_EQ(worker, waitpid(worker, &result, 0));
+  ASSERT_EQ(worker, TEMP_FAILURE_RETRY(waitpid(worker, &result, 0)));
 }
 
 TEST_F(PtraceResumptionTest, seize) {
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index d553ff5..9218078 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -599,6 +599,53 @@
   ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &ts));
 }
 
+TEST(time, clock_gettime_unknown) {
+  errno = 0;
+  timespec ts;
+  ASSERT_EQ(-1, clock_gettime(-1, &ts));
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(time, clock_getres_CLOCK_REALTIME) {
+  timespec ts;
+  ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(1, ts.tv_nsec);
+  ASSERT_EQ(0, ts.tv_sec);
+}
+
+TEST(time, clock_getres_CLOCK_MONOTONIC) {
+  timespec ts;
+  ASSERT_EQ(0, clock_getres(CLOCK_MONOTONIC, &ts));
+  ASSERT_EQ(1, ts.tv_nsec);
+  ASSERT_EQ(0, ts.tv_sec);
+}
+
+TEST(time, clock_getres_CLOCK_PROCESS_CPUTIME_ID) {
+  timespec ts;
+  ASSERT_EQ(0, clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts));
+}
+
+TEST(time, clock_getres_CLOCK_THREAD_CPUTIME_ID) {
+  timespec ts;
+  ASSERT_EQ(0, clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts));
+}
+
+TEST(time, clock_getres_CLOCK_BOOTTIME) {
+  timespec ts;
+  ASSERT_EQ(0, clock_getres(CLOCK_BOOTTIME, &ts));
+  ASSERT_EQ(1, ts.tv_nsec);
+  ASSERT_EQ(0, ts.tv_sec);
+}
+
+TEST(time, clock_getres_unknown) {
+  errno = 0;
+  timespec ts = { -1, -1 };
+  ASSERT_EQ(-1, clock_getres(-1, &ts));
+  ASSERT_EQ(EINVAL, errno);
+  ASSERT_EQ(-1, ts.tv_nsec);
+  ASSERT_EQ(-1, ts.tv_sec);
+}
+
 TEST(time, clock) {
   // clock(3) is hard to test, but a 1s sleep should cost less than 1ms.
   clock_t t0 = clock();
diff --git a/tests/utils.h b/tests/utils.h
index ba006f1..410b427 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -29,6 +29,7 @@
 #include <regex>
 
 #include <android-base/file.h>
+#include <android-base/macros.h>
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 
@@ -140,7 +141,7 @@
 
 static inline void AssertChildExited(int pid, int expected_exit_status) {
   int status;
-  ASSERT_EQ(pid, waitpid(pid, &status, 0));
+  ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)));
   if (expected_exit_status >= 0) {
     ASSERT_TRUE(WIFEXITED(status));
     ASSERT_EQ(expected_exit_status, WEXITSTATUS(status));