Loading bootstat/boot_reason_test.sh +158 −102 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ RED="${ESCAPE}[38;5;196m" 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 Loading @@ -50,11 +51,18 @@ hasPstore() { 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 } Loading Loading @@ -93,7 +101,7 @@ setBootloaderBootReason() { 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 Loading Loading @@ -188,9 +196,9 @@ wait_for_screen() { 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 Loading Loading @@ -223,15 +231,38 @@ EXPECT_EQ() { 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 [ `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 Loading @@ -250,7 +281,7 @@ EXPECT_PROPERTY() { 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 Loading Loading @@ -317,6 +348,7 @@ init : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from 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)'... Loading Loading @@ -392,6 +424,9 @@ end_test() { echo "${GREEN}[ OK ]${NORMAL} ${TEST} ${*}" else echo "${RED}[ FAILED ]${NORMAL} ${TEST} ${*}" if ${STOP_ON_FAILURE}; then exit ${save_ret} fi fi return ${save_ret} } Loading Loading @@ -462,7 +497,7 @@ 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`" val=`get_property ${1}` ret=`validate_reason "${val}"` if [ "reboot" = "${ret}" ]; then ret=`validate_reason "reboot,${val}"` Loading @@ -470,6 +505,17 @@ validate_property() { 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 # Loading @@ -487,6 +533,7 @@ test_properties() { 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 Loading @@ -498,12 +545,11 @@ test_properties() { 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} } Loading Loading @@ -557,7 +603,7 @@ test_ota() { 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 } Loading @@ -572,7 +618,7 @@ test_optional_ota() { 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 } Loading Loading @@ -604,7 +650,7 @@ blind_reboot_test() { 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} } Loading Loading @@ -638,7 +684,7 @@ test_factory_reset() { 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" Loading Loading @@ -670,7 +716,7 @@ test_optional_factory_reset() { ( 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" \ Loading Loading @@ -744,7 +790,7 @@ test_battery() { 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 } Loading @@ -766,7 +812,7 @@ test_optional_battery() { 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 } Loading @@ -787,7 +833,7 @@ test_optional_battery_thermal() { 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 } Loading Loading @@ -824,7 +870,7 @@ test_kernel_panic() { 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 } Loading Loading @@ -852,7 +898,7 @@ test_kernel_panic_subreason() { 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 Loading Loading @@ -883,7 +929,7 @@ test_kernel_panic_hung() { 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 } Loading Loading @@ -916,7 +962,7 @@ test_thermal_shutdown() { 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 } Loading @@ -937,7 +983,7 @@ test_userrequested_shutdown() { 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 } Loading @@ -954,7 +1000,7 @@ test_shell_reboot() { 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 } Loading @@ -971,7 +1017,7 @@ test_adb_reboot() { 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 } Loading Loading @@ -1007,7 +1053,7 @@ test_Its_Just_So_Hard_reboot() { 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 } Loading Loading @@ -1057,7 +1103,7 @@ run_bootloader() { 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}" } Loading Loading @@ -1111,12 +1157,20 @@ if [ ${#} -ge 2 -a X"-s" = X"${1}" ]; then shift 2 fi # Helpful for debugging, allows us to import the functions. if [ X"--macros" != X"${1}" ]; then 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 [ X"--stop" = X"${1}" ]; then STOP_ON_FAILURE=true shift fi # Check if all conditions for the script are sane if [ -z "${ANDROID_SERIAL}" ]; then Loading Loading @@ -1149,13 +1203,13 @@ if [ -z "$*" ]; then 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) # 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_wdog_reset bootloader_wdog_reset \ bootloader_wdog_reset bootloader_cold bootloader_warm \ bootloader_hard bootloader_recovery fi if [ X"nothing" = X"${1}" ]; then Loading Loading @@ -1196,3 +1250,5 @@ if [ -n "${failures}" ]; then echo "${RED}[ FAILED ]${NORMAL} ${failures}" fi exit ${ret} fi bootstat/bootstat.cpp +49 −9 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <cstddef> #include <cstdio> #include <ctime> #include <iterator> #include <map> #include <memory> #include <regex> Loading Loading @@ -123,12 +124,12 @@ std::string GetProperty(const char* key) { 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; Loading Loading @@ -735,8 +736,49 @@ bool addKernelPanicSubReason(const std::string& content, std::string& ret) { 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)); Loading Loading @@ -932,13 +974,11 @@ std::string CalculateBootCompletePrefix() { 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; Loading Loading @@ -1036,7 +1076,7 @@ void SetSystemBootReason() { 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)) { Loading Loading
bootstat/boot_reason_test.sh +158 −102 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ RED="${ESCAPE}[38;5;196m" 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 Loading @@ -50,11 +51,18 @@ hasPstore() { 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 } Loading Loading @@ -93,7 +101,7 @@ setBootloaderBootReason() { 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 Loading Loading @@ -188,9 +196,9 @@ wait_for_screen() { 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 Loading Loading @@ -223,15 +231,38 @@ EXPECT_EQ() { 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 [ `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 Loading @@ -250,7 +281,7 @@ EXPECT_PROPERTY() { 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 Loading Loading @@ -317,6 +348,7 @@ init : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from 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)'... Loading Loading @@ -392,6 +424,9 @@ end_test() { echo "${GREEN}[ OK ]${NORMAL} ${TEST} ${*}" else echo "${RED}[ FAILED ]${NORMAL} ${TEST} ${*}" if ${STOP_ON_FAILURE}; then exit ${save_ret} fi fi return ${save_ret} } Loading Loading @@ -462,7 +497,7 @@ 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`" val=`get_property ${1}` ret=`validate_reason "${val}"` if [ "reboot" = "${ret}" ]; then ret=`validate_reason "reboot,${val}"` Loading @@ -470,6 +505,17 @@ validate_property() { 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 # Loading @@ -487,6 +533,7 @@ test_properties() { 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 Loading @@ -498,12 +545,11 @@ test_properties() { 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} } Loading Loading @@ -557,7 +603,7 @@ test_ota() { 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 } Loading @@ -572,7 +618,7 @@ test_optional_ota() { 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 } Loading Loading @@ -604,7 +650,7 @@ blind_reboot_test() { 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} } Loading Loading @@ -638,7 +684,7 @@ test_factory_reset() { 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" Loading Loading @@ -670,7 +716,7 @@ test_optional_factory_reset() { ( 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" \ Loading Loading @@ -744,7 +790,7 @@ test_battery() { 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 } Loading @@ -766,7 +812,7 @@ test_optional_battery() { 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 } Loading @@ -787,7 +833,7 @@ test_optional_battery_thermal() { 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 } Loading Loading @@ -824,7 +870,7 @@ test_kernel_panic() { 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 } Loading Loading @@ -852,7 +898,7 @@ test_kernel_panic_subreason() { 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 Loading Loading @@ -883,7 +929,7 @@ test_kernel_panic_hung() { 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 } Loading Loading @@ -916,7 +962,7 @@ test_thermal_shutdown() { 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 } Loading @@ -937,7 +983,7 @@ test_userrequested_shutdown() { 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 } Loading @@ -954,7 +1000,7 @@ test_shell_reboot() { 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 } Loading @@ -971,7 +1017,7 @@ test_adb_reboot() { 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 } Loading Loading @@ -1007,7 +1053,7 @@ test_Its_Just_So_Hard_reboot() { 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 } Loading Loading @@ -1057,7 +1103,7 @@ run_bootloader() { 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}" } Loading Loading @@ -1111,12 +1157,20 @@ if [ ${#} -ge 2 -a X"-s" = X"${1}" ]; then shift 2 fi # Helpful for debugging, allows us to import the functions. if [ X"--macros" != X"${1}" ]; then 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 [ X"--stop" = X"${1}" ]; then STOP_ON_FAILURE=true shift fi # Check if all conditions for the script are sane if [ -z "${ANDROID_SERIAL}" ]; then Loading Loading @@ -1149,13 +1203,13 @@ if [ -z "$*" ]; then 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) # 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_wdog_reset bootloader_wdog_reset \ bootloader_wdog_reset bootloader_cold bootloader_warm \ bootloader_hard bootloader_recovery fi if [ X"nothing" = X"${1}" ]; then Loading Loading @@ -1196,3 +1250,5 @@ if [ -n "${failures}" ]; then echo "${RED}[ FAILED ]${NORMAL} ${failures}" fi exit ${ret} fi
bootstat/bootstat.cpp +49 −9 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <cstddef> #include <cstdio> #include <ctime> #include <iterator> #include <map> #include <memory> #include <regex> Loading Loading @@ -123,12 +124,12 @@ std::string GetProperty(const char* key) { 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; Loading Loading @@ -735,8 +736,49 @@ bool addKernelPanicSubReason(const std::string& content, std::string& ret) { 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)); Loading Loading @@ -932,13 +974,11 @@ std::string CalculateBootCompletePrefix() { 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; Loading Loading @@ -1036,7 +1076,7 @@ void SetSystemBootReason() { 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)) { Loading