Merge "Adapt to the new libc++/libc++abi update."
diff --git a/benchmarks/bionic_benchmarks.cpp b/benchmarks/bionic_benchmarks.cpp
index d82c739..fe7a1b1 100644
--- a/benchmarks/bionic_benchmarks.cpp
+++ b/benchmarks/bionic_benchmarks.cpp
@@ -514,28 +514,12 @@
 
 void RegisterAllBenchmarks(const bench_opts_t& opts,
                            std::map<std::string, args_vector_t>& args_shorthand) {
-  // Add the property tests at the end since they might cause segfaults in
-  // tests running afterwards (b/62197783).
-  std::vector<std::string> prop_tests;
-
   for (auto& entry : g_str_to_func) {
-    if (android::base::StartsWith(entry.first, "BM_property_")) {
-      prop_tests.push_back(entry.first);
-    } else {
-      auto& function_info = entry.second;
-      args_vector_t arg_vector;
-      args_vector_t* run_args = ResolveArgs(&arg_vector, function_info.second,
-                                            args_shorthand);
-      RegisterGoogleBenchmarks(bench_opts_t(), opts, entry.first, run_args);
-    }
-  }
-
-  for (auto& prop_name : prop_tests) {
-    auto& function_info = g_str_to_func.at(prop_name);
+    auto& function_info = entry.second;
     args_vector_t arg_vector;
     args_vector_t* run_args = ResolveArgs(&arg_vector, function_info.second,
                                           args_shorthand);
-    RegisterGoogleBenchmarks(bench_opts_t(), opts, prop_name, run_args);
+    RegisterGoogleBenchmarks(bench_opts_t(), opts, entry.first, run_args);
   }
 }
 
diff --git a/benchmarks/tests/interface_test.cpp b/benchmarks/tests/interface_test.cpp
index 64629e6..d34017d 100644
--- a/benchmarks/tests/interface_test.cpp
+++ b/benchmarks/tests/interface_test.cpp
@@ -176,6 +176,8 @@
     "BM_atomic_seq_cst_fence/iterations:1\n"
     "BM_atomic_store_release/iterations:1\n"
     "BM_atomic_store_seq_cst/iterations:1\n"
+    "BM_inttypes_strtoimax/iterations:1\n"
+    "BM_inttypes_strtoumax/iterations:1\n"
     "BM_math_fabs/0/iterations:1\n"
     "BM_math_fabs/1/iterations:1\n"
     "BM_math_fabs/2/iterations:1\n"
@@ -234,6 +236,34 @@
     "BM_math_sin_fesetenv/iterations:1\n"
     "BM_math_sin_feupdateenv/iterations:1\n"
     "BM_math_sqrt/iterations:1\n"
+    "BM_property_find/1/iterations:1\n"
+    "BM_property_find/4/iterations:1\n"
+    "BM_property_find/16/iterations:1\n"
+    "BM_property_find/64/iterations:1\n"
+    "BM_property_find/128/iterations:1\n"
+    "BM_property_find/256/iterations:1\n"
+    "BM_property_find/512/iterations:1\n"
+    "BM_property_get/1/iterations:1\n"
+    "BM_property_get/4/iterations:1\n"
+    "BM_property_get/16/iterations:1\n"
+    "BM_property_get/64/iterations:1\n"
+    "BM_property_get/128/iterations:1\n"
+    "BM_property_get/256/iterations:1\n"
+    "BM_property_get/512/iterations:1\n"
+    "BM_property_read/1/iterations:1\n"
+    "BM_property_read/4/iterations:1\n"
+    "BM_property_read/16/iterations:1\n"
+    "BM_property_read/64/iterations:1\n"
+    "BM_property_read/128/iterations:1\n"
+    "BM_property_read/256/iterations:1\n"
+    "BM_property_read/512/iterations:1\n"
+    "BM_property_serial/1/iterations:1\n"
+    "BM_property_serial/4/iterations:1\n"
+    "BM_property_serial/16/iterations:1\n"
+    "BM_property_serial/64/iterations:1\n"
+    "BM_property_serial/128/iterations:1\n"
+    "BM_property_serial/256/iterations:1\n"
+    "BM_property_serial/512/iterations:1\n"
     "BM_pthread_create/iterations:1\n"
     "BM_pthread_create_and_run/iterations:1\n"
     "BM_pthread_exit_and_join/iterations:1\n"
@@ -300,7 +330,10 @@
     "BM_stdio_printf_s/iterations:1\n"
     "BM_stdio_scanf_d/iterations:1\n"
     "BM_stdio_scanf_maps/iterations:1\n"
+    "BM_stdio_scanf_maps_baseline/iterations:1\n"
     "BM_stdio_scanf_s/iterations:1\n"
+    "BM_stdlib_atoi/iterations:1\n"
+    "BM_stdlib_atol/iterations:1\n"
     "BM_stdlib_malloc_free/8/iterations:1\n"
     "BM_stdlib_malloc_free/64/iterations:1\n"
     "BM_stdlib_malloc_free/512/iterations:1\n"
@@ -312,6 +345,10 @@
     "BM_stdlib_malloc_free/131072/iterations:1\n"
     "BM_stdlib_mbrtowc/0/iterations:1\n"
     "BM_stdlib_mbstowcs/0/0/iterations:1\n"
+    "BM_stdlib_strtol/iterations:1\n"
+    "BM_stdlib_strtoll/iterations:1\n"
+    "BM_stdlib_strtoul/iterations:1\n"
+    "BM_stdlib_strtoull/iterations:1\n"
     "BM_string_memcmp/8/0/0/iterations:1\n"
     "BM_string_memcmp/64/0/0/iterations:1\n"
     "BM_string_memcmp/512/0/0/iterations:1\n"
@@ -460,35 +497,7 @@
     "BM_unistd_getpid/iterations:1\n"
     "BM_unistd_getpid_syscall/iterations:1\n"
     "BM_unistd_gettid/iterations:1\n"
-    "BM_unistd_gettid_syscall/iterations:1\n"
-    "BM_property_find/1/iterations:1\n"
-    "BM_property_find/4/iterations:1\n"
-    "BM_property_find/16/iterations:1\n"
-    "BM_property_find/64/iterations:1\n"
-    "BM_property_find/128/iterations:1\n"
-    "BM_property_find/256/iterations:1\n"
-    "BM_property_find/512/iterations:1\n"
-    "BM_property_get/1/iterations:1\n"
-    "BM_property_get/4/iterations:1\n"
-    "BM_property_get/16/iterations:1\n"
-    "BM_property_get/64/iterations:1\n"
-    "BM_property_get/128/iterations:1\n"
-    "BM_property_get/256/iterations:1\n"
-    "BM_property_get/512/iterations:1\n"
-    "BM_property_read/1/iterations:1\n"
-    "BM_property_read/4/iterations:1\n"
-    "BM_property_read/16/iterations:1\n"
-    "BM_property_read/64/iterations:1\n"
-    "BM_property_read/128/iterations:1\n"
-    "BM_property_read/256/iterations:1\n"
-    "BM_property_read/512/iterations:1\n"
-    "BM_property_serial/1/iterations:1\n"
-    "BM_property_serial/4/iterations:1\n"
-    "BM_property_serial/16/iterations:1\n"
-    "BM_property_serial/64/iterations:1\n"
-    "BM_property_serial/128/iterations:1\n"
-    "BM_property_serial/256/iterations:1\n"
-    "BM_property_serial/512/iterations:1\n";
+    "BM_unistd_gettid_syscall/iterations:1\n";
   Verify(expected, 0, std::vector<const char*>{"--bionic_iterations=1"});
 }
 
diff --git a/libc/Android.bp b/libc/Android.bp
index 20648d0..2bb323c 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1706,15 +1706,18 @@
     // Do not pack libc.so relocations; see http://b/20645321 for details.
     pack_relocations: false,
 
