Merge "bootstat: record reboot reason history in persist.sys.boot.reason.history"
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index ddd1caf..71d3ecb 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -24,6 +24,7 @@
 NORMAL="${ESCAPE}[0m"
 # Best guess to an average device's reboot time, refined as tests return
 DURATION_DEFAULT=45
+STOP_ON_FAILURE=false
 
 # Helper functions
 
@@ -50,11 +51,18 @@
   fi
 }
 
+[ "USAGE: get_property <prop>
+
+Returns the property value" ]
+get_property() {
+  adb shell getprop ${1} 2>&1 </dev/null
+}
+
 [ "USAGE: isDebuggable
 
 Returns: true if device is (likely) a debug build" ]
 isDebuggable() {
-  if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then
+  if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
     false
   fi
 }
@@ -93,7 +101,7 @@
     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`"
+  test_reason="`get_property persist.test.boot.reason`"
   if [ X"${test_reason}" != X"${1}" ]; then
     echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
     return 1
@@ -188,9 +196,9 @@
       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`" ]
+      if [ -n "`get_property sys.boot.reason`" ]
       then
-        vals=`adb shell getprop </dev/null 2>/dev/null |
+        vals=`get_property |
               sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
         if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
         then
@@ -223,15 +231,38 @@
   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
+    if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
+*}" ]; then
+      echo "ERROR: expected \"${lval}\"" >&2
+      echo "       got \"${rval}\"" |
+        sed ': again
+             N
+             s/\(\n\)\([^ ]\)/\1             \2/
+             t again' >&2
+      if [ -n "${*}" ] ; then
+        echo "       ${*}" >&2
+      fi
+    else
+      echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
     fi
     return 1
   fi
   if [ -n "${*}" ] ; then
     if [ X"${lval}" != X"${rval}" ]; then
-      echo "INFO: ok \"${lval}\"(=\"${rval}\") ${*}" >&2
+      if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval%
+*}" ]; then
+        echo "INFO: ok \"${lval}\"" >&2
+        echo "       = \"${rval}\"" |
+          sed ': again
+               N
+               s/\(\n\)\([^ ]\)/\1          \2/
+               t again' >&2
+        if [ -n "${*}" ] ; then
+          echo "      ${*}" >&2
+        fi
+      else
+        echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+      fi
     else
       echo "INFO: ok \"${lval}\" ${*}" >&2
     fi
@@ -250,7 +281,7 @@
   property="${1}"
   value="${2}"
   shift 2
-  val=`adb shell getprop ${property} 2>&1`
+  val=`get_property ${property}`
   EXPECT_EQ "${value}" "${val}" for Android property ${property}
   local_ret=${?}
   if [ 0 != ${local_ret} -a "ro.boot.bootreason" = "${property}" ]; then
@@ -317,6 +348,7 @@
 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:
+init    : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' 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)'...
@@ -392,6 +424,9 @@
     echo "${GREEN}[       OK ]${NORMAL} ${TEST} ${*}"
   else
     echo "${RED}[  FAILED  ]${NORMAL} ${TEST} ${*}"
+    if ${STOP_ON_FAILURE}; then
+      exit ${save_ret}
+    fi
   fi
   return ${save_ret}
 }
@@ -462,7 +497,7 @@
 
 NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
 validate_property() {
-  val="`adb shell getprop ${1} 2>&1`"
+  val=`get_property ${1}`
   ret=`validate_reason "${val}"`
   if [ "reboot" = "${ret}" ]; then
     ret=`validate_reason "reboot,${val}"`
@@ -470,6 +505,17 @@
   echo ${ret}
 }
 
+[ "USAGE: check_boilerblate_properties
+
+Check for common property values" ]
+check_boilerplate_properties() {
+  EXPECT_PROPERTY persist.sys.boot.reason ""
+  save_ret=${?}
+  reason=`validate_property sys.boot.reason`
+  ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
+  EXPECT_PROPERTY persist.sys.boot.reason.history "${reason},[1-9][0-9]*\(\|[^0-9].*\)"
+}
+
 #
 # Actual test frames
 #
@@ -487,6 +533,7 @@
   duration_test 1
   wait_for_screen
   retval=0
+  # sys.boot.reason is last for a reason
   check_set="ro.boot.bootreason sys.boot.reason.last sys.boot.reason"
   bootloader=""
   # NB: this test could fail if performed _after_ optional_factory_reset test
@@ -498,12 +545,11 @@
     check_set="ro.boot.bootreason sys.boot.reason"
     bootloader="bootloader"
   fi
-  EXPECT_PROPERTY persist.sys.boot.reason ""
   for prop in ${check_set}; do
     reason=`validate_property ${prop}`
     EXPECT_PROPERTY ${prop} ${reason} || retval=${?}
   done
-  # sys.boot.reason is last for a reason
+  check_boilerplate_properties || retval=${?}
   report_bootstat_logs ${reason} ${bootloader}
   return ${retval}
 }
