Merge "Add newline at end of error message"
diff --git a/apex/Android.bp b/apex/Android.bp
index f6820d1..8c8853f 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -37,3 +37,28 @@
     key: "com.android.runtime.key",
     certificate: ":com.android.runtime.certificate",
 }
+
+sdk {
+    name: "runtime-module-sdk",
+    defaults: ["linux_bionic_supported"],
+
+    native_header_libs: [
+        "bionic_libc_platform_headers",
+        "libc_headers",
+    ],
+    native_shared_libs: [
+        "libc",
+        "libdl",
+        "libdl_android",
+        "libm",
+    ],
+    native_static_libs: [
+        "libasync_safe",
+    ],
+    native_objects: [
+        "crtbegin_dynamic",
+        "crtbegin_so",
+        "crtend_android",
+        "crtend_so",
+    ],
+}
diff --git a/docs/32-bit-abi.md b/docs/32-bit-abi.md
index 81afd14..3be6b1a 100644
--- a/docs/32-bit-abi.md
+++ b/docs/32-bit-abi.md
@@ -81,13 +81,23 @@
 in the 64-bit ABI even though they're identical to the non-`64` names.
 
 
-## `time_t` is 32-bit
+## `time_t` is 32-bit on LP32 (y2038)
 
-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
-Android all use the 32-bit `time_t`.
+On 32-bit Android, `time_t` is 32-bit, which will overflow in 2038.
 
-In the 64-bit ABI, `time_t` is 64-bit.
+In the 64-bit ABI, `time_t` is 64-bit, which will not overflow until
+long after the death of the star around which we currently circle.
+
+The header `<time64.h>` and type `time64_t` exist as a workaround,
+but the kernel interfaces exposed on 32-bit Android all use the 32-bit
+`time_t` and `struct timespec`/`struct timeval`. Linux 5.x kernels
+do offer extra interfaces so that 32-bit processes can pass 64-bit
+times to/from the kernel, but we do not plan on adding support for
+these to the C library. Convenient use of the new calls would require
+an equivalent to `_FILE_OFFSET_BITS=64`, which we wouldn't be able
+to globally flip for reasons similar to `_FILE_OFFSET_BITS`, mentioned
+above. All apps are already required to offer 64-bit variants, and we
+expect 64-bit-only devices within the next few years.
 
 
 ## `pthread_mutex_t` is too small for large pids
diff --git a/libc/Android.bp b/libc/Android.bp
index 7614784..4e5ae75 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1774,6 +1774,7 @@
         "//system/core/debuggerd:__subpackages__",
         "//system/core/libunwindstack:__subpackages__",
         "//system/memory/libmemunreachable:__subpackages__",
+        "//tools/security/sanitizer-status:__subpackages__",
     ],
     vendor_available: true,
     ramdisk_available: true,
@@ -2387,6 +2388,7 @@
         "SECCOMP_WHITELIST_COMMON.TXT",
         "SECCOMP_WHITELIST_APP.TXT",
         "SECCOMP_BLACKLIST_COMMON.TXT",
+        "SECCOMP_PRIORITY.TXT",
         ":generate_app_zygote_blacklist",
         ":libseccomp_gen_syscall_nrs_arm",
         ":libseccomp_gen_syscall_nrs_arm64",
@@ -2415,6 +2417,7 @@
         "SECCOMP_WHITELIST_APP.TXT",
         "SECCOMP_BLACKLIST_COMMON.TXT",
         "SECCOMP_BLACKLIST_APP.TXT",
+        "SECCOMP_PRIORITY.TXT",
         ":libseccomp_gen_syscall_nrs_arm",
         ":libseccomp_gen_syscall_nrs_arm64",
         ":libseccomp_gen_syscall_nrs_x86",
@@ -2441,6 +2444,7 @@
         "SECCOMP_WHITELIST_COMMON.TXT",
         "SECCOMP_WHITELIST_SYSTEM.TXT",
         "SECCOMP_BLACKLIST_COMMON.TXT",
