Merge "Move some properties users to __system_property_read_callback()"
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index 6734f4d..2c87018 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -65,6 +65,11 @@
     static_libs: ["libbootstat"],
     shared_libs: ["liblogcat"],
     init_rc: ["bootstat.rc"],
+    product_variables: {
+        debuggable: {
+            init_rc: ["bootstat-debug.rc"],
+        },
+    },
     srcs: ["bootstat.cpp"],
 }
 
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index b76011a..7a45e4d 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -22,6 +22,8 @@
 GREEN="${ESCAPE}[38;5;40m"
 RED="${ESCAPE}[38;5;196m"
 NORMAL="${ESCAPE}[0m"
+# Best guess to an average device's reboot time, refined as tests return
+DURATION_DEFAULT=45
 
 # Helper functions
 
@@ -32,6 +34,105 @@
   fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
 }
 
+[ "USAGE: inAdb
+
+Returns: true if device is in adb mode" ]
+inAdb() {
+  adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+}
+
+[ "USAGE: hasPstore
+
+Returns: true if device (likely) has pstore data" ]
+hasPstore() {
+  if inAdb && [ 0 -eq `adb shell su root ls /sys/fs/pstore | wc -l` ]; then
+    false
+  fi
+}
+
+[ "USAGE: isDebuggable
+
+Returns: true if device is (likely) a debug build" ]
+isDebuggable() {
+  if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then
+    false
+  fi
+}
+
+[ "USAGE: checkDebugBuild [--noerror]
+
+Returns: true if device is a userdebug or eng release" ]
+checkDebugBuild() {
+  if isDebuggable; then
+    echo "INFO: '${TEST}' test requires userdebug build"
+  elif [ -n "${1}" ]; then
+    echo "WARNING: '${TEST}' test requires userdebug build"
+    false
+  else
+    echo "ERROR: '${TEST}' test requires userdebug build, skipping FAILURE"
+    false
+  fi >&2
+}
+
+[ "USAGE: setBootloaderBootReason [value]
+
+Returns: true if device supports and set boot reason injection" ]
+setBootloaderBootReason() {
+  inAdb || ( echo "ERROR: device not in adb mode." >&2 ; false ) || return 1
+  if [ -z "`adb shell ls /etc/init/bootstat-debug.rc 2>/dev/null`" ]; then
+    echo "ERROR: '${TEST}' test requires /etc/init/bootstat-debug.rc" >&2
+    return 1
+  fi
+  checkDebugBuild || return 1
+  if adb shell su root "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" |
+     grep '^androidboot[.]bootreason=[^ ]' >/dev/null; then
+    echo "ERROR: '${TEST}' test requires a device with a bootloader that" >&2
+    echo "       does not set androidboot.bootreason kernel parameter." >&2
+    return 1
+  fi
+  adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
+  test_reason="`adb shell getprop persist.test.boot.reason 2>/dev/null`"
+  if [ X"${test_reason}" != X"${1}" ]; then
+    echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
+    return 1
+  fi
+}
+
+[ "USAGE: enterPstore
+
+Prints a warning string requiring functional pstore
+
+Returns: pstore_ok variable set to true or false" ]
+enterPstore() {
+  if hasPstore; then
+    echo "INFO: '${TEST}' test requires functional and reliable pstore"
+    pstore_ok=true
+  else
+    echo "WARNING: '${TEST}' test requires functional pstore"
+    pstore_ok=false
+  fi >&2
+  ${pstore_ok}
+}
+
+[ "USAGE: exitPstore
+
+Prints an error string requiring functional pstore
+
+Returns: clears error if pstore dysfunctional" ]
+exitPstore() {
+  save_ret=${?}
+  if [ ${save_ret} != 0 ]; then
+    if hasPstore; then
+      return ${save_ret}
+    fi
+    if [ true = ${pstore_ok} ]; then
+      echo "WARNING: '${TEST}' test requires functional pstore"
+      return ${save_ret}
+    fi
+    echo "ERROR: '${TEST}' test requires functional pstore, skipping FAILURE"
+  fi >&2
+}
+
 [ "USAGE: format_duration <seconds>
 
 human readable output whole seconds, whole minutes or mm:ss" ]
@@ -77,17 +178,25 @@
   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
+    if inFastboot; then
+      fastboot reboot
+    elif inAdb; then
+      if [ 0 != ${counter} ]; then
+        adb wait-for-device </dev/null >/dev/null 2>/dev/null
+      fi
+      if [ -n "`adb shell getprop sys.boot.reason </dev/null 2>/dev/null`" ]
+      then
+        vals=`adb shell getprop </dev/null 2>/dev/null |
+              sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
+        if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
+        then
+          break
+        fi
+        if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
+        then
+          break
+        fi
+      fi
     fi
     counter=`expr ${counter} + 1`
     if [ ${counter} -gt ${timeout} ]; then
@@ -95,6 +204,7 @@
       echo "ERROR: wait_for_screen() timed out (`format_duration ${timeout}`)" >&2
       return 1
     fi
+    sleep 1
   done
   ${exit_function}
 }
@@ -123,7 +233,7 @@
   return 0
 }
 
-[ "USAGE: EXPECT_PROPERTY <prop> <value>
+[ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
 
 Returns true if current return (regex) value is true and the result matches" ]
 EXPECT_PROPERTY() {
@@ -133,6 +243,7 @@
   shift 2
   val=`adb shell getprop ${property} 2>&1`
   EXPECT_EQ "${value}" "${val}" for Android property ${property} ||
+    [ -n "${1}" ] ||
     save_ret=${?}
   return ${save_ret}
 }
@@ -152,7 +263,7 @@
 report_bootstat_logs() {
   save_ret=${?}
   match=
-  for i in ${*}; do
+  for i in "${@}"; do
     if [ X"${i}" != X"${i#-}" ] ; then
       match="${match}
 ${i#-}"
@@ -172,6 +283,8 @@
 bootstat: Battery level at shutdown 100%
 bootstat: Battery level at startup 100%
 init    : Parsing file /system/etc/init/bootstat.rc...
+init    : processing action (persist.test.boot.reason=*) from (/system/etc/init/bootstat-debug.rc:
+init    : Command 'setprop ro.boot.bootreason \${persist.test.boot.reason}' action=persist.test.boot.reason=* (/system/etc/init/bootstat-debug.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
@@ -198,11 +311,44 @@
 Record start of test, preserve exit status" ]
 start_test() {
   save_ret=${?}
+  duration_prefix="~"
+  duration_estimate=1
   START=`date +%s`
   echo "${GREEN}[ RUN      ]${NORMAL} ${TEST} ${*}"
   return ${save_ret}
 }
 
+duration_sum_diff=0
+duration_num=0
+[ "USAGE: duration_test [[prefix]seconds]
+
+Report the adjusted and expected test duration" ]
+duration_test() {
+  duration_prefix=${1%%[0123456789]*}
+  if [ -z "${duration_prefix}" ]; then
+    duration_prefix="~"
+  fi
+  duration_estimate="${1#${duration_prefix}}"
+  if [ -z "${duration_estimate}" ]; then
+    duration_estimate="${DURATION_DEFAULT}"
+  fi
+  duration_new_estimate="${duration_estimate}"
+  if [ 0 -ne ${duration_num} ]; then
+    duration_new_estimate=`expr ${duration_new_estimate} + \
+      \( ${duration_num} / 2 + ${duration_sum_diff} \) / ${duration_num}`
+    # guard against catastrophe
+    if [ -z "${duration_new_estimate}" ]; then
+      duration_new_estimate=${duration_estimate}
+    fi
+  fi
+  # negative values are so undignified
+  if [ 0 -ge ${duration_new_estimate} ]; then
+    duration_new_estimate=1
+  fi
+  echo "INFO: expected duration of '${TEST}' test" \
+       "${duration_prefix}`format_duration ${duration_new_estimate}`" >&2
+}
+
 [ "USAGE: end_test [message]
 
 Document duration and success of test, preserve exit status" ]
@@ -210,9 +356,16 @@
   save_ret=${?}
   END=`date +%s`
   duration=`expr ${END} - ${START} 2>/dev/null`
-  [ 0 = ${duration} ] ||
-    echo INFO: ${TEST} test duration `format_duration ${duration}` >&2
+  [ 0 -ge ${duration} ] ||
+    echo "INFO: '${TEST}' test duration `format_duration ${duration}`" >&2
   if [ ${save_ret} = 0 ]; then
+    if [ 0 -lt ${duration} -a 0 -lt ${duration_estimate} -a \( \
+           X"~" = X"${duration_prefix}" -o \
+           ${duration_estimate} -gt ${duration} \) ]; then
+      duration_sum_diff=`expr ${duration_sum_diff} + \
+                              ${duration} - ${duration_estimate}`
+      duration_num=`expr ${duration_num} + 1`
+    fi
     echo "${GREEN}[       OK ]${NORMAL} ${TEST} ${*}"
   else
     echo "${RED}[  FAILED  ]${NORMAL} ${TEST} ${*}"
@@ -234,37 +387,33 @@
   end_test ${2}
 }
 
-[ "USAGE: validate_property <property>
+[ "USAGE: validate_reason <value>
 
 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} |
+NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
+validate_reason() {
+  var=`echo -n ${*} |
        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
+    watchdog | watchdog,?* ) ;;
+    kernel_panic | kernel_panic,?*) ;;
+    recovery | recovery,?*) ;;
+    bootloader | bootloader,?*) ;;
+    cold | cold,?*) ;;
+    hard | hard,?*) ;;
+    warm | warm,?*) ;;
+    shutdown | shutdown,?*) ;;
+    reboot,reboot | reboot,reboot,* )     var=${var#reboot,} ; var=${var%,} ;;
+    reboot,cold | reboot,cold,* )         var=${var#reboot,} ; var=${var%,} ;;
+    reboot,hard | reboot,hard,* )         var=${var#reboot,} ; var=${var%,} ;;
+    reboot,warm | reboot,warm,* )         var=${var#reboot,} ; var=${var%,} ;;
+    reboot,recovery | reboot,recovery,* ) var=${var#reboot,} ; var=${var%,} ;;
+    reboot,bootloader | reboot,bootloader,* ) var=${var#reboot,} ; var=${var%,} ;;
+    reboot | reboot,?*) ;;
+    # Aliases and Heuristics
     *wdog* | *watchdog* )     var="watchdog" ;;
     *powerkey* )              var="cold,powerkey" ;;
     *panic* | *kernel_panic*) var="kernel_panic" ;;