-    // WARNING: The only library libc.so should depend on is libdl.so!  If you add other libraries,
-    // make sure to add -Wl,--exclude-libs=libgcc.a to the LOCAL_LDFLAGS for those libraries.  This
-    // ensures that symbols that are pulled into those new libraries from libgcc.a are not declared
-    // external; if that were the case, then libc would not pull those symbols from libgcc.a as it
-    // should, instead relying on the external symbols from the dependent libraries.  That would
-    // create a "cloaked" dependency on libgcc.a in libc though the libraries, which is not what
-    // you wanted!
+    // WARNING: The only libraries libc.so should depend on are libdl.so and ld-android.so!
+    // If you add other libraries, make sure to add -Wl,--exclude-libs=libgcc.a to the
+    // LOCAL_LDFLAGS for those libraries.  This ensures that symbols that are pulled into
+    // those new libraries from libgcc.a are not declared external; if that were the case,
+    // then libc would not pull those symbols from libgcc.a as it should, instead relying
+    // on the external symbols from the dependent libraries.  That would create a "cloaked"
+    // dependency on libgcc.a in libc though the libraries, which is not what you wanted!
 
-    shared_libs: ["libdl"],
+    shared_libs: [
+        "ld-android",
+        "libdl",
+    ],
     whole_static_libs: ["libc_common", "libjemalloc"],
 
     nocrt: true,
@@ -2122,4 +2125,11 @@
     first_version: "9",
 }
 
-subdirs = ["*"]
+// Export these headers for toolbox to process
+filegroup {
+    name: "kernel_input_headers",
+    srcs: [
+        "kernel/uapi/linux/input.h",
+        "kernel/uapi/linux/input-event-codes.h",
+    ],
+}
diff --git a/libc/NOTICE b/libc/NOTICE
index db4b5a5..daf8491 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -1041,6 +1041,34 @@
 
 -------------------------------------------------------------------
 
+Copyright (C) 2018 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.
+
+-------------------------------------------------------------------
+
 Copyright (c) 1980, 1983, 1988, 1993
    The Regents of the University of California.  All rights reserved.
 
diff --git a/libc/SECCOMP_BLACKLIST.TXT b/libc/SECCOMP_BLACKLIST_COMMON.TXT
similarity index 95%
rename from libc/SECCOMP_BLACKLIST.TXT
rename to libc/SECCOMP_BLACKLIST_COMMON.TXT
index 2834515..f279002 100644
--- a/libc/SECCOMP_BLACKLIST.TXT
+++ b/libc/SECCOMP_BLACKLIST_COMMON.TXT
@@ -26,7 +26,7 @@
 #
 #      - Each parameter type is assumed to be stored in 32 bits.
 #
-# This file is processed by a python script named gensyscalls.py.
+# This file is processed by a python script named genseccomp.py.
 
 int     swapon(const char*, int) all
 int     swapoff(const char*) all
diff --git a/libc/SECCOMP_BLACKLIST.TXT b/libc/SECCOMP_WHITELIST_APP.TXT
similarity index 78%
copy from libc/SECCOMP_BLACKLIST.TXT
copy to libc/SECCOMP_WHITELIST_APP.TXT
index 2834515..2f3618c 100644
--- a/libc/SECCOMP_BLACKLIST.TXT
+++ b/libc/SECCOMP_WHITELIST_APP.TXT
@@ -1,9 +1,6 @@
 # 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.
 #
-# The final seccomp whitelist is SYSCALLS.TXT - SECCOMP_BLACKLIST.TXT + SECCOMP_WHITELIST.TXT
-# Any entry in the blacklist must be in the syscalls file and not be in the whitelist file
-#
 # Each non-blank, non-comment line has the following format:
 #
 # return_type func_name[|alias_list][:syscall_name[:socketcall_id]]([parameter_list]) arch_list
@@ -26,7 +23,4 @@
 #
 #      - Each parameter type is assumed to be stored in 32 bits.
 #
-# This file is processed by a python script named gensyscalls.py.
-
-int     swapon(const char*, int) all
-int     swapoff(const char*) all
+# This file is processed by a python script named genseccomp.py.
diff --git a/libc/SECCOMP_WHITELIST.TXT b/libc/SECCOMP_WHITELIST_COMMON.TXT
similarity index 98%
rename from libc/SECCOMP_WHITELIST.TXT
rename to libc/SECCOMP_WHITELIST_COMMON.TXT
index 36a579b..a620b44 100644
--- a/libc/SECCOMP_WHITELIST.TXT
+++ b/libc/SECCOMP_WHITELIST_COMMON.TXT
@@ -23,7 +23,7 @@
 #
 #      - Each parameter type is assumed to be stored in 32 bits.
 #
-# This file is processed by a python script named gensyscalls.py.
+# This file is processed by a python script named genseccomp.py.
 
 # syscalls needed to boot android
 int	pivot_root:pivot_root(const char *new_root, const char *put_old)	arm64,x86_64,mips64
diff --git a/libc/SECCOMP_BLACKLIST.TXT b/libc/SECCOMP_WHITELIST_SYSTEM.TXT
similarity index 78%
copy from libc/SECCOMP_BLACKLIST.TXT
copy to libc/SECCOMP_WHITELIST_SYSTEM.TXT
index 2834515..2f3618c 100644
--- a/libc/SECCOMP_BLACKLIST.TXT
+++ b/libc/SECCOMP_WHITELIST_SYSTEM.TXT
@@ -1,9 +1,6 @@
 # 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.
 #
-# The final seccomp whitelist is SYSCALLS.TXT - SECCOMP_BLACKLIST.TXT + SECCOMP_WHITELIST.TXT
-# Any entry in the blacklist must be in the syscalls file and not be in the whitelist file
-#
 # Each non-blank, non-comment line has the following format:
 #
 # return_type func_name[|alias_list][:syscall_name[:socketcall_id]]([parameter_list]) arch_list
@@ -26,7 +23,4 @@
 #
 #      - Each parameter type is assumed to be stored in 32 bits.
 #
-# This file is processed by a python script named gensyscalls.py.
-
-int     swapon(const char*, int) all
-int     swapoff(const char*) all
+# This file is processed by a python script named genseccomp.py.
diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
index f687fd1..99077c1 100644
--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
+++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
@@ -28,6 +28,8 @@
 };
 
 extern "C" int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle);
+extern "C" void __loader_add_thread_local_dtor(void* dso_handle) __attribute__((weak));
+extern "C" void __loader_remove_thread_local_dtor(void* dso_handle) __attribute__((weak));
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
@@ -40,6 +42,9 @@
   pthread_internal_t* thread = __get_thread();
   dtor->next = thread->thread_local_dtors;
   thread->thread_local_dtors = dtor;
+  if (__loader_add_thread_local_dtor != nullptr) {
+    __loader_add_thread_local_dtor(dso_handle);
+  }
   return 0;
 }
 
@@ -50,6 +55,9 @@
     thread->thread_local_dtors = current->next;
 
     current->func(current->arg);
+    if (__loader_remove_thread_local_dtor != nullptr) {
+      __loader_remove_thread_local_dtor(current->dso_handle);
+    }
     delete current;
   }
 }
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index e26e5f2..a1cc590 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -34,6 +34,22 @@
 #include <stdlib.h>
 #include <sys/cdefs.h>
 
+#if __ANDROID_API__ < __ANDROID_API_K__
+
+__BEGIN_DECLS
+
+static __inline int abs(int __n) { return (__n < 0) ? -__n : __n; }
+
+static __inline long labs(long __n) { return (__n < 0L) ? -__n : __n; }
+
+static __inline long long llabs(long long __n) {
+  return (__n < 0LL) ? -__n : __n;
+}
+
+__END_DECLS
+
+#endif
+
 #if __ANDROID_API__ < __ANDROID_API_L__
 
 __BEGIN_DECLS
@@ -52,14 +68,6 @@
 
 static __inline double atof(const char *nptr) { return (strtod(nptr, NULL)); }
 
-static __inline int abs(int __n) { return (__n < 0) ? -__n : __n; }
-
-static __inline long labs(long __n) { return (__n < 0L) ? -__n : __n; }
-
-static __inline long long llabs(long long __n) {
-  return (__n < 0LL) ? -__n : __n;
-}
-
 static __inline int rand(void) { return (int)lrand48(); }
 
 static __inline void srand(unsigned int __s) { srand48(__s); }
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 1ae3c6e..944d72b 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -172,12 +172,17 @@
 #include <bits/fortify/stdlib.h>
 #endif
 
+#if __ANDROID_API__ >= __ANDROID_API_K__
+int abs(int __x) __attribute_const__ __INTRODUCED_IN(19);
+long labs(long __x) __attribute_const__ __INTRODUCED_IN(19);
+long long llabs(long long __x) __attribute_const__ __INTRODUCED_IN(19);
+#else
+// Implemented as static inlines before 19.
+#endif
+
 #if __ANDROID_API__ >= __ANDROID_API_L__
 float strtof(const char* __s, char** __end_ptr) __INTRODUCED_IN(21);
 double atof(const char* __s) __attribute_pure__ __INTRODUCED_IN(21);