+        "SECCOMP_PRIORITY.TXT",
         ":libseccomp_gen_syscall_nrs_arm",
         ":libseccomp_gen_syscall_nrs_arm64",
         ":libseccomp_gen_syscall_nrs_x86",
@@ -2548,7 +2552,7 @@
         "//apex_available:platform",
         "com.android.media.swcodec",
     ],
-    min_sdk_version: "29",
+    min_sdk_version: "apex_inherit",
 }
 
 subdirs = [
diff --git a/libc/SECCOMP_PRIORITY.TXT b/libc/SECCOMP_PRIORITY.TXT
new file mode 100644
index 0000000..fb5ad4a
--- /dev/null
+++ b/libc/SECCOMP_PRIORITY.TXT
@@ -0,0 +1,10 @@
+# This file is used to populate seccomp's whitelist policy in combination with SYSCALLS.TXT.
+# Note that the resultant policy is applied only to zygote spawned processes.
+#
+# This file is processed by a python script named genseccomp.py.
+#
+# The syscalls below are prioritized above other syscalls when checking seccomp policy, in
+# the order of appearance in this file.
+
+futex
+ioctl
\ No newline at end of file
diff --git a/libc/bionic/clock.cpp b/libc/bionic/clock.cpp
index fda0708..31e6c3c 100644
--- a/libc/bionic/clock.cpp
+++ b/libc/bionic/clock.cpp
@@ -35,8 +35,6 @@
 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock.html
 clock_t clock() {
   timespec ts;
-  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
-    return -1;
-  }
+  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
   return (ts.tv_sec * CLOCKS_PER_SEC) + (ts.tv_nsec / (NS_PER_S / CLOCKS_PER_SEC));
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index a47c2fc..1ede969 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -241,37 +241,38 @@
   // of executing a setuid program or the result of an SELinux
   // security transition.
   static constexpr const char* UNSAFE_VARIABLE_NAMES[] = {
-    "ANDROID_DNS_MODE",
-    "GCONV_PATH",
-    "GETCONF_DIR",
-    "HOSTALIASES",
-    "JE_MALLOC_CONF",
-    "LD_AOUT_LIBRARY_PATH",
-    "LD_AOUT_PRELOAD",
-    "LD_AUDIT",
-    "LD_CONFIG_FILE",
-    "LD_DEBUG",
-    "LD_DEBUG_OUTPUT",
-    "LD_DYNAMIC_WEAK",
-    "LD_LIBRARY_PATH",
-    "LD_ORIGIN_PATH",
-    "LD_PRELOAD",
-    "LD_PROFILE",
-    "LD_SHOW_AUXV",
-    "LD_USE_LOAD_BIAS",
-    "LIBC_DEBUG_MALLOC_OPTIONS",
-    "LIBC_HOOKS_ENABLE",
-    "LOCALDOMAIN",
-    "LOCPATH",
-    "MALLOC_CHECK_",
-    "MALLOC_CONF",
-    "MALLOC_TRACE",
-    "NIS_PATH",
-    "NLSPATH",
-    "RESOLV_HOST_CONF",
-    "RES_OPTIONS",
-    "TMPDIR",
-    "TZDIR",
+      "ANDROID_DNS_MODE",
+      "GCONV_PATH",
+      "GETCONF_DIR",
+      "HOSTALIASES",
+      "JE_MALLOC_CONF",
+      "LD_AOUT_LIBRARY_PATH",
+      "LD_AOUT_PRELOAD",
+      "LD_AUDIT",
+      "LD_CONFIG_FILE",
+      "LD_DEBUG",
+      "LD_DEBUG_OUTPUT",
+      "LD_DYNAMIC_WEAK",
+      "LD_LIBRARY_PATH",
+      "LD_ORIGIN_PATH",
+      "LD_PRELOAD",
+      "LD_PROFILE",
+      "LD_SHOW_AUXV",
+      "LD_USE_LOAD_BIAS",
+      "LIBC_DEBUG_MALLOC_OPTIONS",
+      "LIBC_HOOKS_ENABLE",
+      "LOCALDOMAIN",
+      "LOCPATH",
+      "MALLOC_CHECK_",
+      "MALLOC_CONF",
+      "MALLOC_TRACE",
+      "NIS_PATH",
+      "NLSPATH",
+      "RESOLV_HOST_CONF",
+      "RES_OPTIONS",
+      "SCUDO_OPTIONS",
+      "TMPDIR",
+      "TZDIR",
   };
   for (const auto& unsafe_variable_name : UNSAFE_VARIABLE_NAMES) {
     if (env_match(name, unsafe_variable_name) != nullptr) {
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index 583bf32..1cdb021 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -85,6 +85,28 @@
 
 extern "C" int __rt_sigaction(int, const struct sigaction64*, struct sigaction64*, size_t);
 
+// sigaction and sigaction64 get interposed in ART: ensure that we don't end up calling
+//     sigchain sigaction -> bionic sigaction -> sigchain sigaction64 -> bionic sigaction64
+// by extracting the implementation of sigaction64 to a static function.
+static int __sigaction64(int signal, const struct sigaction64* bionic_new,
+                         struct sigaction64* bionic_old) {
+  struct sigaction64 kernel_new;
+  if (bionic_new) {
+    kernel_new = *bionic_new;
+#if defined(SA_RESTORER)
+    if (!(kernel_new.sa_flags & SA_RESTORER)) {
+      kernel_new.sa_flags |= SA_RESTORER;
+      kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
+    }
+#endif
+    // Don't filter signals here; if the caller asked for everything to be blocked, we should obey.
+    kernel_new.sa_mask = kernel_new.sa_mask;
+  }
+
+  return __rt_sigaction(signal, bionic_new ? &kernel_new : nullptr, bionic_old,
+                        sizeof(kernel_new.sa_mask));
+}
+
 int sigaction(int signal, const struct sigaction* bionic_new, struct sigaction* bionic_old) {
   // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t,
   // so we have to translate to struct sigaction64 first.
@@ -101,7 +123,7 @@
   }
 
   struct sigaction64 kernel_old;
-  int result = sigaction64(signal, bionic_new ? &kernel_new : nullptr, &kernel_old);
+  int result = __sigaction64(signal, bionic_new ? &kernel_new : nullptr, &kernel_old);
   if (bionic_old) {
     *bionic_old = {};
     bionic_old->sa_flags = kernel_old.sa_flags;
@@ -115,23 +137,7 @@
 }
 
 int sigaction64(int signal, const struct sigaction64* bionic_new, struct sigaction64* bionic_old) {
-  struct sigaction64 kernel_new;
-  if (bionic_new) {
-    kernel_new = *bionic_new;
-#if defined(SA_RESTORER)
-    if (!(kernel_new.sa_flags & SA_RESTORER)) {
-      kernel_new.sa_flags |= SA_RESTORER;
-      kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
-    }
-#endif
-    // Don't filter signals here; if the caller asked for everything to be blocked, we should obey.
-    kernel_new.sa_mask = kernel_new.sa_mask;
-  }
-
-  return __rt_sigaction(signal,
-                        bionic_new ? &kernel_new : nullptr,
-                        bionic_old,
-                        sizeof(kernel_new.sa_mask));
+  return __sigaction64(signal, bionic_new, bionic_old);
 }
 
 #endif
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index b04cfe1..760039b 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -173,6 +173,7 @@
 
     shared_libs: [
         "libbase",
+        "libbacktrace",
         "liblog",
         "libunwindstack",
     ],
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 6eaac7d..609f030 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -30,11 +30,13 @@
 #include <inttypes.h>
 #include <malloc.h>
 #include <pthread.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/cdefs.h>
 #include <sys/param.h>
+#include <sys/syscall.h>
 #include <unistd.h>
 
 #include <mutex>
@@ -44,8 +46,9 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <bionic/malloc_tagged_pointers.h>
-#include <private/bionic_malloc_dispatch.h>
+#include <platform/bionic/reserved_signals.h>
 #include <private/MallocXmlElem.h>
+#include <private/bionic_malloc_dispatch.h>
 
 #include "Config.h"
 #include "DebugData.h"
@@ -131,6 +134,40 @@
 };
 pthread_rwlock_t ScopedConcurrentLock::lock_;
 
+// Use this because the sigprocmask* functions filter out the reserved bionic
+// signals including the signal this code blocks.
+static inline int __rt_sigprocmask(int how, const sigset64_t* new_set, sigset64_t* old_set,
+                                   size_t sigset_size) {
+  return syscall(SYS_rt_sigprocmask, how, new_set, old_set, sigset_size);
+}
+
+// Need to block the backtrace signal while in malloc debug routines
+// otherwise there is a chance of a deadlock and timeout when unwinding.
+// This can occur if a thread is paused while owning a malloc debug
+// internal lock.
+class ScopedBacktraceSignalBlocker {
+ public:
+  ScopedBacktraceSignalBlocker() {
+    sigemptyset64(&backtrace_set_);
+    sigaddset64(&backtrace_set_, BIONIC_SIGNAL_BACKTRACE);
+    sigset64_t old_set;
+    __rt_sigprocmask(SIG_BLOCK, &backtrace_set_, &old_set, sizeof(backtrace_set_));
+    if (sigismember64(&old_set, BIONIC_SIGNAL_BACKTRACE)) {
+      unblock_ = false;
+    }
+  }
+
+  ~ScopedBacktraceSignalBlocker() {
+    if (unblock_) {
+      __rt_sigprocmask(SIG_UNBLOCK, &backtrace_set_, nullptr, sizeof(backtrace_set_));
+    }
+  }
+
+ private:
+  bool unblock_ = true;
+  sigset64_t backtrace_set_;
+};
+
 static void InitAtfork() {
   static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
   pthread_once(&atfork_init, []() {
@@ -334,8 +371,8 @@
 void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
                                 size_t* total_memory, size_t* backtrace_size) {
   ScopedConcurrentLock lock;
-
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   // Verify the arguments.
   if (info == nullptr || overall_size == nullptr || info_size == nullptr || total_memory == nullptr ||
@@ -370,6 +407,7 @@
   }
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   if (!VerifyPointer(pointer, "malloc_usable_size")) {
     return 0;
@@ -434,6 +472,7 @@
   }
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   void* pointer = InternalMalloc(size);
 
@@ -510,6 +549,7 @@
   }
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   if (g_debug->config().options() & RECORD_ALLOCS) {
     g_debug->record->AddEntry(new FreeEntry(pointer));
@@ -528,6 +568,7 @@
   }
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   if (bytes == 0) {
     bytes = 1;
@@ -607,6 +648,7 @@
   }
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   if (pointer == nullptr) {
     pointer = InternalMalloc(bytes);
@@ -726,6 +768,7 @@
   }
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   size_t size;
   if (__builtin_mul_overflow(nmemb, bytes, &size)) {
@@ -792,6 +835,7 @@
 
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   // Avoid any issues where allocations are made that will be freed
   // in the fclose.
@@ -880,6 +924,7 @@
   }
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   if (!(g_debug->config().options() & BACKTRACE)) {
     return 0;
@@ -938,6 +983,7 @@
 
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   std::lock_guard<std::mutex> guard(g_dump_lock);
 
@@ -953,6 +999,7 @@
 void debug_dump_heap(const char* file_name) {
   ScopedConcurrentLock lock;
   ScopedDisableDebugCalls disable;
+  ScopedBacktraceSignalBlocker blocked;
 
   std::lock_guard<std::mutex> guard(g_dump_lock);
 
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index ac19cf9..1bfe61e 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -42,12 +42,20 @@
 #include <gtest/gtest.h>
 #include <log/log_read.h>
 
+#include <atomic>
 #include <string>
 #include <thread>
 #include <vector>
 
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
 #include <bionic/malloc.h>
 
+// All DISABLED_ tests are designed to be executed after malloc debug
+// is enabled. These tests don't run be default, and are executed
+// by wrappers that will enable various malloc debug features.
+
 static constexpr time_t kTimeoutSeconds = 10;
 
 extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
@@ -525,3 +533,42 @@
   ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"},
                           std::vector<const char*>{" HAS INVALID TAG ", "USED AFTER FREE ", "UNKNOWN POINTER "}));
 }
+
+TEST(MallocTests, DISABLED_malloc_and_backtrace_deadlock) {
+  std::atomic_bool running(false);
+  pid_t tid;
+  std::thread thread([&tid, &running] {
+    tid = gettid();
+    running = true;
+    while (running) {
+      void* ptr = malloc(200);
+      if (ptr == nullptr) {
+        return;
+      }
+      free(ptr);
+    }
+  });
+
+  while (!running) {
+  }
+
+  static constexpr size_t kNumUnwinds = 1000;
+  for (size_t i = 0; i < kNumUnwinds; i++) {
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
+    ASSERT_TRUE(backtrace->Unwind(0)) << "Failed on unwind " << i;
+    ASSERT_LT(1, backtrace->NumFrames()) << "Failed on unwind " << i;
+  }
+  running = false;
+  thread.join();
+}
+
+TEST(MallocDebugSystemTest, malloc_and_backtrace_deadlock) {
+  pid_t pid;
+  ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_malloc_and_backtrace_deadlock",
+                               "verbose verify_pointers", &pid, 0, 180));
+
+  // Make sure that malloc debug is enabled and that no timeouts occur during
+  // unwinds.
+  ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"},
+                                      std::vector<const char*>{"Timed out waiting for "}));
+}
diff --git a/libc/platform/bionic/mte.h b/libc/platform/bionic/mte.h
index fbf3895..1e393eb 100644
--- a/libc/platform/bionic/mte.h
+++ b/libc/platform/bionic/mte.h
@@ -31,16 +31,14 @@
 #include <sys/auxv.h>
 #include <bionic/mte_kernel.h>
 
