adb: move usb_* to client/usb_*.
am: 456e1ad420

Change-Id: I4429618a7661c2ef7cb6cb8717995d85c5030905
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index ec9b1c3..c3f1fe0 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -388,7 +388,13 @@
 
 static void adb_auth_inotify_init(const std::set<std::string>& paths) {
     LOG(INFO) << "adb_auth_inotify_init...";
+
     int infd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
+    if (infd < 0) {
+        PLOG(ERROR) << "failed to create inotify fd";
+        return;
+    }
+
     for (const std::string& path : paths) {
         int wd = inotify_add_watch(infd, path.c_str(), IN_CREATE | IN_MOVED_TO);
         if (wd < 0) {
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 78be944..f902af3 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -46,24 +46,6 @@
 
   *uptime = file_stat.st_mtime;
 
-  // The following code (till function exit) is a debug test to ensure the
-  // validity of the file mtime value, i.e., to check that the record file
-  // mtime values are not changed once set.
-  // TODO(jhawkins): Remove this code.
-  std::string content;
-  if (!android::base::ReadFileToString(path, &content)) {
-    PLOG(ERROR) << "Failed to read " << path;
-    return false;
-  }
-
-  // Ignore existing bootstat records (which do not contain file content).
-  if (!content.empty()) {
-    int32_t value;
-    if (android::base::ParseInt(content, &value)) {
-      bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
-    }
-  }
-
   return true;
 }
 
@@ -89,16 +71,6 @@
     return;
   }
 
-  // Writing the value as content in the record file is a debug measure to
-  // ensure the validity of the file mtime value, i.e., to check that the record
-  // file mtime values are not changed once set.
-  // TODO(jhawkins): Remove this block.
-  if (!android::base::WriteStringToFd(std::to_string(value), record_fd)) {
-    PLOG(ERROR) << "Failed to write value to " << record_path;
-    close(record_fd);
-    return;
-  }
-
   // Fill out the stat structure for |record_path| in order to get the atime to
   // set in the utime() call.
   struct stat file_stat;
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 01c2cc1..90f6513 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -45,14 +45,6 @@
     return false;
   }
 
-  // Writing the value as content in the record file is a debug measure to
-  // ensure the validity of the file mtime value, i.e., to check that the record
-  // file mtime values are not changed once set.
-  // TODO(jhawkins): Remove this block.
-  if (!android::base::WriteStringToFd(std::to_string(value), record_fd)) {
-    return false;
-  }
-
   // Set the |mtime| of the file to store the value of the boot event while
   // preserving the |atime|.
   struct timeval atime = {/* tv_sec */ 0, /* tv_usec */ 0};
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index b9dfedb..c145933 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -36,7 +36,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
-#include <log/logger.h>
+#include <log/log.h>
 #include <procinfo/process.h>
 #include <selinux/selinux.h>
 
@@ -57,8 +57,9 @@
 }
 
 // Attach to a thread, and verify that it's still a member of the given process
-static bool ptrace_attach_thread(pid_t pid, pid_t tid) {
-  if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+static bool ptrace_seize_thread(pid_t pid, pid_t tid, std::string* error) {
+  if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) {
+    *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno));
     return false;
   }
 
@@ -67,9 +68,15 @@
     if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
       PLOG(FATAL) << "failed to detach from thread " << tid;
     }
-    errno = ECHILD;
+    *error = StringPrintf("thread %d is not in process %d", tid, pid);
     return false;
   }
+
+  // Put the task into ptrace-stop state.
+  if (ptrace(PTRACE_INTERRUPT, tid, 0, 0) != 0) {
+    PLOG(FATAL) << "failed to interrupt thread " << tid;
+  }
+
   return true;
 }
 
@@ -159,11 +166,15 @@
   return true;
 }
 
+static void signal_handler(int) {
+  // We can't log easily, because the heap might be corrupt.
+  // Just die and let the surrounding log context explain things.
+  _exit(1);
+}
+
 static void abort_handler(pid_t target, const bool& tombstoned_connected,
                           unique_fd& tombstoned_socket, unique_fd& output_fd,
                           const char* abort_msg) {
-  LOG(ERROR) << abort_msg;
-
   // If we abort before we get an output fd, contact tombstoned to let any
   // potential listeners know that we failed.
   if (!tombstoned_connected) {
@@ -176,7 +187,6 @@
 
   dprintf(output_fd.get(), "crash_dump failed to dump process %d: %s\n", target, abort_msg);
 
-  // Don't dump ourselves.
   _exit(1);
 }
 
@@ -202,6 +212,11 @@
     abort_handler(target, tombstoned_connected, tombstoned_socket, output_fd, abort_msg);
   });
 
+  // Don't try to dump ourselves.
+  struct sigaction action = {};
+  action.sa_handler = signal_handler;
+  debuggerd_register_handlers(&action);
+
   if (argc != 2) {
     return 1;
   }
@@ -242,11 +257,14 @@
     exit(0);
   }
 
+  // Die if we take too long.
+  alarm(20);
+
   check_process(target_proc_fd, target);
 
-  int attach_error = 0;
-  if (!ptrace_attach_thread(target, main_tid)) {
-    PLOG(FATAL) << "failed to attach to thread " << main_tid << " in process " << target;
+  std::string attach_error;
+  if (!ptrace_seize_thread(target, main_tid, &attach_error)) {
+    LOG(FATAL) << attach_error;
   }
 
   check_process(target_proc_fd, target);
@@ -266,17 +284,14 @@
   } else {
     unique_fd devnull(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
     TEMP_FAILURE_RETRY(dup2(devnull.get(), STDOUT_FILENO));
-  }
-
-  if (attach_error != 0) {
-    PLOG(FATAL) << "failed to attach to thread " << main_tid << " in process " << target;
+    output_fd = std::move(devnull);
   }
 
   LOG(INFO) << "performing dump of process " << target << " (target tid = " << main_tid << ")";
 
-  // At this point, the thread that made the request has been PTRACE_ATTACHed
-  // and has the signal that triggered things queued. Send PTRACE_CONT, and
-  // then wait for the signal.
+  // At this point, the thread that made the request has been attached and is
+  // in ptrace-stopped state. After resumption, the triggering signal that has
+  // been queued will be delivered.
   if (ptrace(PTRACE_CONT, main_tid, 0, 0) != 0) {
     PLOG(ERROR) << "PTRACE_CONT(" << main_tid << ") failed";
     exit(1);
@@ -305,17 +320,19 @@
   // Now that we have the signal that kicked things off, attach all of the
   // sibling threads, and then proceed.
   bool fatal_signal = signo != DEBUGGER_SIGNAL;
-  int resume_signal = fatal_signal ? signo : 0;
   std::set<pid_t> siblings;
-  if (resume_signal == 0) {
+  std::set<pid_t> attached_siblings;
+  if (fatal_signal) {
     if (!android::procinfo::GetProcessTids(target, &siblings)) {
       PLOG(FATAL) << "failed to get process siblings";
     }
     siblings.erase(main_tid);
 
     for (pid_t sibling_tid : siblings) {
-      if (!ptrace_attach_thread(target, sibling_tid)) {
-        PLOG(FATAL) << "failed to attach to thread " << main_tid << " in process " << target;
+      if (!ptrace_seize_thread(target, sibling_tid, &attach_error)) {
+        LOG(WARNING) << attach_error;
+      } else {
+        attached_siblings.insert(sibling_tid);
       }
     }
   }
@@ -328,50 +345,49 @@
   std::string amfd_data;
 
   if (backtrace) {
-    dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, siblings, 0);
+    dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0);
   } else {
     // Collect the list of open files.
     OpenFilesList open_files;
     populate_open_files_list(target, &open_files);
 
-    engrave_tombstone(output_fd.get(), backtrace_map.get(), open_files, target, main_tid, siblings,
-                      abort_address, fatal_signal ? &amfd_data : nullptr);
+    engrave_tombstone(output_fd.get(), backtrace_map.get(), open_files, target, main_tid,
+                      attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
   }
 
+  // We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
+  // group-stop state, which is true as long as no stopping signals are sent.
+
   bool wait_for_gdb = android::base::GetBoolProperty("debug.debuggerd.wait_for_gdb", false);
-  if (wait_for_gdb) {
+  if (!fatal_signal || siginfo.si_code == SI_USER) {
     // Don't wait_for_gdb when the process didn't actually crash.
-    if (!fatal_signal) {
-      wait_for_gdb = false;
-    } else {
-      // Use ALOGI to line up with output from engrave_tombstone.
-      ALOGI(
-        "***********************************************************\n"
-        "* Process %d has been suspended while crashing.\n"
-        "* To attach gdbserver and start gdb, run this on the host:\n"
-        "*\n"
-        "*     gdbclient.py -p %d\n"
-        "*\n"
-        "***********************************************************",
-        target, main_tid);
-    }
+    wait_for_gdb = false;
   }
 
-  for (pid_t tid : siblings) {
-    // Don't send the signal to sibling threads.
-    if (ptrace(PTRACE_DETACH, tid, 0, wait_for_gdb ? SIGSTOP : 0) != 0) {
-      PLOG(ERROR) << "ptrace detach from " << tid << " failed";
+  // If the process crashed or we need to send it SIGSTOP for wait_for_gdb,
+  // get it in a state where it can receive signals, and then send the relevant
+  // signal.
+  if (wait_for_gdb || fatal_signal) {
+    if (ptrace(PTRACE_INTERRUPT, main_tid, 0, 0) != 0) {
+      PLOG(ERROR) << "failed to use PTRACE_INTERRUPT on " << main_tid;
     }
-  }
 
-  if (ptrace(PTRACE_DETACH, main_tid, 0, wait_for_gdb ? SIGSTOP : resume_signal)) {
-    PLOG(ERROR) << "ptrace detach from main thread " << main_tid << " failed";
+    if (tgkill(target, main_tid, wait_for_gdb ? SIGSTOP : signo) != 0) {
+      PLOG(ERROR) << "failed to resend signal " << signo << " to " << main_tid;
+    }
   }
 
   if (wait_for_gdb) {
-    if (tgkill(target, main_tid, resume_signal) != 0) {
-      PLOG(ERROR) << "failed to resend signal to process " << target;
-    }
+    // Use ALOGI to line up with output from engrave_tombstone.
+    ALOGI(
+      "***********************************************************\n"
+      "* Process %d has been suspended while crashing.\n"
+      "* To attach gdbserver and start gdb, run this on the host:\n"
+      "*\n"
+      "*     gdbclient.py -p %d\n"
+      "*\n"
+      "***********************************************************",
+      target, main_tid);
   }
 
   if (fatal_signal) {
@@ -380,7 +396,7 @@
 
   // Close stdout before we notify tombstoned of completion.
   close(STDOUT_FILENO);
-  if (!tombstoned_notify_completion(tombstoned_socket.get())) {
+  if (tombstoned_connected && !tombstoned_notify_completion(tombstoned_socket.get())) {
     LOG(ERROR) << "failed to notify tombstoned of completion";
   }
 
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index f51b5f2..e7503e9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -17,6 +17,7 @@
 #include <err.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 
 #include <chrono>
@@ -90,6 +91,7 @@
   // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
   void FinishIntercept(int* result);
 
+  void StartProcess(std::function<void()> function);
   void StartCrasher(const std::string& crash_type);
   void FinishCrasher();
   void AssertDeath(int signo);
@@ -166,9 +168,8 @@
   }
 }
 
-void CrasherTest::StartCrasher(const std::string& crash_type) {
-  std::string type = "wait-" + crash_type;
-
+void CrasherTest::StartProcess(std::function<void()> function) {
+  unique_fd read_pipe;
   unique_fd crasher_read_pipe;
   if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
     FAIL() << "failed to create pipe: " << strerror(errno);
@@ -182,9 +183,17 @@
     dup2(crasher_read_pipe.get(), STDIN_FILENO);
     dup2(devnull.get(), STDOUT_FILENO);
     dup2(devnull.get(), STDERR_FILENO);
+    function();
+    _exit(0);
+  }
+}
+
+void CrasherTest::StartCrasher(const std::string& crash_type) {
+  std::string type = "wait-" + crash_type;
+  StartProcess([type]() {
     execl(CRASHER_PATH, CRASHER_PATH, type.c_str(), nullptr);
     err(1, "exec failed");
-  }
+  });
 }
 
 void CrasherTest::FinishCrasher() {
@@ -340,24 +349,15 @@
   AssertDeath(SIGABRT);
 }
 
+// wait_for_gdb shouldn't trigger on manually sent signals.
 TEST_F(CrasherTest, wait_for_gdb_signal) {
   if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
     FAIL() << "failed to enable wait_for_gdb";
   }
 
   StartCrasher("abort");
-  ASSERT_EQ(0, kill(crasher_pid, SIGABRT)) << strerror(errno);
-
-  std::this_thread::sleep_for(500ms);
-
-  int status;
-  ASSERT_EQ(crasher_pid, (TIMEOUT(1, waitpid(crasher_pid, &status, WUNTRACED))));
-  ASSERT_TRUE(WIFSTOPPED(status));
-  ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
-
-  ASSERT_EQ(0, kill(crasher_pid, SIGCONT)) << strerror(errno);
-
-  AssertDeath(SIGABRT);
+  ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
+  AssertDeath(SIGSEGV);
 }
 
 TEST_F(CrasherTest, backtrace) {
@@ -388,3 +388,20 @@
   ConsumeFd(std::move(output_fd), &result);
   ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
 }
+
+TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
+  StartProcess([]() {
+    prctl(PR_SET_DUMPABLE, 0);
+    volatile char* null = static_cast<char*>(nullptr);
+    *null = '\0';
+  });
+  AssertDeath(SIGSEGV);
+}
+
+TEST_F(CrasherTest, PR_SET_DUMPABLE_0_raise) {
+  StartProcess([]() {
+    prctl(PR_SET_DUMPABLE, 0);
+    raise(SIGUSR1);
+  });
+  AssertDeath(SIGUSR1);
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 6033a6b..c009869 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -31,6 +31,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <linux/futex.h>
 #include <pthread.h>
 #include <sched.h>
 #include <signal.h>
@@ -46,6 +47,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "private/bionic_futex.h"
 #include "private/libc_logging.h"
 
 // see man(2) prctl, specifically the section about PR_GET_NAME
@@ -61,6 +63,9 @@
 
 static debuggerd_callbacks_t g_callbacks;
 
+// Mutex to ensure only one crashing thread dumps itself.
+static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 // Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
 #define fatal(...)                                             \
   do {                                                         \
@@ -151,8 +156,7 @@
 }
 
 struct debugger_thread_info {
-  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-  bool crash_dump_started = false;
+  bool crash_dump_started;
   pid_t crashing_tid;
   pid_t pseudothread_tid;
   int signal_number;
@@ -228,16 +232,43 @@
     }
   }
 
-  pthread_mutex_unlock(&thread_info->mutex);
+  syscall(__NR_exit, 0);
   return 0;
 }
 
+static void resend_signal(siginfo_t* info, bool crash_dump_started) {
+  // Signals can either be fatal or nonfatal.
+  // For fatal signals, crash_dump will send us the signal we crashed with
+  // before resuming us, so that processes using waitpid on us will see that we
+  // exited with the correct exit status (e.g. so that sh will report
+  // "Segmentation fault" instead of "Killed"). For this to work, we need
+  // to deregister our signal handler for that signal before continuing.
+  if (info->si_signo != DEBUGGER_SIGNAL) {
+    signal(info->si_signo, SIG_DFL);
+  }
+
+  // We need to return from our signal handler so that crash_dump can see the
+  // signal via ptrace and dump the thread that crashed. However, returning
+  // does not guarantee that the signal will be thrown again, even for SIGSEGV
+  // and friends, since the signal could have been sent manually. We blocked
+  // all signals when registering the handler, so resending the signal (using
+  // rt_tgsigqueueinfo(2) to preserve SA_SIGINFO) will cause it to be delivered
+  // when our signal handler returns.
+  if (crash_dump_started || info->si_signo != DEBUGGER_SIGNAL) {
+    int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), info->si_signo, info);
+    if (rc != 0) {
+      fatal("failed to resend signal during crash: %s", strerror(errno));
+    }
+  }
+
+  if (info->si_signo == DEBUGGER_SIGNAL) {
+    pthread_mutex_unlock(&crash_mutex);
+  }
+}
+
 // Handler that does crash dumping by forking and doing the processing in the child.
 // Do this by ptracing the relevant thread, and then execing debuggerd to do the actual dump.
 static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
-  // Mutex to prevent multiple crashing threads from trying to talk
-  // to debuggerd at the same time.
-  static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
   int ret = pthread_mutex_lock(&crash_mutex);
   if (ret != 0) {
     __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
@@ -250,59 +281,10 @@
     info = nullptr;
   }
 
-  log_signal_summary(signal_number, info);
-  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) {
-    // process has disabled core dumps and PTRACE_ATTACH, and does not want to be dumped.
-    // Honor that intention by not connecting to debuggerd and asking it to dump our internal state.
-    __libc_format_log(ANDROID_LOG_INFO, "libc",
-                      "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0");
-
-    pthread_mutex_unlock(&crash_mutex);
-    return;
-  }
-
-  void* abort_message = nullptr;
-  if (g_callbacks.get_abort_message) {
-    abort_message = g_callbacks.get_abort_message();
-  }
-
-  debugger_thread_info thread_info = {
-    .crashing_tid = gettid(),
-    .signal_number = signal_number,
-    .info = info
-  };
-  pthread_mutex_lock(&thread_info.mutex);
-
-  // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread).
-  pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
-                          CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID,
-                          &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid);
-  if (child_pid == -1) {
-    fatal("failed to spawn debuggerd dispatch thread: %s", strerror(errno));
-  }
-
-  // Wait for the child to finish and unlock the mutex.
-  // This relies on bionic behavior that isn't guaranteed by the standard.
-  pthread_mutex_lock(&thread_info.mutex);
-
-  // Signals can either be fatal or nonfatal.
-  // For fatal signals, crash_dump will PTRACE_CONT us with the signal we
-  // crashed with, so that processes using waitpid on us will see that we
-  // exited with the correct exit status (e.g. so that sh will report
-  // "Segmentation fault" instead of "Killed"). For this to work, we need
-  // to deregister our signal handler for that signal before continuing.
-  if (signal_number != DEBUGGER_SIGNAL) {
-    signal(signal_number, SIG_DFL);
-  }
-
-  // We need to return from the signal handler so that debuggerd can dump the
-  // thread that crashed, but returning here does not guarantee that the signal
-  // will be thrown again, even for SIGSEGV and friends, since the signal could
-  // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to
-  // preserve the SA_SIGINFO contents.
-  struct siginfo si;
+  struct siginfo si = {};
   if (!info) {
     memset(&si, 0, sizeof(si));
+    si.si_signo = signal_number;
     si.si_code = SI_USER;
     si.si_pid = getpid();
     si.si_uid = getuid();
@@ -314,23 +296,66 @@
     // check to allow all si_code values in calls coming from inside the house.
   }
 
+  log_signal_summary(signal_number, info);
+  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) {
+    // The process has disabled core dumps and PTRACE_ATTACH, and does not want to be dumped.
+    __libc_format_log(ANDROID_LOG_INFO, "libc",
+                      "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0");
+    resend_signal(info, false);
+    return;
+  }
+
+  if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
+    // The process has NO_NEW_PRIVS enabled, so we can't transition to the crash_dump context.
+    __libc_format_log(ANDROID_LOG_INFO, "libc",
+                      "Suppressing debuggerd output because prctl(PR_GET_NO_NEW_PRIVS)==1");
+    resend_signal(info, false);
+    return;
+  }
+
+  void* abort_message = nullptr;
+  if (g_callbacks.get_abort_message) {
+    abort_message = g_callbacks.get_abort_message();
+  }
   // Populate si_value with the abort message address, if found.
   if (abort_message) {
     info->si_value.sival_ptr = abort_message;
   }
 
-  // Only resend the signal if we know that either crash_dump has ptraced us or
-  // the signal was fatal.
-  if (thread_info.crash_dump_started || signal_number != DEBUGGER_SIGNAL) {
-    int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
-    if (rc != 0) {
-      fatal("failed to resend signal during crash: %s", strerror(errno));
-    }
+  debugger_thread_info thread_info = {
+    .crash_dump_started = false,
+    .pseudothread_tid = -1,
+    .crashing_tid = gettid(),
+    .signal_number = signal_number,
+    .info = info
+  };
+
+  // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread).
+  pid_t child_pid =
+    clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
+          CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
+          &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid);
+  if (child_pid == -1) {
+    fatal("failed to spawn debuggerd dispatch thread: %s", strerror(errno));
   }
 
-  if (signal_number == DEBUGGER_SIGNAL) {
-    pthread_mutex_unlock(&crash_mutex);
+  // Wait for the child to start...
+  __futex_wait(&thread_info.pseudothread_tid, -1, nullptr);
+
+  // and then wait for it to finish.
+  __futex_wait(&thread_info.pseudothread_tid, child_pid, nullptr);
+
+  // Signals can either be fatal or nonfatal.
+  // For fatal signals, crash_dump will PTRACE_CONT us with the signal we
+  // crashed with, so that processes using waitpid on us will see that we
+  // exited with the correct exit status (e.g. so that sh will report
+  // "Segmentation fault" instead of "Killed"). For this to work, we need
+  // to deregister our signal handler for that signal before continuing.
+  if (signal_number != DEBUGGER_SIGNAL) {
+    signal(signal_number, SIG_DFL);
   }
+
+  resend_signal(info, thread_info.crash_dump_started);
 }
 
 void debuggerd_init(debuggerd_callbacks_t* callbacks) {
@@ -363,15 +388,5 @@
 
   // Use the alternate signal stack if available so we can catch stack overflows.
   action.sa_flags |= SA_ONSTACK;
-
-  sigaction(SIGABRT, &action, nullptr);
-  sigaction(SIGBUS, &action, nullptr);
-  sigaction(SIGFPE, &action, nullptr);
-  sigaction(SIGILL, &action, nullptr);
-  sigaction(SIGSEGV, &action, nullptr);
-#if defined(SIGSTKFLT)
-  sigaction(SIGSTKFLT, &action, nullptr);
-#endif
-  sigaction(SIGTRAP, &action, nullptr);
-  sigaction(DEBUGGER_SIGNAL, &action, nullptr);
+  debuggerd_register_handlers(&action);
 }
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 302f4c2..7196e0a 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -39,4 +39,18 @@
 // to the log.
 #define DEBUGGER_SIGNAL (__SIGRTMIN + 3)
 
+static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) {
+  sigaction(SIGABRT, action, nullptr);
+  sigaction(SIGBUS, action, nullptr);
+  sigaction(SIGFPE, action, nullptr);
+  sigaction(SIGILL, action, nullptr);
+  sigaction(SIGSEGV, action, nullptr);
+#if defined(SIGSTKFLT)
+  sigaction(SIGSTKFLT, action, nullptr);
+#endif
+  sigaction(SIGSYS, action, nullptr);
+  sigaction(SIGTRAP, action, nullptr);
+  sigaction(DEBUGGER_SIGNAL, action, nullptr);
+}
+
 __END_DECLS
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 3c1dcaf..8705ece 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -85,7 +85,13 @@
     std::string path = android::base::StringPrintf("%stombstone_%02zu", kTombstoneDirectory, i);
     struct stat st;
     if (stat(path.c_str(), &st) != 0) {
-      PLOG(ERROR) << "failed to stat " << path;
+      if (errno == ENOENT) {
+        oldest_tombstone = i;
+        break;
+      } else {
+        PLOG(ERROR) << "failed to stat " << path;
+        continue;
+      }
     }
 
     if (st.st_mtime < oldest_time) {
@@ -110,7 +116,7 @@
   }
 
   result.reset(
-    openat(tombstone_directory_fd, buf, O_CREAT | O_EXCL | O_WRONLY | O_APPEND, O_CLOEXEC, 0700));
+    openat(tombstone_directory_fd, buf, O_CREAT | O_EXCL | O_WRONLY | O_APPEND | O_CLOEXEC, 0700));
   if (result == -1) {
     PLOG(FATAL) << "failed to create tombstone at " << kTombstoneDirectory << buf;
   }
diff --git a/debuggerd/tombstoned/tombstoned.rc b/debuggerd/tombstoned/tombstoned.rc
index 3aacf33..b8345ca 100644
--- a/debuggerd/tombstoned/tombstoned.rc
+++ b/debuggerd/tombstoned/tombstoned.rc
@@ -1,9 +1,10 @@
 service tombstoned /system/bin/tombstoned
-    class core
-
     user tombstoned
     group system
 
+    # Don't start tombstoned until after the real /data is mounted.
+    class late_start
+
     socket tombstoned_crash seqpacket 0666 system system
     socket tombstoned_intercept seqpacket 0666 system system
     writepid /dev/cpuset/system-background/tasks
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 3f8bc8f..f970e68 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -358,7 +358,7 @@
             "  devices [-l]                             List all connected devices [with\n"
             "                                           device paths].\n"
             "  continue                                 Continue with autoboot.\n"
-            "  reboot [bootloader]                      Reboot device [into bootloader].\n"
+            "  reboot [bootloader|emergency]            Reboot device [into bootloader or emergency mode].\n"
             "  reboot-bootloader                        Reboot device into bootloader.\n"
             "  help                                     Show this help message.\n"
             "\n"
@@ -1397,6 +1397,7 @@
     bool wants_wipe = false;
     bool wants_reboot = false;
     bool wants_reboot_bootloader = false;
+    bool wants_reboot_emergency = false;
     bool skip_reboot = false;
     bool wants_set_active = false;
     bool skip_secondary = false;
@@ -1648,6 +1649,11 @@
                     wants_reboot_bootloader = true;
                     skip(1);
                 }
+                if (!strcmp(*argv, "emergency")) {
+                    wants_reboot = false;
+                    wants_reboot_emergency = true;
+                    skip(1);
+                }
             }
             require(0);
         } else if(!strcmp(*argv, "reboot-bootloader")) {
@@ -1807,6 +1813,9 @@
     } else if (wants_reboot_bootloader) {
         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
         fb_queue_wait_for_disconnect();
+    } else if (wants_reboot_emergency) {
+        fb_queue_command("reboot-emergency", "rebooting into emergency download (EDL) mode");
+        fb_queue_wait_for_disconnect();
     }
 
     return fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 8d5b51b..e321c17 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -11,7 +11,8 @@
     libcrypto \
     libext4_utils \
     libsquashfs_utils \
-    libselinux
+    libselinux \
+    libavb
 
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
@@ -22,7 +23,9 @@
     fs_mgr_format.c \
     fs_mgr_fstab.c \
     fs_mgr_slotselect.c \
-    fs_mgr_verity.cpp
+    fs_mgr_verity.cpp \
+    fs_mgr_avb.cpp \
+    fs_mgr_avb_ops.cpp
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/include \
     system/vold \
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 9a53d62..43fb9ea 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -46,6 +46,7 @@
 #include <private/android_logger.h>
 
 #include "fs_mgr_priv.h"
+#include "fs_mgr_priv_avb.h"
 #include "fs_mgr_priv_verity.h"
 
 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
@@ -407,7 +408,7 @@
     return ret;
 }
 
-static int fs_match(char *in1, char *in2)
+static int fs_match(const char *in1, const char *in2)
 {
     char *n1;
     char *n2;
@@ -670,11 +671,17 @@
     int mret = -1;
     int mount_errno = 0;
     int attempted_idx = -1;
+    int avb_ret = FS_MGR_SETUP_AVB_FAIL;
 
     if (!fstab) {
         return -1;
     }
 
+    if (fs_mgr_is_avb_used() &&
+        (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
+        return -1;
+    }
+
     for (i = 0; i < fstab->num_entries; i++) {
         /* Don't mount entries that are managed by vold or not for the mount mode*/
         if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
@@ -713,7 +720,22 @@
             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
         }
 
-        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+        if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
+            /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
+             * should set up the device without using dm-verity.
+             * The actual mounting still take place in the following
+             * mount_with_alternatives().
+             */
+            if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
+                INFO("AVB HASHTREE disabled\n");
+            } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
+                       FS_MGR_SETUP_AVB_SUCCESS) {
+                ERROR("Failed to set up AVB on partition: %s, skipping!\n",
+                      fstab->recs[i].mount_point);
+                /* Skips mounting the device. */
+                continue;
+            }
+        } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
@@ -722,6 +744,7 @@
                 continue;
             }
         }
+
         int last_idx_inspected;
         int top_idx = i;
 
@@ -825,6 +848,10 @@
         }
     }
 
+    if (fs_mgr_is_avb_used()) {
+        fs_mgr_unload_vbmeta_images();
+    }
+
     if (error_count) {
         return -1;
     } else {
@@ -837,7 +864,7 @@
  * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
  * in turn, and stop on 1st success, or no more match.
  */
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                     char *tmp_mount_point)
 {
     int i = 0;
@@ -845,11 +872,17 @@
     int mount_errors = 0;
     int first_mount_errno = 0;
     char *m;
+    int avb_ret = FS_MGR_SETUP_AVB_FAIL;
 
     if (!fstab) {
         return ret;
     }
 
+    if (fs_mgr_is_avb_used() &&
+        (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
+        return ret;
+    }
+
     for (i = 0; i < fstab->num_entries; i++) {
         if (!fs_match(fstab->recs[i].mount_point, n_name)) {
             continue;
@@ -882,7 +915,22 @@
             do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i]);
         }
 
-        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+        if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
+            /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
+             * should set up the device without using dm-verity.
+             * The actual mounting still take place in the following
+             * mount_with_alternatives().
+             */
+            if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
+                INFO("AVB HASHTREE disabled\n");
+            } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
+                       FS_MGR_SETUP_AVB_SUCCESS) {
+                ERROR("Failed to set up AVB on partition: %s, skipping!\n",
+                      fstab->recs[i].mount_point);
+                /* Skips mounting the device. */
+                continue;
+            }
+        } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
@@ -921,6 +969,9 @@
     }
 
 out:
+    if (fs_mgr_is_avb_used()) {
+        fs_mgr_unload_vbmeta_images();
+    }
     return ret;
 }
 
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
new file mode 100644
index 0000000..51632cf
--- /dev/null
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -0,0 +1,642 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <libavb/libavb.h>
+#include <openssl/sha.h>
+#include <sys/ioctl.h>
+#include <utils/Compat.h>
+
+#include "fs_mgr.h"
+#include "fs_mgr_avb_ops.h"
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_avb.h"
+#include "fs_mgr_priv_dm_ioctl.h"
+#include "fs_mgr_priv_sha.h"
+
+/* The format of dm-verity construction parameters:
+ *     <version> <dev> <hash_dev> <data_block_size> <hash_block_size>
+ *     <num_data_blocks> <hash_start_block> <algorithm> <digest> <salt>
+ */
+#define VERITY_TABLE_FORMAT \
+    "%u %s %s %u %u "       \
+    "%" PRIu64 " %" PRIu64 " %s %s %s "
+
+#define VERITY_TABLE_PARAMS(hashtree_desc, blk_device, digest, salt)  \
+    hashtree_desc.dm_verity_version, blk_device, blk_device,          \
+        hashtree_desc.data_block_size, hashtree_desc.hash_block_size, \
+        hashtree_desc.image_size /                                    \
+            hashtree_desc.data_block_size, /* num_data_blocks. */     \
+        hashtree_desc.tree_offset /                                   \
+            hashtree_desc.hash_block_size, /* hash_start_block. */    \
+        (char *)hashtree_desc.hash_algorithm, digest, salt
+
+#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
+#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
+
+/* The default format of dm-verity optional parameters:
+ *     <#opt_params> ignore_zero_blocks restart_on_corruption
+ */
+#define VERITY_TABLE_OPT_DEFAULT_FORMAT "2 %s %s"
+#define VERITY_TABLE_OPT_DEFAULT_PARAMS \
+    VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
+
+/* The FEC (forward error correction) format of dm-verity optional parameters:
+ *     <#opt_params> use_fec_from_device <fec_dev>
+ *     fec_roots <num> fec_blocks <num> fec_start <offset>
+ *     ignore_zero_blocks restart_on_corruption
+ */
+#define VERITY_TABLE_OPT_FEC_FORMAT                              \
+    "10 use_fec_from_device %s fec_roots %u fec_blocks %" PRIu64 \
+    " fec_start %" PRIu64 " %s %s"
+
+/* Note that fec_blocks is the size that FEC covers, *not* the
+ * size of the FEC data. Since we use FEC for everything up until
+ * the FEC data, it's the same as the offset (fec_start).
+ */
+#define VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device) \
+    blk_device, hashtree_desc.fec_num_roots,                   \
+        hashtree_desc.fec_offset /                             \
+            hashtree_desc.data_block_size, /* fec_blocks */    \
+        hashtree_desc.fec_offset /                             \
+            hashtree_desc.data_block_size, /* fec_start */     \
+        VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
+
+AvbSlotVerifyData *fs_mgr_avb_verify_data = nullptr;
+AvbOps *fs_mgr_avb_ops = nullptr;
+
+enum HashAlgorithm {
+    kInvalid = 0,
+    kSHA256 = 1,
+    kSHA512 = 2,
+};
+
+struct androidboot_vbmeta {
+    HashAlgorithm hash_alg;
+    uint8_t digest[SHA512_DIGEST_LENGTH];
+    size_t vbmeta_size;
+    bool allow_verification_error;
+};
+
+androidboot_vbmeta fs_mgr_vbmeta_prop;
+
+static inline bool nibble_value(const char &c, uint8_t *value)
+{
+    FS_MGR_CHECK(value != nullptr);
+
+    switch (c) {
+        case '0' ... '9':
+            *value = c - '0';
+            break;
+        case 'a' ... 'f':
+            *value = c - 'a' + 10;
+            break;
+        case 'A' ... 'F':
+            *value = c - 'A' + 10;
+            break;
+        default:
+            return false;
+    }
+
+    return true;
+}
+
+static bool hex_to_bytes(uint8_t *bytes,
+                         size_t bytes_len,
+                         const std::string &hex)
+{
+    FS_MGR_CHECK(bytes != nullptr);
+
+    if (hex.size() % 2 != 0) {
+        return false;
+    }
+    if (hex.size() / 2 > bytes_len) {
+        return false;
+    }
+    for (size_t i = 0, j = 0, n = hex.size(); i < n; i += 2, ++j) {
+        uint8_t high;
+        if (!nibble_value(hex[i], &high)) {
+            return false;
+        }
+        uint8_t low;
+        if (!nibble_value(hex[i + 1], &low)) {
+            return false;
+        }
+        bytes[j] = (high << 4) | low;
+    }
+    return true;
+}
+
+static std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len)
+{
+    FS_MGR_CHECK(bytes != nullptr);
+
+    static const char *hex_digits = "0123456789abcdef";
+    std::string hex;
+
+    for (size_t i = 0; i < bytes_len; i++) {
+        hex.push_back(hex_digits[(bytes[i] & 0xF0) >> 4]);
+        hex.push_back(hex_digits[bytes[i] & 0x0F]);
+    }
+    return hex;
+}
+
+static bool load_vbmeta_prop(androidboot_vbmeta *vbmeta_prop)
+{
+    FS_MGR_CHECK(vbmeta_prop != nullptr);
+
+    std::string cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+
+    std::string hash_alg;
+    std::string digest;
+
+    for (const auto &entry :
+         android::base::Split(android::base::Trim(cmdline), " ")) {
+        std::vector<std::string> pieces = android::base::Split(entry, "=");
+        const std::string &key = pieces[0];
+        const std::string &value = pieces[1];
+
+        if (key == "androidboot.vbmeta.device_state") {
+            vbmeta_prop->allow_verification_error = (value == "unlocked");
+        } else if (key == "androidboot.vbmeta.hash_alg") {
+            hash_alg = value;
+        } else if (key == "androidboot.vbmeta.size") {
+            if (!android::base::ParseUint(value.c_str(),
+                                          &vbmeta_prop->vbmeta_size)) {
+                return false;
+            }
+        } else if (key == "androidboot.vbmeta.digest") {
+            digest = value;
+        }
+    }
+
+    // Reads hash algorithm.
+    size_t expected_digest_size = 0;
+    if (hash_alg == "sha256") {
+        expected_digest_size = SHA256_DIGEST_LENGTH * 2;
+        vbmeta_prop->hash_alg = kSHA256;
+    } else if (hash_alg == "sha512") {
+        expected_digest_size = SHA512_DIGEST_LENGTH * 2;
+        vbmeta_prop->hash_alg = kSHA512;
+    } else {
+        ERROR("Unknown hash algorithm: %s\n", hash_alg.c_str());
+        return false;
+    }
+
+    // Reads digest.
+    if (digest.size() != expected_digest_size) {
+        ERROR("Unexpected digest size: %zu (expected %zu)\n", digest.size(),
+              expected_digest_size);
+        return false;
+    }
+
+    if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest),
+                      digest)) {
+        ERROR("Hash digest contains non-hexidecimal character: %s\n",
+              digest.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+template <typename Hasher>
+static std::pair<size_t, bool> verify_vbmeta_digest(
+    const AvbSlotVerifyData &verify_data, const androidboot_vbmeta &vbmeta_prop)
+{
+    size_t total_size = 0;
+    Hasher hasher;
+    for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
+        hasher.update(verify_data.vbmeta_images[n].vbmeta_data,
+                      verify_data.vbmeta_images[n].vbmeta_size);
+        total_size += verify_data.vbmeta_images[n].vbmeta_size;
+    }
+
+    bool matched = (memcmp(hasher.finalize(), vbmeta_prop.digest,
+                           Hasher::DIGEST_SIZE) == 0);
+
+    return std::make_pair(total_size, matched);
+}
+
+static bool verify_vbmeta_images(const AvbSlotVerifyData &verify_data,
+                                 const androidboot_vbmeta &vbmeta_prop)
+{
+    if (verify_data.num_vbmeta_images == 0) {
+        ERROR("No vbmeta images\n");
+        return false;
+    }
+
+    size_t total_size = 0;
+    bool digest_matched = false;
+
+    if (vbmeta_prop.hash_alg == kSHA256) {
+        std::tie(total_size, digest_matched) =
+            verify_vbmeta_digest<SHA256Hasher>(verify_data, vbmeta_prop);
+    } else if (vbmeta_prop.hash_alg == kSHA512) {
+        std::tie(total_size, digest_matched) =
+            verify_vbmeta_digest<SHA512Hasher>(verify_data, vbmeta_prop);
+    }
+
+    if (total_size != vbmeta_prop.vbmeta_size) {
+        ERROR("total vbmeta size mismatch: %zu (expected: %zu)\n", total_size,
+              vbmeta_prop.vbmeta_size);
+        return false;
+    }
+
+    if (!digest_matched) {
+        ERROR("vbmeta digest mismatch\n");
+        return false;
+    }
+
+    return true;
+}
+
+static bool hashtree_load_verity_table(
+    struct dm_ioctl *io,
+    const std::string &dm_device_name,
+    int fd,
+    const std::string &blk_device,
+    const AvbHashtreeDescriptor &hashtree_desc,
+    const std::string &salt,
+    const std::string &root_digest)
+{
+    fs_mgr_verity_ioctl_init(io, dm_device_name, DM_STATUS_TABLE_FLAG);
+
+    // The buffer consists of [dm_ioctl][dm_target_spec][verity_params].
+    char *buffer = (char *)io;
+
+    // Builds the dm_target_spec arguments.
+    struct dm_target_spec *dm_target =
+        (struct dm_target_spec *)&buffer[sizeof(struct dm_ioctl)];
+    io->target_count = 1;
+    dm_target->status = 0;
+    dm_target->sector_start = 0;
+    dm_target->length = hashtree_desc.image_size / 512;
+    strcpy(dm_target->target_type, "verity");
+
+    // Builds the verity params.
+    char *verity_params =
+        buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+    size_t bufsize = DM_BUF_SIZE - (verity_params - buffer);
+
+    int res = 0;
+    if (hashtree_desc.fec_size > 0) {
+        res = snprintf(
+            verity_params, bufsize,
+            VERITY_TABLE_FORMAT VERITY_TABLE_OPT_FEC_FORMAT,
+            VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
+                                root_digest.c_str(), salt.c_str()),
+            VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device.c_str()));
+    } else {
+        res = snprintf(verity_params, bufsize,
+                       VERITY_TABLE_FORMAT VERITY_TABLE_OPT_DEFAULT_FORMAT,
+                       VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
+                                           root_digest.c_str(), salt.c_str()),
+                       VERITY_TABLE_OPT_DEFAULT_PARAMS);
+    }
+
+    if (res < 0 || (size_t)res >= bufsize) {
+        ERROR("Error building verity table; insufficient buffer size?\n");
+        return false;
+    }
+
+    INFO("loading verity table: '%s'", verity_params);
+
+    // Sets ext target boundary.
+    verity_params += strlen(verity_params) + 1;
+    verity_params = (char *)(((unsigned long)verity_params + 7) & ~7);
+    dm_target->next = verity_params - buffer;
+
+    // Sends the ioctl to load the verity table.
+    if (ioctl(fd, DM_TABLE_LOAD, io)) {
+        ERROR("Error loading verity table (%s)\n", strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+static bool hashtree_dm_verity_setup(struct fstab_rec *fstab_entry,
+                                     const AvbHashtreeDescriptor &hashtree_desc,
+                                     const std::string &salt,
+                                     const std::string &root_digest)
+{
+    // Gets the device mapper fd.
+    android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
+    if (fd < 0) {
+        ERROR("Error opening device mapper (%s)\n", strerror(errno));
+        return false;
+    }
+
+    // Creates the device.
+    alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+    struct dm_ioctl *io = (struct dm_ioctl *)buffer;
+    const std::string mount_point(basename(fstab_entry->mount_point));
+    if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
+        ERROR("Couldn't create verity device!\n");
+        return false;
+    }
+
+    // Gets the name of the device file.
+    std::string verity_blk_name;
+    if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
+        ERROR("Couldn't get verity device number!\n");
+        return false;
+    }
+
+    // Loads the verity mapping table.
+    if (!hashtree_load_verity_table(io, mount_point, fd,
+                                    std::string(fstab_entry->blk_device),
+                                    hashtree_desc, salt, root_digest)) {
+        ERROR("Couldn't load verity table!\n");
+        return false;
+    }
+
+    // Activates the device.
+    if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
+        return false;
+    }
+
+    // Marks the underlying block device as read-only.
+    fs_mgr_set_blk_ro(fstab_entry->blk_device);
+
+    // TODO(bowgotsai): support verified all partition at boot.
+    // Updates fstab_rec->blk_device to verity device name.
+    free(fstab_entry->blk_device);
+    fstab_entry->blk_device = strdup(verity_blk_name.c_str());
+
+    // Makes sure we've set everything up properly.
+    if (fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool get_hashtree_descriptor(const std::string &partition_name,
+                                    const AvbSlotVerifyData &verify_data,
+                                    AvbHashtreeDescriptor *out_hashtree_desc,
+                                    std::string *out_salt,
+                                    std::string *out_digest)
+{
+    bool found = false;
+    const uint8_t *desc_partition_name;
+
+    for (size_t i = 0; i < verify_data.num_vbmeta_images && !found; i++) {
+        // Get descriptors from vbmeta_images[i].
+        size_t num_descriptors;
+        std::unique_ptr<const AvbDescriptor *[], decltype(&avb_free)>
+            descriptors(
+                avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
+                                       verify_data.vbmeta_images[i].vbmeta_size,
+                                       &num_descriptors),
+                avb_free);
+
+        if (!descriptors || num_descriptors < 1) {
+            continue;
+        }
+
+        // Ensures that hashtree descriptor is either in /vbmeta or in
+        // the same partition for verity setup.
+        std::string vbmeta_partition_name(
+            verify_data.vbmeta_images[i].partition_name);
+        if (vbmeta_partition_name != "vbmeta" &&
+            vbmeta_partition_name != partition_name) {
+            WARNING("Skip vbmeta image at %s for partition: %s\n",
+                    verify_data.vbmeta_images[i].partition_name,
+                    partition_name.c_str());
+            continue;
+        }
+
+        for (size_t j = 0; j < num_descriptors && !found; j++) {
+            AvbDescriptor desc;
+            if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) {
+                WARNING("Descriptor is invalid.\n");
+                continue;
+            }
+            if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
+                desc_partition_name = (const uint8_t *)descriptors[j] +
+                                      sizeof(AvbHashtreeDescriptor);
+                if (!avb_hashtree_descriptor_validate_and_byteswap(
+                        (AvbHashtreeDescriptor *)descriptors[j],
+                        out_hashtree_desc)) {
+                    continue;
+                }
+                if (out_hashtree_desc->partition_name_len !=
+                    partition_name.length()) {
+                    continue;
+                }
+                // Notes that desc_partition_name is not NUL-terminated.
+                std::string hashtree_partition_name(
+                    (const char *)desc_partition_name,
+                    out_hashtree_desc->partition_name_len);
+                if (hashtree_partition_name == partition_name) {
+                    found = true;
+                }
+            }
+        }
+    }
+
+    if (!found) {
+        ERROR("Partition descriptor not found: %s\n", partition_name.c_str());
+        return false;
+    }
+
+    const uint8_t *desc_salt =
+        desc_partition_name + out_hashtree_desc->partition_name_len;
+    *out_salt = bytes_to_hex(desc_salt, out_hashtree_desc->salt_len);
+
+    const uint8_t *desc_digest = desc_salt + out_hashtree_desc->salt_len;
+    *out_digest = bytes_to_hex(desc_digest, out_hashtree_desc->root_digest_len);
+
+    return true;
+}
+
+static inline bool polling_vbmeta_blk_device(struct fstab *fstab)
+{
+    // It needs the block device symlink: fstab_rec->blk_device to read
+    // /vbmeta partition. However, the symlink created by ueventd might
+    // not be ready at this point. Use test_access() to poll it before
+    // trying to read the partition.
+    struct fstab_rec *fstab_entry =
+        fs_mgr_get_entry_for_mount_point(fstab, "/vbmeta");
+
+    // Makes sure /vbmeta block device is ready to access.
+    if (fs_mgr_test_access(fstab_entry->blk_device) < 0) {
+        return false;
+    }
+    return true;
+}
+
+static bool init_is_avb_used()
+{
+    // When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
+    // size, digest} in kernel cmdline. They will then be imported by init
+    // process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
+    //
+    // Checks hash_alg as an indicator for whether AVB is used.
+    // We don't have to parse and check all of them here. The check will
+    // be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will
+    // be returned when there is an error.
+
+    std::string hash_alg =
+        android::base::GetProperty("ro.boot.vbmeta.hash_alg", "");
+
+    if (hash_alg == "sha256" || hash_alg == "sha512") {
+        return true;
+    }
+
+    return false;
+}
+
+bool fs_mgr_is_avb_used()
+{
+    static bool result = init_is_avb_used();
+    return result;
+}
+
+int fs_mgr_load_vbmeta_images(struct fstab *fstab)
+{
+    FS_MGR_CHECK(fstab != nullptr);
+
+    if (!polling_vbmeta_blk_device(fstab)) {
+        ERROR("Failed to find block device of /vbmeta\n");
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    // Gets the expected hash value of vbmeta images from
+    // kernel cmdline.
+    if (!load_vbmeta_prop(&fs_mgr_vbmeta_prop)) {
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    fs_mgr_avb_ops = fs_mgr_dummy_avb_ops_new(fstab);
+    if (fs_mgr_avb_ops == nullptr) {
+        ERROR("Failed to allocate dummy avb_ops\n");
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    // Invokes avb_slot_verify() to load and verify all vbmeta images.
+    // Sets requested_partitions to nullptr as it's to copy the contents
+    // of HASH partitions into fs_mgr_avb_verify_data, which is not required as
+    // fs_mgr only deals with HASHTREE partitions.
+    const char *requested_partitions[] = {nullptr};
+    const char *ab_suffix =
+        android::base::GetProperty("ro.boot.slot_suffix", "").c_str();
+    AvbSlotVerifyResult verify_result = avb_slot_verify(
+        fs_mgr_avb_ops, requested_partitions, ab_suffix,
+        fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
+
+    // Only allow two verify results:
+    //   - AVB_SLOT_VERIFY_RESULT_OK.
+    //   - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state).
+    if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
+        if (!fs_mgr_vbmeta_prop.allow_verification_error) {
+            ERROR("ERROR_VERIFICATION isn't allowed\n");
+            goto fail;
+        }
+    } else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
+        ERROR("avb_slot_verify failed, result: %d\n", verify_result);
+        goto fail;
+    }
+
+    // Verifies vbmeta images against the digest passed from bootloader.
+    if (!verify_vbmeta_images(*fs_mgr_avb_verify_data, fs_mgr_vbmeta_prop)) {
+        ERROR("verify_vbmeta_images failed\n");
+        goto fail;
+    } else {
+        // Checks whether FLAGS_HASHTREE_DISABLED is set.
+        AvbVBMetaImageHeader vbmeta_header;
+        avb_vbmeta_image_header_to_host_byte_order(
+            (AvbVBMetaImageHeader *)fs_mgr_avb_verify_data->vbmeta_images[0]
+                .vbmeta_data,
+            &vbmeta_header);
+
+        bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
+                                  AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+        if (hashtree_disabled) {
+            return FS_MGR_SETUP_AVB_HASHTREE_DISABLED;
+        }
+    }
+
+    if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
+        return FS_MGR_SETUP_AVB_SUCCESS;
+    }
+
+fail:
+    fs_mgr_unload_vbmeta_images();
+    return FS_MGR_SETUP_AVB_FAIL;
+}
+
+void fs_mgr_unload_vbmeta_images()
+{
+    if (fs_mgr_avb_verify_data != nullptr) {
+        avb_slot_verify_data_free(fs_mgr_avb_verify_data);
+    }
+
+    if (fs_mgr_avb_ops != nullptr) {
+        fs_mgr_dummy_avb_ops_free(fs_mgr_avb_ops);
+    }
+}
+
+int fs_mgr_setup_avb(struct fstab_rec *fstab_entry)
+{
+    if (!fstab_entry || !fs_mgr_avb_verify_data ||
+        fs_mgr_avb_verify_data->num_vbmeta_images < 1) {
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    std::string partition_name(basename(fstab_entry->mount_point));
+    if (!avb_validate_utf8((const uint8_t *)partition_name.c_str(),
+                           partition_name.length())) {
+        ERROR("Partition name: %s is not valid UTF-8.\n",
+              partition_name.c_str());
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    AvbHashtreeDescriptor hashtree_descriptor;
+    std::string salt;
+    std::string root_digest;
+    if (!get_hashtree_descriptor(partition_name, *fs_mgr_avb_verify_data,
+                                 &hashtree_descriptor, &salt, &root_digest)) {
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    // Converts HASHTREE descriptor to verity_table_params.
+    if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt,
+                                  root_digest)) {
+        return FS_MGR_SETUP_AVB_FAIL;
+    }
+
+    return FS_MGR_SETUP_AVB_SUCCESS;
+}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
new file mode 100644
index 0000000..f3030eb
--- /dev/null
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <string>
+
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <libavb/libavb.h>
+#include <utils/Compat.h>
+
+#include "fs_mgr.h"
+#include "fs_mgr_avb_ops.h"
+#include "fs_mgr_priv.h"
+
+static struct fstab *fs_mgr_fstab = nullptr;
+
+static AvbIOResult read_from_partition(AvbOps *ops ATTRIBUTE_UNUSED,
+                                       const char *partition,
+                                       int64_t offset,
+                                       size_t num_bytes,
+                                       void *buffer,
+                                       size_t *out_num_read)
+{
+    // The input |partition| name is with ab_suffix, e.g. system_a.
+    // Slot suffix (e.g. _a) will be appended to the device file path
+    // for partitions having 'slotselect' optin in fstab file, but it
+    // won't be appended to the mount point.
+    //
+    // In AVB, we can assume that there's an entry for the /misc mount
+    // point and use that to get the device file for the misc partition.
+    // From there we'll assume that a by-name scheme is used
+    // so we can just replace the trailing "misc" by the given
+    // |partition|, e.g.
+    //
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
+
+    struct fstab_rec *fstab_entry =
+        fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
+
+    if (fstab_entry == nullptr) {
+        ERROR("Partition (%s) not found in fstab\n", partition);
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
+    std::string partition_name(partition);
+    std::string path(fstab_entry->blk_device);
+    // Replaces the last field of device file if it's not misc.
+    if (!android::base::StartsWith(partition_name, "misc")) {
+        size_t end_slash = path.find_last_of("/");
+        std::string by_name_prefix(path.substr(0, end_slash + 1));
+        path = by_name_prefix + partition_name;
+    }
+
+    android::base::unique_fd fd(
+        TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+
+    if (fd < 0) {
+        ERROR("Failed to open %s (%s)\n", path.c_str(), strerror(errno));
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
+    // If offset is negative, interprets its absolute value as the
+    //  number of bytes from the end of the partition.
+    if (offset < 0) {
+        off64_t total_size = lseek64(fd, 0, SEEK_END);
+        if (total_size == -1) {
+            ERROR("Failed to lseek64 to end of the partition\n");
+            return AVB_IO_RESULT_ERROR_IO;
+        }
+        offset = total_size + offset;
+        // Repositions the offset to the beginning.
+        if (lseek64(fd, 0, SEEK_SET) == -1) {
+            ERROR("Failed to lseek64 to the beginning of the partition\n");
+            return AVB_IO_RESULT_ERROR_IO;
+        }
+    }
+
+    // On Linux, we never get partial reads from block devices (except
+    // for EOF).
+    ssize_t num_read =
+        TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
+
+    if (num_read < 0 || (size_t)num_read != num_bytes) {
+        ERROR("Failed to read %zu bytes from %s offset %" PRId64 " (%s)\n",
+              num_bytes, path.c_str(), offset, strerror(errno));
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
+    if (out_num_read != nullptr) {
+        *out_num_read = num_read;
+    }
+
+    return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult dummy_read_rollback_index(AvbOps *ops ATTRIBUTE_UNUSED,
+                                             size_t rollback_index_location
+                                                 ATTRIBUTE_UNUSED,
+                                             uint64_t *out_rollback_index)
+{
+    // rollback_index has been checked in bootloader phase.
+    // In user-space, returns the smallest value 0 to pass the check.
+    *out_rollback_index = 0;
+    return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult dummy_validate_vbmeta_public_key(
+    AvbOps *ops ATTRIBUTE_UNUSED,
+    const uint8_t *public_key_data ATTRIBUTE_UNUSED,
+    size_t public_key_length ATTRIBUTE_UNUSED,
+    const uint8_t *public_key_metadata ATTRIBUTE_UNUSED,
+    size_t public_key_metadata_length ATTRIBUTE_UNUSED,
+    bool *out_is_trusted)
+{
+    // vbmeta public key has been checked in bootloader phase.
+    // In user-space, returns true to pass the check.
+    //
+    // Addtionally, user-space should check
+    // androidboot.vbmeta.{hash_alg, size, digest} against the digest
+    // of all vbmeta images after invoking avb_slot_verify().
+
+    *out_is_trusted = true;
+    return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult dummy_read_is_device_unlocked(AvbOps *ops ATTRIBUTE_UNUSED,
+                                                 bool *out_is_unlocked)
+{
+    // The function is for bootloader to update the value into
+    // androidboot.vbmeta.device_state in kernel cmdline.
+    // In user-space, returns true as we don't need to update it anymore.
+    *out_is_unlocked = true;
+    return AVB_IO_RESULT_OK;
+}
+
+static AvbIOResult dummy_get_unique_guid_for_partition(
+    AvbOps *ops ATTRIBUTE_UNUSED,
+    const char *partition ATTRIBUTE_UNUSED,
+    char *guid_buf,
+    size_t guid_buf_size)
+{
+    // The function is for bootloader to set the correct UUID
+    // for a given partition in kernel cmdline.
+    // In user-space, returns a faking one as we don't need to update
+    // it anymore.
+    snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
+    return AVB_IO_RESULT_OK;
+}
+
+AvbOps *fs_mgr_dummy_avb_ops_new(struct fstab *fstab)
+{
+    AvbOps *ops;
+
+    // Assigns the fstab to the static variable for later use.
+    fs_mgr_fstab = fstab;
+
+    ops = (AvbOps *)calloc(1, sizeof(AvbOps));
+    if (ops == nullptr) {
+        ERROR("Error allocating memory for AvbOps.\n");
+        return nullptr;
+    }
+
+    // We only need these operations since that's all what is being used
+    // by the avb_slot_verify(); Most of them are dummy operations because
+    // they're only required in bootloader but not required in user-space.
+    ops->read_from_partition = read_from_partition;
+    ops->read_rollback_index = dummy_read_rollback_index;
+    ops->validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
+    ops->read_is_device_unlocked = dummy_read_is_device_unlocked;
+    ops->get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
+
+    return ops;
+}
+
+void fs_mgr_dummy_avb_ops_free(AvbOps *ops)
+{
+    free(ops);
+}
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_avb_ops.h
new file mode 100644
index 0000000..9f99be8
--- /dev/null
+++ b/fs_mgr/fs_mgr_avb_ops.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CORE_FS_MGR_AVB_OPS_H
+#define __CORE_FS_MGR_AVB_OPS_H
+
+#include <libavb/libavb.h>
+
+#include "fs_mgr.h"
+
+__BEGIN_DECLS
+
+/* Allocates a "dummy" AvbOps instance solely for use in user-space.
+ * Returns nullptr on OOM.
+ *
+ * It mainly provides read_from_partitions() for user-space to get
+ * AvbSlotVerifyData.vbmeta_images[] and the caller MUST check their
+ * integrity against the androidboot.vbmeta.{hash_alg, size, digest}
+ * values from /proc/cmdline, e.g. verify_vbmeta_images()
+ * in fs_mgr_avb.cpp.
+ *
+ * Other I/O operations are only required in boot loader so we set
+ * them as dummy operations here.
+ *  - Will allow any public key for signing.
+ *  - returns 0 for any rollback index location.
+ *  - returns device is unlocked regardless of the actual state.
+ *  - returns a dummy guid for any partition.
+ *
+ * Frees with fs_mgr_dummy_avb_ops_free().
+ */
+AvbOps *fs_mgr_dummy_avb_ops_new(struct fstab *fstab);
+
+/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */
+void fs_mgr_dummy_avb_ops_free(AvbOps *ops);
+
+__END_DECLS
+
+#endif /* __CORE_FS_MGR_AVB_OPS_H */
diff --git a/fs_mgr/fs_mgr_dm_ioctl.cpp b/fs_mgr/fs_mgr_dm_ioctl.cpp
index 75ce621..939657e 100644
--- a/fs_mgr/fs_mgr_dm_ioctl.cpp
+++ b/fs_mgr/fs_mgr_dm_ioctl.cpp
@@ -68,7 +68,7 @@
                                    int fd,
                                    std::string *out_dev_name)
 {
-    CHECK(out_dev_name != nullptr);
+    FS_MGR_CHECK(out_dev_name != nullptr);
 
     fs_mgr_verity_ioctl_init(io, name, 0);
     if (ioctl(fd, DM_DEV_STATUS, io)) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 41fb746..b9d5617 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -35,6 +35,8 @@
     unsigned int zram_size;
     uint64_t reserved_size;
     unsigned int file_encryption_mode;
+    unsigned int erase_blk_size;
+    unsigned int logical_blk_size;
 };
 
 struct flag_list {
@@ -77,6 +79,7 @@
     { "max_comp_streams=",  MF_MAX_COMP_STREAMS },
     { "verifyatboot",       MF_VERIFYATBOOT },
     { "verify",             MF_VERIFY },
+    { "avb",                MF_AVB },
     { "noemulatedsd",       MF_NOEMULATEDSD },
     { "notrim",             MF_NOTRIM },
     { "formattable",        MF_FORMATTABLE },
@@ -85,6 +88,8 @@
     { "latemount",          MF_LATEMOUNT },
     { "reservedsize=",      MF_RESERVEDSIZE },
     { "quota",              MF_QUOTA },
+    { "eraseblk=",          MF_ERASEBLKSIZE },
+    { "logicalblk=",        MF_LOGICALBLKSIZE },
     { "defaults",           0 },
     { 0,                    0 },
 };
@@ -239,6 +244,22 @@
                      * reserved size of the partition.  Get it and return it.
                      */
                     flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_ERASEBLKSIZE) && flag_vals) {
+                    /* The erase block size flag is followed by an = and the flash
+                     * erase block size. Get it, check that it is a power of 2 and
+                     * at least 4096, and return it.
+                     */
+                    unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+                    if (val >= 4096 && (val & (val - 1)) == 0)
+                        flag_vals->erase_blk_size = val;
+                } else if ((fl[i].flag == MF_LOGICALBLKSIZE) && flag_vals) {
+                    /* The logical block size flag is followed by an = and the flash
+                     * logical block size. Get it, check that it is a power of 2 and
+                     * at least 4096, and return it.
+                     */
+                    unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+                    if (val >= 4096 && (val & (val - 1)) == 0)
+                        flag_vals->logical_blk_size = val;
                 }
                 break;
             }
@@ -385,6 +406,8 @@
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
         fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
         fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
+        fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
+        fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 33a7496..4bfe202 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <libgen.h>
 #include "fs_mgr_priv.h"
 
+#ifdef _LIBGEN_H
+#warning "libgen.h must not be included"
+#endif
+
 char *me = "";
 
 static void usage(void)
@@ -32,10 +37,10 @@
  * and exit the program, do not return to the caller.
  * Return the number of argv[] entries consumed.
  */
-static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
-                     char **n_name, char **n_blk_dev)
+static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
+                     const char **n_name, const char **n_blk_dev)
 {
-    me = basename(strdup(argv[0]));
+    me = basename(argv[0]);
 
     if (argc <= 1) {
         usage();
@@ -75,14 +80,14 @@
     return;
 }
 
-int main(int argc, char *argv[])
+int main(int argc, char * const argv[])
 {
     int a_flag=0;
     int u_flag=0;
     int n_flag=0;
-    char *n_name=NULL;
-    char *n_blk_dev=NULL;
-    char *fstab_file=NULL;
+    const char *n_name=NULL;
+    const char *n_blk_dev=NULL;
+    const char *fstab_file=NULL;
     struct fstab *fstab=NULL;
 
     klog_set_level(6);
@@ -97,7 +102,7 @@
     if (a_flag) {
         return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
     } else if (n_flag) {
-        return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
+        return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
     } else if (u_flag) {
         return fs_mgr_unmount_all(fstab);
     } else {
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 7f917d9..0a27c7a 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -20,6 +20,17 @@
 #include <cutils/klog.h>
 #include <fs_mgr.h>
 
+#ifdef __cplusplus
+#include <android-base/logging.h>
+/* The CHECK() in logging.h will use program invocation name as the tag.
+ * Thus, the log will have prefix "init: " when libfs_mgr is statically
+ * linked in the init process. This might be opaque when debugging.
+ * Appends "in libfs_mgr" at the end of the abort message to explicitly
+ * indicate the check happens in fs_mgr.
+ */
+#define FS_MGR_CHECK(x) CHECK(x) << "in libfs_mgr "
+#endif
+
 __BEGIN_DECLS
 
 #define INFO(x...)    KLOG_INFO("fs_mgr", x)
@@ -89,6 +100,9 @@
 #define MF_MAX_COMP_STREAMS 0x100000
 #define MF_RESERVEDSIZE     0x200000
 #define MF_QUOTA            0x400000
+#define MF_ERASEBLKSIZE     0x800000
+#define MF_LOGICALBLKSIZE  0X1000000
+#define MF_AVB             0X2000000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/fs_mgr_priv_avb.h
new file mode 100644
index 0000000..6d0171c
--- /dev/null
+++ b/fs_mgr/fs_mgr_priv_avb.h
@@ -0,0 +1,56 @@
+/*
+ * 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 __CORE_FS_MGR_PRIV_AVB_H
+#define __CORE_FS_MGR_PRIV_AVB_H
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include "fs_mgr.h"
+
+__BEGIN_DECLS
+
+#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2)
+#define FS_MGR_SETUP_AVB_FAIL (-1)
+#define FS_MGR_SETUP_AVB_SUCCESS 0
+
+bool fs_mgr_is_avb_used();
+
+/* Gets AVB metadata through external/avb/libavb for all partitions:
+ * AvbSlotVerifyData.vbmeta_images[] and checks their integrity
+ * against the androidboot.vbmeta.{hash_alg, size, digest} values
+ * from /proc/cmdline.
+ *
+ * Return values:
+ *   - FS_MGR_SETUP_AVB_SUCCESS: the metadata cab be trusted.
+ *   - FS_MGR_SETUP_AVB_FAIL: any error when reading and verifying the
+ *     metadata, e.g. I/O error, digest value mismatch, size mismatch.
+ *   - FS_MGR_SETUP_AVB_HASHTREE_DISABLED: to support the existing
+ *     'adb disable-verity' feature in Android. It's very helpful for
+ *     developers to make the filesystem writable to allow replacing
+ *     binaries on the device.
+ */
+int fs_mgr_load_vbmeta_images(struct fstab *fstab);
+
+void fs_mgr_unload_vbmeta_images();
+
+int fs_mgr_setup_avb(struct fstab_rec *fstab_entry);
+
+__END_DECLS
+
+#endif /* __CORE_FS_MGR_PRIV_AVB_H */
diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/fs_mgr_priv_sha.h
new file mode 100644
index 0000000..1abc273
--- /dev/null
+++ b/fs_mgr/fs_mgr_priv_sha.h
@@ -0,0 +1,74 @@
+/*
+ * 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 __CORE_FS_MGR_PRIV_SHA_H
+#define __CORE_FS_MGR_PRIV_SHA_H
+
+#include <openssl/sha.h>
+
+class SHA256Hasher
+{
+   private:
+    SHA256_CTX sha256_ctx;
+    uint8_t hash[SHA256_DIGEST_LENGTH];
+
+   public:
+    enum { DIGEST_SIZE = SHA256_DIGEST_LENGTH };
+
+    SHA256Hasher()
+    {
+        SHA256_Init(&sha256_ctx);
+    }
+
+    void update(const void *data, size_t data_size)
+    {
+        SHA256_Update(&sha256_ctx, data, data_size);
+    }
+
+    const uint8_t *finalize()
+    {
+        SHA256_Final(hash, &sha256_ctx);
+        return hash;
+    }
+};
+
+class SHA512Hasher
+{
+   private:
+    SHA512_CTX sha512_ctx;
+    uint8_t hash[SHA512_DIGEST_LENGTH];
+
+   public:
+    enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH };
+
+    SHA512Hasher()
+    {
+        SHA512_Init(&sha512_ctx);
+    }
+
+    void update(const uint8_t *data, size_t data_size)
+    {
+        SHA512_Update(&sha512_ctx, data, data_size);
+    }
+
+    const uint8_t *finalize()
+    {
+        SHA512_Final(hash, &sha512_ctx);
+        return hash;
+    }
+};
+
+#endif /* __CORE_FS_MGR_PRIV_SHA_H */
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index e7a0a1d..d959798 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -77,6 +77,8 @@
     unsigned int zram_size;
     uint64_t reserved_size;
     unsigned int file_encryption_mode;
+    unsigned int erase_blk_size;
+    unsigned int logical_blk_size;
 };
 
 // Callback function for verity status
@@ -99,7 +101,7 @@
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
 
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
 int fs_mgr_unmount_all(struct fstab *fstab);
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 36c4664..2f69372 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -30,6 +30,8 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <functional>
+
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 
@@ -42,6 +44,7 @@
 #include <cutils/misc.h>
 #include <cutils/uevent.h>
 #include <cutils/properties.h>
+#include <minui/minui.h>
 
 #ifdef CHARGER_ENABLE_SUSPEND
 #include <suspend/autosuspend.h>
@@ -49,7 +52,6 @@
 
 #include "animation.h"
 #include "AnimationParser.h"
-#include "minui/minui.h"
 
 #include <healthd/healthd.h>
 
@@ -563,9 +565,8 @@
     }
 }
 
-static int set_key_callback(int code, int value, void *data)
+static int set_key_callback(struct charger *charger, int code, int value)
 {
-    struct charger *charger = (struct charger *)data;
     int64_t now = curr_time_ms();
     int down = !!value;
 
@@ -600,7 +601,7 @@
 {
     if (ev->type != EV_KEY)
         return;
-    set_key_callback(ev->code, ev->value, charger);
+    set_key_callback(charger, ev->code, ev->value);
 }
 
 static void set_next_key_check(struct charger *charger,
@@ -757,9 +758,8 @@
    return (int)timeout;
 }
 
-static int input_callback(int fd, unsigned int epevents, void *data)
+static int input_callback(struct charger *charger, int fd, unsigned int epevents)
 {
-    struct charger *charger = (struct charger *)data;
     struct input_event ev;
     int ret;
 
@@ -836,7 +836,8 @@
 
     LOGW("--------------- STARTING CHARGER MODE ---------------\n");
 
-    ret = ev_init(input_callback, charger);
+    ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1,
+                            std::placeholders::_2));
     if (!ret) {
         epollfd = ev_get_epollfd();
         healthd_register_event(epollfd, charger_event_handler);
@@ -875,7 +876,8 @@
             anim->frames[i].surface = scale_frames[i];
         }
     }
-    ev_sync_key_state(set_key_callback, charger);
+    ev_sync_key_state(std::bind(&set_key_callback, charger, std::placeholders::_1,
+                                std::placeholders::_2));
 
     charger->next_screen_transition = -1;
     charger->next_key_check = -1;
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index e7cd300..5ae6216 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -23,7 +23,6 @@
 
 __BEGIN_DECLS
 
-int  klog_get_level(void);
 void klog_set_level(int level);
 
 void klog_write(int level, const char *fmt, ...)
diff --git a/init/Android.mk b/init/Android.mk
index 6615692..759be52 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -70,6 +70,7 @@
     init.cpp \
     keychords.cpp \
     property_service.cpp \
+    seccomp.cpp \
     signal_handler.cpp \
     ueventd.cpp \
     ueventd_parser.cpp \
@@ -96,6 +97,7 @@
     libbase \
     libc \
     libselinux \
+    libseccomp_policy \
     liblog \
     libcrypto_utils \
     libcrypto \
@@ -105,6 +107,7 @@
     libz \
     libprocessgroup \
     libnl \
+    libavb
 
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/init.cpp b/init/init.cpp
index ee5add8..1ce3c35 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -62,6 +62,7 @@
 #include "keychords.h"
 #include "log.h"
 #include "property_service.h"
+#include "seccomp.h"
 #include "service.h"
 #include "signal_handler.h"
 #include "ueventd.h"
@@ -262,26 +263,18 @@
     panic();
 }
 
-#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
-#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
-
-/* __attribute__((unused)) due to lack of mips support: see mips block
- * in set_mmap_rnd_bits_action */
-static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
-    std::string path;
-    if (compat) {
-        path = MMAP_RND_COMPAT_PATH;
-    } else {
-        path = MMAP_RND_PATH;
-    }
+static bool set_highest_available_option_value(std::string path, int min, int max)
+{
     std::ifstream inf(path, std::fstream::in);
     if (!inf) {
         LOG(ERROR) << "Cannot open for reading: " << path;
         return false;
     }
-    while (start >= min) {
+
+    int current = max;
+    while (current >= min) {
         // try to write out new value
-        std::string str_val = std::to_string(start);
+        std::string str_val = std::to_string(current);
         std::ofstream of(path, std::fstream::out);
         if (!of) {
             LOG(ERROR) << "Cannot open for writing: " << path;
@@ -297,16 +290,33 @@
         if (str_val.compare(str_rec) == 0) {
             break;
         }
-        start--;
+        current--;
     }
     inf.close();
-    if (start < min) {
-        LOG(ERROR) << "Unable to set minimum required entropy " << min << " in " << path;
+
+    if (current < min) {
+        LOG(ERROR) << "Unable to set minimum option value " << min << " in " << path;
         return false;
     }
     return true;
 }
 
+#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+/* __attribute__((unused)) due to lack of mips support: see mips block
+ * in set_mmap_rnd_bits_action */
+static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
+    std::string path;
+    if (compat) {
+        path = MMAP_RND_COMPAT_PATH;
+    } else {
+        path = MMAP_RND_PATH;
+    }
+
+    return set_highest_available_option_value(path, min, start);
+}
+
 /*
  * Set /proc/sys/vm/mmap_rnd_bits and potentially
  * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
@@ -359,6 +369,25 @@
     return ret;
 }
 
+#define KPTR_RESTRICT_PATH "/proc/sys/kernel/kptr_restrict"
+#define KPTR_RESTRICT_MINVALUE 2
+#define KPTR_RESTRICT_MAXVALUE 4
+
+/* Set kptr_restrict to the highest available level.
+ *
+ * Aborts if unable to set this to an acceptable value.
+ */
+static int set_kptr_restrict_action(const std::vector<std::string>& args)
+{
+    std::string path = KPTR_RESTRICT_PATH;
+
+    if (!set_highest_available_option_value(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) {
+        LOG(ERROR) << "Unable to set adequate kptr_restrict value!";
+        security_failure();
+    }
+    return 0;
+}
+
 static int keychord_init_action(const std::vector<std::string>& args)
 {
     keychord_init();
@@ -763,6 +792,12 @@
 
         // Now set up SELinux for second stage.
         selinux_initialize(false);
+
+        // Install system-wide seccomp filter
+        if (!set_seccomp_filter()) {
+            LOG(ERROR) << "Failed to set seccomp policy";
+            security_failure();
+        }
     }
 
     // These directories were necessarily created before initial policy load
@@ -800,7 +835,12 @@
     parser.AddSectionParser("service",std::make_unique<ServiceParser>());
     parser.AddSectionParser("on", std::make_unique<ActionParser>());
     parser.AddSectionParser("import", std::make_unique<ImportParser>());
-    parser.ParseConfig("/init.rc");
+    std::string bootscript = property_get("ro.boot.init_rc");
+    if (bootscript.empty()) {
+        parser.ParseConfig("/init.rc");
+    } else {
+        parser.ParseConfig(bootscript);
+    }
 
     ActionManager& am = ActionManager::GetInstance();
 
@@ -811,6 +851,7 @@
     // ... so that we can start queuing up actions that require stuff from /dev.
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
     am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
+    am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
     am.QueueBuiltinAction(keychord_init_action, "keychord_init");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 498a5a1..d323425 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -27,6 +27,7 @@
 #include <sys/poll.h>
 
 #include <memory>
+#include <vector>
 
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
@@ -48,6 +49,7 @@
 
 #include <fs_mgr.h>
 #include <android-base/file.h>
+#include <android-base/strings.h>
 #include "bootimg.h"
 
 #include "property_service.h"
@@ -70,30 +72,30 @@
     }
 }
 
-static int check_mac_perms(const char *name, char *sctx, struct ucred *cr)
-{
-    char *tctx = NULL;
-    int result = 0;
+static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
+
+    if (!sctx) {
+      return false;
+    }
+
+    if (!sehandle_prop) {
+      return false;
+    }
+
+    char* tctx = nullptr;
+    if (selabel_lookup(sehandle_prop, &tctx, name.c_str(), 1) != 0) {
+      return false;
+    }
+
     property_audit_data audit_data;
 
-    if (!sctx)
-        goto err;
-
-    if (!sehandle_prop)
-        goto err;
-
-    if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
-        goto err;
-
-    audit_data.name = name;
+    audit_data.name = name.c_str();
     audit_data.cr = cr;
 
-    if (selinux_check_access(sctx, tctx, "property_service", "set", reinterpret_cast<void*>(&audit_data)) == 0)
-        result = 1;
+    bool has_access = (selinux_check_access(sctx, tctx, "property_service", "set", &audit_data) == 0);
 
     freecon(tctx);
- err:
-    return result;
+    return has_access;
 }
 
 static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
@@ -142,11 +144,9 @@
     }
 }
 
-bool is_legal_property_name(const std::string &name)
-{
+bool is_legal_property_name(const std::string& name) {
     size_t namelen = name.size();
 
-    if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
     if (name[namelen - 1] == '.') return false;
@@ -169,60 +169,219 @@
     return true;
 }
 
-int property_set(const char* name, const char* value) {
-    size_t valuelen = strlen(value);
+uint32_t property_set(const std::string& name, const std::string& value) {
+    size_t valuelen = value.size();
 
     if (!is_legal_property_name(name)) {
         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";
-        return -1;
+        return PROP_ERROR_INVALID_NAME;
     }
+
     if (valuelen >= PROP_VALUE_MAX) {
         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                    << "value too long";
-        return -1;
+        return PROP_ERROR_INVALID_VALUE;
     }
 
-    if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
-        if (restorecon(value, SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+    if (name == "selinux.restorecon_recursive" && valuelen > 0) {
+        if (restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
             LOG(ERROR) << "Failed to restorecon_recursive " << value;
         }
     }
 
-    prop_info* pi = (prop_info*) __system_property_find(name);
+    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
     if (pi != nullptr) {
         // ro.* properties are actually "write-once".
-        if (!strncmp(name, "ro.", 3)) {
+        if (android::base::StartsWith(name, "ro.")) {
             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                        << "property already set";
-            return -1;
+            return PROP_ERROR_READ_ONLY_PROPERTY;
         }
 
-        __system_property_update(pi, value, valuelen);
+        __system_property_update(pi, value.c_str(), valuelen);
     } else {
-        int rc = __system_property_add(name, strlen(name), value, valuelen);
+        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
         if (rc < 0) {
             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                        << "__system_property_add failed";
-            return rc;
+            return PROP_ERROR_SET_FAILED;
         }
     }
 
     // Don't write properties to disk until after we have read all default
     // properties to prevent them from being overwritten by default values.
-    if (persistent_properties_loaded && strncmp("persist.", name, strlen("persist.")) == 0) {
-        write_persistent_property(name, value);
+    if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
+        write_persistent_property(name.c_str(), value.c_str());
     }
-    property_changed(name, value);
-    return 0;
+    property_changed(name.c_str(), value.c_str());
+    return PROP_SUCCESS;
 }
 
-static void handle_property_set_fd()
-{
-    prop_msg msg;
-    int r;
-    char * source_ctx = NULL;
+class SocketConnection {
+ public:
+  SocketConnection(int socket, const struct ucred& cred)
+      : socket_(socket), cred_(cred) {}
 
-    int s = accept(property_set_fd, nullptr, nullptr);
+  ~SocketConnection() {
+    close(socket_);
+  }
+
+  bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
+    return RecvFully(value, sizeof(*value), timeout_ms);
+  }
+
+  bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
+    return RecvFully(chars, size, timeout_ms);
+  }
+
+  bool RecvString(std::string* value, uint32_t* timeout_ms) {
+    uint32_t len = 0;
+    if (!RecvUint32(&len, timeout_ms)) {
+      return false;
+    }
+
+    if (len == 0) {
+      *value = "";
+      return true;
+    }
+
+    std::vector<char> chars(len);
+    if (!RecvChars(&chars[0], len, timeout_ms)) {
+      return false;
+    }
+
+    *value = std::string(&chars[0], len);
+    return true;
+  }
+
+  bool SendUint32(uint32_t value) {
+    int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
+    return result == sizeof(value);
+  }
+
+  int socket() {
+    return socket_;
+  }
+
+  const struct ucred& cred() {
+    return cred_;
+  }
+
+ private:
+  bool PollIn(uint32_t* timeout_ms) {
+    struct pollfd ufds[1];
+    ufds[0].fd = socket_;
+    ufds[0].events = POLLIN;
+    ufds[0].revents = 0;
+    while (*timeout_ms > 0) {
+      Timer timer;
+      int nr = poll(ufds, 1, *timeout_ms);
+      uint64_t millis = timer.duration_ns()/1000000;
+      *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
+
+      if (nr > 0) {
+        return true;
+      }
+
+      if (nr == 0) {
+        // Timeout
+        break;
+      }
+
+      if (nr < 0 && errno != EINTR) {
+        PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message";
+        return false;
+      } else { // errno == EINTR
+        // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
+        // to avoid slowing init down by causing EINTR with under millisecond timeout.
+        if (*timeout_ms > 0) {
+          --(*timeout_ms);
+        }
+      }
+    }
+
+    LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message.";
+    return false;
+  }
+
+  bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
+    size_t bytes_left = size;
+    char* data = static_cast<char*>(data_ptr);
+    while (*timeout_ms > 0 && bytes_left > 0) {
+      if (!PollIn(timeout_ms)) {
+        return false;
+      }
+
+      int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
+      if (result <= 0) {
+        return false;
+      }
+
+      bytes_left -= result;
+      data += result;
+    }
+
+    return bytes_left == 0;
+  }
+
+  int socket_;
+  struct ucred cred_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
+};
+
+static void handle_property_set(SocketConnection& socket,
+                                const std::string& name,
+                                const std::string& value,
+                                bool legacy_protocol) {
+  const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
+  if (!is_legal_property_name(name)) {
+    LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
+    socket.SendUint32(PROP_ERROR_INVALID_NAME);
+    return;
+  }
+
+  struct ucred cr = socket.cred();
+  char* source_ctx = nullptr;
+  getpeercon(socket.socket(), &source_ctx);
+
+  if (android::base::StartsWith(name, "ctl.")) {
+    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
+      handle_control_message(name.c_str() + 4, value.c_str());
+      if (!legacy_protocol) {
+        socket.SendUint32(PROP_SUCCESS);
+      }
+    } else {
+      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
+                 << " service ctl [" << value << "]"
+                 << " uid:" << cr.uid
+                 << " gid:" << cr.gid
+                 << " pid:" << cr.pid;
+      if (!legacy_protocol) {
+        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
+      }
+    }
+  } else {
+    if (check_mac_perms(name, source_ctx, &cr)) {
+      uint32_t result = property_set(name, value);
+      if (!legacy_protocol) {
+        socket.SendUint32(result);
+      }
+    } else {
+      LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
+      if (!legacy_protocol) {
+        socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
+      }
+    }
+  }
+
+  freecon(source_ctx);
+}
+
+static void handle_property_set_fd() {
+    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
+
+    int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
     if (s == -1) {
         return;
     }
@@ -236,72 +395,50 @@
         return;
     }
 
-    static constexpr int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
-    struct pollfd ufds[1];
-    ufds[0].fd = s;
-    ufds[0].events = POLLIN;
-    ufds[0].revents = 0;
-    int nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
-    if (nr == 0) {
-        LOG(ERROR) << "sys_prop: timeout waiting for uid " << cr.uid << " to send property message.";
-        close(s);
-        return;
-    } else if (nr < 0) {
-        PLOG(ERROR) << "sys_prop: error waiting for uid " << cr.uid << " to send property message";
-        close(s);
+    SocketConnection socket(s, cr);
+    uint32_t timeout_ms = kDefaultSocketTimeout;
+
+    uint32_t cmd = 0;
+
+    if (!socket.RecvUint32(&cmd, &timeout_ms)) {
+        PLOG(ERROR) << "sys_prop: error while reading command from the socket";
+        socket.SendUint32(PROP_ERROR_READ_CMD);
         return;
     }
 
-    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
-    if(r != sizeof(prop_msg)) {
-        PLOG(ERROR) << "sys_prop: mis-match msg size received: " << r << " expected: " << sizeof(prop_msg);
-        close(s);
-        return;
-    }
+    switch(cmd) {
+    case PROP_MSG_SETPROP: {
+        char prop_name[PROP_NAME_MAX];
+        char prop_value[PROP_VALUE_MAX];
 
-    switch(msg.cmd) {
-    case PROP_MSG_SETPROP:
-        msg.name[PROP_NAME_MAX-1] = 0;
-        msg.value[PROP_VALUE_MAX-1] = 0;
-
-        if (!is_legal_property_name(msg.name)) {
-            LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
-            close(s);
-            return;
+        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
+            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
+          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
+          return;
         }
 
-        getpeercon(s, &source_ctx);
+        prop_name[PROP_NAME_MAX-1] = 0;
+        prop_value[PROP_VALUE_MAX-1] = 0;
 
-        if(memcmp(msg.name,"ctl.",4) == 0) {
-            // Keep the old close-socket-early behavior when handling
-            // ctl.* properties.
-            close(s);
-            if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
-                handle_control_message((char*) msg.name + 4, (char*) msg.value);
-            } else {
-                LOG(ERROR) << "sys_prop: Unable to " << (msg.name + 4)
-                           << " service ctl [" << msg.value << "]"
-                           << " uid:" << cr.uid
-                           << " gid:" << cr.gid
-                           << " pid:" << cr.pid;
-            }
-        } else {
-            if (check_mac_perms(msg.name, source_ctx, &cr)) {
-                property_set((char*) msg.name, (char*) msg.value);
-            } else {
-                LOG(ERROR) << "sys_prop: permission denied uid:" << cr.uid << " name:" << msg.name;
-            }
-
-            // Note: bionic's property client code assumes that the
-            // property server will not close the socket until *AFTER*
-            // the property is written to memory.
-            close(s);
-        }
-        freecon(source_ctx);
+        handle_property_set(socket, prop_value, prop_value, true);
         break;
+      }
 
+    case PROP_MSG_SETPROP2: {
+        std::string name;
+        std::string value;
+        if (!socket.RecvString(&name, &timeout_ms) ||
+            !socket.RecvString(&value, &timeout_ms)) {
+          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
+          socket.SendUint32(PROP_ERROR_READ_DATA);
+          return;
+        }
+
+        handle_property_set(socket, name, value, false);
+        break;
+      }
     default:
-        close(s);
+        socket.SendUint32(PROP_ERROR_INVALID_CMD);
         break;
     }
 }
@@ -439,6 +576,8 @@
 
 void property_load_boot_defaults() {
     load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
+    load_properties_from_file(PROP_PATH_ODM_DEFAULT, NULL);
+    load_properties_from_file(PROP_PATH_VENDOR_DEFAULT, NULL);
 }
 
 static void load_override_properties() {
@@ -501,12 +640,15 @@
 
 void load_system_props() {
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
+    load_properties_from_file(PROP_PATH_ODM_BUILD, NULL);
     load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
     load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
     load_recovery_id_prop();
 }
 
 void start_property_service() {
+    property_set("ro.property_service.version", "2");
+
     property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                     0666, 0, 0, NULL);
     if (property_set_fd == -1) {
diff --git a/init/property_service.h b/init/property_service.h
index e3a2acb..5d59473 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -27,14 +27,14 @@
     const char* name;
 };
 
-extern void property_init(void);
-extern void property_load_boot_defaults(void);
-extern void load_persist_props(void);
-extern void load_system_props(void);
-extern void start_property_service(void);
+void property_init(void);
+void property_load_boot_defaults(void);
+void load_persist_props(void);
+void load_system_props(void);
+void start_property_service(void);
 std::string property_get(const char* name);
-extern int property_set(const char *name, const char *value);
-extern bool is_legal_property_name(const std::string &name);
+uint32_t property_set(const std::string& name, const std::string& value);
+bool is_legal_property_name(const std::string& name);
 
 
 #endif  /* _INIT_PROPERTY_H */
diff --git a/init/seccomp.cpp b/init/seccomp.cpp
new file mode 100644
index 0000000..d632302
--- /dev/null
+++ b/init/seccomp.cpp
@@ -0,0 +1,225 @@
+/*
+ * 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 "seccomp.h"
+
+#include <vector>
+
+#include <sys/prctl.h>
+
+#include <linux/unistd.h>
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+
+#include "log.h"
+#include "seccomp_policy.h"
+
+#define syscall_nr (offsetof(struct seccomp_data, nr))
+#define arch_nr (offsetof(struct seccomp_data, arch))
+
+#if   defined __arm__
+#define AUDIT_ARCH_NR AUDIT_ARCH_ARM
+#elif defined __aarch64__
+#define AUDIT_ARCH_NR AUDIT_ARCH_AARCH64
+#define AUDIT_ARCH_NR32 AUDIT_ARCH_ARM
+#elif defined __i386__
+#define AUDIT_ARCH_NR AUDIT_ARCH_I386
+#elif defined __x86_64__
+#define AUDIT_ARCH_NR AUDIT_ARCH_X86_64
+#define AUDIT_ARCH_NR32 AUDIT_ARCH_I386
+#elif defined __mips64__
+#define AUDIT_ARCH_NR AUDIT_ARCH_MIPS64
+#define AUDIT_ARCH_NR32 AUDIT_ARCH_MIPS
+#elif defined __mips__ && !defined __mips64__
+#define AUDIT_ARCH_NR AUDIT_ARCH_MIPS
+#else
+#error "Could not determine AUDIT_ARCH_NR for this architecture"
+#endif
+
+typedef std::vector<sock_filter> filter;
+
+// We want to keep the below inline functions for debugging and future
+// development even though they are not used currently.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+
+static inline void Kill(filter& f) {
+    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL));
+}
+
+static inline void Trap(filter& f) {
+    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
+}
+
+static inline void Error(filter& f, __u16 retcode) {
+    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO + retcode));
+}
+
+inline static void Trace(filter& f) {
+    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE));
+}
+
+inline static void Allow(filter& f) {
+    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
+}
+
+inline static void AllowSyscall(filter& f, __u32 num) {
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, num, 0, 1));
+    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
+}
+
+inline static void ExamineSyscall(filter& f) {
+    f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
+}
+
+#ifdef AUDIT_ARCH_NR32
+inline static int SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
+    auto jump_length = f.size() - offset - 1;
+    auto u8_jump_length = (__u8) jump_length;
+    if (u8_jump_length != jump_length) {
+        LOG(ERROR) << "Can't set jump greater than 255 - actual jump is " << jump_length;
+        return -1;
+    }
+    f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, u8_jump_length, 0);
+    return 0;
+}
+#endif
+
+inline static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
+    f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
+
+#ifdef AUDIT_ARCH_NR32
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 2, 0));
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, 1, 0));
+    Kill(f);
+    return f.size() - 2;
+#else
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 1, 0));
+    Kill(f);
+    return 0;
+#endif
+}
+
+#pragma clang diagnostic pop
+
+static bool install_filter(filter const& f) {
+    struct sock_fprog prog = {
+        (unsigned short) f.size(),
+        (struct sock_filter*) &f[0],
+    };
+
+    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
+        PLOG(ERROR) << "SECCOMP: Could not set seccomp filter";
+        return false;
+    }
+
+    LOG(INFO) << "SECCOMP: Global filter installed";
+    return true;
+}
+
+bool set_seccomp_filter() {
+    filter f;
+
+    // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
+    // jump that must be changed to point to the start of the 32-bit policy
+    // 32 bit syscalls will not hit the policy between here and the call to SetJump
+#ifdef AUDIT_ARCH_NR32
+    auto offset_to_32bit_filter =
+#endif
+        ValidateArchitectureAndJumpIfNeeded(f);
+
+    // Native filter
+    ExamineSyscall(f);
+
+#ifdef __aarch64__
+    // Syscalls needed to boot Android
+    AllowSyscall(f, __NR_pivot_root);
+    AllowSyscall(f, __NR_ioprio_get);
+    AllowSyscall(f, __NR_ioprio_set);
+    AllowSyscall(f, __NR_gettid);
+    AllowSyscall(f, __NR_futex);
+    AllowSyscall(f, __NR_clone);
+    AllowSyscall(f, __NR_rt_sigreturn);
+    AllowSyscall(f, __NR_rt_tgsigqueueinfo);
+    AllowSyscall(f, __NR_add_key);
+    AllowSyscall(f, __NR_request_key);
+    AllowSyscall(f, __NR_keyctl);
+    AllowSyscall(f, __NR_restart_syscall);
+    AllowSyscall(f, __NR_getrandom);
+
+    // Needed for performance tools
+    AllowSyscall(f, __NR_perf_event_open);
+
+    // Needed for treble
+    AllowSyscall(f, __NR_finit_module);
+
+    // Needed for trusty
+    AllowSyscall(f, __NR_syncfs);
+
+    // Needed for strace
+    AllowSyscall(f, __NR_tkill);  // __NR_tkill
+
+    // Needed for kernel to restart syscalls
+    AllowSyscall(f, __NR_restart_syscall);
+
+     // arm64-only filter - autogenerated from bionic syscall usage
+    for (size_t i = 0; i < arm64_filter_size; ++i)
+        f.push_back(arm64_filter[i]);
+#else
+    // Generic policy
+    Allow(f);
+#endif
+
+#ifdef AUDIT_ARCH_NR32
+    if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0)
+        return -1;
+
+    // 32-bit filter for 64-bit platforms
+    ExamineSyscall(f);
+
+#ifdef __aarch64__
+    // Syscalls needed to boot android
+    AllowSyscall(f, 120); // __NR_clone
+    AllowSyscall(f, 240); // __NR_futex
+    AllowSyscall(f, 119); // __NR_sigreturn
+    AllowSyscall(f, 173); // __NR_rt_sigreturn
+    AllowSyscall(f, 363); // __NR_rt_tgsigqueueinfo
+    AllowSyscall(f, 224); // __NR_gettid
+
+    // Syscalls needed to run Chrome
+    AllowSyscall(f, 383); // __NR_seccomp - needed to start Chrome
+    AllowSyscall(f, 384); // __NR_getrandom - needed to start Chrome
+
+    // Syscalls needed to run GFXBenchmark
+    AllowSyscall(f, 190); // __NR_vfork
+
+    // Needed for strace
+    AllowSyscall(f, 238);  // __NR_tkill
+
+    // Needed for kernel to restart syscalls
+    AllowSyscall(f, 0);  // __NR_restart_syscall
+
+    // arm32-on-arm64 only filter - autogenerated from bionic syscall usage
+    for (size_t i = 0; i < arm_filter_size; ++i)
+        f.push_back(arm_filter[i]);
+#else
+    // Generic policy
+    Allow(f);
+#endif
+#endif
+    return install_filter(f);
+}
diff --git a/init/seccomp.h b/init/seccomp.h
new file mode 100644
index 0000000..cda7a89
--- /dev/null
+++ b/init/seccomp.h
@@ -0,0 +1,22 @@
+/*
+ * 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 SECCOMP_H
+#define SECCOMP_H
+
+bool set_seccomp_filter();
+
+#endif
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 594b23d..013999a 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -177,8 +177,11 @@
                                            CAP_MASK_LONG(CAP_SETPCAP),
                                               "system/bin/webview_zygote64" },
 
-    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump32" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump64" },
+    { 00755, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SYS_PTRACE),
+                                              "system/bin/crash_dump32" },
+    { 00755, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SYS_PTRACE),
+                                              "system/bin/crash_dump64" },
+
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/debuggerd" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
@@ -197,7 +200,10 @@
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
     { 00600, AID_ROOT,      AID_ROOT,      0, "system/build.prop" },
     { 00600, AID_ROOT,      AID_ROOT,      0, "vendor/build.prop" },
+    { 00600, AID_ROOT,      AID_ROOT,      0, "odm/build.prop" },
     { 00600, AID_ROOT,      AID_ROOT,      0, "default.prop" },
+    { 00600, AID_ROOT,      AID_ROOT,      0, "vendor/default.prop" },
+    { 00600, AID_ROOT,      AID_ROOT,      0, "odm/default.prop" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
 };
 
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 15adf6b..d301276 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -29,10 +29,6 @@
 
 static int klog_level = KLOG_INFO_LEVEL;
 
-int klog_get_level(void) {
-    return klog_level;
-}
-
 void klog_set_level(int level) {
     klog_level = level;
 }
diff --git a/liblog/Android.bp b/liblog/Android.bp
index bbe7d79..40cdcee 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -57,7 +57,7 @@
             srcs: liblog_target_sources,
             // AddressSanitizer runtime library depends on liblog.
             sanitize: {
-                never: true,
+                address: false,
             },
         },
         android_arm: {
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index f19c3ab..1a2d506 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -262,6 +262,8 @@
     }
 
 #if defined(__ANDROID__)
+    clock_gettime(android_log_clockid(), &ts);
+
     if (log_id == LOG_ID_SECURITY) {
         if (vec[0].iov_len < 4) {
             return -EINVAL;
@@ -351,8 +353,6 @@
             return -EPERM;
         }
     }
-
-    clock_gettime(android_log_clockid(), &ts);
 #else
     /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
     {
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index c204a16..d9935c3 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -581,24 +581,36 @@
 
 } /* namespace android */
 
+void reportErrorName(const char **current,
+                     const char* name,
+                     bool blockSecurity) {
+    if (*current) {
+       return;
+    }
+    if (blockSecurity && (android_name_to_log_id(name) == LOG_ID_SECURITY)) {
+       return;
+    }
+    *current = name;
+}
 
 int main(int argc, char **argv)
 {
     using namespace android;
     int err;
     int hasSetLogFormat = 0;
-    int clearLog = 0;
-    int getLogSize = 0;
+    bool clearLog = false;
+    bool allSelected = false;
+    bool getLogSize = false;
+    bool getPruneList = false;
+    bool printStatistics = false;
+    bool printDividers = false;
     unsigned long setLogSize = 0;
-    int getPruneList = 0;
     char *setPruneList = NULL;
     char *setId = NULL;
-    int printStatistics = 0;
     int mode = ANDROID_LOG_RDONLY;
     const char *forceFilters = NULL;
     log_device_t* devices = NULL;
     log_device_t* dev;
-    bool printDividers = false;
     struct logger_list *logger_list;
     size_t tail_lines = 0;
     log_time tail_time(log_time::EPOCH);
@@ -710,7 +722,7 @@
             break;
 
             case 'c':
-                clearLog = 1;
+                clearLog = true;
                 mode |= ANDROID_LOG_WRONLY;
             break;
 
@@ -771,7 +783,7 @@
 
             case 'g':
                 if (!optarg) {
-                    getLogSize = 1;
+                    getLogSize = true;
                     break;
                 }
                 // FALLTHRU
@@ -813,7 +825,7 @@
 
             case 'p':
                 if (!optarg) {
-                    getPruneList = 1;
+                    getPruneList = true;
                     break;
                 }
                 // FALLTHRU
@@ -830,6 +842,7 @@
                                   (1 << LOG_ID_SYSTEM) |
                                   (1 << LOG_ID_CRASH);
                     } else if (strcmp(optarg, "all") == 0) {
+                        allSelected = true;
                         idMask = (unsigned)-1;
                     } else {
                         log_id_t log_id = android_name_to_log_id(optarg);
@@ -839,6 +852,7 @@
                             logcat_panic(HELP_TRUE,
                                          "unknown buffer %s\n", optarg);
                         }
+                        if (log_id == LOG_ID_SECURITY) allSelected = false;
                         idMask |= (1 << log_id);
                     }
                     optarg = NULL;
@@ -992,7 +1006,7 @@
                 break;
 
             case 'S':
-                printStatistics = 1;
+                printStatistics = true;
                 break;
 
             case ':':
@@ -1114,7 +1128,7 @@
         dev->logger = android_logger_open(logger_list,
                                           android_name_to_log_id(dev->device));
         if (!dev->logger) {
-            openDeviceFail = openDeviceFail ?: dev->device;
+            reportErrorName(&openDeviceFail, dev->device, allSelected);
             dev = dev->next;
             continue;
         }
@@ -1136,7 +1150,7 @@
 
                     if (file.length() == 0) {
                         perror("while clearing log files");
-                        clearFail = clearFail ?: dev->device;
+                        reportErrorName(&clearFail, dev->device, allSelected);
                         break;
                     }
 
@@ -1144,17 +1158,17 @@
 
                     if (err < 0 && errno != ENOENT && clearFail == NULL) {
                         perror("while clearing log files");
-                        clearFail = dev->device;
+                        reportErrorName(&clearFail, dev->device, allSelected);
                     }
                 }
             } else if (android_logger_clear(dev->logger)) {
-                clearFail = clearFail ?: dev->device;
+                reportErrorName(&clearFail, dev->device, allSelected);
             }
         }
 
         if (setLogSize) {
             if (android_logger_set_log_size(dev->logger, setLogSize)) {
-                setSizeFail = setSizeFail ?: dev->device;
+                reportErrorName(&setSizeFail, dev->device, allSelected);
             }
         }
 
@@ -1163,7 +1177,7 @@
             long readable = android_logger_get_log_readable_size(dev->logger);
 
             if ((size < 0) || (readable < 0)) {
-                getSizeFail = getSizeFail ?: dev->device;
+                reportErrorName(&getSizeFail, dev->device, allSelected);
             } else {
                 printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
                        "max entry is %db, max payload is %db\n", dev->device,
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 99c2e0a..cb8b061 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -55,6 +55,6 @@
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 725d76e..337861e 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -23,10 +23,12 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
 #include <memory>
 #include <string>
 
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 #include <log/log.h>
 #include <log/log_event_list.h>
@@ -53,6 +55,11 @@
 TEST(logcat, buckets) {
     FILE *fp;
 
+#undef LOG_TAG
+#define LOG_TAG "inject"
+    RLOGE("logcat.buckets");
+    sleep(1);
+
     ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b radio -b events -b system -b main -d 2>/dev/null",
       "r")));
@@ -164,13 +171,39 @@
         if (!ep) {
             continue;
         }
-        ep -= 7;
+        static const size_t tag_field_width = 7;
+        ep -= tag_field_width;
         *ep = '\0';
         return cp;
     }
     return NULL;
 }
 
+// If there is not enough background noise in the logs, then spam the logs to
+// permit tail checking so that the tests can progress.
+static size_t inject(ssize_t count) {
+    if (count <= 0) return 0;
+
+    static const size_t retry = 3;
+    size_t errors = retry;
+    size_t num = 0;
+    for(;;) {
+        log_time ts(CLOCK_MONOTONIC);
+        if (__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) >= 0) {
+            if (++num >= (size_t)count) {
+                sleep(1); // let data settle end-to-end
+                return num;
+            }
+            errors = retry;
+            usleep(50);
+        } else if (--errors <= 0) {
+            return num;
+        }
+    }
+    // NOTREACH
+    return num;
+}
+
 TEST(logcat, tz) {
 
     if (android_log_clockid() == CLOCK_MONOTONIC) {
@@ -200,7 +233,7 @@
 
         pclose(fp);
 
-    } while ((count < 3) && --tries && (sleep(1), true));
+    } while ((count < 3) && --tries && inject(3 - count));
 
     ASSERT_EQ(3, count);
 }