@@ -557,7 +603,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
   EXPECT_PROPERTY sys.boot.reason.last bootloader
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,ota bootloader
 }
 
@@ -572,7 +618,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,ota
   EXPECT_PROPERTY sys.boot.reason.last reboot,ota
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,ota
 }
 
@@ -604,7 +650,7 @@
   fi
   EXPECT_PROPERTY sys.boot.reason ${reasons}
   EXPECT_PROPERTY sys.boot.reason.last ${reason}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs ${reason} ${bootloader_reason}
 }
 
@@ -638,7 +684,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
   EXPECT_PROPERTY sys.boot.reason.last "reboot,.*"
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   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"
@@ -670,7 +716,7 @@
   ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
   EXPECT_PROPERTY sys.boot.reason.last ""
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   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" \
@@ -744,7 +790,7 @@
 
   EXPECT_PROPERTY sys.boot.reason shutdown,battery
   EXPECT_PROPERTY sys.boot.reason.last cold
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
   exitPstore
 }
@@ -766,7 +812,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,battery
   EXPECT_PROPERTY sys.boot.reason.last shutdown,battery
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,battery
 }
 
@@ -787,7 +833,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery
   EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal,battery
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,thermal,battery
 }
 
@@ -824,7 +870,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs kernel_panic,sysrq
   exitPstore
 }
@@ -852,7 +898,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs kernel_panic,sysrq,test \
     "-bootstat: Unknown boot reason: kernel_panic,sysrq,test"
   exitPstore
@@ -883,7 +929,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs kernel_panic,hung
   exitPstore
 }
@@ -916,7 +962,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,thermal
   EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,thermal
 }
 
@@ -937,7 +983,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,userrequested
   EXPECT_PROPERTY sys.boot.reason.last shutdown,userrequested
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,userrequested
 }
 
@@ -954,7 +1000,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,shell
   EXPECT_PROPERTY sys.boot.reason.last reboot,shell
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,shell
 }
 
@@ -971,7 +1017,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,adb
   EXPECT_PROPERTY sys.boot.reason.last reboot,adb
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,adb
 }
 
@@ -1007,7 +1053,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
   EXPECT_PROPERTY sys.boot.reason.last reboot,its_just_so_hard
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,its_just_so_hard
 }
 
@@ -1057,7 +1103,7 @@
   EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}"
   EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
   EXPECT_PROPERTY sys.boot.reason.last "${last_expected}"
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs "${sys_expected}"
 }
 
@@ -1111,88 +1157,98 @@
   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
+# Helpful for debugging, allows us to import the functions.
+if [ X"--macros" != X"${1}" ]; then
 
-# Check if all conditions for the script are sane
+  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
 
-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
+  if [ X"--stop" = X"${1}" ]; then
+    STOP_ON_FAILURE=true
+    shift
   fi
-  echo "WARNING: no target device specified" >&2
-fi
 
-ret=0
+  # Check if all conditions for the script are sane
 
-# 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 properties ota cold factory_reset hard battery unknown \
-             kernel_panic kernel_panic_subreason kernel_panic_hung 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
-  fi
-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
-  wrap_test ${t}
-  retval=${?}
-  if [ 0 = ${retval} ]; then
-    if [ -z "${successes}" ]; then
-      successes=${t}
-    else
-      successes="${successes} ${t}"
+  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
-  else
-    ret=${retval}
-    if [ -z "${failures}" ]; then
-      failures=${t}
-    else
-      failures="${failures} ${t}"
+    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 (search/permission issues)
+      eval set properties ota cold factory_reset hard battery unknown \
+               kernel_panic kernel_panic_subreason kernel_panic_hung 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_cold bootloader_warm \
+               bootloader_hard bootloader_recovery
+    fi
+    if [ X"nothing" = X"${1}" ]; then
+      shift 1
+    fi
+  fi
+  echo "INFO: selected test(s): ${@}" >&2
   echo