-#ifdef __aarch64__
 inline bool mte_supported() {
-#ifdef ANDROID_EXPERIMENTAL_MTE
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
   static bool supported = getauxval(AT_HWCAP2) & HWCAP2_MTE;
 #else
   static bool supported = false;
 #endif
   return supported;
 }
-#endif
 
 #ifdef __aarch64__
 class ScopedDisableMTE {
diff --git a/libc/platform/bionic/reserved_signals.h b/libc/platform/bionic/reserved_signals.h
index c90fc06..e8e517e 100644
--- a/libc/platform/bionic/reserved_signals.h
+++ b/libc/platform/bionic/reserved_signals.h
@@ -48,6 +48,7 @@
 // in <android/legacy_signal_inlines.h> to match.
 
 #define BIONIC_SIGNAL_POSIX_TIMERS (__SIGRTMIN + 0)
+#define BIONIC_SIGNAL_BACKTRACE (__SIGRTMIN + 1)
 #define BIONIC_SIGNAL_DEBUGGER (__SIGRTMIN + 3)
 #define BIONIC_SIGNAL_PROFILER (__SIGRTMIN + 4)
 #define BIONIC_SIGNAL_ART_PROFILER (__SIGRTMIN + 6)
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
index cc0ff99..ba7e2ca 100755
--- a/libc/tools/genseccomp.py
+++ b/libc/tools/genseccomp.py
@@ -12,6 +12,7 @@
 
 
 BPF_JGE = "BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, {0}, {1}, {2})"
+BPF_JEQ = "BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, {0}, {1}, {2})"
 BPF_ALLOW = "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)"
 
 
@@ -37,6 +38,24 @@
   return set([x["name"] for x in parser.syscalls if x.get(architecture)])
 
 
+def load_syscall_priorities_from_file(file_path):
+  format_re = re.compile(r'^\s*([A-Za-z_][A-Za-z0-9_]+)\s*$')
+  priorities = []
+  with open(file_path) as f:
+    for line in f:
+      m = format_re.match(line)
+      if not m:
+        continue
+      try:
+        name = m.group(1)
+        priorities.append(name)
+      except:
+        logging.debug('Failed to parse %s from %s', (line, file_path))
+        pass
+
+  return priorities
+
+
 def merge_names(base_names, whitelist_names, blacklist_names):
   if bool(blacklist_names - base_names):
     raise RuntimeError("Blacklist item not in bionic - aborting " + str(
@@ -45,6 +64,20 @@
   return (base_names - blacklist_names) | whitelist_names
 
 
+def extract_priority_syscalls(syscalls, priorities):
+  # Extract syscalls that are not in the priority list
+  other_syscalls = \
+    [syscall for syscall in syscalls if syscall[0] not in priorities]
+  # For prioritized syscalls, keep the order in which they appear in th
+  # priority list
+  syscall_dict = {syscall[0]: syscall[1] for syscall in syscalls}
+  priority_syscalls = []
+  for name in priorities:
+    if name in syscall_dict.keys():
+      priority_syscalls.append((name, syscall_dict[name]))
+  return priority_syscalls, other_syscalls
+
+
 def parse_syscall_NRs(names_path):
   # The input is now the preprocessed source file. This will contain a lot
   # of junk from the preprocessor, but our lines will be in the format:
@@ -123,8 +156,21 @@
     return jump + first + second
 
 
-def convert_ranges_to_bpf(ranges):
-  bpf = convert_to_intermediate_bpf(ranges)
+# Converts the prioritized syscalls to a bpf list that  is prepended to the
+# tree generated by convert_to_intermediate_bpf(). If we hit one of these
+# syscalls, shortcut to the allow statement at the bottom of the tree
+# immediately
+def convert_priority_to_intermediate_bpf(priority_syscalls):
+  result = []
+  for i, syscall in enumerate(priority_syscalls):
+    result.append(BPF_JEQ.format(syscall[1], "{allow}", 0) +
+                  ", //" + syscall[0])
+  return result
+
+
+def convert_ranges_to_bpf(ranges, priority_syscalls):
+  bpf = convert_priority_to_intermediate_bpf(priority_syscalls) + \
+    convert_to_intermediate_bpf(ranges)
 
   # Now we know the size of the tree, we can substitute the {fail} and {allow}
   # placeholders
@@ -135,9 +181,8 @@
     # With bpfs jmp 0 means the next statement, so the distance to the end is
     # len(bpf) - i - 1, which is where we will put the kill statement, and
     # then the statement after that is the allow statement
-    if "{fail}" in statement and "{allow}" in statement:
-      bpf[i] = statement.format(fail=str(len(bpf) - i),
-                                allow=str(len(bpf) - i - 1))
+    bpf[i] = statement.format(fail=str(len(bpf) - i),
+                              allow=str(len(bpf) - i - 1))
 
   # Add the allow calls at the end. If the syscall is not matched, we will
   # continue. This allows the user to choose to match further syscalls, and
@@ -174,13 +219,15 @@
   return header + "\n".join(bpf) + footer
 
 
-def construct_bpf(syscalls, architecture, name_modifier):
-  ranges = convert_NRs_to_ranges(syscalls)
-  bpf = convert_ranges_to_bpf(ranges)
+def construct_bpf(syscalls, architecture, name_modifier, priorities):
+  priority_syscalls, other_syscalls = \
+    extract_priority_syscalls(syscalls, priorities)
+  ranges = convert_NRs_to_ranges(other_syscalls)
+  bpf = convert_ranges_to_bpf(ranges, priority_syscalls)
   return convert_bpf_to_output(bpf, architecture, name_modifier)
 
 
-def gen_policy(name_modifier, out_dir, base_syscall_file, syscall_files, syscall_NRs):
+def gen_policy(name_modifier, out_dir, base_syscall_file, syscall_files, syscall_NRs, priority_file):
   for arch in SupportedArchitectures:
     base_names = load_syscall_names_from_file(base_syscall_file, arch)
     whitelist_names = set()
@@ -190,6 +237,9 @@
         blacklist_names |= load_syscall_names_from_file(f, arch)
       else:
         whitelist_names |= load_syscall_names_from_file(f, arch)
+    priorities = []
+    if priority_file:
+      priorities = load_syscall_priorities_from_file(priority_file)
 
     allowed_syscalls = []
     for name in merge_names(base_names, whitelist_names, blacklist_names):
@@ -198,7 +248,7 @@
       except:
         logging.exception("Failed to find %s in %s", name, arch)
         raise
-    output = construct_bpf(allowed_syscalls, arch, name_modifier)
+    output = construct_bpf(allowed_syscalls, arch, name_modifier, priorities)
 
     # And output policy
     existing = ""
@@ -226,6 +276,7 @@
                             "following files: \n"
                             "* /blacklist.*\.txt$/ syscall blacklist.\n"
                             "* /whitelist.*\.txt$/ syscall whitelist.\n"
+                            "* /priority.txt$/ priorities for bpf rules.\n"
                             "* otherwise, syscall name-number mapping.\n"))
   args = parser.parse_args()
 
@@ -235,17 +286,21 @@
     logging.basicConfig(level=logging.INFO)
 
   syscall_files = []
+  priority_file = None
   syscall_NRs = {}
   for filename in args.files:
     if filename.lower().endswith('.txt'):
-      syscall_files.append(filename)
+      if filename.lower().endswith('priority.txt'):
+        priority_file = filename
+      else:
+        syscall_files.append(filename)
     else:
       m = re.search(r"libseccomp_gen_syscall_nrs_([^/]+)", filename)
       syscall_NRs[m.group(1)] = parse_syscall_NRs(filename)
 
   gen_policy(name_modifier=args.name_modifier, out_dir=args.out_dir,
              syscall_NRs=syscall_NRs, base_syscall_file=args.base_file,
-             syscall_files=args.files)
+             syscall_files=syscall_files, priority_file=priority_file)
 
 
 if __name__ == "__main__":