-int abs(int __x) __attribute_const__ __INTRODUCED_IN(21);
-long labs(long __x) __attribute_const__ __INTRODUCED_IN(21);
-long long llabs(long long __x) __attribute_const__ __INTRODUCED_IN(21);
 int rand(void) __INTRODUCED_IN(21);
 void srand(unsigned int __seed) __INTRODUCED_IN(21);
 long random(void) __INTRODUCED_IN(21);
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index bb56cb8..b7a12a5 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -484,15 +484,15 @@
     adb shell setprop libc.debug.malloc.options backtrace
     adb shell start
 
-Enable multiple options (backtrace and guards):
+Enable multiple options (backtrace and guard):
 
     adb shell stop
-    adb shell setprop libc.debug.malloc.options "\"backtrace guards\""
+    adb shell setprop libc.debug.malloc.options "\"backtrace guard\""
     adb shell start
 
 Note: The two levels of quoting in the adb shell command is necessary.
 The outer layer of quoting is for the shell on the host, to ensure that the
-inner layer of quoting is sent to the device, to make 'backtrace guards'
+inner layer of quoting is sent to the device, to make 'backtrace guard'
 a single argument.
 
 Enable malloc debug using an environment variable (pre-O Android release):
diff --git a/libc/seccomp/Android.bp b/libc/seccomp/Android.bp
index b3707bc..bb91849 100644
--- a/libc/seccomp/Android.bp
+++ b/libc/seccomp/Android.bp
@@ -2,18 +2,24 @@
     name: "libseccomp_policy",
     srcs: [
         "seccomp_policy.cpp",
-        "arm_policy.cpp",
+        "arm_app_policy.cpp",
         "arm_global_policy.cpp",
-        "arm64_policy.cpp",
+        "arm_system_policy.cpp",
+        "arm64_app_policy.cpp",
         "arm64_global_policy.cpp",
-        "x86_policy.cpp",
+        "arm64_system_policy.cpp",
+        "x86_app_policy.cpp",
         "x86_global_policy.cpp",
-        "x86_64_policy.cpp",
+        "x86_system_policy.cpp",
+        "x86_64_app_policy.cpp",
         "x86_64_global_policy.cpp",
-        "mips_policy.cpp",
+        "x86_64_system_policy.cpp",
+        "mips_app_policy.cpp",
         "mips_global_policy.cpp",
-        "mips64_policy.cpp",
+        "mips_system_policy.cpp",
+        "mips64_app_policy.cpp",
         "mips64_global_policy.cpp",
+        "mips64_system_policy.cpp",
     ],
     export_include_dirs: ["include"],
     cflags: ["-Wall", "-Werror"],