@@ -272,12 +421,26 @@
     *s3_wakeup*)              var="warm,s3_wakeup" ;;
     *hw_reset*)               var="hard,hw_reset" ;;
     *bootloader*)             var="bootloader" ;;
-    ?*)                       var="reboot,${var}" ;;
     *)                        var="reboot" ;;
   esac
   echo ${var}
 }
 
+[ "USAGE: validate_property <property>
+
+Check property for CTS compliance with our expectations. Return a cleansed
+string representing what is acceptable.
+
+NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
+validate_property() {
+  val="`adb shell getprop ${1} 2>&1`"
+  ret=`validate_reason "${val}"`
+  if [ "reboot" = "${ret}" ]; then
+    ret=`validate_reason "reboot,${val}"`
+  fi
+  echo ${ret}
+}
+
 #
 # Actual test frames
 #
@@ -291,6 +454,7 @@
 - adb shell getprop sys.boot.reason (system reason)
 - NB: all should have a value that is compliant with our known set." ]
 test_properties() {
+  duration_test 1
   wait_for_screen
   retval=0
   check_set="ro.boot.bootreason persist.sys.boot.reason sys.boot.reason"
@@ -300,7 +464,7 @@
   #  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
+  if [ "reboot,factory_reset" = "`validate_property ro.boot_bootreason`" ]; then
     check_set="ro.boot.bootreason sys.boot.reason"
     bootloader="bootloader"
   fi
@@ -329,7 +493,7 @@
 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
+  duration_test ">300"
   echo "      extended by build and flashing times" >&2
   if [ -z "${TARGET_PRODUCT}" -o \
        -z "${ANDROID_PRODUCT_OUT}" -o \
@@ -361,7 +525,7 @@
   popd >&2
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
-  EXPECT_PROPERTY persist.sys.boot.reason reboot,bootloader
+  EXPECT_PROPERTY persist.sys.boot.reason bootloader
   report_bootstat_logs reboot,ota bootloader
 }
 
@@ -369,8 +533,8 @@
 
 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
-  echo "WARNING: ${TEST} requires userdebug build" >&2
+  checkDebugBuild || return
+  duration_test
   adb shell su root touch /data/misc/bootstat/build_date >&2
   adb reboot ota
   wait_for_screen
@@ -379,27 +543,28 @@
   report_bootstat_logs reboot,ota
 }
 
-[ "USAGE: [TEST=<test>] blind_reboot_test [<match>]
+[ "USAGE: [TEST=<test>] blind_reboot_test
 
 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>
+- NB: should report <test>, or reboot,<test> depending on canonical rules
 
 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
+  duration_test
+  case ${TEST} in
+    bootloader | recovery | cold | hard | warm ) reason=${TEST} ;;
+    *)                                           reason=reboot,${TEST} ;;
+  esac
   adb reboot ${TEST}
   wait_for_screen
-  EXPECT_PROPERTY sys.boot.reason ${1}
-  EXPECT_PROPERTY persist.sys.boot.reason reboot,${TEST}
-  report_bootstat_logs ${1}
+  EXPECT_PROPERTY sys.boot.reason ${reason}
+  EXPECT_PROPERTY persist.sys.boot.reason ${reason}
+  report_bootstat_logs ${reason}
 }
 
 [ "USAGE: test_cold
@@ -425,8 +590,8 @@
 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
-  echo "WARNING: ${TEST} requires userdebug build" >&2
+  checkDebugBuild || return
+  duration_test
   adb shell su root rm /data/misc/bootstat/build_date >&2
   adb reboot >&2
   wait_for_screen
@@ -449,7 +614,7 @@
 
 For realz, and disruptive" ]
 test_optional_factory_reset() {
-  echo "INFO: expected duration of ${TEST} test roughly a minute" >&2
+  duration_test 60
   if ! inFastboot; then
     adb reboot-bootloader
   fi
@@ -502,8 +667,9 @@
 - 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 "WARNING: ${TEST} requires userdebug build" >&2
+  checkDebugBuild || return
+  duration_test 120
+  enterPstore
   # Send it _many_ times to combat devices with flakey pstore
   for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
     echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
@@ -529,8 +695,49 @@
     )
 
   EXPECT_PROPERTY sys.boot.reason shutdown,battery
-  EXPECT_PROPERTY persist.sys.boot.reason reboot,cold
+  EXPECT_PROPERTY persist.sys.boot.reason cold
   report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
+  exitPstore
+}
+
+[ "USAGE: test_optional_battery
+
+battery shutdown test:
+- adb shell setprop sys.powerctl shutdown,battery
+- (power up the device)
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report shutdown,battery" ]
+test_optional_battery() {
+  duration_test ">60"
+  echo "      power on request" >&2
+  adb shell setprop sys.powerctl shutdown,battery
+  sleep 5
+  echo -n "WARNING: Please power device back up, waiting ... " >&2
+  wait_for_screen -n >&2
+  EXPECT_PROPERTY sys.boot.reason shutdown,battery
+  EXPECT_PROPERTY persist.sys.boot.reason shutdown,battery
+  report_bootstat_logs shutdown,battery
+}
+
+[ "USAGE: test_optional_battery_thermal
+
+battery thermal shutdown test:
+- adb shell setprop sys.powerctl shutdown,thermal,battery
+- (power up the device)
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report shutdown,thermal,battery" ]
+test_optional_battery_thermal() {
+  duration_test ">60"
+  echo "      power on request" >&2
+  adb shell setprop sys.powerctl shutdown,thermal,battery
+  sleep 5
+  echo -n "WARNING: Please power device back up, waiting ... " >&2
+  wait_for_screen -n >&2
+  EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery
+  EXPECT_PROPERTY persist.sys.boot.reason shutdown,thermal,battery
+  report_bootstat_logs shutdown,thermal,battery
 }
 
 [ "USAGE: test_unknown
@@ -542,7 +749,7 @@
 - NB: should report reboot,unknown
 - NB: expect log \"... I bootstat: Unknown boot reason: reboot,unknown\"" ]
 test_unknown() {
-  blind_reboot_test reboot,unknown
+  blind_reboot_test
 }
 
 [ "USAGE: test_kernel_panic
@@ -553,13 +760,16 @@
 - 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 "WARNING: ${TEST} requires userdebug build" >&2
+  checkDebugBuild || return
+  duration_test ">90"
+  panic_msg="kernel_panic,sysrq"
+  enterPstore || panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
   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
+  EXPECT_PROPERTY sys.boot.reason ${panic_msg}
+  EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg}
   report_bootstat_logs kernel_panic,sysrq
+  exitPstore
 }
 
 [ "USAGE: test_warm
@@ -582,7 +792,7 @@
 - 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
+  durtion_test ">60"
   echo "      power on request" >&2
   adb shell setprop sys.powerctl shutdown,thermal
   sleep 5
@@ -602,7 +812,7 @@
 - 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
+  duration_test ">60"
   echo "      power on request" >&2
   adb shell setprop sys.powerctl shutdown,userrequested
   sleep 5
@@ -621,7 +831,7 @@
 - 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
+  duration_test
   adb shell reboot
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,shell
@@ -637,7 +847,7 @@
 - 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
+  duration_test
   adb reboot
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,adb
@@ -654,17 +864,109 @@
 - NB: should report reboot,its_just_so_hard
 - NB: expect log \"... I bootstat: Unknown boot reason: reboot,its_just_so_hard\"" ]
 test_Its_Just_So_Hard_reboot() {
-  echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
-  echo "INFO: ${TEST} cleanup requires userdebug build" >&2
+  duration_test
   adb shell 'reboot "Its Just So Hard"'
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
   EXPECT_PROPERTY persist.sys.boot.reason "reboot,Its Just So Hard"
   adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
-  EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard
+  if checkDebugBuild; then
+    flag=""
+  else
+    flag="--allow_failure"
+  fi
+  EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard ${flag}
   report_bootstat_logs reboot,its_just_so_hard
 }
 
+[ "USAGE: run_bootloader [value [expected]]
+
+bootloader boot reason injection tests:
+- setBootloaderBootReason value
+- adb shell reboot
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report reboot,value" ]
+run_bootloader() {
+  bootloader_expected="${1}"
+  if [ -z "${bootloader_expected}" ]; then
+    bootloader_expected="${TEST#bootloader_}"
+  fi
+  if ! setBootloaderBootReason ${bootloader_expected}; then
+    echo "       Skipping FAILURE." 2>&1
+    return
+  fi
+  duration_test
+  if [ X"warm" = X"${bootloader_expected}" ]; then
+    last_expected=cold
+  else
+    last_expected=warm
+  fi
+  adb reboot ${last_expected}
+  wait_for_screen
+  # Reset so that other tests do not get unexpected injection
+  setBootloaderBootReason
+  # Determine the expected values
+  sys_expected="${2}"
+  if [ -z "${sys_expected}" ]; then
+    sys_expected="`validate_reason ${bootloader_expected}`"
+    if [ "reboot" = "${sys_expected}" ]; then
+      sys_expected="${last_expected}"
+    fi
+  else
+    sys_expected=`validate_reason ${sys_expected}`
+  fi
+  case ${sys_expected} in
+    kernel_panic | kernel_panic,* | watchdog | watchdog,* )
+      last_expected=${sys_expected}
+      ;;
+  esac
+  # Check values
+  EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}"
+  EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
+  EXPECT_PROPERTY persist.sys.boot.reason "${last_expected}"
+  report_bootstat_logs "${sys_expected}"
+}
+
+[ "USAGE: test_bootloader_<type>
+
+bootloader boot reasons test injection" ]
+test_bootloader_normal() {
+  run_bootloader
+}
+
+test_bootloader_watchdog() {
+  run_bootloader
+}
+
+test_bootloader_kernel_panic() {
+  run_bootloader
+}
+
+test_bootloader_oem_powerkey() {
+  run_bootloader
+}
+
+test_bootloader_wdog_reset() {
+  run_bootloader
+}
+
+test_bootloader_cold() {
+  run_bootloader
+}
+
+test_bootloader_warm() {
+  run_bootloader
+}
+
+test_bootloader_hard() {
+  run_bootloader
+}
+
+test_bootloader_recovery() {
+  run_bootloader
+}
+
 [ "USAGE: ${0##*/} [-s SERIAL] [tests]
 
 Mainline executive to run the above tests" ]
@@ -715,8 +1017,13 @@
                             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
+    eval set properties ota cold factory_reset hard battery unknown \
+             kernel_panic warm thermal_shutdown userrequested_shutdown \
+             shell_reboot adb_reboot Its_Just_So_Hard_reboot \
+             bootloader_normal bootloader_watchdog bootloader_kernel_panic \
+             bootloader_oem_powerkey bootloader_wdog_reset \
+             bootloader_wdog_reset bootloader_wdog_reset bootloader_hard \
+             bootloader_recovery
   fi
   if [ X"nothing" = X"${1}" ]; then
     shift 1
@@ -724,6 +1031,9 @@
 fi
 echo "INFO: selected test(s): ${@}" >&2
 echo
+# Prepare device
+setBootloaderBootReason 2>/dev/null
+# Start pouring through the tests.
 failures=
 successes=
 for t in "${@}"; do
diff --git a/bootstat/bootstat-debug.rc b/bootstat/bootstat-debug.rc
new file mode 100644
index 0000000..6a00440
--- /dev/null
+++ b/bootstat/bootstat-debug.rc
@@ -0,0 +1,7 @@
+# This file is the userdebug LOCAL_INIT_RC file for the bootstat command.
+
+# FOR TESTING
+# For devices w/o bootloader boot reason reported, mirror test boot reason
+# to bootloader boot reason to allow test to inject reasons
+on property:persist.test.boot.reason=*
+    setprop ro.boot.bootreason ${persist.test.boot.reason}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index d26cf85..f8eaa1c 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -129,6 +129,7 @@
   property_set(key, val);
 }
 
+constexpr int32_t kEmptyBootReason = 0;
 constexpr int32_t kUnknownBootReason = 1;
 
 // A mapping from boot reason string, as read from the ro.boot.bootreason
@@ -136,6 +137,7 @@
 // the boot_reason metric may refer to this mapping to discern the histogram
 // values.
 const std::map<std::string, int32_t> kBootReasonMap = {
+    {"empty", kEmptyBootReason},
     {"unknown", kUnknownBootReason},
     {"normal", 2},
     {"recovery", 3},
@@ -205,6 +207,11 @@
     {"reboot,adb", 67},
     {"reboot,userrequested", 68},
     {"shutdown,container", 69},  // Host OS asking Android Container to shutdown
+    {"cold,powerkey", 70},
+    {"warm,s3_wakeup", 71},
+    {"hard,hw_reset", 72},
+    {"shutdown,suspend", 73},    // Suspend to RAM
+    {"shutdown,hibernate", 74},  // Suspend to DISK
 };
 
 // Converts a string value representing the reason the system booted to an
@@ -216,6 +223,10 @@
     return mapping->second;
   }
 
