Merge "liblog: event_tag_map benchmark"
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 115095c..caa7a5f 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -43,6 +43,7 @@
 #include "adb_utils.h"
 #include "file_sync_service.h"
 #include "line_printer.h"
+#include "sysdeps/stat.h"
 
 #include <android-base/file.h>
 #include <android-base/strings.h>
@@ -64,15 +65,11 @@
 }
 
 static bool should_pull_file(mode_t mode) {
-    return mode & (S_IFREG | S_IFBLK | S_IFCHR);
+    return S_ISREG(mode) || S_ISBLK(mode) || S_ISCHR(mode);
 }
 
 static bool should_push_file(mode_t mode) {
-    mode_t mask = S_IFREG;
-#if !defined(_WIN32)
-    mask |= S_IFLNK;
-#endif
-    return mode & mask;
+    return S_ISREG(mode) || S_ISLNK(mode);
 }
 
 struct copyinfo {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 0489d09..05d9fde 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -180,8 +180,6 @@
     /* nothing really */
 }
 
-#define  S_ISLNK(m)   0   /* no symlinks on Win32 */
-
 extern int  adb_unlink(const char*  path);
 #undef  unlink
 #define unlink  ___xxx_unlink
diff --git a/adb/sysdeps/stat.h b/adb/sysdeps/stat.h
index 5953595..ed2cf25fb 100644
--- a/adb/sysdeps/stat.h
+++ b/adb/sysdeps/stat.h
@@ -43,4 +43,21 @@
 // Windows doesn't have lstat.
 #define lstat adb_stat
 
+// mingw doesn't define S_IFLNK or S_ISLNK.
+#define S_IFLNK 0120000
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+
+// mingw defines S_IFBLK to a different value from bionic.
+#undef S_IFBLK
+#define S_IFBLK 0060000
+#undef S_ISBLK
+#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
 #endif
+
+// Make sure that host file mode values match the ones on the device.
+static_assert(S_IFMT == 00170000, "");
+static_assert(S_IFLNK == 0120000, "");
+static_assert(S_IFREG == 0100000, "");
+static_assert(S_IFBLK == 0060000, "");
+static_assert(S_IFDIR == 0040000, "");
+static_assert(S_IFCHR == 0020000, "");
diff --git a/adb/test_device.py b/adb/test_device.py
index 02a16e4..e76aaed 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -890,7 +890,8 @@
             except subprocess.CalledProcessError as e:
                 output = e.output
 
-            self.assertIn('Permission denied', output)
+            self.assertTrue('Permission denied' in output or
+                            'Read-only file system' in output)
 
     def _test_pull(self, remote_file, checksum):
         tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
diff --git a/base/Android.bp b/base/Android.bp
index e6ad15b..b9a6e0b 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -49,6 +49,11 @@
             srcs: ["errors_unix.cpp"],
             cppflags: ["-Wexit-time-destructors"],
         },
+        linux_bionic: {
+            srcs: ["errors_unix.cpp"],
+            cppflags: ["-Wexit-time-destructors"],
+            enabled: true,
+        },
         linux: {
             srcs: ["errors_unix.cpp"],
             cppflags: ["-Wexit-time-destructors"],
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 155b309..607745d 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -18,6 +18,7 @@
     debuggerd.cpp \
     elf_utils.cpp \
     getevent.cpp \
+    open_files_list.cpp \
     signal_sender.cpp \
     tombstone.cpp \
     utility.cpp \
@@ -108,9 +109,11 @@
 
 debuggerd_test_src_files := \
     utility.cpp \
+    open_files_list.cpp \
     test/dump_memory_test.cpp \
     test/elf_fake.cpp \
     test/log_fake.cpp \
+    test/open_files_list_test.cpp \
     test/property_fake.cpp \
     test/ptrace_fake.cpp \
     test/tombstone_test.cpp \
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 5ae66db..272fbf6 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -55,6 +55,7 @@
 
 #include "backtrace.h"
 #include "getevent.h"
+#include "open_files_list.h"
 #include "signal_sender.h"
 #include "tombstone.h"
 #include "utility.h"
@@ -452,7 +453,8 @@
 }
 
 static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