diff --git a/libc/seccomp/arm64_policy.cpp b/libc/seccomp/arm64_app_policy.cpp
similarity index 96%
copy from libc/seccomp/arm64_policy.cpp
copy to libc/seccomp/arm64_app_policy.cpp
index c52c737..12722e1 100644
--- a/libc/seccomp/arm64_policy.cpp
+++ b/libc/seccomp/arm64_app_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter arm64_filter[] = {
+const sock_filter arm64_app_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 32),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 15, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 7, 0),
@@ -40,4 +40,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t arm64_filter_size = sizeof(arm64_filter) / sizeof(struct sock_filter);
+const size_t arm64_app_filter_size = sizeof(arm64_app_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/arm64_policy.cpp b/libc/seccomp/arm64_system_policy.cpp
similarity index 96%
rename from libc/seccomp/arm64_policy.cpp
rename to libc/seccomp/arm64_system_policy.cpp
index c52c737..a8d7193 100644
--- a/libc/seccomp/arm64_policy.cpp
+++ b/libc/seccomp/arm64_system_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter arm64_filter[] = {
+const sock_filter arm64_system_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 32),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 15, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 7, 0),
@@ -40,4 +40,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t arm64_filter_size = sizeof(arm64_filter) / sizeof(struct sock_filter);
+const size_t arm64_system_filter_size = sizeof(arm64_system_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/arm_policy.cpp b/libc/seccomp/arm_app_policy.cpp
similarity index 98%
copy from libc/seccomp/arm_policy.cpp
copy to libc/seccomp/arm_app_policy.cpp
index 2bc168a..d0fd6ca 100644
--- a/libc/seccomp/arm_policy.cpp
+++ b/libc/seccomp/arm_app_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter arm_filter[] = {
+const sock_filter arm_app_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 126),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 63, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 31, 0),
@@ -134,4 +134,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
+const size_t arm_app_filter_size = sizeof(arm_app_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/arm_policy.cpp b/libc/seccomp/arm_system_policy.cpp
similarity index 98%
rename from libc/seccomp/arm_policy.cpp
rename to libc/seccomp/arm_system_policy.cpp
index 2bc168a..de67038 100644
--- a/libc/seccomp/arm_policy.cpp
+++ b/libc/seccomp/arm_system_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter arm_filter[] = {
+const sock_filter arm_system_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 126),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 63, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 31, 0),
@@ -134,4 +134,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
+const size_t arm_system_filter_size = sizeof(arm_system_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/include/seccomp_policy.h b/libc/seccomp/include/seccomp_policy.h
index e337dec..ed1901b 100644
--- a/libc/seccomp/include/seccomp_policy.h
+++ b/libc/seccomp/include/seccomp_policy.h
@@ -20,8 +20,11 @@
 #include <stddef.h>
 #include <linux/filter.h>
 
+// TODO(victorhsieh): remove once the callers are switched to the new API.
 bool set_seccomp_filter();
+
+bool set_app_seccomp_filter();
+bool set_system_seccomp_filter();
 bool set_global_seccomp_filter();
-void get_seccomp_filter(const sock_filter*& filter, size_t& filter_size);
 
 #endif
diff --git a/libc/seccomp/mips64_policy.cpp b/libc/seccomp/mips64_app_policy.cpp
similarity index 97%
copy from libc/seccomp/mips64_policy.cpp
copy to libc/seccomp/mips64_app_policy.cpp
index 26967ce..27bb0fa 100644
--- a/libc/seccomp/mips64_policy.cpp
+++ b/libc/seccomp/mips64_app_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter mips64_filter[] = {
+const sock_filter mips64_app_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 84),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5164, 41, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 21, 0),
@@ -92,4 +92,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t mips64_filter_size = sizeof(mips64_filter) / sizeof(struct sock_filter);
+const size_t mips64_app_filter_size = sizeof(mips64_app_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/mips64_policy.cpp b/libc/seccomp/mips64_system_policy.cpp
similarity index 97%
rename from libc/seccomp/mips64_policy.cpp
rename to libc/seccomp/mips64_system_policy.cpp
index 26967ce..8f34d41 100644
--- a/libc/seccomp/mips64_policy.cpp
+++ b/libc/seccomp/mips64_system_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter mips64_filter[] = {
+const sock_filter mips64_system_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 84),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5164, 41, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 21, 0),
@@ -92,4 +92,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t mips64_filter_size = sizeof(mips64_filter) / sizeof(struct sock_filter);
+const size_t mips64_system_filter_size = sizeof(mips64_system_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/mips_policy.cpp b/libc/seccomp/mips_app_policy.cpp
similarity index 98%
rename from libc/seccomp/mips_policy.cpp
rename to libc/seccomp/mips_app_policy.cpp
index 7485b90..abda7eb 100644
--- a/libc/seccomp/mips_policy.cpp
+++ b/libc/seccomp/mips_app_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter mips_filter[] = {
+const sock_filter mips_app_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4001, 0, 110),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4131, 55, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4063, 27, 0),
@@ -118,4 +118,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t mips_filter_size = sizeof(mips_filter) / sizeof(struct sock_filter);
+const size_t mips_app_filter_size = sizeof(mips_app_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/mips_policy.cpp b/libc/seccomp/mips_system_policy.cpp
similarity index 98%
copy from libc/seccomp/mips_policy.cpp
copy to libc/seccomp/mips_system_policy.cpp
index 7485b90..7b9da60 100644
--- a/libc/seccomp/mips_policy.cpp
+++ b/libc/seccomp/mips_system_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter mips_filter[] = {
+const sock_filter mips_system_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4001, 0, 110),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4131, 55, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4063, 27, 0),
@@ -118,4 +118,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t mips_filter_size = sizeof(mips_filter) / sizeof(struct sock_filter);
+const size_t mips_system_filter_size = sizeof(mips_system_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/seccomp_bpfs.h b/libc/seccomp/seccomp_bpfs.h
index a8f47ca..8728c36 100644
--- a/libc/seccomp/seccomp_bpfs.h
+++ b/libc/seccomp/seccomp_bpfs.h
@@ -20,28 +20,45 @@
 #include <stddef.h>
 #include <linux/seccomp.h>
 
-extern const struct sock_filter arm_filter[];
-extern const size_t arm_filter_size;
+extern const struct sock_filter arm_app_filter[];
+extern const size_t arm_app_filter_size;
+extern const struct sock_filter arm_system_filter[];
+extern const size_t arm_system_filter_size;
 extern const struct sock_filter arm_global_filter[];
 extern const size_t arm_global_filter_size;
-extern const struct sock_filter arm64_filter[];
-extern const size_t arm64_filter_size;
+
+extern const struct sock_filter arm64_app_filter[];
+extern const size_t arm64_app_filter_size;
+extern const struct sock_filter arm64_system_filter[];
+extern const size_t arm64_system_filter_size;
 extern const struct sock_filter arm64_global_filter[];
 extern const size_t arm64_global_filter_size;
-extern const struct sock_filter x86_filter[];
-extern const size_t x86_filter_size;
+
+extern const struct sock_filter x86_app_filter[];
+extern const size_t x86_app_filter_size;
+extern const struct sock_filter x86_system_filter[];
+extern const size_t x86_system_filter_size;
 extern const struct sock_filter x86_global_filter[];
 extern const size_t x86_global_filter_size;
-extern const struct sock_filter x86_64_filter[];
-extern const size_t x86_64_filter_size;
+
+extern const struct sock_filter x86_64_app_filter[];
+extern const size_t x86_64_app_filter_size;
+extern const struct sock_filter x86_64_system_filter[];
+extern const size_t x86_64_system_filter_size;
 extern const struct sock_filter x86_64_global_filter[];
 extern const size_t x86_64_global_filter_size;
-extern const struct sock_filter mips_filter[];
-extern const size_t mips_filter_size;
+
+extern const struct sock_filter mips_app_filter[];
+extern const size_t mips_app_filter_size;
+extern const struct sock_filter mips_system_filter[];
+extern const size_t mips_system_filter_size;
 extern const struct sock_filter mips_global_filter[];
 extern const size_t mips_global_filter_size;
-extern const struct sock_filter mips64_filter[];
-extern const size_t mips64_filter_size;
+
+extern const struct sock_filter mips64_app_filter[];
+extern const size_t mips64_app_filter_size;
+extern const struct sock_filter mips64_system_filter[];
+extern const size_t mips64_system_filter_size;
 extern const struct sock_filter mips64_global_filter[];
 extern const size_t mips64_global_filter_size;
 
diff --git a/libc/seccomp/seccomp_policy.cpp b/libc/seccomp/seccomp_policy.cpp
index 19ef299..99a821f 100644
--- a/libc/seccomp/seccomp_policy.cpp
+++ b/libc/seccomp/seccomp_policy.cpp
@@ -32,13 +32,17 @@
 
 #define DUAL_ARCH
 #define PRIMARY_ARCH AUDIT_ARCH_AARCH64
-static const struct sock_filter* primary_filter = arm64_filter;
-static const size_t primary_filter_size = arm64_filter_size;
+static const struct sock_filter* primary_app_filter = arm64_app_filter;
+static const size_t primary_app_filter_size = arm64_app_filter_size;
+static const struct sock_filter* primary_system_filter = arm64_system_filter;
+static const size_t primary_system_filter_size = arm64_system_filter_size;
 static const struct sock_filter* primary_global_filter = arm64_global_filter;
 static const size_t primary_global_filter_size = arm64_global_filter_size;
 #define SECONDARY_ARCH AUDIT_ARCH_ARM
-static const struct sock_filter* secondary_filter = arm_filter;
-static const size_t secondary_filter_size = arm_filter_size;
+static const struct sock_filter* secondary_app_filter = arm_app_filter;
+static const size_t secondary_app_filter_size = arm_app_filter_size;
+static const struct sock_filter* secondary_system_filter = arm_system_filter;
+static const size_t secondary_system_filter_size = arm_system_filter_size;
 static const struct sock_filter* secondary_global_filter = arm_global_filter;
 static const size_t secondary_global_filter_size = arm_global_filter_size;
 
@@ -46,13 +50,17 @@
 
 #define DUAL_ARCH
 #define PRIMARY_ARCH AUDIT_ARCH_X86_64
-static const struct sock_filter* primary_filter = x86_64_filter;
-static const size_t primary_filter_size = x86_64_filter_size;
+static const struct sock_filter* primary_app_filter = x86_64_app_filter;
+static const size_t primary_app_filter_size = x86_64_app_filter_size;
+static const struct sock_filter* primary_system_filter = x86_64_system_filter;
+static const size_t primary_system_filter_size = x86_64_system_filter_size;
 static const struct sock_filter* primary_global_filter = x86_64_global_filter;
 static const size_t primary_global_filter_size = x86_64_global_filter_size;
 #define SECONDARY_ARCH AUDIT_ARCH_I386
-static const struct sock_filter* secondary_filter = x86_filter;
-static const size_t secondary_filter_size = x86_filter_size;
+static const struct sock_filter* secondary_app_filter = x86_app_filter;
+static const size_t secondary_app_filter_size = x86_app_filter_size;
+static const struct sock_filter* secondary_system_filter = x86_system_filter;
+static const size_t secondary_system_filter_size = x86_system_filter_size;
 static const struct sock_filter* secondary_global_filter = x86_global_filter;
 static const size_t secondary_global_filter_size = x86_global_filter_size;
 
@@ -60,13 +68,17 @@
 
 #define DUAL_ARCH
 #define PRIMARY_ARCH AUDIT_ARCH_MIPSEL64
-static const struct sock_filter* primary_filter = mips64_filter;
-static const size_t primary_filter_size = mips64_filter_size;
+static const struct sock_filter* primary_app_filter = mips64_app_filter;
+static const size_t primary_app_filter_size = mips64_app_filter_size;
+static const struct sock_filter* primary_system_filter = mips64_system_filter;
+static const size_t primary_system_filter_size = mips64_system_filter_size;
 static const struct sock_filter* primary_global_filter = mips64_global_filter;
 static const size_t primary_global_filter_size = mips64_global_filter_size;
 #define SECONDARY_ARCH AUDIT_ARCH_MIPSEL
-static const struct sock_filter* secondary_filter = mips_filter;
-static const size_t secondary_filter_size = mips_filter_size;
+static const struct sock_filter* secondary_app_filter = mips_app_filter;
+static const size_t secondary_app_filter_size = mips_app_filter_size;
+static const struct sock_filter* secondary_system_filter = mips_system_filter;
+static const size_t secondary_system_filter_size = mips_system_filter_size;
 static const struct sock_filter* secondary_global_filter = mips_global_filter;
 static const size_t secondary_global_filter_size = mips_global_filter_size;
 
@@ -122,30 +134,48 @@
         const_cast<struct sock_filter*>(&f[0]),
     };
 
+    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
+        PLOG(FATAL) << "Could not set to no new privs";
+        return false;
+    }
     if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
         PLOG(FATAL) << "Could not set seccomp filter of size " << f.size();
         return false;
     }
-
-    LOG(INFO) << "Global filter of size " << f.size() << " installed";
     return true;
 }
 