diff --git a/linker/Android.bp b/linker/Android.bp
index 1792c74..08b2c7b 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -318,6 +318,10 @@
         "linker_version_script_overlay",
     ],
 
+    srcs: [
+        "linker_translate_path.cpp",
+    ],
+
     symlinks: ["linker_asan"],
     multilib: {
         lib64: {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b368e96..edf0329 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -65,6 +65,7 @@
 #include "linker_phdr.h"
 #include "linker_relocate.h"
 #include "linker_tls.h"
+#include "linker_translate_path.h"
 #include "linker_utils.h"
 
 #include "private/bionic_call_ifunc_resolver.h"
@@ -103,7 +104,6 @@
 static const char* const kAsanSystemLibDir    = "/data/asan/system/lib64";
 static const char* const kAsanOdmLibDir       = "/data/asan/odm/lib64";
 static const char* const kAsanVendorLibDir    = "/data/asan/vendor/lib64";
-static const char* const kI18nApexLibDir      = "/apex/com.android.i18n/lib64";
 #else
 static const char* const kSystemLibDir        = "/system/lib";
 static const char* const kOdmLibDir           = "/odm/lib";
@@ -111,7 +111,6 @@
 static const char* const kAsanSystemLibDir    = "/data/asan/system/lib";
 static const char* const kAsanOdmLibDir       = "/data/asan/odm/lib";
 static const char* const kAsanVendorLibDir    = "/data/asan/vendor/lib";
-static const char* const kI18nApexLibDir      = "/apex/com.android.i18n/lib";
 #endif
 
 static const char* const kAsanLibDirPrefix = "/data/asan";
@@ -235,44 +234,6 @@
 }
 // END OF WORKAROUND
 
-// Workaround for dlopen(/system/lib(64)/<soname>) when .so is in /apex. http://b/121248172
-/**
- * Translate /system path to /apex path if needed
- * The workaround should work only when targetSdkVersion < Q.
- *
- * param out_name_to_apex pointing to /apex path
- * return true if translation is needed
- */
-static bool translateSystemPathToApexPath(const char* name, std::string* out_name_to_apex) {
-  static const char* const kSystemToArtApexLibs[] = {
-    "libicuuc.so",
-    "libicui18n.so",
-  };
-  // New mapping for new apex should be added below
-
-  // Nothing to do if target sdk version is Q or above
-  if (get_application_target_sdk_version() >= 29) {
-    return false;
-  }
-
-  // If the path isn't /system/lib, there's nothing to do.
-  if (name == nullptr || dirname(name) != kSystemLibDir) {
-    return false;
-  }
-
-  const char* base_name = basename(name);
-
-  for (const char* soname : kSystemToArtApexLibs) {
-    if (strcmp(base_name, soname) == 0) {
-      *out_name_to_apex = std::string(kI18nApexLibDir) + "/" + base_name;
-      return true;
-    }
-  }
-
-  return false;
-}
-// End Workaround for dlopen(/system/lib/<soname>) when .so is in /apex.
-
 static std::vector<std::string> g_ld_preload_names;
 
 static void notify_gdb_of_load(soinfo* info) {
diff --git a/linker/linker_translate_path.cpp b/linker/linker_translate_path.cpp
new file mode 100644
index 0000000..4f3fdfb
--- /dev/null
+++ b/linker/linker_translate_path.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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 "linker.h"
+#include "linker_translate_path.h"
+#include "linker_utils.h"
+
+#if defined(__LP64__)
+#define APEX_LIB(apex, name) \
+  { "/system/lib64/" name, "/apex/" apex "/lib64/" name }
+#else
+#define APEX_LIB(apex, name) \
+  { "/system/lib/" name, "/apex/" apex "/lib/" name }
+#endif
+
+
+// Workaround for dlopen(/system/lib(64)/<soname>) when .so is in /apex. http://b/121248172
+/**
+ * Translate /system path to /apex path if needed
+ * The workaround should work only when targetSdkVersion < Q.
+ *
+ * param out_name_to_apex pointing to /apex path
+ * return true if translation is needed
+ */
+bool translateSystemPathToApexPath(const char* name, std::string* out_name_to_apex) {
+  static constexpr const char* kPathTranslationQ[][2] = {
+      APEX_LIB("com.android.i18n", "libicui18n.so"),
+      APEX_LIB("com.android.i18n", "libicuuc.so")
+  };
+
+  if (name == nullptr) {
+    return false;
+  }
+
+  auto comparator = [name](auto p) { return strcmp(name, p[0]) == 0; };
+
+  if (get_application_target_sdk_version() < __ANDROID_API_Q__) {
+    if (auto it =
+            std::find_if(std::begin(kPathTranslationQ), std::end(kPathTranslationQ), comparator);
+        it != std::end(kPathTranslationQ)) {
+      *out_name_to_apex = (*it)[1];
+      return true;
+    }
+  }
+
+  return false;
+}
+// End Workaround for dlopen(/system/lib/<soname>) when .so is in /apex.
diff --git a/linker/linker_translate_path.h b/linker/linker_translate_path.h
new file mode 100644
index 0000000..86a3ec1
--- /dev/null
+++ b/linker/linker_translate_path.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 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 <string>
+
+bool translateSystemPathToApexPath(const char* name, std::string* out_name_to_apex);
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 3241a1e..1139e53 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -244,7 +244,6 @@
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicui18n.so", RTLD_NOW) != nullptr);
 }
 
-/* TODO: Re-enable test when the cuttlefish build is fixed. http://b/156315785
 TEST(dlfcn, dlopen_system_libicuuc_android_api_level_29) {
   android_set_application_target_sdk_version(29);
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicuuc.so", RTLD_NOW) == nullptr);
@@ -255,7 +254,6 @@
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicuuc.so", RTLD_NOW) == nullptr);
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicui18n.so", RTLD_NOW) == nullptr);
 }
-*/
 
 TEST(dlfcn, dlopen_from_zip_absolute_path) {
   const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
diff --git a/tests/gtest_globals_cts.cpp b/tests/gtest_globals_cts.cpp
index 8e67f29..78bb3ca 100644
--- a/tests/gtest_globals_cts.cpp
+++ b/tests/gtest_globals_cts.cpp
@@ -16,17 +16,6 @@
 
 #include "gtest_globals.h"
 
-#include <string>
-#include <vector>
-
-// Use the normal gtest format so that cts can parse the results.
-extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
-  static const char* initial_args[] = {"--gtest_format"};
-  *args = initial_args;
-  *num_args = 1;
-  return true;
-}
-
 std::string GetTestlibRoot() {
   return "/data/local/tmp/lib/bionic-loader-test-libs";
 }