-                         BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,
+                         BacktraceMap* backtrace_map, const OpenFilesList& open_files,
+                         const std::set<pid_t>& siblings,
                          int* crash_signal, std::string* amfd_data) {
   if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
     ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
@@ -471,7 +473,8 @@
       case SIGSTOP:
         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
           ALOGV("debuggerd: stopped -- dumping to tombstone");
-          engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+          engrave_tombstone(tombstone_fd, backtrace_map, open_files,
+                            request.pid, request.tid, siblings,
                             request.abort_msg_address, amfd_data);
         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
           ALOGV("debuggerd: stopped -- dumping to fd");
@@ -498,7 +501,8 @@
       case SIGTRAP:
         ALOGV("stopped -- fatal signal\n");
         *crash_signal = signal;
-        engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+        engrave_tombstone(tombstone_fd, backtrace_map, open_files,
+                          request.pid, request.tid, siblings,
                           request.abort_msg_address, amfd_data);
         break;
 
@@ -593,6 +597,10 @@
   // Generate the backtrace map before dropping privileges.
   std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
 
+  // Collect the list of open files before dropping privileges.
+  OpenFilesList open_files;
+  populate_open_files_list(request.pid, &open_files);
+
   int amfd = -1;
   std::unique_ptr<std::string> amfd_data;
   if (request.action == DEBUGGER_ACTION_CRASH) {
@@ -610,8 +618,8 @@
   }
 
   int crash_signal = SIGKILL;
-  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
-                           &crash_signal, amfd_data.get());
+  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), open_files,
+                           siblings, &crash_signal, amfd_data.get());
   if (succeeded) {
     if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
       if (!tombstone_path.empty()) {
diff --git a/debuggerd/open_files_list.cpp b/debuggerd/open_files_list.cpp
new file mode 100644
index 0000000..5ef2abc
--- /dev/null
+++ b/debuggerd/open_files_list.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DEBUG"
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android/log.h>
+
+#include "open_files_list.h"
+
+#include "utility.h"
+
+void populate_open_files_list(pid_t pid, OpenFilesList* list) {
+  std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd";
+  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(fd_dir_name.c_str()), closedir);
+  if (dir == nullptr) {
+    ALOGE("failed to open directory %s: %s", fd_dir_name.c_str(), strerror(errno));
+    return;
+  }
+
+  struct dirent* de;
+  while ((de = readdir(dir.get())) != nullptr) {
+    if (*de->d_name == '.') {
+      continue;
+    }
+
+    int fd = atoi(de->d_name);
+    std::string path = fd_dir_name + "/" + std::string(de->d_name);
+    std::string target;
+    if (android::base::Readlink(path, &target)) {
+      list->emplace_back(fd, target);
+    } else {
+      ALOGE("failed to readlink %s: %s", path.c_str(), strerror(errno));
+      list->emplace_back(fd, "???");
+    }
+  }
+}
+
+void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix) {
+  for (auto& file : files) {
+    _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str());
+  }
+}
+
diff --git a/debuggerd/open_files_list.h b/debuggerd/open_files_list.h
new file mode 100644
index 0000000..b37228d
--- /dev/null
+++ b/debuggerd/open_files_list.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DEBUGGERD_OPEN_FILES_LIST_H
+#define _DEBUGGERD_OPEN_FILES_LIST_H
+
+#include <sys/types.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "utility.h"
+
+typedef std::vector<std::pair<int, std::string>> OpenFilesList;
+
+/* Populates the given list with open files for the given process. */
+void populate_open_files_list(pid_t pid, OpenFilesList* list);
+
+/* Dumps the open files list to the log. */
+void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix);
+
+#endif // _DEBUGGERD_OPEN_FILES_LIST_H
diff --git a/debuggerd/test/open_files_list_test.cpp b/debuggerd/test/open_files_list_test.cpp
new file mode 100644
index 0000000..85e0695
--- /dev/null
+++ b/debuggerd/test/open_files_list_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "android-base/test_utils.h"
+
+#include "open_files_list.h"
+
+// Check that we can produce a list of open files for the current process, and
+// that it includes a known open file.
+TEST(OpenFilesListTest, BasicTest) {
+  // Open a temporary file that we can check for in the list of open files.
+  TemporaryFile tf;
+
+  // Get the list of open files for this process.
+  OpenFilesList list;
+  populate_open_files_list(getpid(), &list);
+
+  // Verify our open file is in the list.
+  bool found = false;
+  for (auto&  file : list) {
+    if (file.first == tf.fd) {
+      EXPECT_EQ(file.second, std::string(tf.path));
+      found = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(found);
+}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 1e47483..e76edb9 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -46,6 +46,7 @@
 #include "backtrace.h"
 #include "elf_utils.h"
 #include "machine.h"
+#include "open_files_list.h"
 #include "tombstone.h"
 
 #define STACK_WORDS 16
@@ -571,7 +572,7 @@
 
     if (log_entry.id() == LOG_ID_EVENTS) {
       if (!g_eventTagMap) {
-        g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+        g_eventTagMap = android_openEventTagMap(NULL);
       }
       AndroidLogEntry e;
       char buf[512];
@@ -620,7 +621,8 @@
 }
 
 // Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
+static void dump_crash(log_t* log, BacktraceMap* map,
+                       const OpenFilesList& open_files, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
   // don't copy log messages to tombstone unless this is a dev device
   bool want_logs = __android_log_is_debuggable();
@@ -639,6 +641,9 @@
     }
   }
 
+  _LOG(log, logtype::OPEN_FILES, "\nopen files:\n");
+  dump_open_files_list_to_log(open_files, log, "    ");
+
   if (want_logs) {
     dump_logs(log, pid, 0);
   }
@@ -697,7 +702,8 @@
   return fd;
 }
 
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
+                       const OpenFilesList& open_files, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
                        std::string* amfd_data) {
   log_t log;
@@ -711,5 +717,5 @@
 
   log.tfd = tombstone_fd;
   log.amfd_data = amfd_data;
-  dump_crash(&log, map, pid, tid, siblings, abort_msg_address);
+  dump_crash(&log, map, open_files, pid, tid, siblings, abort_msg_address);
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index e1c39c5..126f804 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -32,7 +32,8 @@
 int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
+                       const OpenFilesList& open_files, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
                        std::string* amfd_data);
 
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index d820f0f..f7a3f73 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -70,7 +70,8 @@
   MAPS,
   MEMORY,
   STACK,
-  LOGS
+  LOGS,
+  OPEN_FILES
 };
 
 // Log information onto the tombstone.
diff --git a/libion/ion.c b/libion/ion.c
index 2db8845..a7b22b8 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -34,7 +34,7 @@
 
 int ion_open()
 {
-    int fd = open("/dev/ion", O_RDONLY);
+    int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC);
     if (fd < 0)
         ALOGE("open /dev/ion failed!\n");
     return fd;
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 16aa4fa..c498153 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -73,6 +73,9 @@
         linux: {
             host_ldlibs: ["-lrt"],
         },
+        linux_bionic: {
+            enabled: true,
+        },
     },
 
     cflags: [
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index f9cad99..e8e0335 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -73,12 +73,13 @@
     EventTagMap* newTagMap;
     off_t end;
     int save_errno;
+    const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
 
-    int fd = open(fileName, O_RDONLY | O_CLOEXEC);
+    int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
         save_errno = errno;
         fprintf(stderr, "%s: unable to open map '%s': %s\n",
-                OUT_TAG, fileName, strerror(save_errno));
+                OUT_TAG, tagfile, strerror(save_errno));
         goto fail_errno;
     }
 
@@ -87,7 +88,7 @@
     (void) lseek(fd, 0L, SEEK_SET);
     if (end < 0) {
         fprintf(stderr, "%s: unable to seek map '%s' %s\n",
-                OUT_TAG, fileName, strerror(save_errno));
+                OUT_TAG, tagfile, strerror(save_errno));
         goto fail_close;
     }
 
@@ -103,7 +104,7 @@
     fd = -1;
     if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
         fprintf(stderr, "%s: mmap(%s) failed: %s\n",
-                OUT_TAG, fileName, strerror(save_errno));
+                OUT_TAG, tagfile, strerror(save_errno));
         goto fail_free;
     }
 
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 157bd88..f19c3ab 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -48,7 +48,7 @@
 
 static int check_log_uid_permissions()
 {
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     uid_t uid = __android_log_uid();
 
     /* Matches clientHasLogCredentials() in logd */
@@ -130,7 +130,7 @@
     return kLogNotAvailable;
 }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
 static atomic_uintptr_t tagMap;
 #endif
 
@@ -140,7 +140,7 @@
 LIBLOG_ABI_PUBLIC void __android_log_close()
 {
     struct android_log_transport_write *transport;
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     EventTagMap *m;
 #endif
 
@@ -170,7 +170,7 @@
         }
     }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     /*
      * Additional risk here somewhat mitigated by immediately unlock flushing
      * the processor cache. The multi-threaded race that we choose to accept,
@@ -188,7 +188,7 @@
 
     __android_log_unlock();
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
 #endif
 
@@ -261,7 +261,7 @@
         return -EINVAL;
     }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     if (log_id == LOG_ID_SECURITY) {
         if (vec[0].iov_len < 4) {
             return -EINVAL;
@@ -293,7 +293,7 @@
             ret = __android_log_trylock();
             m = (EventTagMap *)atomic_load(&tagMap); /* trylock flush cache */
             if (!m) {
-                m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+                m = android_openEventTagMap(NULL);
                 if (ret) { /* trylock failed, use local copy, mark for close */
                     f = m;
                 } else {
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 25c779e..217b8c3 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -86,6 +86,13 @@
                 "ProcessCallStack.cpp",
             ],
         },
+        linux_bionic: {
+            enabled: true,
+            srcs: [
+                "Looper.cpp",
+                "ProcessCallStack.cpp",
+            ],
+        },
 
         darwin: {
             cflags: ["-Wno-unused-parameter"],
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 5ed0fe8..fce1378 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -62,7 +62,17 @@
         android: {
             static_libs: ["libz"],
         },
-        host: {
+        linux_bionic: {
+            static_libs: ["libz"],
+            enabled: true,
+        },
+        linux: {
+            shared_libs: ["libz-host"],
+        },
+        darwin: {
+            shared_libs: ["libz-host"],
+        },
+        windows: {
             shared_libs: ["libz-host"],
         },
     },
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 41f2280..94b8691 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -177,7 +177,7 @@
         static EventTagMap *eventTagMap = NULL;
 
         if (!eventTagMap && !hasOpenedEventTagMap) {
-            eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            eventTagMap = android_openEventTagMap(NULL);
             hasOpenedEventTagMap = true;
         }
         err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
diff --git a/logd/main.cpp b/logd/main.cpp
index 7550c41..c3343d7 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -311,7 +311,7 @@
     if (!map) {
         sem_wait(&sem_name);
         if (!map) {
-            map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            map = android_openEventTagMap(NULL);
         }
         sem_post(&sem_name);
         if (!map) {
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index bc502a0..df3ce85 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -331,6 +331,27 @@
     return true;
 }
 
+static bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path,
+                                        gid_t gid, mode_t mask) {
+    std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid);
+
+    if (mount(source_path.c_str(), dest_path.c_str(), nullptr,
+            MS_BIND, nullptr) != 0) {
+        PLOG(ERROR) << "failed to bind mount sdcardfs filesystem";
+        return false;
+    }
+
+    if (mount(source_path.c_str(), dest_path.c_str(), "none",
+            MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
+        PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+        if (umount2(dest_path.c_str(), MNT_DETACH))
+            PLOG(WARNING) << "Failed to unmount bind";
+        return false;
+    }
+
+    return true;
+}
+
 static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
         gid_t gid, userid_t userid, bool multi_user, bool full_write) {
     std::string dest_path_default = "/mnt/runtime/default/" + label;
@@ -343,9 +364,8 @@
         // permissions are completely masked off.
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
                                                       AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
-                                                      AID_EVERYBODY, 0027)
-                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027)
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
                                                       AID_EVERYBODY, full_write ? 0007 : 0027)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
@@ -355,9 +375,9 @@
         // deep inside attr_from_stat().
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
                                                       AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read,
                                                       AID_EVERYBODY, full_write ? 0027 : 0022)
-                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
                                                       AID_EVERYBODY, full_write ? 0007 : 0022)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 5319ff4..d6ead1a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -81,15 +81,6 @@
 $(INPUT_H_LABELS_H):
 	$(transform-generated-source)
 
-# We only want 'r' on userdebug and eng builds.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := r.c
-LOCAL_CFLAGS += $(common_cflags)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
-LOCAL_MODULE := r
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_EXECUTABLE)
-
 
 # We build BSD grep separately, so it can provide egrep and fgrep too.
 include $(CLEAR_VARS)
diff --git a/toolbox/r.c b/toolbox/r.c
deleted file mode 100644
index b96cdb2..0000000
--- a/toolbox/r.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#if __LP64__
-#define strtoptr strtoull
-#else
-#define strtoptr strtoul
-#endif
-
-static int usage()
-{
-    fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
-    return -1;
-}
-
-int main(int argc, char *argv[])
-{
-    if(argc < 2) return usage();
-
-    int width = 4;
-    if(!strcmp(argv[1], "-b")) {
-        width = 1;
-        argc--;
-        argv++;
-    } else if(!strcmp(argv[1], "-s")) {
-        width = 2;
-        argc--;
-        argv++;
-    }
-
-    if(argc < 2) return usage();
-    uintptr_t addr = strtoptr(argv[1], 0, 16);
-
-    uintptr_t endaddr = 0;
-    char* end = strchr(argv[1], '-');
-    if (end)
-        endaddr = strtoptr(end + 1, 0, 16);
-
-    if (!endaddr)
-        endaddr = addr + width - 1;
-
-    if (endaddr <= addr) {
-        fprintf(stderr, "end address <= start address\n");
-        return -1;
-    }
-
-    bool set = false;
-    uint32_t value = 0;
-    if(argc > 2) {
-        set = true;
-        value = strtoul(argv[2], 0, 16);
-    }
-
-    int fd = open("/dev/mem", O_RDWR | O_SYNC);
-    if(fd < 0) {
-        fprintf(stderr,"cannot open /dev/mem\n");
-        return -1;
-    }
-
-    off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
-    size_t mmap_size = endaddr - mmap_start + 1;
-    mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
-    void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
-                        MAP_SHARED, fd, mmap_start);
-
-    if(page == MAP_FAILED){
-        fprintf(stderr,"cannot mmap region\n");
-        return -1;
-    }
-
-    while (addr <= endaddr) {
-        switch(width){
-        case 4: {
-            uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
-            break;
-        }
-        case 2: {
-            uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
-            break;
-        }
-        case 1: {
-            uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
-            break;
-        }
-        }
-        addr += width;
-    }
-    return 0;
-}