bootstat: test: inject ro.boot.bootreason values

Adding a set of automated engineering unit tests with a strict list of
prerequisites.  Not meant for "user" builds.  Must have a crafted
bootloader that does not set the boot reason.  Only works on platforms
where the bootloader either by accident or specifically does not set
the ro.boot.bootreason via kernel command line configuration
androidboot.bootreason=.  If the tests do not have the prerequisites,
the test will report success, but with protest.

These new tests should work on current Hikey and Hikey960 bootloaders
but could very well become obsolete if those platform bootloaders
start setting the boot reason.

We do not want a platform solution as it could allow a third party to
override the bootloader boot reason.

Test: system/core/bootstat/boot_reason_test.sh
Bug: 63736262
Change-Id: I1793184a8484b83e1d9077475bc65af9816dadf7
This commit is contained in:
Mark Salyzyn 2017-10-10 14:57:12 -07:00
parent bb52cbf35d
commit 9a3870490a
3 changed files with 172 additions and 28 deletions

View file

@ -65,6 +65,11 @@ cc_binary {
static_libs: ["libbootstat"],
shared_libs: ["liblogcat"],
init_rc: ["bootstat.rc"],
product_variables: {
debuggable: {
init_rc: ["bootstat-debug.rc"],
},
},
srcs: ["bootstat.cpp"],
}

View file

@ -74,6 +74,30 @@ checkDebugBuild() {
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
@ -259,6 +283,8 @@ bootstat: Service started: /system/bin/bootstat -l
bootstat: Battery level at shutdown 100%
bootstat: Battery level at startup 100%
init : Parsing file /system/etc/init/bootstat.rc...
init : processing action (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
@ -361,37 +387,33 @@ wrap_test() {
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" ;;
@ -399,12 +421,26 @@ validate_property() {
*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
#
@ -428,7 +464,7 @@ test_properties() {
# 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
@ -843,6 +879,94 @@ test_Its_Just_So_Hard_reboot() {
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" ]
@ -893,8 +1017,13 @@ if [ -z "$*" ]; then
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
@ -902,6 +1031,9 @@ if [ -z "$*" ]; then
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

View file

@ -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}