+  if (boot_reason.empty()) {
+    return kEmptyBootReason;
+  }
+
   LOG(INFO) << "Unknown boot reason: " << boot_reason;
   return kUnknownBootReason;
 }
@@ -233,6 +244,7 @@
     "cold",
     "hard",
     "warm",
+    // super blunt
     "shutdown",    // Can not happen from ro.boot.bootreason
     "reboot",      // Default catch-all for anything unknown
     // clang-format on
@@ -543,19 +555,9 @@
       std::transform(content.begin(), content.end(), content.begin(), tounderline);
       std::transform(content.begin(), content.end(), content.begin(), toprintable);
 
-      // String is either "reboot,<reason>" or "shutdown,<reason>".
-      // We will set if default reasons, only override with detail if thermal.
-      if ((android::base::StartsWith(content, ret.c_str()) && (content[ret.length()] == ',')) ||
-          !isBluntRebootReason(content)) {
-        // Ok, we want it, let's squash it if secondReason is known.
-        size_t pos = content.find(',');
-        if (pos != std::string::npos) {
-          ++pos;
-          std::string secondReason(content.substr(pos));
-          ret = isKnownRebootReason(secondReason) ? secondReason : content;
-        } else {
-          ret = content;
-        }
+      // Anything in last is better than 'super-blunt' reboot or shutdown.
+      if ((ret == "") || (ret == "reboot") || (ret == "shutdown") || !isBluntRebootReason(content)) {
+        ret = content;
       }
     }
 
@@ -611,17 +613,11 @@
     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;
@@ -762,8 +758,16 @@
 // property.
 void RecordBootReason() {
   const std::string reason(GetProperty(bootloader_reboot_reason_property));
-  android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT,
-                                         android::metricslogger::FIELD_PLATFORM_REASON, reason);
+
+  if (reason.empty()) {
+    // Log an empty boot reason value as '<EMPTY>' to ensure the value is intentional
+    // (and not corruption anywhere else in the reporting pipeline).
+    android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT,
+                                           android::metricslogger::FIELD_PLATFORM_REASON, "<EMPTY>");
+  } else {
+    android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT,
+                                           android::metricslogger::FIELD_PLATFORM_REASON, reason);
+  }
 
   // Log the raw bootloader_boot_reason property value.
   int32_t boot_reason = BootReasonStrToEnum(reason);
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index dbf81a4..45e768d 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -19,6 +19,7 @@
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/ptrace.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
 
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index e79dd96..934ceba 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -113,7 +113,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (1 entry):\n"
 #if defined(__LP64__)
 "    12345678'9abcd000-12345678'9abdefff ---         0     12000\n";
 #else
@@ -148,7 +148,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (1 entry):\n"
 #if defined(__LP64__)
 "    12345678'9abcd000-12345678'9abdefff r--         0     12000  /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
 #else
