Merge "libbacktrace: make Backtrace::FormatFrameData static."
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index e7f44c6..7025f28 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -412,8 +412,13 @@
     if (it != usb_handles.end()) {
         if (!it->second->device_handle) {
             // If the handle is null, we were never able to open the device.
-            unregister_usb_transport(it->second.get());
+
+            // Temporarily release the usb handles mutex to avoid deadlock.
+            std::unique_ptr<usb_handle> handle = std::move(it->second);
             usb_handles.erase(it);
+            lock.unlock();
+            unregister_usb_transport(handle.get());
+            lock.lock();
         } else {
             // Closure of the transport will erase the usb_handle.
         }
diff --git a/adb/services.cpp b/adb/services.cpp
index dbf71d3..ca34556 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -150,6 +150,7 @@
 
     sync();
 
+    if (!reboot_arg || !reboot_arg[0]) reboot_arg = "adb";
     std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg);
     if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
         WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str());
diff --git a/adb/socket.h b/adb/socket.h
index 4acdf4a..64d05a9 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -19,84 +19,83 @@
 
 #include <stddef.h>
 
+#include <memory>
+
 #include "fdevent.h"
 
 struct apacket;
 class atransport;
 
 /* An asocket represents one half of a connection between a local and
-** remote entity.  A local asocket is bound to a file descriptor.  A
-** remote asocket is bound to the protocol engine.
-*/
+ * remote entity.  A local asocket is bound to a file descriptor.  A
+ * remote asocket is bound to the protocol engine.
+ */
 struct asocket {
-        /* chain pointers for the local/remote list of
-        ** asockets that this asocket lives in
-        */
-    asocket *next;
-    asocket *prev;
+    /* chain pointers for the local/remote list of
+     * asockets that this asocket lives in
+     */
+    asocket* next;
+    asocket* prev;
 
-        /* the unique identifier for this asocket
-        */
+    /* the unique identifier for this asocket
+     */
     unsigned id;
 
-        /* flag: set when the socket's peer has closed
-        ** but packets are still queued for delivery
-        */
-    int    closing;
+    /* flag: set when the socket's peer has closed
+     * but packets are still queued for delivery
+     */
+    int closing;
 
     // flag: set when the socket failed to write, so the socket will not wait to
     // write packets and close directly.
     bool has_write_error;
 
-        /* flag: quit adbd when both ends close the
-        ** local service socket
-        */
-    int    exit_on_close;
+    /* flag: quit adbd when both ends close the
+     * local service socket
+     */
+    int exit_on_close;
 
-        /* the asocket we are connected to
-        */
+    // the asocket we are connected to
+    asocket* peer;
 
-    asocket *peer;
-
-        /* For local asockets, the fde is used to bind
-        ** us to our fd event system.  For remote asockets
-        ** these fields are not used.
-        */
+    /* For local asockets, the fde is used to bind
+     * us to our fd event system.  For remote asockets
+     * these fields are not used.
+     */
     fdevent fde;
     int fd;
 
-        /* queue of apackets waiting to be written
-        */
-    apacket *pkt_first;
-    apacket *pkt_last;
+    // queue of apackets waiting to be written
+    apacket* pkt_first;
+    apacket* pkt_last;
 
-        /* enqueue is called by our peer when it has data
-        ** for us.  It should return 0 if we can accept more
-        ** data or 1 if not.  If we return 1, we must call
-        ** peer->ready() when we once again are ready to
-        ** receive data.
-        */
-    int (*enqueue)(asocket *s, apacket *pkt);
+    /* enqueue is called by our peer when it has data
+     * for us.  It should return 0 if we can accept more
+     * data or 1 if not.  If we return 1, we must call
+     * peer->ready() when we once again are ready to
+     * receive data.
+     */
+    int (*enqueue)(asocket* s, apacket* pkt);
 
-        /* ready is called by the peer when it is ready for
-        ** us to send data via enqueue again
-        */
-    void (*ready)(asocket *s);
+    /* ready is called by the peer when it is ready for
+     * us to send data via enqueue again
+     */
+    void (*ready)(asocket* s);
 
-        /* shutdown is called by the peer before it goes away.
-        ** the socket should not do any further calls on its peer.
-        ** Always followed by a call to close. Optional, i.e. can be NULL.
-        */
-    void (*shutdown)(asocket *s);
+    /* shutdown is called by the peer before it goes away.
+     * the socket should not do any further calls on its peer.
+     * Always followed by a call to close. Optional, i.e. can be NULL.
+     */
+    void (*shutdown)(asocket* s);
 
-        /* close is called by the peer when it has gone away.
-        ** we are not allowed to make any further calls on the
-        ** peer once our close method is called.
-        */
-    void (*close)(asocket *s);
+    /* close is called by the peer when it has gone away.
+     * we are not allowed to make any further calls on the
+     * peer once our close method is called.
+     */
+    void (*close)(asocket* s);
 
-        /* A socket is bound to atransport */
-    atransport *transport;
+    /* A socket is bound to atransport */
+    atransport* transport;
 
     size_t get_max_payload() const;
 };
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index f28a3df..c53fbb4 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -96,7 +96,7 @@
 }
 
 void remove_socket(asocket* s) {
-    // socket_list_lock should already be held
+    std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
     if (s->prev && s->next) {
         s->prev->next = s->next;
         s->next->prev = s->prev;
diff --git a/adb/transport.cpp b/adb/transport.cpp
index b2e03a0..1b597fd 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -615,15 +615,15 @@
 static void transport_unref(atransport* t) {
     CHECK(t != nullptr);
 
-    size_t old_refcount = t->ref_count--;
-    CHECK_GT(old_refcount, 0u);
-
-    if (old_refcount == 1u) {
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
+    CHECK_GT(t->ref_count, 0u);
+    t->ref_count--;
+    if (t->ref_count == 0) {
         D("transport: %s unref (kicking and closing)", t->serial);
         t->close(t);
         remove_transport(t);
     } else {
-        D("transport: %s unref (count=%zu)", t->serial, old_refcount - 1);
+        D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
     }
 }
 
diff --git a/adb/transport.h b/adb/transport.h
index 00fad56..374bfc3 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -64,7 +64,7 @@
     // it's better to do this piece by piece.
 
     atransport(ConnectionState state = kCsOffline)
-        : id(NextTransportId()), ref_count(0), connection_state_(state) {
+        : id(NextTransportId()), connection_state_(state) {
         transport_fde = {};
         protocol_version = A_VERSION;
         max_payload = MAX_PAYLOAD;
@@ -88,7 +88,7 @@
     int fd = -1;
     int transport_socket = -1;
     fdevent transport_fde;
-    std::atomic<size_t> ref_count;
+    size_t ref_count = 0;
     uint32_t sync_token = 0;
     bool online = false;
     TransportType type = kTransportAny;
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index c0bf0c1..07a5edd 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -26,6 +26,10 @@
   TemporaryFile();
   ~TemporaryFile();
 
+  // Release the ownership of fd, caller is reponsible for closing the
+  // fd or stream properly.
+  int release();
+
   int fd;
   char path[1024];
 
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 636477d..1cfa9e6 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -85,10 +85,18 @@
 }
 
 TemporaryFile::~TemporaryFile() {
-  close(fd);
+  if (fd != -1) {
+    close(fd);
+  }
   unlink(path);
 }
 
+int TemporaryFile::release() {
+  int result = fd;
+  fd = -1;
+  return result;
+}
+
 void TemporaryFile::init(const std::string& tmp_dir) {
   snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
            OS_PATH_SEPARATOR);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index dd357ed..6734f4d 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -63,6 +63,7 @@
     name: "bootstat",
     defaults: ["bootstat_defaults"],
     static_libs: ["libbootstat"],
+    shared_libs: ["liblogcat"],
     init_rc: ["bootstat.rc"],
     srcs: ["bootstat.cpp"],
 }
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
new file mode 100755
index 0000000..d789808
--- /dev/null
+++ b/bootstat/boot_reason_test.sh
@@ -0,0 +1,721 @@
+#! /bin/bash
+#
+# Bootstat boot reason tests
+#
+# throughout testing:
+# - manual tests can only run on eng/userdebug builds
+# - watch adb logcat -b all -d -s bootstat
+# - watch adb logcat -b all -d | audit2allow
+# - wait until screen is up, boot has completed, can mean wait for
+#   sys.boot_completed=1 and sys.logbootcomplete=1 to be true
+#
+# All test frames, and nothing else, must be function names prefixed and
+# specifiged with the pattern 'test_<test>() {' as this is also how the
+# script discovers the full list of tests by inspecting its own code.
+#
+
+# Helper variables
+
+SPACE=" "
+ESCAPE=""
+TAB="	"
+GREEN="${ESCAPE}[38;5;40m"
+RED="${ESCAPE}[38;5;196m"
+NORMAL="${ESCAPE}[0m"
+
+# Helper functions
+
+[ "USAGE: inFastboot
+
+Returns: true if device is in fastboot mode" ]
+inFastboot() {
+  fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+}
+
+[ "USAGE: format_duration <seconds>
+
+human readable output whole seconds, whole minutes or mm:ss" ]
+format_duration() {
+  if [ -z "${1}" ]; then
+    echo unknown
+    return
+  fi
+  seconds=`expr ${1} % 60`
+  minutes=`expr ${1} / 60`
+  if [ 0 -eq ${minutes} ]; then
+    if [ 1 -eq ${1} ]; then
+      echo 1 second
+      return
+    fi
+    echo ${1} seconds
+    return
+  elif [ 60 -eq ${1} ]; then
+    echo 1 minute
+    return
+  elif [ 0 -eq ${seconds} ]; then
+    echo ${minutes} minutes
+    return
+  fi
+  echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10`
+}
+
+wait_for_screen_timeout=900
+[ "USAGE: wait_for_screen [-n] [TIMEOUT]
+
+-n - echo newline at exit
+TIMEOUT - default `format_duration ${wait_for_screen_timeout}`" ]
+wait_for_screen() {
+  exit_function=true
+  if [ X"-n" = X"${1}" ]; then
+    exit_function=echo
+    shift
+  fi
+  timeout=${wait_for_screen_timeout}
+  if [ ${#} -gt 0 ]; then
+    timeout=${1}
+    shift
+  fi
+  counter=0
+  while true; do
+    [ 0 = ${counter} ] ||
+      adb wait-for-device </dev/null >/dev/null 2>/dev/null
+    vals=`adb shell getprop </dev/null 2>/dev/null |
+          sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
+    [ 0 = ${counter} ] ||
+      sleep 1
+    if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]; then
+      break
+    fi
+    if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]; then
+      break
+    fi
+    counter=`expr ${counter} + 1`
+    if [ ${counter} -gt ${timeout} ]; then
+      ${exit_function}
+      echo "ERROR: wait_for_screen() timed out (`format_duration ${timeout}`)" >&2
+      return 1
+    fi
+  done
+  ${exit_function}
+}
+
+[ "USAGE: EXPECT_EQ <lval> <rval> [message]
+
+Returns true if (regex) lval matches rval" ]
+EXPECT_EQ() {
+  lval="${1}"
+  rval="${2}"
+  shift 2
+  if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
+    echo "ERROR: expected \"${lval}\" got \"${rval}\"" >&2
+    if [ -n "${*}" ] ; then
+      echo "       ${*}" >&2
+    fi
+    return 1
+  fi
+  if [ -n "${*}" ] ; then
+    if [ X"${lval}" != X"${rval}" ]; then
+      echo "INFO: ok \"${lval}\"(=\"${rval}\") ${*}" >&2
+    else
+      echo "INFO: ok \"${lval}\" ${*}" >&2
+    fi
+  fi
+  return 0
+}
+
+[ "USAGE: EXPECT_PROPERTY <prop> <value>
+
+Returns true if current return (regex) value is true and the result matches" ]
+EXPECT_PROPERTY() {
+  save_ret=${?}
+  property="${1}"
+  value="${2}"
+  shift 2
+  val=`adb shell getprop ${property} 2>&1`
+  EXPECT_EQ "${value}" "${val}" for Android property ${property} ||
+    save_ret=${?}
+  return ${save_ret}
+}
+
+[ "USAGE: report_bootstat_logs <expected> ...
+
+if not prefixed with a minus (-), <expected> will become a series of expected
+matches:
+
+    bootstat: Canonical boot reason: <expected_property_value>
+
+If prefixed with a minus, <expected> will look for an exact match after
+removing the minux prefix.  All expected content is _dropped_ from the output
+and in essence forms a known blacklist, unexpected content will show.
+
+Report any logs, minus a known blacklist, preserve the current exit status" ]
+report_bootstat_logs() {
+  save_ret=${?}
+  match=
+  for i in ${*}; do
+    if [ X"${i}" != X"${i#-}" ] ; then
+      match="${match}
+${i#-}"
+    else
+      match="${match}
+bootstat: Canonical boot reason: ${i}"
+    fi
+  done
+  adb logcat -b all -d |
+  grep bootstat |
+  grep -v -F "bootstat: Service started: /system/bin/bootstat --record_boot_complete${match}
+bootstat: Failed to read /data/misc/bootstat/post_decrypt_time_elapsed: No such file or directory
+bootstat: Failed to parse boot time record: /data/misc/bootstat/post_decrypt_time_elapsed
+bootstat: Service started: /system/bin/bootstat --record_boot_reason
+bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset
+bootstat: Service started: /system/bin/bootstat -l
+bootstat: Battery level at shutdown 100%
+bootstat: Battery level at startup 100%
+init    : Parsing file /system/etc/init/bootstat.rc...
+init    : processing action (post-fs-data) from (/system/etc/init/bootstat.rc
+init    : processing action (boot) from (/system/etc/init/bootstat.rc
+init    : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
+init    : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
+init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
+init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
+init    : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
+ (/system/bin/bootstat --record_boot_complete)'...
+ (/system/bin/bootstat --record_boot_complete)' (pid${SPACE}
+ (/system/bin/bootstat --record_boot_reason)'...
+ (/system/bin/bootstat --record_boot_reason)' (pid${SPACE}
+ (/system/bin/bootstat --record_time_since_factory_reset)'...
+ (/system/bin/bootstat --record_time_since_factory_reset)' (pid${SPACE}
+ (/system/bin/bootstat -l)'...
+ (/system/bin/bootstat -l)' (pid " |
+  grep -v 'bootstat: Unknown boot reason: $' # Hikey Special
+  return ${save_ret}
+}
+
+[ "USAGE: start_test [message]
+
+Record start of test, preserve exit status" ]
+start_test() {
+  save_ret=${?}
+  START=`date +%s`
+  echo "${GREEN}[ RUN      ]${NORMAL} ${TEST} ${*}"
+  return ${save_ret}
+}
+
+[ "USAGE: end_test [message]
+
+Document duration and success of test, preserve exit status" ]
+end_test() {
+  save_ret=${?}
+  END=`date +%s`
+  duration=`expr ${END} - ${START} 2>/dev/null`
+  [ 0 = ${duration} ] ||
+    echo INFO: ${TEST} test duration `format_duration ${duration}` >&2
+  if [ ${save_ret} = 0 ]; then
+    echo "${GREEN}[       OK ]${NORMAL} ${TEST} ${*}"
+  else
+    echo "${RED}[  FAILED  ]${NORMAL} ${TEST} ${*}"
+  fi
+  return ${save_ret}
+}
+
+[ "USAGE: wrap_test <test> [message]
+
+All tests below are wrapped with this helper" ]
+wrap_test() {
+  if [ -z "${1}" -o X"nothing" = X"${1}" ]; then
+    return
+  fi
+  TEST=${1}
+  shift
+  start_test ${1}
+  eval test_${TEST}
+  end_test ${2}
+}
+
+[ "USAGE: validate_property <property>
+
+Check property for CTS compliance with our expectations. Return a cleansed
+string representing what is acceptable.
+
+NB: must roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
+validate_property() {
+  var=`adb shell getprop ${1} 2>&1`
+  var=`echo -n ${var} |
+       tr '[A-Z]' '[a-z]' |
+       tr ' \f\t\r\n' '_____'`
+  case ${var} in
+    watchdog) ;;
+    watchdog,?*) ;;
+    kernel_panic) ;;
+    kernel_panic,?*) ;;
+    recovery) ;;
+    recovery,?*) ;;
+    bootloader) ;;
+    bootloader,?*) ;;
+    cold) ;;
+    cold,?*) ;;
+    hard) ;;
+    hard,?*) ;;
+    warm) ;;
+    warm,?*) ;;
+    shutdown) ;;
+    shutdown,?*) ;;
+    reboot) ;;
+    reboot,?*) ;;
+    # Aliases
+    *wdog* | *watchdog* )     var="watchdog" ;;
+    *powerkey* )              var="cold,powerkey" ;;
+    *panic* | *kernel_panic*) var="kernel_panic" ;;
+    *thermal*)                var="shutdown,thermal" ;;
+    *s3_wakeup*)              var="warm,s3_wakeup" ;;
+    *hw_reset*)               var="hard,hw_reset" ;;
+    *bootloader*)             var="bootloader" ;;
+    ?*)                       var="reboot,${var}" ;;
+    *)                        var="reboot" ;;
+  esac
+  echo ${var}
+}
+
+#
+# Actual test frames
+#
+
+[ "USAGE: test_properties
+
+properties test
+- (wait until screen is up, boot has completed)
+- adb shell getprop ro.boot.bootreason (bootloader reason)
+- adb shell getprop persist.sys.boot.reason (last reason)
+- adb shell getprop sys.boot.reason (system reason)
+- NB: all should have a value that is compliant with our known set." ]
+test_properties() {
+  wait_for_screen
+  retval=0
+  check_set="ro.boot.bootreason persist.sys.boot.reason sys.boot.reason"
+  bootloader=""
+  # NB: this test could fail if performed _after_ optional_factory_reset test
+  # and will report
+  #  ERROR: expected "reboot" got ""
+  #        for Android property persist.sys.boot.reason
+  # following is mitigation for the persist.sys.boot.reason, skip it
+  if [ "reboot,factory_reset" = `validate_property ro.boot_bootreason` ]; then
+    check_set="ro.boot.bootreason sys.boot.reason"
+    bootloader="bootloader"
+  fi
+  for prop in ${check_set}; do
+    reason=`validate_property ${prop}`
+    EXPECT_PROPERTY ${prop} ${reason} || retval=${?}
+  done
+  # sys.boot.reason is last for a reason
+  report_bootstat_logs ${reason} ${bootloader}
+  return ${retval}
+}
+
+[ "USAGE: test_ota
+
+ota test
+- rm out/.kati_stamp-* out/build_date.txt out/build_number.txt
+- rm out/target/product/*/*/*.prop
+- rm -r out/target/product/*/obj/ETC/system_build_prop_intermediates
+- m
+- NB: ro.build.date.utc should update
+- fastboot flashall
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report ota
+
+Decision to change the build itself rather than trick bootstat by
+rummaging through its data files was made." ]
+test_ota() {
+  echo "INFO: expected duration of ${TEST} test about 5 minutes or more" >&2
+  echo "      extended by build and flashing times" >&2
+  if [ -z "${TARGET_PRODUCT}" -o \
+       -z "${ANDROID_PRODUCT_OUT}" -o \
+       -z "${ANDROID_BUILD_TOP}" -o \
+       -z "${TARGET_BUILD_VARIANT}" ]; then
+    echo "ERROR: Missing envsetup.sh and lunch" >&2
+    return 1
+  fi
+  rm ${ANDROID_PRODUCT_OUT%/out/*}/out/.kati_stamp-* ||
+    true
+  rm ${ANDROID_PRODUCT_OUT%/out/*}/out/build_date.txt ||
+    true
+  rm ${ANDROID_PRODUCT_OUT%/out/*}/out/build_number.txt ||
+    true
+  rm ${ANDROID_PRODUCT_OUT}/*/*.prop ||
+    true
+  rm -r ${ANDROID_PRODUCT_OUT}/obj/ETC/system_build_prop_intermediates ||
+    true
+  pushd ${ANDROID_BUILD_TOP} >&2
+  make -j50 >&2
+  if [ ${?} != 0 ]; then
+    popd >&2
+    return 1
+  fi
+  if ! inFastboot; then
+    adb reboot-bootloader >&2
+  fi
+  fastboot flashall >&2
+  popd >&2
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
+  EXPECT_PROPERTY persist.sys.boot.reason reboot,bootloader
+  report_bootstat_logs reboot,ota bootloader
+}
+
+[ "USAGE: test_optional_ota
+
+fast and fake (touch build_date on device to make it different)" ]
+test_optional_ota() {
+  echo "INFO: expected duration of ${TEST} test about 45 seconds" >&2
+  adb shell su root touch /data/misc/bootstat/build_date >&2
+  adb reboot ota
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason reboot,ota
+  EXPECT_PROPERTY persist.sys.boot.reason reboot,ota
+  report_bootstat_logs reboot,ota
+}
+
+[ "USAGE: [TEST=<test>] blind_reboot_test [<match>]
+
+Simple tests helper
+- adb reboot <test>
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report <test>, or overriden <match>
+
+We interleave the simple reboot tests between the hard/complex ones
+as a means of checking sanity and any persistent side effect of the
+other tests." ]
+blind_reboot_test() {
+  if [ -z "${1}" ]; then
+    set ${TEST}
+  fi
+  echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
+  adb reboot ${TEST}
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason ${1}
+  EXPECT_PROPERTY persist.sys.boot.reason reboot,${TEST}
+  report_bootstat_logs ${1}
+}
+
+[ "USAGE: test_cold
+
+cold test
+- adb reboot cold
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report cold" ]
+test_cold() {
+  blind_reboot_test
+}
+
+[ "USAGE: test_factory_reset
+
+factory_reset test
+- adb shell su root rm /data/misc/bootstat/build_date
+- adb reboot
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report factory_reset
+
+Decision to rummage through bootstat data files was made as
+a _real_ factory_reset is too destructive to the device." ]
+test_factory_reset() {
+  echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
+  adb shell su root rm /data/misc/bootstat/build_date >&2
+  adb reboot >&2
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
+  EXPECT_PROPERTY persist.sys.boot.reason "reboot,.*"
+  report_bootstat_logs reboot,factory_reset reboot, reboot,adb \
+    "-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \
+    "-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date"
+}
+
+[ "USAGE: test_optional_factory_reset
+
+factory_reset test
+- adb reboot-bootloader
+- fastboot format userdata
+- fastboot reboot
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report factory_reset
+
+For realz, and disruptive" ]
+test_optional_factory_reset() {
+  echo "INFO: expected duration of ${TEST} test roughly a minute" >&2
+  if ! inFastboot; then
+    adb reboot-bootloader
+  fi
+  fastboot format userdata >&2
+  fastboot reboot >&2
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
+  EXPECT_PROPERTY persist.sys.boot.reason ""
+  report_bootstat_logs reboot,factory_reset bootloader \
+    "-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \
+    "-bootstat: Failed to parse boot time record: /data/misc/bootstat/last_boot_time_utc" \
+    "-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \
+    "-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date" \
+    "-bootstat: Failed to read /data/misc/bootstat/factory_reset: No such file or directory" \
+    "-bootstat: Failed to parse boot time record: /data/misc/bootstat/factory_reset"
+}
+
+[ "USAGE: test_hard
+
+hard test:
+- adb reboot hard
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report hard" ]
+test_hard() {
+  blind_reboot_test
+}
+
+[ "USAGE: test_battery
+
+battery test (trick):
+- echo healthd: battery l=2 | adb shell su root tee /dev/kmsg ; adb reboot warm
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report reboot,battery, unless healthd managed to log
+  before reboot in above trick.
+
+- Bonus points (manual extras)
+- Make sure the following is added to the /init.rc file in post-fs
+  section before logd is started:
+    +    setprop logd.kernel false
+    +    rm /sys/fs/pstore/console-ramoops
+    +    rm /sys/fs/pstore/console-ramoops-0
+    +    write /dev/kmsg \"healthd: battery l=2
+    +\"
+- adb reboot fs
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report reboot,battery
+- (replace set logd.kernel true to the above, and retry test)" ]
+test_battery() {
+  echo "INFO: expected duration of ${TEST} test roughly two minutes" >&2
+  echo healthd: battery l=2 | adb shell su root tee /dev/kmsg >/dev/null
+  adb reboot warm >&2
+  wait_for_screen
+  adb shell su root \
+    cat /proc/fs/pstore/console-ramoops \
+        /proc/fs/pstore/console-ramoops-0 2>/dev/null |
+    grep 'healthd: battery l=' |
+    tail -1 |
+    grep 'healthd: battery l=2' >/dev/null || (
+      if ! EXPECT_PROPERTY sys.boot.reason reboot,battery >/dev/null 2>/dev/null; then
+        # retry
+        echo healthd: battery l=2 | adb shell su root tee /dev/kmsg >/dev/null
+        adb reboot warm >&2
+        wait_for_screen
+      fi
+    )
+
+  EXPECT_PROPERTY sys.boot.reason shutdown,battery
+  EXPECT_PROPERTY persist.sys.boot.reason reboot,warm
+  report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
+}
+
+[ "USAGE: test_unknown
+
+unknown test
+- adb reboot unknown
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report reboot,unknown
+- NB: expect log \"... I bootstat: Unknown boot reason: reboot,unknown\"" ]
+test_unknown() {
+  blind_reboot_test reboot,unknown
+}
+
+[ "USAGE: test_kernel_panic
+
+kernel_panic test:
+- echo c | adb shell su root tee /proc/sysrq-trigger
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report kernel_panic,sysrq" ]
+test_kernel_panic() {
+  echo "INFO: expected duration of ${TEST} test > 2 minutes" >&2
+  echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason kernel_panic,sysrq
+  EXPECT_PROPERTY persist.sys.boot.reason kernel_panic,sysrq
+  report_bootstat_logs kernel_panic,sysrq
+}
+
+[ "USAGE: test_warm
+
+warm test
+- adb reboot warm
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report warm" ]
+test_warm() {
+  blind_reboot_test
+}
+
+[ "USAGE: test_thermal_shutdown
+
+thermal shutdown test:
+- adb shell setprop sys.powerctl shutdown,thermal
+- (power up the device)
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report shutdown,thermal" ]
+test_thermal_shutdown() {
+  echo "INFO: expected duration of ${TEST} test roughly a minute plus" >&2
+  echo "      power on request" >&2
+  adb shell setprop sys.powerctl shutdown,thermal
+  sleep 5
+  echo -n "WARNING: Please power device back up, waiting ... " >&2
+  wait_for_screen -n >&2
+  EXPECT_PROPERTY sys.boot.reason shutdown,thermal
+  EXPECT_PROPERTY persist.sys.boot.reason shutdown,thermal
+  report_bootstat_logs shutdown,thermal
+}
+
+[ "USAGE: test_userrequested_shutdown
+
+userrequested shutdown test:
+- adb shell setprop sys.powerctl shutdown,userrequested
+- (power up the device)
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report shutdown,userrequested" ]
+test_userrequested_shutdown() {
+  echo "INFO: expected duration of ${TEST} test roughly a minute plus" >&2
+  echo "      power on request" >&2
+  adb shell setprop sys.powerctl shutdown,userrequested
+  sleep 5
+  echo -n "WARNING: Please power device back up, waiting ... " >&2
+  wait_for_screen -n >&2
+  EXPECT_PROPERTY sys.boot.reason shutdown,userrequested
+  EXPECT_PROPERTY persist.sys.boot.reason shutdown,userrequested
+  report_bootstat_logs shutdown,userrequested
+}
+
+[ "USAGE: test_shell_reboot
+
+shell reboot test:
+- adb shell reboot
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report reboot,shell" ]
+test_shell_reboot() {
+  echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
+  adb shell reboot
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason reboot,shell
+  EXPECT_PROPERTY persist.sys.boot.reason reboot,shell
+  report_bootstat_logs reboot,shell
+}
+
+[ "USAGE: test_adb_reboot
+
+adb reboot test:
+- adb reboot
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report reboot,adb" ]
+test_adb_reboot() {
+  echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
+  adb reboot
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason reboot,adb
+  EXPECT_PROPERTY persist.sys.boot.reason reboot,adb
+  report_bootstat_logs reboot,adb
+}
+
+[ "USAGE: ${0##*/} [-s SERIAL] [tests]
+
+Mainline executive to run the above tests" ]
+
+# Rudimentary argument parsing
+
+if [ ${#} -ge 2 -a X"-s" = X"${1}" ]; then
+  export ANDROID_SERIAL="${2}"
+  shift 2
+fi
+
+if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
+  echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
+  echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+  exit 0
+fi
+
+# Check if all conditions for the script are sane
+
+if [ -z "${ANDROID_SERIAL}" ]; then
+  ndev=`(
+      adb devices | grep -v 'List of devices attached'
+      fastboot devices
+    ) |
+    grep -v "^[${SPACE}${TAB}]*\$" |
+    wc -l`
+  if [ ${ndev} -gt 1 ]; then
+    echo "ERROR: no target device specified, ${ndev} connected" >&2
+    echo "${RED}[  FAILED  ]${NORMAL}"
+    exit 1
+  fi
+  echo "WARNING: no target device specified" >&2
+fi
+
+ret=0
+
+# Test Series
+if [ X"all" = X"${*}" ]; then
+  # automagically pick up all test_<function>s.
+  eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+  if [ X"nothing" = X"${1}" ]; then
+    shift 1
+  fi
+fi
+if [ -z "$*" ]; then
+  # automagically pick up all test_<function>, except test_optional_<function>.
+  eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
+                            grep -v '^optional_'`
+  if [ -z "${2}" ]; then
+    # Hard coded should shell fail to find them above (search/permission issues)
+    eval set ota cold factory_reset hard battery unknown kernel_panic warm \
+             thermal_shutdown userrequested_shutdown shell_reboot adb_reboot
+  fi
+  if [ X"nothing" = X"${1}" ]; then
+    shift 1
+  fi
+fi
+echo "INFO: selected test(s): ${@}" >&2
+echo
+failures=
+successes=
+for t in "${@}"; do
+  wrap_test ${t}
+  retval=${?}
+  if [ 0 = ${retval} ]; then
+    if [ -z "${successes}" ]; then
+      successes=${t}
+    else
+      successes="${successes} ${t}"
+    fi
+  else
+    ret=${retval}
+    if [ -z "${failures}" ]; then
+      failures=${t}
+    else
+      failures="${failures} ${t}"
+    fi
+  fi
+  echo
+done
+
+if [ -n "${successes}" ]; then
+  echo "${GREEN}[  PASSED  ]${NORMAL} ${successes}"
+fi
+if [ -n "${failures}" ]; then
+  echo "${RED}[  FAILED  ]${NORMAL} ${failures}"
+fi
+exit ${ret}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index bd611f0..a0a9307 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -20,6 +20,7 @@
 
 #include <getopt.h>
 #include <unistd.h>
+#include <sys/klog.h>
 
 #include <chrono>
 #include <cmath>
@@ -32,11 +33,14 @@
 #include <vector>
 
 #include <android-base/chrono_utils.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <android/log.h>
+#include <cutils/android_reboot.h>
 #include <cutils/properties.h>
+#include <log/logcat.h>
 #include <metricslogger/metrics_logger.h>
 
 #include "boot_event_record_store.h"
@@ -118,6 +122,14 @@
   return std::string(&temp[0], len);
 }
 
+void SetProperty(const char* key, const std::string& val) {
+  property_set(key, val.c_str());
+}
+
+void SetProperty(const char* key, const char* val) {
+  property_set(key, val);
+}
+
 constexpr int32_t kUnknownBootReason = 1;
 
 // A mapping from boot reason string, as read from the ro.boot.bootreason
@@ -175,7 +187,23 @@
   {"reboot,cold", 48},
   {"reboot,recovery", 49},
   {"thermal_shutdown", 50},
-  {"s3_wakeup", 51}
+  {"s3_wakeup", 51},
+  {"kernel_panic,sysrq", 52},
+  {"kernel_panic,NULL", 53},
+  {"kernel_panic,BUG", 54},
+  {"bootloader", 55},
+  {"cold", 56},
+  {"hard", 57},
+  {"warm", 58},
+  {"recovery", 59},
+  {"thermal-shutdown", 60},
+  {"shutdown,thermal", 61},
+  {"shutdown,battery", 62},
+  {"reboot,ota", 63},
+  {"reboot,factory_reset", 64},
+  {"reboot,", 65},
+  {"reboot,shell", 66},
+  {"reboot,adb", 67},
 };
 
 // Converts a string value representing the reason the system booted to an
@@ -191,6 +219,323 @@
   return kUnknownBootReason;
 }
 
+// Canonical list of supported primary reboot reasons.
+const std::vector<const std::string> knownReasons = {
+  // kernel
+  "watchdog",
+  "kernel_panic",
+  // strong
+  "recovery",      // Should not happen from ro.boot.bootreason
+  "bootloader",    // Should not happen from ro.boot.bootreason
+  // blunt
+  "cold",
+  "hard",
+  "warm",
+  "shutdown",      // Can not happen from ro.boot.bootreason
+  "reboot",        // Default catch-all for anything unknown
+};
+
+// Returns true if the supplied reason prefix is considered detailed enough.
+bool isStrongRebootReason(const std::string& r) {
+  for (auto &s : knownReasons) {
+    if (s == "cold") break;
+    // Prefix defined as terminated by a nul or comma (,).
+    if (android::base::StartsWith(r, s.c_str()) &&
+        ((r.length() == s.length()) || (r[s.length()] == ','))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Returns true if the supplied reason prefix is associated with the kernel.
+bool isKernelRebootReason(const std::string& r) {
+  for (auto &s : knownReasons) {
+    if (s == "recovery") break;
+    // Prefix defined as terminated by a nul or comma (,).
+    if (android::base::StartsWith(r, s.c_str()) &&
+        ((r.length() == s.length()) || (r[s.length()] == ','))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Returns true if the supplied reason prefix is considered known.
+bool isKnownRebootReason(const std::string& r) {
+  for (auto &s : knownReasons) {
+    // Prefix defined as terminated by a nul or comma (,).
+    if (android::base::StartsWith(r, s.c_str()) &&
+        ((r.length() == s.length()) || (r[s.length()] == ','))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// If the reboot reason should be improved, report true if is too blunt.
+bool isBluntRebootReason(const std::string& r) {
+  if (isStrongRebootReason(r)) return false;
+
+  if (!isKnownRebootReason(r)) return true; // Can not support unknown as detail
+
+  size_t pos = 0;
+  while ((pos = r.find(',', pos)) != std::string::npos) {
+    ++pos;
+    std::string next(r.substr(pos));
+    if (next.length() == 0) break;
+    if (next[0] == ',') continue;
+    if (!isKnownRebootReason(next)) return false; // Unknown subreason is good.
+    if (isStrongRebootReason(next)) return false; // eg: reboot,reboot
+  }
+  return true;
+}
+
+// std::transform Helper callback functions:
+// Converts a string value representing the reason the system booted to a
+// string complying with Android system standard reason.
+char tounderline(char c) { return ::isblank(c) ? '_' : c; }
+char toprintable(char c) { return ::isprint(c) ? c : '?'; }
+
+const char system_reboot_reason_property[] = "sys.boot.reason";
+const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
+const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
+
+// Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
+std::string BootReasonStrToReason(const std::string& boot_reason) {
+  std::string ret(GetProperty(system_reboot_reason_property));
+  std::string reason(boot_reason);
+  // If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
+  if (reason == ret) ret = "";
+
+  // Cleanup boot_reason regarding acceptable character set
+  std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
+  std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
+  std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
+
+  // Is the current system boot reason sys.boot.reason valid?
+  if (!isKnownRebootReason(ret)) ret = "";
+
+  if (ret == "") {
+    // Is the bootloader boot reason ro.boot.bootreason known?
+    std::vector<std::string> words(android::base::Split(reason, ",_-"));
+    for (auto &s : knownReasons) {
+      std::string blunt;
+      for (auto &r : words) {
+        if (r == s) {
+          if (isBluntRebootReason(s)) {
+            blunt = s;
+          } else {
+            ret = s;
+            break;
+          }
+        }
+      }
+      if (ret == "") ret = blunt;
+      if (ret != "") break;
+    }
+  }
+
+  if (ret == "") {
+    // A series of checks to take some officially unsupported reasons
+    // reported by the bootloader and find some logical and canonical
+    // sense.  In an ideal world, we would require those bootloaders
+    // to behave and follow our standards.
+    static const std::vector<std::pair<const std::string, const std::string>> aliasReasons = {
+      {"watchdog", "wdog"},
+      {"cold,powerkey", "powerkey"},
+      {"kernel_panic", "panic"},
+      {"shutdown,thermal", "thermal"},
+      {"warm,s3_wakeup", "s3_wakeup"},
+      {"hard,hw_reset", "hw_reset"},
+      {"bootloader", ""},
+    };
+
+    // Either the primary or alias is found _somewhere_ in the reason string.
+    for (auto &s : aliasReasons) {
+      if (reason.find(s.first) != std::string::npos) {
+        ret = s.first;
+        break;
+      }
+      if (s.second.size() && (reason.find(s.second) != std::string::npos)) {
+        ret = s.first;
+        break;
+      }
+    }
+  }
+
+  // If watchdog is the reason, see if there is a security angle?
+  if (ret == "watchdog") {
+    if (reason.find("sec") != std::string::npos) {
+      ret += ",security";
+    }
+  }
+
+  // Check the other reason resources if the reason is still blunt.
+  if (isBluntRebootReason(ret)) {
+    // Check to see if last klog has some refinement hints.
+    std::string content;
+    if (!android::base::ReadFileToString("/sys/fs/pstore/console-ramoops-0",
+                                         &content)) {
+        android::base::ReadFileToString("/sys/fs/pstore/console-ramoops",
+                                         &content);
+    }
+
+    // The toybox reboot command used directly (unlikely)? But also
+    // catches init's response to the Android's more controlled reboot command.
+    if (content.rfind("reboot: Power down") != std::string::npos) {
+      ret = "shutdown"; // Still too blunt, but more accurate.
+      // ToDo: init should record the shutdown reason to kernel messages ala:
+      //           init: shutdown system with command 'last_reboot_reason'
+      //       so that if pstore has persistence we can get some details
+      //       that could be missing in last_reboot_reason_property.
+    }
+
+    static const char cmd[] = "reboot: Restarting system with command '";
+    size_t pos = content.rfind(cmd);
+    if (pos != std::string::npos) {
+      pos += strlen(cmd);
+      std::string subReason(content.substr(pos));
+      pos = subReason.find('\'');
+      if (pos != std::string::npos) subReason.erase(pos);
+      if (subReason != "") { // Will not land "reboot" as that is too blunt.
+        if (isKernelRebootReason(subReason)) {
+          ret = "reboot," + subReason; // User space can't talk kernel reasons.
+        } else {
+          ret = subReason;
+        }
+      }
+    }
+
+    // Check for kernel panics, but allowed to override reboot command.
+    if (content.rfind("sysrq: SysRq : Trigger a crash") != std::string::npos) {
+      // Can not happen, except on userdebug, during testing/debugging.
+      ret = "kernel_panic,sysrq";
+    } else if (content.rfind(
+        "Unable to handle kernel NULL pointer dereference at virtual address")
+               != std::string::npos) {
+      ret = "kernel_panic,NULL";
+    } else if (content.rfind("Kernel BUG at ") != std::string::npos) {
+      ret = "kernel_panic,BUG";
+    } else if ((content.rfind("Power held for ") != std::string::npos) ||
+        (content.rfind("charger: [") != std::string::npos)) {
+      ret = "cold";
+    }
+
+    // The following battery test should migrate to a default system health HAL
+
+    // Let us not worry if the reboot command was issued, for the cases of
+    // reboot -p, reboot <no reason>, reboot cold, reboot warm and reboot hard.
+    // Same for bootloader and ro.boot.bootreasons of this set, but a dead
+    // battery could conceivably lead to these, so worthy of override.
+    if (isBluntRebootReason(ret)) {
+      // Heuristic to determine if shutdown possibly because of a dead battery?
+      // Really a hail-mary pass to find it in last klog content ...
+      static const int battery_dead_threshold = 2; // percent
+      static const char battery[] = "healthd: battery l=";
+      pos = content.rfind(battery); // last one
+      if (pos != std::string::npos) {
+        int level = atoi(content.substr(pos + strlen(battery)).c_str());
+        LOG(INFO) << "Battery level at shutdown " << level << "%";
+        if (level <= battery_dead_threshold) {
+          ret = "shutdown,battery";
+        }
+      } else { // Most likely
+        // Content buffer no longer will have console data. Beware if more
+        // checks added below, that depend on parsing console content.
+        content = "";
+
+        LOG(DEBUG) << "Can not find last low battery in last console messages";
+        android_logcat_context ctx = create_android_logcat();
+        FILE *fp = android_logcat_popen(&ctx, "logcat -b kernel -v brief -d");
+        if (fp != nullptr) {
+          android::base::ReadFdToString(fileno(fp), &content);
+        }
+        android_logcat_pclose(&ctx, fp);
+        android_logcat_destroy(&ctx);
+        static const char logcat_battery[] = "W/healthd (    0): battery l=";
+        const char* match = logcat_battery;
+
+        if (content == "") {
+          // Service logd.klog not running, go to smaller buffer in the kernel.
+          int rc = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
+          if (rc > 0) {
+            ssize_t len = rc + 1024; // 1K Margin should it grow between calls.
+            std::unique_ptr<char[]> buf(new char[len]);
+            rc = klogctl(KLOG_READ_ALL, buf.get(), len);
+            if (rc < len) {
+              len = rc + 1;
+            }
+            buf[--len] = '\0';
+            content = buf.get();
+          }
+          match = battery;
+        }
+
+        pos = content.find(match); // The first one it finds.
+        if (pos != std::string::npos) {
+          pos += strlen(match);
+          int level = atoi(content.substr(pos).c_str());
+          LOG(INFO) << "Battery level at startup " << level << "%";
+          if (level <= battery_dead_threshold) {
+            ret = "shutdown,battery";
+          }
+        } else {
+          LOG(DEBUG) << "Can not find first battery level in dmesg or logcat";
+        }
+      }
+    }
+
+    // Is there a controlled shutdown hint in last_reboot_reason_property?
+    if (isBluntRebootReason(ret)) {
+      // Content buffer no longer will have console data. Beware if more
+      // checks added below, that depend on parsing console content.
+      content = GetProperty(last_reboot_reason_property);
+
+      // String is either "reboot,<reason>" or "shutdown,<reason>".
+      // We will set if default reasons, only override with detail if thermal.
+      if (!isBluntRebootReason(content)) {
+        // Ok, we want it, let's squash it if secondReason is known.
+        pos = content.find(',');
+        if (pos != std::string::npos) {
+          ++pos;
+          std::string secondReason(content.substr(pos));
+          ret = isKnownRebootReason(secondReason) ? secondReason : content;
+        } else {
+          ret = content;
+        }
+      }
+    }
+
+    // Other System Health HAL reasons?
+
+    // ToDo: /proc/sys/kernel/boot_reason needs a HAL interface to
+    //       possibly offer hardware-specific clues from the PMIC.
+  }
+
+  // If unknown left over from above, make it "reboot,<boot_reason>"
+  if (ret == "") {
+    ret = "reboot";
+    if (android::base::StartsWith(reason, "reboot")) {
+      reason = reason.substr(strlen("reboot"));
+      while (reason[0] == ',') {
+        reason = reason.substr(1);
+      }
+    }
+    if (reason != "") {
+      ret += ",";
+      ret += reason;
+    }
+  }
+
+  LOG(INFO) << "Canonical boot reason: " << ret;
+  if (isKernelRebootReason(ret) && (GetProperty(last_reboot_reason_property) != "")) {
+    // Rewrite as it must be old news, kernel reasons trump user space.
+    SetProperty(last_reboot_reason_property, ret);
+  }
+  return ret;
+}
+
 // Returns the appropriate metric key prefix for the boot_complete metric such
 // that boot metrics after a system update are labeled as ota_boot_complete;
 // otherwise, they are labeled as boot_complete.  This method encapsulates the
@@ -212,9 +557,19 @@
   if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) {
     boot_complete_prefix = "factory_reset_" + boot_complete_prefix;
     boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
+    LOG(INFO) << "Canonical boot reason: " << "reboot,factory_reset";
+    SetProperty(system_reboot_reason_property, "reboot,factory_reset");
+    if (GetProperty(bootloader_reboot_reason_property) == "") {
+      SetProperty(bootloader_reboot_reason_property, "reboot,factory_reset");
+    }
   } else if (build_date != record.second) {
     boot_complete_prefix = "ota_" + boot_complete_prefix;
     boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
+    LOG(INFO) << "Canonical boot reason: " << "reboot,ota";
+    SetProperty(system_reboot_reason_property, "reboot,ota");
+    if (GetProperty(bootloader_reboot_reason_property) == "") {
+      SetProperty(bootloader_reboot_reason_property, "reboot,ota");
+    }
   }
 
   return boot_complete_prefix;
@@ -358,9 +713,23 @@
 // Records the boot_reason metric by querying the ro.boot.bootreason system
 // property.
 void RecordBootReason() {
-  int32_t boot_reason = BootReasonStrToEnum(GetProperty("ro.boot.bootreason"));
+  const std::string reason(GetProperty(bootloader_reboot_reason_property));
+
+  // Log the raw bootloader_boot_reason property value.
+  int32_t boot_reason = BootReasonStrToEnum(reason);
   BootEventRecordStore boot_event_store;
   boot_event_store.AddBootEventWithValue("boot_reason", boot_reason);
+
+  // Log the scrubbed system_boot_reason.
+  const std::string system_reason(BootReasonStrToReason(reason));
+  int32_t system_boot_reason = BootReasonStrToEnum(system_reason);
+  boot_event_store.AddBootEventWithValue("system_boot_reason", system_boot_reason);
+
+  // Record the scrubbed system_boot_reason to the property
+  SetProperty(system_reboot_reason_property, system_reason);
+  if (reason == "") {
+    SetProperty(bootloader_reboot_reason_property, system_reason);
+  }
 }
 
 // Records two metrics related to the user resetting a device: the time at
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index d697efb..410b854 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -1,5 +1,9 @@
 # This file is the LOCAL_INIT_RC file for the bootstat command.
 
+# mirror bootloader boot reason to system boot reason
+on property:ro.boot.bootreason=*
+    setprop sys.boot.reason ${ro.boot.bootreason}
+
 on post-fs-data
     mkdir /data/misc/bootstat 0700 system log
     # To deal with ota transition resulting from a change in DAC from
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index dfc74fb..6ef3ed6 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -462,14 +462,14 @@
   if (wait_for_gdb) {
     // 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);
+        "***********************************************************\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, target);
   }
 
   if (fatal_signal) {
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 50d19bd..f5ecf48 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -800,10 +800,22 @@
   dump_abort_message(backtrace.get(), &log, abort_msg_address);
   dump_registers(&log, ucontext);
 
-  // TODO: Dump registers from the ucontext.
   if (backtrace->Unwind(0, ucontext)) {
     dump_backtrace_and_stack(backtrace.get(), &log);
   } else {
     ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
   }
+
+  // TODO: Make this match the format of dump_all_maps above.
+  _LOG(&log, logtype::MAPS, "memory map:\n");
+  android::base::unique_fd maps_fd(open("/proc/self/maps", O_RDONLY | O_CLOEXEC));
+  if (maps_fd == -1) {
+    _LOG(&log, logtype::MAPS, "    failed to open /proc/self/maps: %s", strerror(errno));
+  } else {
+    char buf[256];
+    ssize_t rc;
+    while ((rc = TEMP_FAILURE_RETRY(read(maps_fd.get(), buf, sizeof(buf)))) > 0) {
+      android::base::WriteFully(tombstone_fd, buf, rc);
+    }
+  }
 }
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 93c7fb5..1bf8f14 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -389,8 +389,9 @@
 
   intercept_manager = new InterceptManager(base, intercept_socket);
 
-  evconnlistener* tombstone_listener = evconnlistener_new(
-      base, crash_accept_cb, CrashQueue::for_tombstones(), -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
+  evconnlistener* tombstone_listener =
+      evconnlistener_new(base, crash_accept_cb, CrashQueue::for_tombstones(), LEV_OPT_CLOSE_ON_FREE,
+                         -1 /* backlog */, crash_socket);
   if (!tombstone_listener) {
     LOG(FATAL) << "failed to create evconnlistener for tombstones.";
   }
@@ -402,8 +403,9 @@
     }
 
     evutil_make_socket_nonblocking(java_trace_socket);
-    evconnlistener* java_trace_listener = evconnlistener_new(
-        base, crash_accept_cb, CrashQueue::for_anrs(), -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket);
+    evconnlistener* java_trace_listener =
+        evconnlistener_new(base, crash_accept_cb, CrashQueue::for_anrs(), LEV_OPT_CLOSE_ON_FREE,
+                           -1 /* backlog */, java_trace_socket);
     if (!java_trace_listener) {
       LOG(FATAL) << "failed to create evconnlistener for java traces.";
     }
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 608917a..7fd67c2 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -37,7 +37,6 @@
         "fs_mgr_avb_ops.cpp",
     ],
     static_libs: [
-        "liblogwrap",
         "libfec",
         "libfec_rs",
         "libbase",
@@ -53,6 +52,7 @@
         "libfstab",
     ],
     whole_static_libs: [
+        "liblogwrap",
         "libfstab",
     ],
     product_variables: {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 18ccc43..007189d 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -20,6 +20,7 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_MODULE:= fs_mgr
 LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := mke2fs mke2fs.conf e2fsdroid
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index a03d92c..75feee7 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -24,25 +24,21 @@
 #include <cutils/partition_utils.h>
 #include <sys/mount.h>
 
-#include <ext4_utils/ext4_utils.h>
 #include <ext4_utils/ext4.h>
-#include <ext4_utils/make_ext4fs.h>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
+#include <ext4_utils/ext4_utils.h>
+#include <logwrap/logwrap.h>
 #include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
 
 #include "fs_mgr_priv.h"
 #include "cryptfs.h"
 
-extern "C" {
-extern struct fs_info info;     /* magic global from ext4_utils */
-extern void reset_ext4fs_info();
-}
-
 static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
 {
     uint64_t dev_sz;
     int fd, rc = 0;
+    int status;
 
     if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
         PERROR << "Cannot open block device";
@@ -55,30 +51,36 @@
         return -1;
     }
 
-    struct selabel_handle *sehandle = selinux_android_file_context_handle();
-    if (!sehandle) {
-        /* libselinux logs specific error */
-        LERROR << "Cannot initialize android file_contexts";
-        close(fd);
-        return -1;
-    }
-
-    /* Format the partition using the calculated length */
-    reset_ext4fs_info();
-    info.len = (off64_t)dev_sz;
-    if (crypt_footer) {
-        info.len -= CRYPT_FOOTER_OFFSET;
-    }
-
-    /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
-    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 0, 0, NULL, NULL, NULL);
-    if (rc) {
-        LERROR << "make_ext4fs returned " << rc;
-    }
     close(fd);
 
-    if (sehandle) {
-        selabel_close(sehandle);
+    /* Format the partition using the calculated length */
+    if (crypt_footer) {
+        dev_sz -= CRYPT_FOOTER_OFFSET;
+    }
+
+    std::string size_str = std::to_string(dev_sz / 4096);
+    const char* const mke2fs_args[] = {
+        "/system/bin/mke2fs", "-t", "ext4", "-b", "4096", fs_blkdev, size_str.c_str(), nullptr};
+
+    rc = android_fork_execvp_ext(arraysize(mke2fs_args), const_cast<char**>(mke2fs_args), &status,
+                                 true, LOG_KLOG, true, nullptr, nullptr, 0);
+    if (rc) {
+        LERROR << "mke2fs returned " << rc;
+        return rc;
+    }
+
+    const char* const e2fsdroid_args[] = {
+        "/system/bin/e2fsdroid",
+        "-e",
+        "-a",
+        fs_mnt_point,
+        fs_blkdev,
+        nullptr};
+
+    rc = android_fork_execvp_ext(arraysize(e2fsdroid_args), const_cast<char**>(e2fsdroid_args),
+                                 &status, true, LOG_KLOG, true, nullptr, nullptr, 0);
+    if (rc) {
+        LERROR << "e2fsdroid returned " << rc;
     }
 
     return rc;
@@ -86,44 +88,11 @@
 
 static int format_f2fs(char *fs_blkdev)
 {
-    char * args[5];
-    int pid;
-    int rc = 0;
+    int status;
+    const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
 
-    args[0] = (char *)"/system/bin/make_f2fs";
-    args[1] = (char *)"-f";
-    args[2] = (char *)"-O encrypt";
-    args[3] = fs_blkdev;
-    args[4] = (char *)0;
-
-    pid = fork();
-    if (pid < 0) {
-       return pid;
-    }
-    if (!pid) {
-        /* This doesn't return */
-        execv(args[0], args);
-        exit(1);
-    }
-    for(;;) {
-        pid_t p = waitpid(pid, &rc, 0);
-        if (p != pid) {
-            LERROR << "Error waiting for child process - " << p;
-            rc = -1;
-            break;
-        }
-        if (WIFEXITED(rc)) {
-            rc = WEXITSTATUS(rc);
-            LINFO << args[0] << " done, status " << rc;
-            if (rc) {
-                rc = -1;
-            }
-            break;
-        }
-        LERROR << "Still waiting for " << args[0] << "...";
-    }
-
-    return rc;
+    return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), &status, true,
+                                   LOG_KLOG, true, nullptr, nullptr, 0);
 }
 
 int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index 92d1752..2f4f4d7 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -27,10 +27,10 @@
 
 #include <android-base/memory.h>
 #include <gatekeeper/gatekeeper.h>
-#include <nativehelper/UniquePtr.h>
 
 #include <iostream>
 #include <unordered_map>
+#include <memory>
 
 namespace gatekeeper {
 
@@ -173,7 +173,7 @@
     typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
     typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
 
-    UniquePtr<uint8_t[]> key_;
+    std::unique_ptr<uint8_t[]> key_;
     FailureRecordMap failure_map_;
     FastHashMap fast_hash_map_;
 };
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
index 229f9a9..e3dc068 100644
--- a/gatekeeperd/SoftGateKeeperDevice.h
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -19,7 +19,7 @@
 
 #include "SoftGateKeeper.h"
 
-#include <nativehelper/UniquePtr.h>
+#include <memory>
 
 using namespace gatekeeper;
 
@@ -68,7 +68,7 @@
             const uint8_t *provided_password, uint32_t provided_password_length,
             uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
 private:
-    UniquePtr<SoftGateKeeper> impl_;
+    std::unique_ptr<SoftGateKeeper> impl_;
 };
 
 } // namespace gatekeeper
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index e6eb3bc..73dab9b 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -23,6 +23,7 @@
 #include <inttypes.h>
 #include <stdint.h>
 #include <unistd.h>
+#include <memory>
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -375,7 +376,7 @@
 
 private:
     sp<IGatekeeper> hw_device;
-    UniquePtr<SoftGateKeeperDevice> soft_device;
+    std::unique_ptr<SoftGateKeeperDevice> soft_device;
 };
 }// namespace android
 
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
index b3aea7b..100375f 100644
--- a/gatekeeperd/tests/gatekeeper_test.cpp
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -19,7 +19,6 @@
 
 #include <gtest/gtest.h>
 #include <hardware/hw_auth_token.h>
-#include <nativehelper/UniquePtr.h>
 
 #include "../SoftGateKeeper.h"
 
diff --git a/init/Android.bp b/init/Android.bp
index 8737def..672942e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -119,7 +119,7 @@
         "init_first_stage.cpp",
         "keychords.cpp",
         "reboot.cpp",
-        "signal_handler.cpp",
+        "sigchld_handler.cpp",
         "ueventd.cpp",
         "watchdogd.cpp",
     ],
diff --git a/init/Android.mk b/init/Android.mk
index 23ada73..6c28517 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -48,7 +48,7 @@
     init_first_stage.cpp \
     keychords.cpp \
     reboot.cpp \
-    signal_handler.cpp \
+    sigchld_handler.cpp \
     ueventd.cpp \
     watchdogd.cpp \
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 140ef75..5f359cf 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -66,7 +66,6 @@
 #include "reboot.h"
 #include "rlimit_parser.h"
 #include "service.h"
-#include "signal_handler.h"
 #include "util.h"
 
 using namespace std::literals::string_literals;
@@ -268,7 +267,7 @@
                 "--prompt_and_wipe_data",
                 "--reason=set_policy_failed:"s + args[1]};
             reboot_into_recovery(options);
-            return Error() << "reboot into recovery failed";
+            return Success();
         }
     }
     return Success();
@@ -473,7 +472,7 @@
         PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
         const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
         reboot_into_recovery(options);
-        return Error() << "reboot_into_recovery() failed";
+        return Success();
         /* If reboot worked, there is no return. */
     } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
         if (e4crypt_install_keyring()) {
diff --git a/init/init.cpp b/init/init.cpp
index 678f49f..817b33e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <sys/epoll.h>
 #include <sys/mount.h>
+#include <sys/signalfd.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -51,7 +52,7 @@
 #include "reboot.h"
 #include "security.h"
 #include "selinux.h"
-#include "signal_handler.h"
+#include "sigchld_handler.h"
 #include "ueventd.h"
 #include "util.h"
 #include "watchdogd.h"
@@ -72,11 +73,14 @@
 std::string default_console = "/dev/console";
 
 static int epoll_fd = -1;
+static int sigterm_signal_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
 static std::string wait_prop_name;
 static std::string wait_prop_value;
 static bool shutting_down;
+static std::string shutdown_command;
+static bool do_shutdown = false;
 
 std::vector<std::string> late_import_paths;
 
@@ -155,9 +159,16 @@
     // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
     // commands to be executed.
     if (name == "sys.powerctl") {
-        if (HandlePowerctlMessage(value)) {
-            shutting_down = true;
-        }
+        // Despite the above comment, we can't call HandlePowerctlMessage() in this function,
+        // because it modifies the contents of the action queue, which can cause the action queue
+        // to get into a bad state if this function is called from a command being executed by the
+        // action queue.  Instead we set this flag and ensure that shutdown happens before the next
+        // command is run in the main init loop.
+        // TODO: once property service is removed from init, this will never happen from a builtin,
+        // but rather from a callback from the property service socket, in which case this hack can
+        // go away.
+        shutdown_command = value;
+        do_shutdown = true;
     }
 
     if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
@@ -392,6 +403,41 @@
     sigaction(SIGTRAP, &action, nullptr);
 }
 
+static void HandleSigtermSignal() {
+    signalfd_siginfo siginfo;
+    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo)));
+    if (bytes_read != sizeof(siginfo)) {
+        PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd";
+        return;
+    }
+
+    if (siginfo.ssi_pid != 0) {
+        // Drop any userspace SIGTERM requests.
+        LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid;
+        return;
+    }
+
+    LOG(INFO) << "Handling SIGTERM, shutting system down";
+    HandlePowerctlMessage("shutdown");
+}
+
+static void InstallSigtermHandler() {
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGTERM);
+
+    if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
+        PLOG(FATAL) << "failed to block SIGTERM";
+    }
+
+    sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+    if (sigterm_signal_fd == -1) {
+        PLOG(FATAL) << "failed to create signalfd for SIGTERM";
+    }
+
+    register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal);
+}
+
 int main(int argc, char** argv) {
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
@@ -527,7 +573,13 @@
         exit(1);
     }
 
-    signal_handler_init();
+    sigchld_handler_init();
+
+    if (!IsRebootCapable()) {
+        // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
+        // In that case, receiving SIGTERM will cause the system to shut down.
+        InstallSigtermHandler();
+    }
 
     property_load_boot_defaults();
     export_oem_lock_status();
@@ -579,6 +631,13 @@
         // By default, sleep until something happens.
         int epoll_timeout_ms = -1;
 
+        if (do_shutdown && !shutting_down) {
+            do_shutdown = false;
+            if (HandlePowerctlMessage(shutdown_command)) {
+                shutting_down = true;
+            }
+        }
+
         if (!(waiting_for_prop || Service::is_exec_service_running())) {
             am.ExecuteOneCommand();
         }
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 891ca03..049c952 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -54,7 +54,7 @@
 #include "init.h"
 #include "property_service.h"
 #include "service.h"
-#include "signal_handler.h"
+#include "sigchld_handler.h"
 
 using android::base::StringPrintf;
 using android::base::Timer;
@@ -169,9 +169,7 @@
                  << stat;
 }
 
-// Determines whether the system is capable of rebooting. This is conservative,
-// so if any of the attempts to determine this fail, it will still return true.
-static bool IsRebootCapable() {
+bool IsRebootCapable() {
     if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
         PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
         return true;
diff --git a/init/reboot.h b/init/reboot.h
index ece407f..1c58bd1 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -38,6 +38,10 @@
 // Parses and handles a setprop sys.powerctl message.
 bool HandlePowerctlMessage(const std::string& command);
 
+// Determines whether the system is capable of rebooting. This is conservative,
+// so if any of the attempts to determine this fail, it will still return true.
+bool IsRebootCapable();
+
 }  // namespace init
 }  // namespace android
 
diff --git a/init/result.h b/init/result.h
index 36c3b83..fc03962 100644
--- a/init/result.h
+++ b/init/result.h
@@ -153,8 +153,14 @@
 template <typename T>
 class Result {
   public:
-    template <typename... U>
-    Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {}
+    Result() {}
+
+    template <typename U, typename... V,
+              typename = std::enable_if_t<!(std::is_same_v<std::decay_t<U>, Result<T>> &&
+                                            sizeof...(V) == 0)>>
+    Result(U&& result, V&&... results)
+        : contents_(std::in_place_index_t<0>(), std::forward<U>(result),
+                    std::forward<V>(results)...) {}
 
     Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {}
     Result(const ResultError& result_error)
diff --git a/init/result_test.cpp b/init/result_test.cpp
index 19caaf5..327b444 100644
--- a/init/result_test.cpp
+++ b/init/result_test.cpp
@@ -276,6 +276,49 @@
     EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
 }
 
+// Below two tests require that we do not hide the move constructor with our forwarding reference
+// constructor.  This is done with by disabling the forwarding reference constructor if its first
+// and only type is Result<T>.
+TEST(result, result_result_with_success) {
+    auto return_result_result_with_success = []() -> Result<Result<Success>> {
+        return Result<Success>();
+    };
+    auto result = return_result_result_with_success();
+    ASSERT_TRUE(result);
+    ASSERT_TRUE(*result);
+
+    auto inner_result = result.value();
+    ASSERT_TRUE(inner_result);
+}
+
+TEST(result, result_result_with_failure) {
+    auto return_result_result_with_error = []() -> Result<Result<Success>> {
+        return Result<Success>(ResultError("failure string", 6));
+    };
+    auto result = return_result_result_with_error();
+    ASSERT_TRUE(result);
+    ASSERT_FALSE(*result);
+    EXPECT_EQ("failure string", result->error_string());
+    EXPECT_EQ(6, result->error_errno());
+}
+
+// This test requires that we disable the forwarding reference constructor if Result<T> is the
+// *only* type that we are forwarding.  In otherwords, if we are forwarding Result<T>, int to
+// construct a Result<T>, then we still need the constructor.
+TEST(result, result_two_parameter_constructor_same_type) {
+    struct TestStruct {
+        TestStruct(int value) : value_(value) {}
+        TestStruct(Result<TestStruct> result, int value) : value_(result->value_ * value) {}
+        int value_;
+    };
+
+    auto return_test_struct = []() -> Result<TestStruct> { return {Result<TestStruct>(6), 6}; };
+
+    auto result = return_test_struct();
+    ASSERT_TRUE(result);
+    EXPECT_EQ(36, result->value_);
+}
+
 TEST(result, die_on_access_failed_result) {
     Result<std::string> result = Error();
     ASSERT_DEATH(*result, "");
diff --git a/init/service.cpp b/init/service.cpp
index 6f27a4b..86b910a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -135,17 +135,21 @@
     }
 }
 
-static void ExpandArgs(const std::vector<std::string>& args, std::vector<char*>* strs) {
+static bool ExpandArgsAndExecv(const std::vector<std::string>& args) {
     std::vector<std::string> expanded_args;
+    std::vector<char*> c_strings;
+
     expanded_args.resize(args.size());
-    strs->push_back(const_cast<char*>(args[0].c_str()));
+    c_strings.push_back(const_cast<char*>(args[0].data()));
     for (std::size_t i = 1; i < args.size(); ++i) {
         if (!expand_props(args[i], &expanded_args[i])) {
             LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'";
         }
-        strs->push_back(const_cast<char*>(expanded_args[i].c_str()));
+        c_strings.push_back(expanded_args[i].data());
     }
-    strs->push_back(nullptr);
+    c_strings.push_back(nullptr);
+
+    return execv(c_strings[0], c_strings.data()) == 0;
 }
 
 unsigned long Service::next_start_order_ = 1;
@@ -785,10 +789,8 @@
         // priority. Aborts on failure.
         SetProcessAttributes();
 
-        std::vector<char*> strs;
-        ExpandArgs(args_, &strs);
-        if (execv(strs[0], (char**)&strs[0]) < 0) {
-            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
+        if (!ExpandArgsAndExecv(args_)) {
+            PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
         }
 
         _exit(127);
diff --git a/init/signal_handler.cpp b/init/sigchld_handler.cpp
similarity index 98%
rename from init/signal_handler.cpp
rename to init/sigchld_handler.cpp
index 9e49c48..8fc9956 100644
--- a/init/signal_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "signal_handler.h"
+#include "sigchld_handler.h"
 
 #include <signal.h>
 #include <string.h>
@@ -115,7 +115,7 @@
     }
 }
 
-void signal_handler_init() {
+void sigchld_handler_init() {
     // Create a signalling mechanism for SIGCHLD.
     int s[2];
     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
diff --git a/init/signal_handler.h b/init/sigchld_handler.h
similarity index 88%
rename from init/signal_handler.h
rename to init/sigchld_handler.h
index 9362be5..c86dc8d 100644
--- a/init/signal_handler.h
+++ b/init/sigchld_handler.h
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_SIGNAL_HANDLER_H_
-#define _INIT_SIGNAL_HANDLER_H_
+#ifndef _INIT_SIGCHLD_HANDLER_H_
+#define _INIT_SIGCHLD_HANDLER_H_
 
 namespace android {
 namespace init {
 
 void ReapAnyOutstandingChildren();
 
-void signal_handler_init(void);
+void sigchld_handler_init(void);
 
 }  // namespace init
 }  // namespace android
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index 4a5f2a7..47de12a 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -17,6 +17,9 @@
 cc_library {
     name: "libcrypto_utils",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     host_supported: true,
     srcs: [
         "android_pubkey.c",
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index a1dbd78..1185040 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -175,6 +175,8 @@
                                            CAP_MASK_LONG(CAP_AUDIT_CONTROL) |
                                            CAP_MASK_LONG(CAP_SETGID),
                                               "system/bin/logd" },
+    { 00550, AID_SYSTEM,    AID_LOG,      CAP_MASK_LONG(CAP_SYSLOG),
+                                              "system/bin/bootstat" },
     { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) |
                                            CAP_MASK_LONG(CAP_SETGID),
                                               "system/bin/run-as" },
diff --git a/libdiskconfig/Android.bp b/libdiskconfig/Android.bp
index 088981a..23a5c79 100644
--- a/libdiskconfig/Android.bp
+++ b/libdiskconfig/Android.bp
@@ -1,6 +1,9 @@
 cc_library {
     name: "libdiskconfig",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     srcs: [
         "diskconfig.c",
         "diskutils.c",
diff --git a/liblog/Android.bp b/liblog/Android.bp
index e74aa82..b98d18f 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -42,6 +42,24 @@
     "logd_writer.c",
 ]
 
+cc_library_headers {
+    name: "liblog_headers",
+    host_supported: true,
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+        vendor: {
+            export_include_dirs: ["include_vndk"],
+        },
+    },
+}
+
 // Shared and static library for host and device
 // ========================================================
 cc_library {
@@ -81,7 +99,8 @@
         },
     },
 
-    export_include_dirs: ["include"],
+    header_libs: ["liblog_headers"],
+    export_header_lib_headers: ["liblog_headers"],
 
     cflags: [
         "-Werror",
@@ -100,7 +119,7 @@
 }
 
 ndk_headers {
-    name: "liblog_headers",
+    name: "liblog_ndk_headers",
     from: "include/android",
     to: "android",
     srcs: ["include/android/log.h"],
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 5a3f04c..339a06d 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -18,10 +18,9 @@
 #define _LIBS_LOG_LOG_MAIN_H
 
 #include <android/log.h>
+#include <sys/cdefs.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
 /*
  * Normally we strip the effects of ALOGV (VERBOSE messages),
@@ -385,8 +384,6 @@
 #pragma clang diagnostic pop
 #endif
 
-#ifdef __cplusplus
-}
-#endif
+__END_DECLS
 
 #endif /* _LIBS_LOG_LOG_MAIN_H */
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 68c580a..0955633 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -2,6 +2,10 @@
 
 cc_library_shared {
     name: "libmemtrack",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     srcs: ["memtrack.cpp"],
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
diff --git a/libmemunreachable/tests/DisableMalloc_test.cpp b/libmemunreachable/tests/DisableMalloc_test.cpp
index c630049..f446719 100644
--- a/libmemunreachable/tests/DisableMalloc_test.cpp
+++ b/libmemunreachable/tests/DisableMalloc_test.cpp
@@ -73,15 +73,18 @@
 TEST_F(DisableMallocTest, deadlock_new) {
   ASSERT_DEATH(
       {
-        char* ptr = new (char);
+        // C++ allows `new Foo` to be replaced with a stack allocation or merged
+        // with future `new Foo` expressions, provided certain conditions are
+        // met [expr.new/10]. None of this applies to `operator new(size_t)`.
+        void* ptr = ::operator new(1);
         ASSERT_NE(ptr, nullptr);
-        delete (ptr);
+        ::operator delete(ptr);
         {
           alarm(100ms);
           ScopedDisableMalloc disable_malloc;
-          char* ptr = new (std::nothrow)(char);
+          void* ptr = ::operator new(1);
           ASSERT_NE(ptr, nullptr);
-          delete (ptr);
+          ::operator delete(ptr);
         }
       },
       "");
@@ -90,14 +93,12 @@
 TEST_F(DisableMallocTest, deadlock_delete) {
   ASSERT_DEATH(
       {
-        char* ptr = new (char);
+        void* ptr = ::operator new(1);
         ASSERT_NE(ptr, nullptr);
         {
           alarm(250ms);
           ScopedDisableMalloc disable_malloc;
-          delete (ptr);
-          // Force ptr usage or this code gets optimized away by the arm64 compiler.
-          ASSERT_NE(ptr, nullptr);
+          ::operator delete(ptr);
         }
       },
       "");
diff --git a/libnetutils/Android.bp b/libnetutils/Android.bp
index 9967ef8..1d43775 100644
--- a/libnetutils/Android.bp
+++ b/libnetutils/Android.bp
@@ -1,6 +1,9 @@
 cc_library_shared {
     name: "libnetutils",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: [
         "dhcpclient.c",
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index aedaa38..b568ee5 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -23,6 +23,9 @@
 cc_library {
     name: "libprocinfo",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     host_supported: true,
     srcs: [
         "process.cpp",
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
index 130800e..32f1e1f 100644
--- a/libsuspend/Android.bp
+++ b/libsuspend/Android.bp
@@ -3,6 +3,9 @@
 cc_library {
     name: "libsuspend",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: [
         "autosuspend.c",
diff --git a/libsync/Android.bp b/libsync/Android.bp
index 1646348..3fae5e6 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -22,10 +22,15 @@
 
 cc_library_shared {
     name: "libsync",
-    vendor_available: true,
     defaults: ["libsync_defaults"],
 }
 
+llndk_library {
+    name: "libsync",
+    symbol_file: "libsync.map.txt",
+    export_include_dirs: ["include"],
+}
+
 // libsync_recovery is only intended for the recovery binary.
 // Future versions of the kernel WILL require an updated libsync, and will break
 // anything statically linked against the current libsync.
diff --git a/libsync/libsync.map.txt b/libsync/libsync.map.txt
index daa28ae..53bb07a 100644
--- a/libsync/libsync.map.txt
+++ b/libsync/libsync.map.txt
@@ -17,16 +17,12 @@
 LIBSYNC {
   global:
     sync_merge; # introduced=26
-    sync_get_fence_info; # introduced=26
-    sync_free_fence_info; # introduced=26
+    sync_file_info; # introduced=26
+    sync_file_info_free; # introduced=26
+    sync_wait; # vndk
+    sync_fence_info; # vndk
+    sync_pt_info; # vndk
+    sync_fence_info_free; # vndk
   local:
     *;
 };
-
-LIBSYNC_PLATFORM {
-  global:
-    sync_wait;
-    sync_fence_info;
-    sync_pt_info;
-    sync_fence_info_free;
-} LIBSYNC_PLATFORM;
diff --git a/libsync/sync.c b/libsync/sync.c
index baeccda..e657658 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -275,7 +275,6 @@
     info = calloc(1, sizeof(struct sync_file_info) +
                      num_fences * sizeof(struct sync_fence_info));
     if (!info) {
-        free(legacy_info);
         return NULL;
     }
     info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index 550ef42..d076a1a 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -1,6 +1,9 @@
 cc_library_shared {
     name: "libsysutils",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: [
         "src/SocketListener.cpp",
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index f8965b2..a66d0c5 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -22,7 +22,6 @@
 #include <sys/mman.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
-#include <time.h>
 #include <unistd.h>
 
 #include <vector>
@@ -34,32 +33,18 @@
 #include <unwindstack/Memory.h>
 
 #include "MemoryFake.h"
+#include "TestUtils.h"
 
 namespace unwindstack {
 
 class MemoryRemoteTest : public ::testing::Test {
  protected:
-  static uint64_t NanoTime() {
-    struct timespec t = { 0, 0 };
-    clock_gettime(CLOCK_MONOTONIC, &t);
-    return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
-  }
-
   static bool Attach(pid_t pid) {
     if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
       return false;
     }
 
-    uint64_t start = NanoTime();
-    siginfo_t si;
-    while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) {
-      if ((NanoTime() - start) > 10 * NS_PER_SEC) {
-        printf("%d: Failed to stop after 10 seconds.\n", pid);
-        return false;
-      }
-      usleep(30);
-    }
-    return true;
+    return TestQuiescePid(pid);
   }
 
   static bool Detach(pid_t pid) {
@@ -79,6 +64,7 @@
     exit(1);
   }
   ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
 
   ASSERT_TRUE(Attach(pid));
 
@@ -91,9 +77,6 @@
   }
 
   ASSERT_TRUE(Detach(pid));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_fail) {
@@ -111,6 +94,7 @@
     exit(1);
   }
   ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
 
   ASSERT_TRUE(Attach(pid));
 
@@ -132,9 +116,6 @@
   ASSERT_EQ(0, munmap(src, pagesize));
 
   ASSERT_TRUE(Detach(pid));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_overflow) {
@@ -152,6 +133,7 @@
     exit(1);
   }
   ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
 
   ASSERT_TRUE(Attach(pid));
 
@@ -162,9 +144,6 @@
   ASSERT_FALSE(remote.Read(0, dst.data(), 100));
 
   ASSERT_TRUE(Detach(pid));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
new file mode 100644
index 0000000..8c31aa6
--- /dev/null
+++ b/libunwindstack/tests/TestUtils.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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 _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
+#define _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
+
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+namespace unwindstack {
+
+class TestScopedPidReaper {
+ public:
+  TestScopedPidReaper(pid_t pid) : pid_(pid) {}
+  ~TestScopedPidReaper() {
+    kill(pid_, SIGKILL);
+    waitpid(pid_, nullptr, 0);
+  }
+
+ private:
+  pid_t pid_;
+};
+
+inline bool TestQuiescePid(pid_t pid) {
+  siginfo_t si;
+  bool ready = false;
+  // Wait for up to 5 seconds.
+  for (size_t i = 0; i < 5000; i++) {
+    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+      ready = true;
+      break;
+    }
+    usleep(1000);
+  }
+  return ready;
+}
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index a0c45bd..a4f920a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -15,10 +15,9 @@
  */
 
 #include <errno.h>
-#include <string.h>
-
 #include <signal.h>
 #include <stdint.h>
+#include <string.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 #include <unistd.h>
@@ -39,14 +38,24 @@
 #include <unwindstack/Regs.h>
 #include <unwindstack/RegsGetLocal.h>
 
+#include "TestUtils.h"
+
 namespace unwindstack {
 
-static std::atomic_bool g_ready(false);
-static volatile bool g_ready_for_remote = false;
-static volatile bool g_signal_ready_for_remote = false;
-static std::atomic_bool g_finish(false);
+static std::atomic_bool g_ready;
+static volatile bool g_ready_for_remote;
+static volatile bool g_signal_ready_for_remote;
+static std::atomic_bool g_finish;
 static std::atomic_uintptr_t g_ucontext;
 
+static void ResetGlobals() {
+  g_ready = false;
+  g_ready_for_remote = false;
+  g_signal_ready_for_remote = false;
+  g_finish = false;
+  g_ucontext = 0;
+}
+
 static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
 
 static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
@@ -156,48 +165,52 @@
   MiddleFunction(local);
 }
 
-TEST(UnwindTest, local) {
+class UnwindTest : public ::testing::Test {
+ public:
+  void SetUp() override { ResetGlobals(); }
+};
+
+TEST_F(UnwindTest, local) {
   OuterFunction(true);
 }
 
 void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
   *completed = false;
   // Need to sleep before attempting first ptrace. Without this, on the
-  // host it becomes impossible to attach and ptrace set errno to EPERM.
+  // host it becomes impossible to attach and ptrace sets errno to EPERM.
   usleep(1000);
-  for (size_t i = 0; i < 100; i++) {
-    ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
-    for (size_t j = 0; j < 100; j++) {
-      siginfo_t si;
-      if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
-        MemoryRemote memory(pid);
-        // Read the remote value to see if we are ready.
-        bool value;
-        if (memory.Read(addr, &value, sizeof(value)) && value) {
-          *completed = true;
-          break;
-        }
+  for (size_t i = 0; i < 1000; i++) {
+    if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
+      ASSERT_TRUE(TestQuiescePid(pid))
+          << "Waiting for process to quiesce failed: " << strerror(errno);
+
+      MemoryRemote memory(pid);
+      // Read the remote value to see if we are ready.
+      bool value;
+      if (memory.Read(addr, &value, sizeof(value)) && value) {
+        *completed = true;
       }
-      usleep(1000);
+      if (!*completed || !leave_attached) {
+        ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+      }
+      if (*completed) {
+        break;
+      }
+    } else {
+      ASSERT_EQ(ESRCH, errno) << "ptrace attach failed with unexpected error: " << strerror(errno);
     }
-    if (leave_attached && *completed) {
-      break;
-    }
-    ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-    if (*completed) {
-      break;
-    }
-    usleep(1000);
+    usleep(5000);
   }
 }
 
-TEST(UnwindTest, remote) {
+TEST_F(UnwindTest, remote) {
   pid_t pid;
   if ((pid = fork()) == 0) {
     OuterFunction(false);
     exit(0);
   }
   ASSERT_NE(-1, pid);
+  TestScopedPidReaper reap(pid);
 
   bool completed;
   WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
@@ -210,13 +223,11 @@
 
   VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder);
 
-  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+      << "ptrace detach failed with unexpected error: " << strerror(errno);
 }
 
-TEST(UnwindTest, from_context) {
+TEST_F(UnwindTest, from_context) {
   std::atomic_int tid(0);
   std::thread thread([&]() {
     tid = syscall(__NR_gettid);
@@ -263,10 +274,6 @@
 }
 
 static void RemoteThroughSignal(unsigned int sa_flags) {
-  g_ready = false;
-  g_signal_ready_for_remote = false;
-  g_finish = false;
-
   pid_t pid;
   if ((pid = fork()) == 0) {
     struct sigaction act, oldact;
@@ -279,6 +286,7 @@
     exit(0);
   }
   ASSERT_NE(-1, pid);
+  TestScopedPidReaper reap(pid);
 
   bool completed;
   WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
@@ -294,17 +302,15 @@
 
   VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder);
 
-  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+      << "ptrace detach failed with unexpected error: " << strerror(errno);
 }
 
-TEST(UnwindTest, remote_through_signal) {
+TEST_F(UnwindTest, remote_through_signal) {
   RemoteThroughSignal(0);
 }
 
-TEST(UnwindTest, remote_through_signal_sa_siginfo) {
+TEST_F(UnwindTest, remote_through_signal_sa_siginfo) {
   RemoteThroughSignal(SA_SIGINFO);
 }
 
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp
index a0d6b9b..fc6f305 100644
--- a/libusbhost/Android.bp
+++ b/libusbhost/Android.bp
@@ -16,6 +16,10 @@
 
 cc_library {
     name: "libusbhost",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     host_supported: true,
     srcs: ["usbhost.c"],
     cflags: ["-Werror"],
diff --git a/libutils/Android.bp b/libutils/Android.bp
index adcde81..038fd73 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,10 +18,12 @@
     host_supported: true,
 
     header_libs: [
+        "liblog_headers",
         "libsystem_headers",
         "libcutils_headers"
     ],
     export_header_lib_headers: [
+        "liblog_headers",
         "libsystem_headers",
         "libcutils_headers"
     ],
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 0c20607..ae6d9c8 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -82,9 +82,10 @@
 
     // Accessors
 
-    inline  T&      operator* () const  { return *m_ptr; }
-    inline  T*      operator-> () const { return m_ptr;  }
-    inline  T*      get() const         { return m_ptr; }
+    inline T&       operator* () const     { return *m_ptr; }
+    inline T*       operator-> () const    { return m_ptr;  }
+    inline T*       get() const            { return m_ptr; }
+    inline explicit operator bool () const { return m_ptr != nullptr; }
 
     // Operators
 
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 333835c..f395c74 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -58,6 +58,9 @@
     name: "libziparchive",
     host_supported: true,
     vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     defaults: [
         "libziparchive_defaults",
diff --git a/reboot/reboot.c b/reboot/reboot.c
index 007dfba..f0cf40c 100644
--- a/reboot/reboot.c
+++ b/reboot/reboot.c
@@ -56,6 +56,7 @@
 
     if (argc > optind)
         optarg = argv[optind];
+    if (!optarg || !optarg[0]) optarg = "shell";
 
     prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);
     if (prop_len >= sizeof(property_val)) {
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index 5d10c18..c4e8aac 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -4,20 +4,25 @@
 Since IceCreamSandwich Android has used
 [mksh](https://www.mirbsd.org/mksh.htm) as its shell. Before then it used
 [ash](https://en.wikipedia.org/wiki/Almquist_shell) (which actually
-remained in the tree up to and including KitKat).
+remained unused in the tree up to and including KitKat).
 
-Initially Android had a very limited command-line provided by its
-own "toolbox" binary. These days almost everything is supplied by
+Initially Android had a very limited command-line provided by its own
+"toolbox" binary. Since Marshmallow almost everything is supplied by
 [toybox](http://landley.net/toybox/) instead.
 
 We started moving a few of the more important tools to full
-BSD implementations in JellyBean before we started in earnest in
+BSD implementations in JellyBean, and continued this work in
 Lollipop. Lollipop was a major break with the past in many ways (LP64
 support and the switch to ART both having lots of knock-on effects around
 the system), so although this was the beginning of the end of toolbox it
 (a) didn't stand out given all the other systems-level changes and (b)
 in Marshmallow we changed direction and started the move to toybox.
 
+Not everything is provided by toybox, though. We currently still use
+the BSD dd and grep (because the toybox versions are still unfinished),
+and for the bzip2 command-line tools we use the ones that are part of
+the bzip2 distribution.
+
 The lists below show what tools were provided and where they came from in
 each release starting with Gingerbread. This doesn't tell the full story,
 because the toolbox implementations did have bugs fixed and options added
@@ -25,6 +30,10 @@
 `-f`. But this gives you an idea of what was available in any given release,
 and how usable it was likely to be.
 
+Also note that in any given release `toybox` probably contains more
+commands than there are symlinks for in `/system/bin`. You can get the
+full list for a release by running `toybox` directly.
+
 
 Android 2.3 (Gingerbread)
 -------------------------
@@ -132,26 +141,26 @@
 uptime usleep vmstat wc which whoami xargs xxd yes
 
 
-Current AOSP
-------------
+Android 8.0 (Oreo)
+------------------
 
 BSD: dd grep
 
 bzip2: bzcat bzip2 bunzip2
 
-toolbox: getevent gzip newfs\_msdos gunzip zcat
+toolbox: getevent newfs\_msdos
 
 toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
 chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
 dos2unix du echo env expand expr fallocate false file find flock free
-getenforce getprop groups head hostname hwclock id ifconfig inotifyd
-insmod ionice iorenice kill killall ln load\_policy log logname losetup
-ls lsmod lsof lsusb md5sum microcom mkdir mknod mkswap mktemp modinfo
-modprobe more mount mountpoint mv netstat nice nl nohup od paste patch
-pgrep pidof pkill pmap printenv printf ps pwd readlink realpath renice
-restorecon rm rmdir rmmod runcon sed sendevent seq setenforce setprop
-setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split
-start stat stop strings swapoff swapon sync sysctl tac tail tar taskset
-tee time timeout top touch tr true truncate tty ulimit umount uname uniq
-unix2dos uptime usleep uudecode uuencode vmstat wc which whoami xargs
-xxd yes
+getenforce getprop groups gunzip gzip head hostname hwclock id ifconfig
+inotifyd insmod ionice iorenice kill killall ln load\_policy log logname
+losetup ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod
+mkswap mktemp modinfo modprobe more mount mountpoint mv netstat nice
+nl nohup od paste patch pgrep pidof pkill pmap printenv printf ps pwd
+readlink realpath renice restorecon rm rmdir rmmod runcon sed sendevent
+seq setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum
+sha512sum sleep sort split start stat stop strings swapoff swapon sync
+sysctl tac tail tar taskset tee time timeout top touch tr true truncate
+tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
+vmstat wc which whoami xargs xxd yes zcat