-bool _set_seccomp_filter(bool global) {
+enum FilterType {
+  APP,
+  SYSTEM,
+  GLOBAL
+};
+
+bool _set_seccomp_filter(FilterType type) {
     const sock_filter *p, *s;
     size_t p_size, s_size;
     filter f;
 
-    if (global) {
+    switch (type) {
+      case APP:
+        p = primary_app_filter;
+        p_size = primary_app_filter_size;
+        s = secondary_app_filter;
+        s_size = secondary_app_filter_size;
+        break;
+      case SYSTEM:
+        p = primary_system_filter;
+        p_size = primary_system_filter_size;
+        s = secondary_system_filter;
+        s_size = secondary_system_filter_size;
+        break;
+      case GLOBAL:
         p = primary_global_filter;
         p_size = primary_global_filter_size;
         s = secondary_global_filter;
         s_size = secondary_global_filter_size;
-    } else {
-        p = primary_filter;
-        p_size = primary_filter_size;
-        s = secondary_filter;
-        s_size = secondary_filter_size;
+        break;
+
     }
 
 #ifdef DUAL_ARCH
@@ -181,19 +211,17 @@
 }
 
 bool set_seccomp_filter() {
-    return _set_seccomp_filter(false);
+    return _set_seccomp_filter(FilterType::APP);
+}
+
+bool set_app_seccomp_filter() {
+    return _set_seccomp_filter(FilterType::APP);
+}
+
+bool set_system_seccomp_filter() {
+    return _set_seccomp_filter(FilterType::SYSTEM);
 }
 
 bool set_global_seccomp_filter() {
-    return _set_seccomp_filter(true);
-}
-
-void get_seccomp_filter(const sock_filter*& filter, size_t& filter_size) {
-#if defined __aarch64__ || defined __x86_64__ || defined __mips64__
-    filter = primary_filter;
-    filter_size = primary_filter_size;
-#else
-    filter = secondary_filter;
-    filter_size = secondary_filter_size;
-#endif
+    return _set_seccomp_filter(FilterType::GLOBAL);
 }
diff --git a/libc/seccomp/x86_64_policy.cpp b/libc/seccomp/x86_64_app_policy.cpp
similarity index 97%
rename from libc/seccomp/x86_64_policy.cpp
rename to libc/seccomp/x86_64_app_policy.cpp
index 025e24f..171b959 100644
--- a/libc/seccomp/x86_64_policy.cpp
+++ b/libc/seccomp/x86_64_app_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter x86_64_filter[] = {
+const sock_filter x86_64_app_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 88),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 175, 43, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 21, 0),
@@ -96,4 +96,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t x86_64_filter_size = sizeof(x86_64_filter) / sizeof(struct sock_filter);
+const size_t x86_64_app_filter_size = sizeof(x86_64_app_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/x86_64_policy.cpp b/libc/seccomp/x86_64_system_policy.cpp
similarity index 97%
copy from libc/seccomp/x86_64_policy.cpp
copy to libc/seccomp/x86_64_system_policy.cpp
index 025e24f..f2b2601 100644
--- a/libc/seccomp/x86_64_policy.cpp
+++ b/libc/seccomp/x86_64_system_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter x86_64_filter[] = {
+const sock_filter x86_64_system_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 88),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 175, 43, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 21, 0),
@@ -96,4 +96,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t x86_64_filter_size = sizeof(x86_64_filter) / sizeof(struct sock_filter);
+const size_t x86_64_system_filter_size = sizeof(x86_64_system_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/x86_policy.cpp b/libc/seccomp/x86_app_policy.cpp
similarity index 98%
copy from libc/seccomp/x86_policy.cpp
copy to libc/seccomp/x86_app_policy.cpp
index 494a42a..2db2368 100644
--- a/libc/seccomp/x86_policy.cpp
+++ b/libc/seccomp/x86_app_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter x86_filter[] = {
+const sock_filter x86_app_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 116),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 57, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 29, 0),
@@ -124,4 +124,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t x86_filter_size = sizeof(x86_filter) / sizeof(struct sock_filter);
+const size_t x86_app_filter_size = sizeof(x86_app_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/x86_policy.cpp b/libc/seccomp/x86_system_policy.cpp
similarity index 98%
rename from libc/seccomp/x86_policy.cpp
rename to libc/seccomp/x86_system_policy.cpp
index 494a42a..b45e609 100644
--- a/libc/seccomp/x86_policy.cpp
+++ b/libc/seccomp/x86_system_policy.cpp
@@ -4,7 +4,7 @@
 #include <errno.h>
 
 #include "seccomp_bpfs.h"
-const sock_filter x86_filter[] = {
+const sock_filter x86_system_filter[] = {
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 116),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 57, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 29, 0),
@@ -124,4 +124,4 @@
 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
 };
 
-const size_t x86_filter_size = sizeof(x86_filter) / sizeof(struct sock_filter);
+const size_t x86_system_filter_size = sizeof(x86_system_filter) / sizeof(struct sock_filter);
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
index f3a232e..dad9113 100755
--- a/libc/tools/genseccomp.py
+++ b/libc/tools/genseccomp.py
@@ -26,47 +26,18 @@
     self.names.append(name)
 
 
-def get_names(syscall_files, architecture, global_policy):
-  syscall_lists = []
-  for syscall_file in syscall_files:
-    parser = SysCallsTxtParser()
-    parser.parse_open_file(syscall_file)
-    syscall_lists.append(parser.syscalls)
+def load_syscall_names_from_file(file_path, architecture):
+  parser = SysCallsTxtParser()
+  parser.parse_open_file(open(file_path))
+  return set([x["name"] for x in parser.syscalls if x.get(architecture)])
 
-  bionic, whitelist, blacklist = syscall_lists[0], syscall_lists[1], syscall_lists[2]
-  if global_policy:
-    global_whitelist = syscall_lists[-1]
-  else:
-    global_whitelist = []
 
-  for x in blacklist:
-    if not x in bionic:
-      raise RuntimeError("Blacklist item not in bionic - aborting " + str(x))
+def merge_names(base_names, whitelist_names, blacklist_names):
+  if bool(blacklist_names - base_names):
+    raise RuntimeError("Blacklist item not in bionic - aborting " + str(
+        blacklist_name - base_names))
 
-    if x in whitelist:
-      raise RuntimeError("Blacklist item in whitelist - aborting " + str(x))
-
-  bionic_minus_blacklist = [x for x in bionic if x not in blacklist]
-  syscalls = bionic_minus_blacklist + whitelist + global_whitelist
-
-  # Select only elements matching required architecture
-  syscalls = [x for x in syscalls if architecture in x and x[architecture]]
-
-  # We only want the name
-  names = [x["name"] for x in syscalls]
-
-  # Check for duplicates
-  dups = [name for name, count in collections.Counter(names).items() if count > 1]
-
-  # x86 has duplicate socketcall entries, so hard code for this
-  if architecture == "x86":
-    dups.remove("socketcall")
-
-  if len(dups) > 0:
-    raise RuntimeError("Duplicate entries found - aborting " + str(dups))
-
-  # Remove remaining duplicates
-  return list(set(names))
+  return (base_names - blacklist_names) | whitelist_names
 
 
 def convert_names_to_NRs(names, header_dir, extra_switches):
@@ -175,8 +146,11 @@
   return bpf
 
 
-def convert_bpf_to_output(bpf, architecture, global_policy):
-  suffix = "global_" if global_policy else ""
+def convert_bpf_to_output(bpf, architecture, name_modifier):
+  if name_modifier:
+    name_modifier = name_modifier + "_"
+  else:
+    name_modifier = ""
   header = textwrap.dedent("""\
     // Autogenerated file - edit at your peril!!
 
@@ -185,29 +159,51 @@
 
     #include "seccomp_bpfs.h"
     const sock_filter {architecture}_{suffix}filter[] = {{
-    """).format(architecture=architecture,suffix=suffix)
+    """).format(architecture=architecture,suffix=name_modifier)
 
   footer = textwrap.dedent("""\
 
     }};
 
     const size_t {architecture}_{suffix}filter_size = sizeof({architecture}_{suffix}filter) / sizeof(struct sock_filter);
-    """).format(architecture=architecture,suffix=suffix)
+    """).format(architecture=architecture,suffix=name_modifier)
   return header + "\n".join(bpf) + footer
 
 
-def construct_bpf(syscall_files, architecture, header_dir, extra_switches,
-                  global_policy):
-  names = get_names(syscall_files, architecture, global_policy)
+def construct_bpf(names, architecture, header_dir, extra_switches,
+                  name_modifier):
   syscalls = convert_names_to_NRs(names, header_dir, extra_switches)
   ranges = convert_NRs_to_ranges(syscalls)
   bpf = convert_ranges_to_bpf(ranges)