-done
+  # Prepare device
+  setBootloaderBootReason 2>/dev/null
+  # Start pouring through the tests.
+  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}"
+  if [ -n "${successes}" ]; then
+    echo "${GREEN}[  PASSED  ]${NORMAL} ${successes}"
+  fi
+  if [ -n "${failures}" ]; then
+    echo "${RED}[  FAILED  ]${NORMAL} ${failures}"
+  fi
+  exit ${ret}
+
 fi
-if [ -n "${failures}" ]; then
-  echo "${RED}[  FAILED  ]${NORMAL} ${failures}"
-fi
-exit ${ret}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index cd19c26..4d9f1ac 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -27,6 +27,7 @@
 #include <cstddef>
 #include <cstdio>
 #include <ctime>
+#include <iterator>
 #include <map>
 #include <memory>
 #include <regex>
@@ -123,12 +124,12 @@
   return std::string(&temp[0], len);
 }
 
-void SetProperty(const char* key, const std::string& val) {
-  property_set(key, val.c_str());
+bool SetProperty(const char* key, const std::string& val) {
+  return property_set(key, val.c_str()) == 0;
 }
 
-void SetProperty(const char* key, const char* val) {
-  property_set(key, val);
+bool SetProperty(const char* key, const char* val) {
+  return property_set(key, val) == 0;
 }
 
 constexpr int32_t kEmptyBootReason = 0;
@@ -735,8 +736,49 @@
 const char system_reboot_reason_property[] = "sys.boot.reason";
 const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
 const char last_last_reboot_reason_property[] = "sys.boot.reason.last";
+constexpr size_t history_reboot_reason_size = 4;
+const char history_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY ".history";
 const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
 
+// Land system_boot_reason into system_reboot_reason_property.
+// Shift system_boot_reason into history_reboot_reason_property.
+void BootReasonAddToHistory(const std::string& system_boot_reason) {
+  if (system_boot_reason.empty()) return;
+  LOG(INFO) << "Canonical boot reason: " << system_boot_reason;
+  auto old_system_boot_reason = GetProperty(system_reboot_reason_property);
+  if (!SetProperty(system_reboot_reason_property, system_boot_reason)) {
+    SetProperty(system_reboot_reason_property, system_boot_reason.substr(0, PROPERTY_VALUE_MAX - 1));
+  }
+  auto reason_history = android::base::Split(GetProperty(history_reboot_reason_property), "\n");
+  static auto mark = time(nullptr);
+  auto mark_str = std::string(",") + std::to_string(mark);
+  auto marked_system_boot_reason = system_boot_reason + mark_str;
+  if (!reason_history.empty()) {
+    // delete any entries that we just wrote in a previous
+    // call and leveraging duplicate line handling
+    auto last = old_system_boot_reason + mark_str;
+    // trim the list to (history_reboot_reason_size - 1)
+    ssize_t max = history_reboot_reason_size;
+    for (auto it = reason_history.begin(); it != reason_history.end();) {
+      if (it->empty() || (last == *it) || (marked_system_boot_reason == *it) || (--max <= 0)) {
+        it = reason_history.erase(it);
+      } else {
+        last = *it;
+        ++it;
+      }
+    }
+  }
+  // insert at the front, concatenating mark (<epoch time>) detail to the value.
+  reason_history.insert(reason_history.begin(), marked_system_boot_reason);
+  // If the property string is too long ( > PROPERTY_VALUE_MAX)
+  // we get an error, so trim out last entry and try again.
+  while (!(SetProperty(history_reboot_reason_property, android::base::Join(reason_history, '\n')))) {
+    auto it = std::prev(reason_history.end());
+    if (it == reason_history.end()) break;
+    reason_history.erase(it);
+  }
+}
+
 // 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));
@@ -932,13 +974,11 @@
   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");
+    BootReasonAddToHistory("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");
+    BootReasonAddToHistory("reboot,ota");
   }
 
   return boot_complete_prefix;
@@ -1036,7 +1076,7 @@
   const std::string bootloader_boot_reason(GetProperty(bootloader_reboot_reason_property));
   const std::string system_boot_reason(BootReasonStrToReason(bootloader_boot_reason));
   // Record the scrubbed system_boot_reason to the property
-  SetProperty(system_reboot_reason_property, system_boot_reason);
+  BootReasonAddToHistory(system_boot_reason);
   // Shift last_reboot_reason_property to last_last_reboot_reason_property
   std::string last_boot_reason(GetProperty(last_reboot_reason_property));
   if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {