Merge "debuggerd_fallback: print maps."
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/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/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/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..886c572 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;
diff --git a/init/init.cpp b/init/init.cpp
index 678f49f..c3e08fb 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,6 +73,7 @@
 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;
@@ -392,6 +394,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 +564,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();
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/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/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/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/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/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/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/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)) {