@@ -187,7 +187,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (2 entries):\n"
 #if defined(__LP64__)
 "    12345678'9abcd000-12345678'9abdefff -w-         0     12000\n"
 "    12345678'9abcd000-12345678'9abdefff -w-         0     12000  /system/lib/libfake.so\n";
@@ -245,7 +245,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump =
-      "\nmemory map:\n"
+      "\nmemory map (5 entries):\n"
 #if defined(__LP64__)
       "    00000000'0a234000-00000000'0a234fff ---         0      1000\n"
       "    00000000'0a334000-00000000'0a334fff r--      f000      1000\n"
@@ -305,7 +305,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump =
-      "\nmemory map: (fault address prefixed with --->)\n"
+      "\nmemory map (3 entries):\n"
 #if defined(__LP64__)
       "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
@@ -363,7 +363,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump =
-      "\nmemory map: (fault address prefixed with --->)\n"
+      "\nmemory map (3 entries): (fault address prefixed with --->)\n"
 #if defined(__LP64__)
       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
       "--->Fault address falls at 00000000'0a533000 between mapped regions\n"
@@ -421,7 +421,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump =
-      "\nmemory map: (fault address prefixed with --->)\n"
+      "\nmemory map (3 entries): (fault address prefixed with --->)\n"
 #if defined(__LP64__)
       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
       "--->00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
@@ -481,7 +481,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump =
-      "\nmemory map: (fault address prefixed with --->)\n"
+      "\nmemory map (3 entries): (fault address prefixed with --->)\n"
 #if defined(__LP64__)
       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
       "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
@@ -521,7 +521,7 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump =
-      "\nmemory map:\n"
+      "\nmemory map (1 entry):\n"
 #if defined(__LP64__)
       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n";
 #else
@@ -571,7 +571,7 @@
     }
 
     const char* expected_addr_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+"\nmemory map (1 entry):\n"
 #if defined(__LP64__)
 "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
 "    00000000'0a434000-00000000'0a434fff -w-         0      1000\n";
@@ -580,7 +580,7 @@
 "    0a434000-0a434fff -w-         0      1000\n";
 #endif
     const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (1 entry):\n"
 #if defined(__LP64__)
 "    00000000'0a434000-00000000'0a434fff -w-         0      1000\n";
 #else
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index e455693..6fb29a9 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -414,16 +414,18 @@
   ScopedBacktraceMapIteratorLock lock(map);
   _LOG(log, logtype::MAPS,
        "\n"
-       "memory map (%zu entries):\n",
-       map->size());
+       "memory map (%zu entr%s):",
+       map->size(), map->size() == 1 ? "y" : "ies");
   if (print_fault_address_marker) {
     if (map->begin() != map->end() && addr < map->begin()->start) {
-      _LOG(log, logtype::MAPS, "--->Fault address falls at %s before any mapped regions\n",
+      _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
            get_addr_string(addr).c_str());
       print_fault_address_marker = false;
     } else {
-      _LOG(log, logtype::MAPS, "(fault address prefixed with --->)\n");
+      _LOG(log, logtype::MAPS, " (fault address prefixed with --->)\n");
     }
+  } else {
+    _LOG(log, logtype::MAPS, "\n");
   }
 
   std::string line;
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index f56a9be..c93e2ab 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -428,6 +428,14 @@
   ASSERT_EQ("_ZN3one3twoEDa", demangler.Parse("_ZN3one3twoEDa", 12));
 }
 
+TEST(DemangleTest, BooleanLiterals) {
+  Demangler demangler;
+
+  ASSERT_EQ("one<true>", demangler.Parse("_ZN3oneILb1EEE"));
+  ASSERT_EQ("one<false>", demangler.Parse("_ZN3oneILb0EEE"));
+  ASSERT_EQ("one<false, true>", demangler.Parse("_ZN3oneILb0ELb1EEE"));
+}
+
 TEST(DemangleTest, demangle) {
   std::string str;
 
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index c0a96aa..f148b21 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -660,6 +660,29 @@
   return nullptr;
 }
 
+const char* Demangler::ParseTemplateLiteral(const char* name) {
+  if (*name == 'E') {
+    parse_func_ = parse_funcs_.back();
+    parse_funcs_.pop_back();
+    return name + 1;
+  }
+  // Only understand boolean values with 0 or 1.
+  if (*name == 'b') {
+    name++;
+    if (*name == '0') {
+      AppendArgument("false");
+      cur_state_.str.clear();
+    } else if (*name == '1') {
+      AppendArgument("true");
+      cur_state_.str.clear();
+    } else {
+      return nullptr;
+    }
+    return name + 1;
+  }
+  return nullptr;
+}
+
 const char* Demangler::ParseTemplateArgumentsComplex(const char* name) {
   if (*name == 'E') {
     if (parse_funcs_.empty()) {
@@ -670,6 +693,11 @@
     FinalizeTemplate();
     Save(cur_state_.str, false);
     return name + 1;
+  } else if (*name == 'L') {
+    // Literal value for a template.
+    parse_funcs_.push_back(parse_func_);
+    parse_func_ = &Demangler::ParseTemplateLiteral;
+    return name + 1;
   }
   return ParseArguments(name);
 }
diff --git a/demangle/Demangler.h b/demangle/Demangler.h
index 3bd4f3c..f76def6 100644
--- a/demangle/Demangler.h
+++ b/demangle/Demangler.h
@@ -92,6 +92,7 @@
   const char* ParseArguments(const char* name);
   const char* ParseTemplateArguments(const char* name);
   const char* ParseTemplateArgumentsComplex(const char* name);
+  const char* ParseTemplateLiteral(const char* name);
   const char* ParseFunctionArgument(const char* name);
   const char* ParseFunctionName(const char* name);
   const char* FindFunctionName(const char* name);
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3d3faf3..5c26c2e 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -31,8 +31,6 @@
 // turn verity off in userdebug builds.
 #define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
 
-__BEGIN_DECLS
-
 // Verity modes
 enum verity_mode {
     VERITY_MODE_EIO = 0,
@@ -85,6 +83,4 @@
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
 int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
 
-__END_DECLS
-
 #endif /* __CORE_FS_MGR_H */
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index ef51724..bc2942d 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -22,13 +22,7 @@
 #include <stdint.h>
 #include <stdio.h>
 
-// C++ only headers
-// TODO: move this into separate header files under include/fs_mgr/*.h
-#ifdef __cplusplus
 #include <string>
-#endif
-
-__BEGIN_DECLS
 
 /*
  * The entries must be kept in the same order as they were seen in the fstab.
@@ -70,6 +64,7 @@
 
 int fs_mgr_add_entry(struct fstab* fstab, const char* mount_point, const char* fs_type,
                      const char* blk_device);
+struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path);
 int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab);
 int fs_mgr_is_nonremovable(const struct fstab_rec* fstab);
 int fs_mgr_is_verified(const struct fstab_rec* fstab);
@@ -88,13 +83,6 @@
 int fs_mgr_is_latemount(const struct fstab_rec* fstab);
 int fs_mgr_is_quota(const struct fstab_rec* fstab);
 
-__END_DECLS
-
-// C++ only functions
-// TODO: move this into separate header files under include/fs_mgr/*.h
-#ifdef __cplusplus
 std::string fs_mgr_get_slot_suffix();
-struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path);
-#endif
 
 #endif /* __CORE_FS_TAB_H */
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0df96bf..223d34e 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -57,6 +57,7 @@
 #include "persistent_properties.h"
 #include "util.h"
 
+using android::base::StartsWith;
 using android::base::StringPrintf;
 using android::base::Timer;
 
@@ -153,7 +154,7 @@
         return PROP_ERROR_INVALID_NAME;
     }
 
-    if (valuelen >= PROP_VALUE_MAX) {
+    if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                    << "value too long";
         return PROP_ERROR_INVALID_VALUE;
@@ -162,7 +163,7 @@
     prop_info* pi = (prop_info*) __system_property_find(name.c_str());
     if (pi != nullptr) {
         // ro.* properties are actually "write-once".
-        if (android::base::StartsWith(name, "ro.")) {
+        if (StartsWith(name, "ro.")) {
             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
                        << "property already set";
             return PROP_ERROR_READ_ONLY_PROPERTY;
@@ -180,7 +181,7 @@
 
     // Don't write properties to disk until after we have read all default
     // properties to prevent them from being overwritten by default values.
-    if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
+    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
         WritePersistentProperty(name, value);
     }
     property_changed(name, value);
@@ -401,7 +402,7 @@
   char* source_ctx = nullptr;
   getpeercon(socket.socket(), &source_ctx);
 
-  if (android::base::StartsWith(name, "ctl.")) {
+  if (StartsWith(name, "ctl.")) {
     if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
       handle_control_message(name.c_str() + 4, value.c_str());
       if (!legacy_protocol) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index a4a20f3..b17dbaf 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -56,6 +56,7 @@
 #include "service.h"
 #include "sigchld_handler.h"
 
+using android::base::Split;
 using android::base::StringPrintf;
 using android::base::Timer;
 
@@ -346,7 +347,16 @@
     Timer t;
     LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
 
-    property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str());
+    // Ensure last reboot reason is reduced to canonical
+    // alias reported in bootloader or system boot reason.
+    size_t skip = 0;
+    std::vector<std::string> reasons = Split(reason, ",");
+    if (reasons.size() >= 2 && reasons[0] == "reboot" &&
+        (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
+         reasons[1] == "hard" || reasons[1] == "warm")) {
+        skip = strlen("reboot,");
+    }
+    property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
     sync();
 
     bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
@@ -469,7 +479,7 @@
 
 bool HandlePowerctlMessage(const std::string& command) {
     unsigned int cmd = 0;
-    std::vector<std::string> cmd_params = android::base::Split(command, ",");
+    std::vector<std::string> cmd_params = Split(command, ",");
     std::string reboot_target = "";
     bool run_fsck = false;
     bool command_invalid = false;
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index b4abb79..95f2259 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -51,7 +51,7 @@
     int ret;
     struct stat st;
 
-    int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR));
+    int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR | O_CLOEXEC));
     if (fd < 0) {
         return fd;
     }
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index bd66873..91d551c 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -25,6 +25,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <string>
 #include <unistd.h>
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index fb1fbd4..d503ffe 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -721,6 +721,7 @@
     user shell
     group shell log readproc
     seclabel u:r:shell:s0
+    setenv HOSTNAME console
 
 on property:ro.debuggable=1
     # Give writes to anyone for the trace folder on debug builds.
diff --git a/trusty/nvram/trusty_nvram_device.cpp b/trusty/nvram/trusty_nvram_device.cpp
index 2c50915..82a1228 100644
--- a/trusty/nvram/trusty_nvram_device.cpp
+++ b/trusty/nvram/trusty_nvram_device.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <errno.h>
+
 #include <nvram/hal/nvram_device_adapter.h>
 
 #include "trusty_nvram_implementation.h"