-  return convert_bpf_to_output(bpf, architecture, global_policy)
+  return convert_bpf_to_output(bpf, architecture, name_modifier)
 
 
-ANDROID_SYSCALL_FILES = ["SYSCALLS.TXT",
-                         "SECCOMP_WHITELIST.TXT",
-                         "SECCOMP_BLACKLIST.TXT"]
+# final syscalls = base - blacklists + whitelists
+ANDROID_SYSTEM_SYSCALL_FILES = {
+    "base": "SYSCALLS.TXT",
+    "whitelists": [
+        "SECCOMP_WHITELIST_COMMON.TXT",
+        "SECCOMP_WHITELIST_SYSTEM.TXT"],
+    "blacklists": ["SECCOMP_BLACKLIST_COMMON.TXT"]
+}
+
+ANDROID_APP_SYSCALL_FILES = {
+    "base": "SYSCALLS.TXT",
+    "whitelists": [
+        "SECCOMP_WHITELIST_COMMON.TXT",
+        "SECCOMP_WHITELIST_APP.TXT"],
+    "blacklists": ["SECCOMP_BLACKLIST_COMMON.TXT"]
+}
+
+ANDROID_GLOBAL_SYSCALL_FILES = {
+    "base": "SYSCALLS.TXT",
+    "whitelists": [
+        "SECCOMP_WHITELIST_COMMON.TXT",
+        "SECCOMP_WHITELIST_SYSTEM.TXT",
+        "SECCOMP_WHITELIST_APP.TXT",
+        "SECCOMP_WHITELIST_GLOBAL.TXT"],
+    "blacklists": ["SECCOMP_BLACKLIST_COMMON.TXT"]
+}
 
 
 POLICY_CONFIGS = [("arm", "kernel/uapi/asm-arm", []),
@@ -223,18 +219,23 @@
   os.chdir(os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc"))
 
 
-def gen_policy(global_policy):
-  if global_policy:
-    ANDROID_SYSCALL_FILES.append("SECCOMP_WHITELIST_GLOBAL.TXT")
-
+def gen_policy(syscall_files, name_modifier):
   for arch, header_path, switches in POLICY_CONFIGS:
-    files = [open(filename) for filename in ANDROID_SYSCALL_FILES]
-    output = construct_bpf(files, arch, header_path, switches, global_policy)
+    base_names = load_syscall_names_from_file(syscall_files["base"], arch)
+    whitelist_names = set()
+    for f in syscall_files["whitelists"]:
+      whitelist_names |= load_syscall_names_from_file(f, arch)
+    blacklist_names = set()
+    for f in syscall_files["blacklists"]:
+      blacklist_names |= load_syscall_names_from_file(f, arch)
+
+    names = merge_names(base_names, whitelist_names, blacklist_names)
+    output = construct_bpf(names, arch, header_path, switches, name_modifier)
 
     # And output policy
     existing = ""
-    global_string = "_global" if global_policy else ""
-    output_path = "seccomp/{}{}_policy.cpp".format(arch, global_string)
+    filename_modifier = "_" + name_modifier if name_modifier else ""
+    output_path = "seccomp/{}{}_policy.cpp".format(arch, filename_modifier)
     if os.path.isfile(output_path):
       existing = open(output_path).read()
     if output == existing:
@@ -247,8 +248,10 @@
 
 def main():
   set_dir()
-  gen_policy(False)
-  gen_policy(True)
+  gen_policy(ANDROID_SYSTEM_SYSCALL_FILES, 'system')
+  gen_policy(ANDROID_APP_SYSCALL_FILES, 'app')
+  gen_policy(ANDROID_GLOBAL_SYSCALL_FILES, 'global')
+
 
 if __name__ == "__main__":
   main()
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 44daaec..3889bdb 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -97,52 +97,6 @@
     },
 }
 
-cc_library {
-    // NOTE: --exclude-libs=libgcc.a makes sure that any symbols libdl.so pulls from
-    // libgcc.a are made static to ld-android.so.  This in turn ensures that libraries that
-    // a) pull symbols from libgcc.a and b) depend on ld-android.so will not rely on ld-android.so
-    // to provide those symbols, but will instead pull them from libgcc.a.  Specifically,
-    // we use this property to make sure libc.so has its own copy of the code from
-    // libgcc.a it uses.
-    //
-    // DO NOT REMOVE --exclude-libs!
-
-    ldflags: ["-Wl,--exclude-libs=libgcc.a"],
-
-    // for x86, exclude libgcc_eh.a for the same reasons as above
-    arch: {
-        x86: {
-            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
-        },
-        x86_64: {
-            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
-        },
-    },
-    srcs: ["ld_android.c"],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Wunused",
-        "-Werror",
-    ],
-    stl: "none",
-
-    name: "ld-android",
-    defaults: ["linux_bionic_supported"],
-
-    // NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
-    // few symbols from libc. Using --no-undefined here results in having to link
-    // against libc creating a circular dependency which is removed and we end up
-    // with missing symbols. Since this library is just a bunch of stubs, we set
-    // LOCAL_ALLOW_UNDEFINED_SYMBOLS to remove --no-undefined from the linker flags.
-    allow_undefined_symbols: true,
-    system_shared_libs: [],
-
-    sanitize: {
-        never: true,
-    },
-}
-
 ndk_library {
     name: "libdl",
     symbol_file: "libdl.map.txt",
diff --git a/libdl/ld_android.c b/libdl/ld_android.c
deleted file mode 100644
index 8b13789..0000000
--- a/libdl/ld_android.c
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/linker/Android.bp b/linker/Android.bp
index f802f45..8d7fae5 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -130,6 +130,7 @@
         "-shared",
         "-Wl,-Bsymbolic",
         "-Wl,--exclude-libs,ALL",
+        "-Wl,-soname,ld-android.so",
     ],
 
     cflags: [
@@ -220,3 +221,64 @@
     // looking up symbols in the linker by mistake.
     prefix_symbols: "__dl_",
 }
+
+cc_library {
+    // NOTE: --exclude-libs=libgcc.a makes sure that any symbols ld-android.so pulls from
+    // libgcc.a are made static to ld-android.so.  This in turn ensures that libraries that
+    // a) pull symbols from libgcc.a and b) depend on ld-android.so will not rely on ld-android.so
+    // to provide those symbols, but will instead pull them from libgcc.a.  Specifically,
+    // we use this property to make sure libc.so has its own copy of the code from
+    // libgcc.a it uses.
+    //
+    // DO NOT REMOVE --exclude-libs!
+
+    ldflags: ["-Wl,--exclude-libs=libgcc.a"],
+
+    // for x86, exclude libgcc_eh.a for the same reasons as above
+    arch: {
+        arm: {
+            version_script: "linker.arm.map",
+        },
+        arm64: {
+            version_script: "linker.generic.map",
+        },
+        x86: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+            version_script: "linker.generic.map",
+        },
+        x86_64: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+            version_script: "linker.generic.map",
+        },
+        mips: {
+            version_script: "linker.generic.map",
+        },
+        mips64: {
+            version_script: "linker.generic.map",
+        },
+    },
+
+    srcs: ["ld_android.cpp"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+        "-Werror",
+    ],
+    stl: "none",
+
+    name: "ld-android",
+    defaults: ["linux_bionic_supported"],
+
+    // NOTE: ld-android.so needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a
+    // needs a few symbols from libc. Using --no-undefined here results in having to
+    // link against libc creating a circular dependency which is removed and we end
+    // up with missing symbols. Since this library is just a bunch of stubs, we set
+    // allow_undefined_symbols to remove --no-undefined from the linker flags.
+    allow_undefined_symbols: true,
+    system_shared_libs: [],
+
+    sanitize: {
+        never: true,
+    },
+}
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 7f9bf7e..7f40f90 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -82,6 +82,8 @@
                       const char* symbol,
                       const char* version,
                       const void* caller_addr) __LINKER_PUBLIC__;
+void __loader_add_thread_local_dtor(void* dso_handle) __LINKER_PUBLIC__;
+void __loader_remove_thread_local_dtor(void* dso_handle) __LINKER_PUBLIC__;
 #if defined(__arm__)
 _Unwind_Ptr __loader_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) __LINKER_PUBLIC__;
 #endif
@@ -272,6 +274,16 @@
   CFIShadowWriter::CfiFail(CallSiteTypeId, Ptr, DiagData, CallerPc);
 }
 
+void __loader_add_thread_local_dtor(void* dso_handle) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  increment_dso_handle_reference_counter(dso_handle);
+}
+
+void __loader_remove_thread_local_dtor(void* dso_handle) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  decrement_dso_handle_reference_counter(dso_handle);
+}
+
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
 static soinfo* __libdl_info = nullptr;
 
@@ -298,7 +310,7 @@
     __libdl_info->ref_count_ = 1;
     __libdl_info->strtab_size_ = linker_si.strtab_size_;
     __libdl_info->local_group_root_ = __libdl_info;
-    __libdl_info->soname_ = "ld-android.so";
+    __libdl_info->soname_ = linker_si.soname_;
     __libdl_info->target_sdk_version_ = __ANDROID_API__;
     __libdl_info->generate_handle();
     __libdl_info->link_map_head.l_addr = linker_map.l_addr;
diff --git a/linker/ld_android.cpp b/linker/ld_android.cpp
new file mode 100644
index 0000000..c4ce1b9
--- /dev/null
+++ b/linker/ld_android.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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 <stdlib.h>
+#include <sys/cdefs.h>
+
+extern "C" void __somehow_you_managed_to_not_get_the_actual_symbols_from_the_linker();
+
+extern "C" void __ld_android_init() __attribute__((constructor));
+
+void __ld_android_init() {
+  __somehow_you_managed_to_not_get_the_actual_symbols_from_the_linker();
+}
+
+extern "C" void __internal_linker_error() {
+  abort();
+}
+
+__strong_alias(__loader_android_create_namespace, __internal_linker_error);
+__strong_alias(__loader_android_dlopen_ext, __internal_linker_error);
+__strong_alias(__loader_android_dlwarning, __internal_linker_error);
+__strong_alias(__loader_android_get_application_target_sdk_version, __internal_linker_error);
+__strong_alias(__loader_android_get_LD_LIBRARY_PATH, __internal_linker_error);
+__strong_alias(__loader_android_get_exported_namespace, __internal_linker_error);
+__strong_alias(__loader_android_init_anonymous_namespace, __internal_linker_error);
+__strong_alias(__loader_android_link_namespaces, __internal_linker_error);
+__strong_alias(__loader_android_set_application_target_sdk_version, __internal_linker_error);
+__strong_alias(__loader_android_update_LD_LIBRARY_PATH, __internal_linker_error);
+__strong_alias(__loader_cfi_fail, __internal_linker_error);
+__strong_alias(__loader_dl_iterate_phdr, __internal_linker_error);
+__strong_alias(__loader_dladdr, __internal_linker_error);
+__strong_alias(__loader_dlclose, __internal_linker_error);
+__strong_alias(__loader_dlerror, __internal_linker_error);
+__strong_alias(__loader_dlopen, __internal_linker_error);
+__strong_alias(__loader_dlsym, __internal_linker_error);
+__strong_alias(__loader_dlvsym, __internal_linker_error);
+__strong_alias(__loader_add_thread_local_dtor, __internal_linker_error);
+__strong_alias(__loader_remove_thread_local_dtor, __internal_linker_error);
+#if defined(__arm__)
+__strong_alias(__loader_dl_unwind_find_exidx, __internal_linker_error);
+#endif
+__strong_alias(rtld_db_dlactivity, __internal_linker_error);
+
diff --git a/linker/linker.arm.map b/linker/linker.arm.map
index 67b0632..4a3f177 100644
--- a/linker/linker.arm.map
+++ b/linker/linker.arm.map
@@ -19,6 +19,8 @@
     __loader_android_link_namespaces;
     __loader_android_get_exported_namespace;
     __loader_dl_unwind_find_exidx;
+    __loader_add_thread_local_dtor;
+    __loader_remove_thread_local_dtor;
     rtld_db_dlactivity;
   local:
     *;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 4ad44fa..317fdff 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -75,6 +75,8 @@
 #undef ELF_ST_TYPE
 #define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
 
+static std::unordered_map<void*, size_t> g_dso_handle_counters;
+
 static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
 static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
 
@@ -1780,26 +1782,10 @@
   return si;
 }
 