@@ -235,8 +268,7 @@
         char buffer[BIG_BUFFER];
 
         snprintf(buffer, sizeof(buffer),
-          "logcat -v long -b radio -b events -b system -b main -t %d 2>/dev/null",
-          num);
+                 "logcat -v long -b all -t %d 2>/dev/null", num);
 
         FILE *fp;
         ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
@@ -249,7 +281,7 @@
 
         pclose(fp);
 
-    } while ((count < num) && --tries && (sleep(1), true));
+    } while ((count < num) && --tries && inject(num - count));
 
     ASSERT_EQ(num, count);
 }
@@ -272,26 +304,34 @@
 
 TEST(logcat, tail_time) {
     FILE *fp;
-
-    ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
-
+    int count;
     char buffer[BIG_BUFFER];
     char *last_timestamp = NULL;
     char *first_timestamp = NULL;
-    int count = 0;
-
     char *cp;
-    while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) {
-        ++count;
-        if (!first_timestamp) {
-            first_timestamp = strdup(cp);
-        }
-        free(last_timestamp);
-        last_timestamp = strdup(cp);
-    }
-    pclose(fp);
 
-    EXPECT_EQ(10, count);
+    int tries = 3; // in case run too soon after system start or buffer clear
+
+    // Do not be tempted to use -v usec because that increases the
+    // chances of an occasional test failure by 1000 (see below).
+    do {
+        ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
+
+        count = 0;
+
+        while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) {
+            ++count;
+            if (!first_timestamp) {
+                first_timestamp = strdup(cp);
+            }
+            free(last_timestamp);
+            last_timestamp = strdup(cp);
+        }
+        pclose(fp);
+
+    } while ((count < 10) && --tries && inject(10 - count));
+
+    EXPECT_EQ(10, count); // We want _some_ history, too small, falses below
     EXPECT_TRUE(last_timestamp != NULL);
     EXPECT_TRUE(first_timestamp != NULL);
 
@@ -1412,3 +1452,22 @@
         EXPECT_TRUE(End_to_End(sync.tagStr, ""));
     }
 }
+
+static bool reportedSecurity(const char* command) {
+    FILE* fp = popen(command, "r");
+    if (!fp) return true;
+
+    std::string ret;
+    bool val = android::base::ReadFdToString(fileno(fp), &ret);
+    pclose(fp);
+
+    if (!val) return true;
+    return std::string::npos != ret.find("'security'");
+}
+
+TEST(logcat, security) {
+    EXPECT_FALSE(reportedSecurity("logcat -b all -g 2>&1"));
+    EXPECT_TRUE(reportedSecurity("logcat -b security -g 2>&1"));
+    EXPECT_TRUE(reportedSecurity("logcat -b security -c 2>&1"));
+    EXPECT_TRUE(reportedSecurity("logcat -b security -G 256K 2>&1"));
+}
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 703c0fb..13a7922 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -196,7 +196,9 @@
     EXPECT_TRUE(NULL != main_logs);
 
     char *radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
-    EXPECT_TRUE(NULL != radio_logs);
+    if (!radio_logs) GTEST_LOG_(INFO) << "Value of: NULL != radio_logs\n"
+                                         "Actual: false\n"
+                                         "Expected: false\n";
 
     char *system_logs = strstr(cp, "\nChattiest UIDs in system ");
     EXPECT_TRUE(NULL != system_logs);
@@ -942,8 +944,16 @@
         return 0;
     }
 
-    // Requests dac_read_search, falls back to request dac_override
-    rate /= 2;
+    // The key here is we are root, but we are in u:r:shell:s0,
+    // and the directory does not provide us DAC access
+    // (eg: 0700 system system) so we trigger the pair dac_override
+    // and dac_read_search on every try to get past the message
+    // de-duper.  We will also rotate the file name in the directory
+    // as another measure.
+    static const char file[] = "/data/backup/cannot_access_directory_%u";
+    static const unsigned avc_requests_per_access = 2;
+
+    rate /= avc_requests_per_access;
     useconds_t usec;
     if (rate == 0) {
         rate = 1;
@@ -951,15 +961,12 @@
     } else {
         usec = (1000000 + (rate / 2)) / rate;
     }
-    num = (num + 1) / 2;
+    num = (num + (avc_requests_per_access / 2)) / avc_requests_per_access;
 
     if (usec < 2) usec = 2;
 
     while (num > 0) {
-        if (access(android::base::StringPrintf(
-                       "/data/misc/logd/cannot_access_directory_%u",
-                       num).c_str(),
-                   F_OK) == 0) {
+        if (access(android::base::StringPrintf(file, num).c_str(), F_OK) == 0) {
             _exit(-1);
             // NOTREACHED
             return 0;
@@ -1002,7 +1009,7 @@
 
         // int len = get4LE(eventData + 4 + 1);
         log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
-        const char *cp = strstr(eventData + 4 + 1 + 4, "): avc: ");
+        const char *cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
         if (!cp) continue;
 
         ++count;
@@ -1055,8 +1062,7 @@
     // give logd another 3 seconds to react to the burst before checking
     sepolicy_rate(rate, rate * 3);
     // maximum period at double the maximum burst rate (spam filter kicked in)
-    EXPECT_GE(((AUDIT_RATE_LIMIT_MAX * AUDIT_RATE_LIMIT_BURST_DURATION) * 130) /
-                                        100, // +30% margin
+    EXPECT_GE(threshold * 2,
               count_avc(sepolicy_rate(rate,
                                       rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
     // cool down, and check unspammy rate still works
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 791d67f..d6ae6f0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -118,7 +118,6 @@
     write /proc/sys/kernel/sched_child_runs_first 0
 
     write /proc/sys/kernel/randomize_va_space 2
-    write /proc/sys/kernel/kptr_restrict 2
     write /proc/sys/vm/mmap_min_addr 32768
     write /proc/sys/net/ipv4/ping_group_range "0 2147483647"
     write /proc/sys/net/unix/max_dgram_qlen 600
@@ -356,10 +355,6 @@
     # We restorecon /data in case the userdata partition has been reset.
     restorecon /data
 
-    # start debuggerd to make debugging early-boot crashes easier.
-    start debuggerd
-    start debuggerd64
-
     # Make sure we have the device encryption key.
     start vold
     installkey /data