-static void soinfo_unload(soinfo* unload_si) {
-  // Note that the library can be loaded but not linked;
-  // in which case there is no root but we still need
-  // to walk the tree and unload soinfos involved.
-  //
-  // This happens on unsuccessful dlopen, when one of
-  // the DT_NEEDED libraries could not be linked/found.
-  bool is_linked = unload_si->is_linked();
-  soinfo* root = is_linked ? unload_si->get_local_group_root() : unload_si;
-
-  LD_LOG(kLogDlopen,
-         "... dlclose(realpath=\"%s\"@%p) ... load group root is \"%s\"@%p",
-         unload_si->get_realpath(),
-         unload_si,
-         root->get_realpath(),
-         root);
-
+static void soinfo_unload_impl(soinfo* root) {
   ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
+  bool is_linked = root->is_linked();
 
-  size_t ref_count = is_linked ? root->decrement_ref_count() : 0;
   if (!root->can_unload()) {
     LD_LOG(kLogDlopen,
            "... dlclose(root=\"%s\"@%p) ... not unloading - the load group is flagged with NODELETE",
@@ -1808,14 +1794,6 @@
     return;
   }
 
-  if (ref_count > 0) {
-    LD_LOG(kLogDlopen,
-           "... dlclose(root=\"%s\"@%p) ... not unloading - decrementing ref_count to %zd",
-           root->get_realpath(),
-           root,
-           ref_count);
-    return;
-  }
 
   soinfo_list_t unload_list;
   unload_list.push_back(root);
@@ -1916,6 +1894,86 @@
   }
 }
 
+static void soinfo_unload(soinfo* unload_si) {
+  // Note that the library can be loaded but not linked;
+  // in which case there is no root but we still need
+  // to walk the tree and unload soinfos involved.
+  //
+  // This happens on unsuccessful dlopen, when one of
+  // the DT_NEEDED libraries could not be linked/found.
+  bool is_linked = unload_si->is_linked();
+  soinfo* root = is_linked ? unload_si->get_local_group_root() : unload_si;
+
+  LD_LOG(kLogDlopen,
+         "... dlclose(realpath=\"%s\"@%p) ... load group root is \"%s\"@%p",
+         unload_si->get_realpath(),
+         unload_si,
+         root->get_realpath(),
+         root);
+
+
+  size_t ref_count = is_linked ? root->decrement_ref_count() : 0;
+  if (ref_count > 0) {
+    LD_LOG(kLogDlopen,
+           "... dlclose(root=\"%s\"@%p) ... not unloading - decrementing ref_count to %zd",
+           root->get_realpath(),
+           root,
+           ref_count);
+    return;
+  }
+
+  soinfo_unload_impl(root);
+}
+
+void increment_dso_handle_reference_counter(void* dso_handle) {
+  if (dso_handle == nullptr) {
+    return;
+  }
+
+  auto it = g_dso_handle_counters.find(dso_handle);
+  if (it != g_dso_handle_counters.end()) {
+    CHECK(++it->second != 0);
+  } else {
+    soinfo* si = find_containing_library(dso_handle);
+    if (si != nullptr) {
+      ProtectedDataGuard guard;
+      si->set_tls_nodelete();
+    } else {
+      async_safe_fatal(
+          "increment_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
+          dso_handle);
+    }
+    g_dso_handle_counters[dso_handle] = 1U;
+  }
+}
+
+void decrement_dso_handle_reference_counter(void* dso_handle) {
+  if (dso_handle == nullptr) {
+    return;
+  }
+
+  auto it = g_dso_handle_counters.find(dso_handle);
+  CHECK(it != g_dso_handle_counters.end());
+  CHECK(it->second != 0);
+
+  if (--it->second == 0) {
+    soinfo* si = find_containing_library(dso_handle);
+    if (si != nullptr) {
+      ProtectedDataGuard guard;
+      si->unset_tls_nodelete();
+      if (si->get_ref_count() == 0) {
+        // Perform deferred unload - note that soinfo_unload_impl does not decrement ref_count
+        soinfo_unload_impl(si);
+      }
+    } else {
+      async_safe_fatal(
+          "decrement_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
+          dso_handle);
+    }
+    g_dso_handle_counters.erase(it);
+  }
+}
+
 static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
   if (sym_ver == nullptr) {
     return sym_name;
diff --git a/linker/linker.generic.map b/linker/linker.generic.map
index abd792a..04f4c8a 100644
--- a/linker/linker.generic.map
+++ b/linker/linker.generic.map
@@ -18,6 +18,8 @@
     __loader_cfi_fail;
     __loader_android_link_namespaces;
     __loader_android_get_exported_namespace;
+    __loader_add_thread_local_dtor;
+    __loader_remove_thread_local_dtor;
     rtld_db_dlactivity;
   local:
     *;
diff --git a/linker/linker.h b/linker/linker.h
index f5a202f..6ebca4c 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -182,4 +182,7 @@
 
 android_namespace_t* get_exported_namespace(const char* name);
 
+void increment_dso_handle_reference_counter(void* dso_handle);
+void decrement_dso_handle_reference_counter(void* dso_handle);
+
 #endif
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index dd91752..54bfcf0 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -537,6 +537,14 @@
   rtld_flags_ |= RTLD_NODELETE;
 }
 
+void soinfo::set_tls_nodelete() {
+  flags_ |= FLAG_TLS_NODELETE;
+}
+
+void soinfo::unset_tls_nodelete() {
+  flags_ &= ~FLAG_TLS_NODELETE;
+}
+
 const char* soinfo::get_realpath() const {
 #if defined(__work_around_b_24465209__)
   if (has_min_version(2)) {
@@ -650,7 +658,11 @@
 }
 
 bool soinfo::can_unload() const {
-  return !is_linked() || ((get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0);
+  return !is_linked() ||
+         (
+             (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0 &&
+             (flags_ & FLAG_TLS_NODELETE) == 0
+         );
 }
 
 bool soinfo::is_linked() const {
@@ -693,6 +705,10 @@
   return --local_group_root_->ref_count_;
 }
 
+size_t soinfo::get_ref_count() const {
+  return local_group_root_->ref_count_;
+}
+
 soinfo* soinfo::get_local_group_root() const {
   return local_group_root_;
 }
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 273c36c..91118b0 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -52,6 +52,14 @@
                                          // when load group is crossing
                                          // namespace boundary twice and second
                                          // local group depends on the same libraries.
+#define FLAG_TLS_NODELETE     0x00000200 // This flag set when there is at least one
+                                         // outstanding thread_local dtor
+                                         // registered with this soinfo. In such
+                                         // a case the actual unload is
+                                         // postponed until the last thread_local
+                                         // destructor associated with this
+                                         // soinfo is executed and this flag is
+                                         // unset.
 #define FLAG_NEW_SOINFO       0x40000000 // new soinfo format
 
 #define SOINFO_VERSION 3
@@ -253,9 +261,12 @@
   void set_linker_flag();
   void set_main_executable();
   void set_nodelete();
+  void set_tls_nodelete();
+  void unset_tls_nodelete();
 
   size_t increment_ref_count();
   size_t decrement_ref_count();
+  size_t get_ref_count() const;
 
   soinfo* get_local_group_root() const;
 
diff --git a/tests/complex_test.cpp b/tests/complex_test.cpp
index 85b20de..2aaa192 100644
--- a/tests/complex_test.cpp
+++ b/tests/complex_test.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
 #if defined(__BIONIC_LP32_USE_LONG_DOUBLE)
 #define COMPLEX_TEST complex_h_force_long_double
 #else
@@ -43,26 +41,27 @@
 
 #include <math.h> // For M_PI_2/M_PI_2l.
 
-#if 0
-// Note that gtest doesn't support complex numbers, so the output from
-// assertion failures is misleading/useless (at best you'll only see the real
-// part).
-// TODO: find out why gtest doesn't use these; until then they're only useful
-// for manual printf^Woperator<< debugging.
+// Prettify gtest Complex printing.
 #include <iostream>
-std::ostream& operator<<(std::ostream& os, const double _Complex c) {
-  os << "(" << creal(c) << "," << cimag(c) << "i)";
- return os;
+namespace testing {
+namespace internal {
+inline void PrintTo(const double _Complex& c, std::ostream* os) {
+  *os << "(" << creal(c) << "," << cimag(c) << "i)";
 }
-std::ostream& operator<<(std::ostream& os, const float _Complex c) {
-  os << "(" << crealf(c) << "," << cimagf(c) << "i)";
-  return os;
+inline void PrintTo(const float _Complex& c, std::ostream* os) {
+  *os << "(" << crealf(c) << "," << cimagf(c) << "i)";
 }
-std::ostream& operator<<(std::ostream& os, const long double _Complex c) {
-  os << "(" << creall(c) << "," << cimagl(c) << "i)";
-  return os;
+inline void PrintTo(const long double _Complex& c, std::ostream* os) {
+  *os << "(" << creall(c) << "," << cimagl(c) << "i)";
 }
-#endif
+}
+}
+
+// Macro 'I' defined in complex.h conflicts with gtest.h.
+#pragma push_macro("I")
+#undef I
+#include <gtest/gtest.h>
+#pragma pop_macro("I")
 
 TEST(COMPLEX_TEST, cabs) {
   ASSERT_EQ(0.0, cabs(0));
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 6bd6e0c..000d1f7 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1317,6 +1317,84 @@
   dlclose(handle);
 }
 
+TEST(dlfcn, dlclose_after_thread_local_dtor) {
+  bool is_dtor_triggered = false;
+
+  auto f = [](void* handle, bool* is_dtor_triggered) {
+    typedef void (*fn_t)(bool*);
+    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
+    ASSERT_TRUE(fn != nullptr) << dlerror();
+
+    fn(is_dtor_triggered);
+
+    ASSERT_TRUE(!*is_dtor_triggered);
+  };
+
+  void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
+  ASSERT_TRUE(handle == nullptr);
+
+  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  std::thread t(f, handle, &is_dtor_triggered);
+  t.join();
+
+  ASSERT_TRUE(is_dtor_triggered);
+  dlclose(handle);
+
+  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
+  ASSERT_TRUE(handle == nullptr);
+}
+
+TEST(dlfcn, dlclose_before_thread_local_dtor) {
+  bool is_dtor_triggered = false;
+
+  auto f = [](bool* is_dtor_triggered) {
+    void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
+    ASSERT_TRUE(handle == nullptr);
+
+    handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
+    ASSERT_TRUE(handle != nullptr) << dlerror();
+
+    typedef void (*fn_t)(bool*);
+    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
+    ASSERT_TRUE(fn != nullptr) << dlerror();
+
+    fn(is_dtor_triggered);
+
+    dlclose(handle);
+
+    ASSERT_TRUE(!*is_dtor_triggered);
+
+    // Since we have thread_atexit dtors associated with handle - the library should
+    // still be availabe.
+    handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
+    ASSERT_TRUE(handle != nullptr) << dlerror();
+    dlclose(handle);
+  };
+
+  void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  dlclose(handle);
+
+  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
+  ASSERT_TRUE(handle == nullptr);
+
+  std::thread t(f, &is_dtor_triggered);
+  t.join();
+#if defined(__BIONIC__)
+  // ld-android.so unloads unreferenced libraries on pthread_exit()
+  ASSERT_TRUE(is_dtor_triggered);
+  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
+  ASSERT_TRUE(handle == nullptr);
+#else
+  // GLIBC does not unload libraries with ref_count = 0 on pthread_exit
+  ASSERT_TRUE(is_dtor_triggered);
+  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+#endif
+}
+
 TEST(dlfcn, RTLD_macros) {
 #if !defined(RTLD_LOCAL)
 #error no RTLD_LOCAL
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index e45eb6e..61a837f 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -636,6 +636,16 @@
 }
 
 // -----------------------------------------------------------------------------
+// Library with non-trivial thread_local variable to test dlclose()
+// -----------------------------------------------------------------------------
+cc_test_library {
+    name: "libtest_thread_local_dtor",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["thread_local_dtor.cpp"],
+}
+
+
+// -----------------------------------------------------------------------------
 // Tool to use to align the shared libraries in a zip file.
 // -----------------------------------------------------------------------------
 cc_binary_host {
diff --git a/tests/libs/thread_local_dtor.cpp b/tests/libs/thread_local_dtor.cpp
new file mode 100644
index 0000000..cefff7a
--- /dev/null
+++ b/tests/libs/thread_local_dtor.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+namespace {
+
+class TestClass {
+ public:
+  TestClass(bool* flag) : flag_(flag) {}
+  ~TestClass() {
+    *flag_ = true;
+  }
+ private:
+  bool* flag_;
+};
+
+};  // namespace
+
+extern "C" void init_thread_local_variable(bool* flag) {
+  thread_local TestClass test(flag);
+}