Home | History | Annotate | Download | only in bootstat
      1 #! /bin/bash
      2 #
      3 # Bootstat boot reason tests
      4 #
      5 # throughout testing:
      6 # - manual tests can only run on eng/userdebug builds
      7 # - watch adb logcat -b all -d -s bootstat
      8 # - watch adb logcat -b all -d | audit2allow
      9 # - wait until screen is up, boot has completed, can mean wait for
     10 #   sys.boot_completed=1 and sys.logbootcomplete=1 to be true
     11 #
     12 # All test frames, and nothing else, must be function names prefixed and
     13 # specifiged with the pattern 'test_<test>() {' as this is also how the
     14 # script discovers the full list of tests by inspecting its own code.
     15 #
     16 
     17 # Helper variables
     18 
     19 SPACE=" "
     20 ESCAPE=""
     21 TAB="	"
     22 GREEN="${ESCAPE}[38;5;40m"
     23 RED="${ESCAPE}[38;5;196m"
     24 NORMAL="${ESCAPE}[0m"
     25 # Best guess to an average device's reboot time, refined as tests return
     26 DURATION_DEFAULT=45
     27 
     28 # Helper functions
     29 
     30 [ "USAGE: inFastboot
     31 
     32 Returns: true if device is in fastboot mode" ]
     33 inFastboot() {
     34   fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
     35 }
     36 
     37 [ "USAGE: inAdb
     38 
     39 Returns: true if device is in adb mode" ]
     40 inAdb() {
     41   adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
     42 }
     43 
     44 [ "USAGE: hasPstore
     45 
     46 Returns: true if device (likely) has pstore data" ]
     47 hasPstore() {
     48   if inAdb && [ 0 -eq `adb shell su root ls /sys/fs/pstore | wc -l` ]; then
     49     false
     50   fi
     51 }
     52 
     53 [ "USAGE: isDebuggable
     54 
     55 Returns: true if device is (likely) a debug build" ]
     56 isDebuggable() {
     57   if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then
     58     false
     59   fi
     60 }
     61 
     62 [ "USAGE: checkDebugBuild [--noerror]
     63 
     64 Returns: true if device is a userdebug or eng release" ]
     65 checkDebugBuild() {
     66   if isDebuggable; then
     67     echo "INFO: '${TEST}' test requires userdebug build"
     68   elif [ -n "${1}" ]; then
     69     echo "WARNING: '${TEST}' test requires userdebug build"
     70     false
     71   else
     72     echo "ERROR: '${TEST}' test requires userdebug build, skipping FAILURE"
     73     duration_prefix="~"
     74     duration_estimate=1
     75     false
     76   fi >&2
     77 }
     78 
     79 [ "USAGE: setBootloaderBootReason [value]
     80 
     81 Returns: true if device supports and set boot reason injection" ]
     82 setBootloaderBootReason() {
     83   inAdb || ( echo "ERROR: device not in adb mode." >&2 ; false ) || return 1
     84   if [ -z "`adb shell ls /etc/init/bootstat-debug.rc 2>/dev/null`" ]; then
     85     echo "ERROR: '${TEST}' test requires /etc/init/bootstat-debug.rc" >&2
     86     return 1
     87   fi
     88   checkDebugBuild || return 1
     89   if adb shell su root "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" |
     90      grep '^androidboot[.]bootreason=[^ ]' >/dev/null; then
     91     echo "ERROR: '${TEST}' test requires a device with a bootloader that" >&2
     92     echo "       does not set androidboot.bootreason kernel parameter." >&2
     93     return 1
     94   fi
     95   adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
     96   test_reason="`adb shell getprop persist.test.boot.reason 2>/dev/null`"
     97   if [ X"${test_reason}" != X"${1}" ]; then
     98     echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
     99     return 1
    100   fi
    101 }
    102 
    103 [ "USAGE: enterPstore
    104 
    105 Prints a warning string requiring functional pstore
    106 
    107 Returns: pstore_ok variable set to true or false" ]
    108 enterPstore() {
    109   if hasPstore; then
    110     echo "INFO: '${TEST}' test requires functional and reliable pstore"
    111     pstore_ok=true
    112   else
    113     echo "WARNING: '${TEST}' test requires functional pstore"
    114     pstore_ok=false
    115   fi >&2
    116   ${pstore_ok}
    117 }
    118 
    119 [ "USAGE: exitPstore
    120 
    121 Prints an error string requiring functional pstore
    122 
    123 Returns: clears error if pstore dysfunctional" ]
    124 exitPstore() {
    125   save_ret=${?}
    126   if [ ${save_ret} != 0 ]; then
    127     if hasPstore; then
    128       return ${save_ret}
    129     fi
    130     if [ true = ${pstore_ok} ]; then
    131       echo "WARNING: '${TEST}' test requires functional pstore"
    132       return ${save_ret}
    133     fi
    134     echo "ERROR: '${TEST}' test requires functional pstore, skipping FAILURE"
    135     duration_prefix="~"
    136     duration_estimate=1
    137   fi >&2
    138 }
    139 
    140 [ "USAGE: format_duration <seconds>
    141 
    142 human readable output whole seconds, whole minutes or mm:ss" ]
    143 format_duration() {
    144   if [ -z "${1}" ]; then
    145     echo unknown
    146     return
    147   fi
    148   seconds=`expr ${1} % 60`
    149   minutes=`expr ${1} / 60`
    150   if [ 0 -eq ${minutes} ]; then
    151     if [ 1 -eq ${1} ]; then
    152       echo 1 second
    153       return
    154     fi
    155     echo ${1} seconds
    156     return
    157   elif [ 60 -eq ${1} ]; then
    158     echo 1 minute
    159     return
    160   elif [ 0 -eq ${seconds} ]; then
    161     echo ${minutes} minutes
    162     return
    163   fi
    164   echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10`
    165 }
    166 
    167 wait_for_screen_timeout=900
    168 [ "USAGE: wait_for_screen [-n] [TIMEOUT]
    169 
    170 -n - echo newline at exit
    171 TIMEOUT - default `format_duration ${wait_for_screen_timeout}`" ]
    172 wait_for_screen() {
    173   exit_function=true
    174   if [ X"-n" = X"${1}" ]; then
    175     exit_function=echo
    176     shift
    177   fi
    178   timeout=${wait_for_screen_timeout}
    179   if [ ${#} -gt 0 ]; then
    180     timeout=${1}
    181     shift
    182   fi
    183   counter=0
    184   while true; do
    185     if inFastboot; then
    186       fastboot reboot
    187     elif inAdb; then
    188       if [ 0 != ${counter} ]; then
    189         adb wait-for-device </dev/null >/dev/null 2>/dev/null
    190       fi
    191       if [ -n "`adb shell getprop sys.boot.reason </dev/null 2>/dev/null`" ]
    192       then
    193         vals=`adb shell getprop </dev/null 2>/dev/null |
    194               sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
    195         if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
    196         then
    197           sleep 1
    198           break
    199         fi
    200         if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
    201         then
    202           sleep 1
    203           break
    204         fi
    205       fi
    206     fi
    207     counter=`expr ${counter} + 1`
    208     if [ ${counter} -gt ${timeout} ]; then
    209       ${exit_function}
    210       echo "ERROR: wait_for_screen() timed out (`format_duration ${timeout}`)" >&2
    211       return 1
    212     fi
    213     sleep 1
    214   done
    215   ${exit_function}
    216 }
    217 
    218 [ "USAGE: EXPECT_EQ <lval> <rval> [message]
    219 
    220 Returns true if (regex) lval matches rval" ]
    221 EXPECT_EQ() {
    222   lval="${1}"
    223   rval="${2}"
    224   shift 2
    225   if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
    226     echo "ERROR: expected \"${lval}\" got \"${rval}\"" >&2
    227     if [ -n "${*}" ] ; then
    228       echo "       ${*}" >&2
    229     fi
    230     return 1
    231   fi
    232   if [ -n "${*}" ] ; then
    233     if [ X"${lval}" != X"${rval}" ]; then
    234       echo "INFO: ok \"${lval}\"(=\"${rval}\") ${*}" >&2
    235     else
    236       echo "INFO: ok \"${lval}\" ${*}" >&2
    237     fi
    238   fi
    239   return 0
    240 }
    241 
    242 [ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
    243 
    244 Returns true (0) if current return (regex) value is true and the result matches
    245 and the incoming return value is true as well (wired-or)" ]
    246 EXPECT_PROPERTY() {
    247   save_ret=${?}
    248   property="${1}"
    249   value="${2}"
    250   shift 2
    251   val=`adb shell getprop ${property} 2>&1`
    252   EXPECT_EQ "${value}" "${val}" for Android property ${property} ||
    253     [ -n "${1}" ] ||
    254     save_ret=${?}
    255   return ${save_ret}
    256 }
    257 
    258 [ "USAGE: report_bootstat_logs <expected> ...
    259 
    260 if not prefixed with a minus (-), <expected> will become a series of expected
    261 matches:
    262 
    263     bootstat: Canonical boot reason: <expected_property_value>
    264 
    265 If prefixed with a minus, <expected> will look for an exact match after
    266 removing the minux prefix.  All expected content is _dropped_ from the output
    267 and in essence forms a known blacklist, unexpected content will show.
    268 
    269 Report any logs, minus a known blacklist, preserve the current exit status" ]
    270 report_bootstat_logs() {
    271   save_ret=${?}
    272   match=
    273   for i in "${@}"; do
    274     if [ X"${i}" != X"${i#-}" ] ; then
    275       match="${match}
    276 ${i#-}"
    277     else
    278       match="${match}
    279 bootstat: Canonical boot reason: ${i}"
    280     fi
    281   done
    282   adb logcat -b all -d |
    283   grep bootstat[^e] |
    284   grep -v -F "bootstat: Service started: /system/bin/bootstat --record_boot_complete${match}
    285 bootstat: Failed to read /data/misc/bootstat/post_decrypt_time_elapsed: No such file or directory
    286 bootstat: Failed to parse boot time record: /data/misc/bootstat/post_decrypt_time_elapsed
    287 bootstat: Service started: /system/bin/bootstat --record_boot_reason
    288 bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset
    289 bootstat: Service started: /system/bin/bootstat -l
    290 bootstat: Battery level at shutdown 100%
    291 bootstat: Battery level at startup 100%
    292 init    : Parsing file /system/etc/init/bootstat.rc...
    293 init    : Parsing file /system/etc/init/bootstat-debug.rc...
    294 init    : processing action (persist.test.boot.reason=*) from (/system/etc/init/bootstat-debug.rc:
    295 init    : Command 'setprop ro.boot.bootreason \${persist.test.boot.reason}' action=persist.test.boot.reason=* (/system/etc/init/bootstat-debug.rc:
    296 init    : processing action (post-fs-data) from (/system/etc/init/bootstat.rc
    297 init    : processing action (boot) from (/system/etc/init/bootstat.rc
    298 init    : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
    299 init    : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
    300  (/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
    301  (/system/bin/bootstat -r post_decrypt_time_elapsed)'
    302 init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
    303 init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
    304 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:
    305  (/system/bin/bootstat --record_boot_complete)'...
    306  (/system/bin/bootstat --record_boot_complete)' (pid${SPACE}
    307  (/system/bin/bootstat --record_boot_reason)'...
    308  (/system/bin/bootstat --record_boot_reason)' (pid${SPACE}
    309  (/system/bin/bootstat --record_time_since_factory_reset)'...
    310  (/system/bin/bootstat --record_time_since_factory_reset)' (pid${SPACE}
    311  (/system/bin/bootstat -l)'...
    312  (/system/bin/bootstat -l)' (pid " |
    313   grep -v 'bootstat: Unknown boot reason: $' # Hikey Special
    314   return ${save_ret}
    315 }
    316 
    317 [ "USAGE: start_test [message]
    318 
    319 Record start of test, preserve exit status" ]
    320 start_test() {
    321   save_ret=${?}
    322   duration_prefix="~"
    323   duration_estimate=1
    324   START=`date +%s`
    325   echo "${GREEN}[ RUN      ]${NORMAL} ${TEST} ${*}"
    326   return ${save_ret}
    327 }
    328 
    329 duration_sum_diff=0
    330 duration_num=0
    331 [ "USAGE: duration_test [[prefix]seconds]
    332 
    333 Report the adjusted and expected test duration" ]
    334 duration_test() {
    335   duration_prefix=${1%%[0123456789]*}
    336   if [ -z "${duration_prefix}" ]; then
    337     duration_prefix="~"
    338   fi
    339   duration_estimate="${1#${duration_prefix}}"
    340   if [ -z "${duration_estimate}" ]; then
    341     duration_estimate="${DURATION_DEFAULT}"
    342   fi
    343   duration_new_estimate="${duration_estimate}"
    344   if [ 0 -ne ${duration_num} ]; then
    345     duration_new_estimate=`expr ${duration_new_estimate} + \
    346       \( ${duration_num} / 2 + ${duration_sum_diff} \) / ${duration_num}`
    347     # guard against catastrophe
    348     if [ -z "${duration_new_estimate}" ]; then
    349       duration_new_estimate=${duration_estimate}
    350     fi
    351   fi
    352   # negative values are so undignified
    353   if [ 0 -ge ${duration_new_estimate} ]; then
    354     duration_new_estimate=1
    355   fi
    356   echo "INFO: expected duration of '${TEST}' test" \
    357        "${duration_prefix}`format_duration ${duration_new_estimate}`" >&2
    358 }
    359 
    360 [ "USAGE: end_test [message]
    361 
    362 Document duration and success of test, preserve exit status" ]
    363 end_test() {
    364   save_ret=${?}
    365   END=`date +%s`
    366   duration=`expr ${END} - ${START} 2>/dev/null`
    367   [ 0 -ge ${duration} ] ||
    368     echo "INFO: '${TEST}' test duration `format_duration ${duration}`" >&2
    369   if [ ${save_ret} = 0 ]; then
    370     if [ 0 -lt ${duration} -a 0 -lt ${duration_estimate} -a \( \
    371            X"~" = X"${duration_prefix}" -o \
    372            ${duration_estimate} -gt ${duration} \) ]; then
    373       duration_sum_diff=`expr ${duration_sum_diff} + \
    374                               ${duration} - ${duration_estimate}`
    375       duration_num=`expr ${duration_num} + 1`
    376     fi
    377     echo "${GREEN}[       OK ]${NORMAL} ${TEST} ${*}"
    378   else
    379     echo "${RED}[  FAILED  ]${NORMAL} ${TEST} ${*}"
    380   fi
    381   return ${save_ret}
    382 }
    383 
    384 [ "USAGE: wrap_test <test> [message]
    385 
    386 All tests below are wrapped with this helper" ]
    387 wrap_test() {
    388   if [ -z "${1}" -o X"nothing" = X"${1}" ]; then
    389     return
    390   fi
    391   TEST=${1}
    392   shift
    393   start_test ${1}
    394   eval test_${TEST}
    395   end_test ${2}
    396 }
    397 
    398 [ "USAGE: validate_reason <value>
    399 
    400 Check property for CTS compliance with our expectations. Return a cleansed
    401 string representing what is acceptable.
    402 
    403 NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
    404 validate_reason() {
    405   var=`echo -n ${*} |
    406        tr '[A-Z]' '[a-z]' |
    407        tr ' \f\t\r\n' '_____'`
    408   case ${var} in
    409     watchdog | watchdog,?* ) ;;
    410     kernel_panic | kernel_panic,?*) ;;
    411     recovery | recovery,?*) ;;
    412     bootloader | bootloader,?*) ;;
    413     cold | cold,?*) ;;
    414     hard | hard,?*) ;;
    415     warm | warm,?*) ;;
    416     shutdown | shutdown,?*) ;;
    417     reboot,reboot | reboot,reboot,* )     var=${var#reboot,} ; var=${var%,} ;;
    418     reboot,cold | reboot,cold,* )         var=${var#reboot,} ; var=${var%,} ;;
    419     reboot,hard | reboot,hard,* )         var=${var#reboot,} ; var=${var%,} ;;
    420     reboot,warm | reboot,warm,* )         var=${var#reboot,} ; var=${var%,} ;;
    421     reboot,recovery | reboot,recovery,* ) var=${var#reboot,} ; var=${var%,} ;;
    422     reboot,bootloader | reboot,bootloader,* ) var=${var#reboot,} ; var=${var%,} ;;
    423     reboot | reboot,?*) ;;
    424     # Aliases and Heuristics
    425     *wdog* | *watchdog* )     var="watchdog" ;;
    426     *powerkey* )              var="cold,powerkey" ;;
    427     *panic* | *kernel_panic*) var="kernel_panic" ;;
    428     *thermal*)                var="shutdown,thermal" ;;
    429     *s3_wakeup*)              var="warm,s3_wakeup" ;;
    430     *hw_reset*)               var="hard,hw_reset" ;;
    431     *bootloader*)             var="bootloader" ;;
    432     *)                        var="reboot" ;;
    433   esac
    434   echo ${var}
    435 }
    436 
    437 [ "USAGE: validate_property <property>
    438 
    439 Check property for CTS compliance with our expectations. Return a cleansed
    440 string representing what is acceptable.
    441 
    442 NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
    443 validate_property() {
    444   val="`adb shell getprop ${1} 2>&1`"
    445   ret=`validate_reason "${val}"`
    446   if [ "reboot" = "${ret}" ]; then
    447     ret=`validate_reason "reboot,${val}"`
    448   fi
    449   echo ${ret}
    450 }
    451 
    452 #
    453 # Actual test frames
    454 #
    455 
    456 [ "USAGE: test_properties
    457 
    458 properties test
    459 - (wait until screen is up, boot has completed)
    460 - adb shell getprop ro.boot.bootreason (bootloader reason)
    461 - adb shell getprop persist.sys.boot.reason (last reason)
    462 - adb shell getprop sys.boot.reason (system reason)
    463 - NB: all should have a value that is compliant with our known set." ]
    464 test_properties() {
    465   duration_test 1
    466   wait_for_screen
    467   retval=0
    468   check_set="ro.boot.bootreason persist.sys.boot.reason sys.boot.reason"
    469   bootloader=""
    470   # NB: this test could fail if performed _after_ optional_factory_reset test
    471   # and will report
    472   #  ERROR: expected "reboot" got ""
    473   #        for Android property persist.sys.boot.reason
    474   # following is mitigation for the persist.sys.boot.reason, skip it
    475   if [ "reboot,factory_reset" = "`validate_property ro.boot_bootreason`" ]; then
    476     check_set="ro.boot.bootreason sys.boot.reason"
    477     bootloader="bootloader"
    478   fi
    479   for prop in ${check_set}; do
    480     reason=`validate_property ${prop}`
    481     EXPECT_PROPERTY ${prop} ${reason} || retval=${?}
    482   done
    483   # sys.boot.reason is last for a reason
    484   report_bootstat_logs ${reason} ${bootloader}
    485   return ${retval}
    486 }
    487 
    488 [ "USAGE: test_ota
    489 
    490 ota test
    491 - rm out/.kati_stamp-* out/build_date.txt out/build_number.txt
    492 - rm out/target/product/*/*/*.prop
    493 - rm -r out/target/product/*/obj/ETC/system_build_prop_intermediates
    494 - m
    495 - NB: ro.build.date.utc should update
    496 - fastboot flashall
    497 - (wait until screen is up, boot has completed)
    498 - adb shell getprop sys.boot.reason
    499 - NB: should report ota
    500 
    501 Decision to change the build itself rather than trick bootstat by
    502 rummaging through its data files was made." ]
    503 test_ota() {
    504   duration_test ">300"
    505   echo "      extended by build and flashing times" >&2
    506   if [ -z "${TARGET_PRODUCT}" -o \
    507        -z "${ANDROID_PRODUCT_OUT}" -o \
    508        -z "${ANDROID_BUILD_TOP}" -o \
    509        -z "${TARGET_BUILD_VARIANT}" ]; then
    510     echo "ERROR: Missing envsetup.sh and lunch" >&2
    511     return 1
    512   fi
    513   rm ${ANDROID_PRODUCT_OUT%/out/*}/out/.kati_stamp-* ||
    514     true
    515   rm ${ANDROID_PRODUCT_OUT%/out/*}/out/build_date.txt ||
    516     true
    517   rm ${ANDROID_PRODUCT_OUT%/out/*}/out/build_number.txt ||
    518     true
    519   rm ${ANDROID_PRODUCT_OUT}/*/*.prop ||
    520     true
    521   rm -r ${ANDROID_PRODUCT_OUT}/obj/ETC/system_build_prop_intermediates ||
    522     true
    523   pushd ${ANDROID_BUILD_TOP} >&2
    524   make -j50 >&2
    525   if [ ${?} != 0 ]; then
    526     popd >&2
    527     return 1
    528   fi
    529   if ! inFastboot; then
    530     adb reboot-bootloader >&2
    531   fi
    532   fastboot flashall >&2
    533   popd >&2
    534   wait_for_screen
    535   EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
    536   EXPECT_PROPERTY persist.sys.boot.reason bootloader
    537   report_bootstat_logs reboot,ota bootloader
    538 }
    539 
    540 [ "USAGE: test_optional_ota
    541 
    542 fast and fake (touch build_date on device to make it different)" ]
    543 test_optional_ota() {
    544   checkDebugBuild || return
    545   duration_test
    546   adb shell su root touch /data/misc/bootstat/build_date >&2
    547   adb reboot ota
    548   wait_for_screen
    549   EXPECT_PROPERTY sys.boot.reason reboot,ota
    550   EXPECT_PROPERTY persist.sys.boot.reason reboot,ota
    551   report_bootstat_logs reboot,ota
    552 }
    553 
    554 [ "USAGE: [TEST=<test>] blind_reboot_test
    555 
    556 Simple tests helper
    557 - adb reboot <test>
    558 - (wait until screen is up, boot has completed)
    559 - adb shell getprop sys.boot.reason
    560 - NB: should report <test>, or reboot,<test> depending on canonical rules
    561 
    562 We interleave the simple reboot tests between the hard/complex ones
    563 as a means of checking sanity and any persistent side effect of the
    564 other tests." ]
    565 blind_reboot_test() {
    566   duration_test
    567   case ${TEST} in
    568     bootloader | recovery | cold | hard | warm ) reason=${TEST} ;;
    569     *)                                           reason=reboot,${TEST} ;;
    570   esac
    571   adb reboot ${TEST}
    572   wait_for_screen
    573   bootloader_reason=`validate_property ro.boot.bootreason`
    574   EXPECT_PROPERTY ro.boot.bootreason ${bootloader_reason}
    575   EXPECT_PROPERTY sys.boot.reason ${reason}
    576   EXPECT_PROPERTY persist.sys.boot.reason ${reason}
    577   report_bootstat_logs ${reason}
    578 }
    579 
    580 [ "USAGE: test_cold
    581 
    582 cold test
    583 - adb reboot cold
    584 - (wait until screen is up, boot has completed)
    585 - adb shell getprop sys.boot.reason
    586 - NB: should report cold" ]
    587 test_cold() {
    588   blind_reboot_test
    589 }
    590 
    591 [ "USAGE: test_factory_reset
    592 
    593 factory_reset test
    594 - adb shell su root rm /data/misc/bootstat/build_date
    595 - adb reboot
    596 - (wait until screen is up, boot has completed)
    597 - adb shell getprop sys.boot.reason
    598 - NB: should report factory_reset
    599 
    600 Decision to rummage through bootstat data files was made as
    601 a _real_ factory_reset is too destructive to the device." ]
    602 test_factory_reset() {
    603   checkDebugBuild || return
    604   duration_test
    605   adb shell su root rm /data/misc/bootstat/build_date >&2
    606   adb reboot >&2
    607   wait_for_screen
    608   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
    609   EXPECT_PROPERTY persist.sys.boot.reason "reboot,.*"
    610   report_bootstat_logs reboot,factory_reset reboot, reboot,adb \
    611     "-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \
    612     "-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date"
    613 }
    614 
    615 [ "USAGE: test_optional_factory_reset
    616 
    617 factory_reset test
    618 - adb reboot-bootloader
    619 - fastboot format userdata
    620 - fastboot reboot
    621 - (wait until screen is up, boot has completed)
    622 - adb shell getprop sys.boot.reason
    623 - NB: should report factory_reset
    624 
    625 For realz, and disruptive" ]
    626 test_optional_factory_reset() {
    627   duration_test 60
    628   if ! inFastboot; then
    629     adb reboot-bootloader
    630   fi
    631   fastboot format userdata >&2
    632   save_ret=${?}
    633   if [ 0 != ${save_ret} ]; then
    634     echo "ERROR: fastboot can not format userdata" >&2
    635   fi
    636   fastboot reboot >&2
    637   wait_for_screen
    638   ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
    639   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
    640   EXPECT_PROPERTY persist.sys.boot.reason ""
    641   report_bootstat_logs reboot,factory_reset bootloader \
    642     "-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \
    643     "-bootstat: Failed to parse boot time record: /data/misc/bootstat/last_boot_time_utc" \
    644     "-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \
    645     "-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date" \
    646     "-bootstat: Failed to read /data/misc/bootstat/factory_reset: No such file or directory" \
    647     "-bootstat: Failed to parse boot time record: /data/misc/bootstat/factory_reset"
    648 }
    649 
    650 [ "USAGE: test_hard
    651 
    652 hard test:
    653 - adb reboot hard
    654 - (wait until screen is up, boot has completed)
    655 - adb shell getprop sys.boot.reason
    656 - NB: should report hard" ]
    657 test_hard() {
    658   blind_reboot_test
    659 }
    660 
    661 [ "USAGE: test_battery
    662 
    663 battery test (trick):
    664 - echo healthd: battery l=2<space> | adb shell su root tee /dev/kmsg
    665 - adb reboot cold
    666 - (wait until screen is up, boot has completed)
    667 - adb shell getprop sys.boot.reason
    668 - NB: should report reboot,battery, unless healthd managed to log
    669   before reboot in above trick.
    670 
    671 - Bonus points (manual extras)
    672 - Make sure the following is added to the /init.rc file in post-fs
    673   section before logd is started:
    674     +    setprop logd.kernel false
    675     +    rm /sys/fs/pstore/console-ramoops
    676     +    rm /sys/fs/pstore/console-ramoops-0
    677     +    write /dev/kmsg \"healthd: battery l=2${SPACE}
    678     +\"
    679 - adb reboot fs
    680 - (wait until screen is up, boot has completed)
    681 - adb shell getprop sys.boot.reason
    682 - NB: should report reboot,battery
    683 - (replace set logd.kernel true to the above, and retry test)" ]
    684 test_battery() {
    685   checkDebugBuild || return
    686   duration_test 120
    687   enterPstore
    688   # Send it _many_ times to combat devices with flakey pstore
    689   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
    690     echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
    691   done
    692   adb reboot cold >&2
    693   adb wait-for-device
    694   wait_for_screen
    695   adb shell su root \
    696     cat /proc/fs/pstore/console-ramoops \
    697         /proc/fs/pstore/console-ramoops-0 2>/dev/null |
    698     grep 'healthd: battery l=' |
    699     tail -1 |
    700     grep 'healthd: battery l=2 ' >/dev/null || (
    701       if ! EXPECT_PROPERTY sys.boot.reason reboot,battery >/dev/null 2>/dev/null; then
    702         # retry
    703         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
    704           echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
    705         done
    706         adb reboot cold >&2
    707         adb wait-for-device
    708         wait_for_screen
    709       fi
    710     )
    711 
    712   EXPECT_PROPERTY sys.boot.reason shutdown,battery
    713   EXPECT_PROPERTY persist.sys.boot.reason cold
    714   report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
    715   exitPstore
    716 }
    717 
    718 [ "USAGE: test_optional_battery
    719 
    720 battery shutdown test:
    721 - adb shell setprop sys.powerctl shutdown,battery
    722 - (power up the device)
    723 - (wait until screen is up, boot has completed)
    724 - adb shell getprop sys.boot.reason
    725 - NB: should report shutdown,battery" ]
    726 test_optional_battery() {
    727   duration_test ">60"
    728   echo "      power on request" >&2
    729   adb shell setprop sys.powerctl shutdown,battery
    730   sleep 5
    731   echo -n "WARNING: Please power device back up, waiting ... " >&2
    732   wait_for_screen -n >&2
    733   EXPECT_PROPERTY sys.boot.reason shutdown,battery
    734   EXPECT_PROPERTY persist.sys.boot.reason shutdown,battery
    735   report_bootstat_logs shutdown,battery
    736 }
    737 
    738 [ "USAGE: test_optional_battery_thermal
    739 
    740 battery thermal shutdown test:
    741 - adb shell setprop sys.powerctl shutdown,thermal,battery
    742 - (power up the device)
    743 - (wait until screen is up, boot has completed)
    744 - adb shell getprop sys.boot.reason
    745 - NB: should report shutdown,thermal,battery" ]
    746 test_optional_battery_thermal() {
    747   duration_test ">60"
    748   echo "      power on request" >&2
    749   adb shell setprop sys.powerctl shutdown,thermal,battery
    750   sleep 5
    751   echo -n "WARNING: Please power device back up, waiting ... " >&2
    752   wait_for_screen -n >&2
    753   EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery
    754   EXPECT_PROPERTY persist.sys.boot.reason shutdown,thermal,battery
    755   report_bootstat_logs shutdown,thermal,battery
    756 }
    757 
    758 [ "USAGE: test_unknown
    759 
    760 unknown test
    761 - adb reboot unknown
    762 - (wait until screen is up, boot has completed)
    763 - adb shell getprop sys.boot.reason
    764 - NB: should report reboot,unknown
    765 - NB: expect log \"... I bootstat: Unknown boot reason: reboot,unknown\"" ]
    766 test_unknown() {
    767   blind_reboot_test
    768 }
    769 
    770 [ "USAGE: test_kernel_panic
    771 
    772 kernel_panic test:
    773 - echo c | adb shell su root tee /proc/sysrq-trigger
    774 - (wait until screen is up, boot has completed)
    775 - adb shell getprop sys.boot.reason
    776 - NB: should report kernel_panic,sysrq" ]
    777 test_kernel_panic() {
    778   checkDebugBuild || return
    779   duration_test ">90"
    780   panic_msg="kernel_panic,sysrq"
    781   enterPstore
    782   if [ ${?} != 0 ]; then
    783     echo "         or functional bootloader" >&2
    784     panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
    785     pstore_ok=true
    786   fi
    787   echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
    788   wait_for_screen
    789   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
    790   EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg}
    791   report_bootstat_logs kernel_panic,sysrq
    792   exitPstore
    793 }
    794 
    795 [ "USAGE: test_warm
    796 
    797 warm test
    798 - adb reboot warm
    799 - (wait until screen is up, boot has completed)
    800 - adb shell getprop sys.boot.reason
    801 - NB: should report warm" ]
    802 test_warm() {
    803   blind_reboot_test
    804 }
    805 
    806 [ "USAGE: test_thermal_shutdown
    807 
    808 thermal shutdown test:
    809 - adb shell setprop sys.powerctl shutdown,thermal
    810 - (power up the device)
    811 - (wait until screen is up, boot has completed)
    812 - adb shell getprop sys.boot.reason
    813 - NB: should report shutdown,thermal" ]
    814 test_thermal_shutdown() {
    815   duration_test ">60"
    816   echo "      power on request" >&2
    817   adb shell setprop sys.powerctl shutdown,thermal
    818   sleep 5
    819   echo -n "WARNING: Please power device back up, waiting ... " >&2
    820   wait_for_screen -n >&2
    821   EXPECT_PROPERTY sys.boot.reason shutdown,thermal
    822   EXPECT_PROPERTY persist.sys.boot.reason shutdown,thermal
    823   report_bootstat_logs shutdown,thermal
    824 }
    825 
    826 [ "USAGE: test_userrequested_shutdown
    827 
    828 userrequested shutdown test:
    829 - adb shell setprop sys.powerctl shutdown,userrequested
    830 - (power up the device)
    831 - (wait until screen is up, boot has completed)
    832 - adb shell getprop sys.boot.reason
    833 - NB: should report shutdown,userrequested" ]
    834 test_userrequested_shutdown() {
    835   duration_test ">60"
    836   echo "      power on request" >&2
    837   adb shell setprop sys.powerctl shutdown,userrequested
    838   sleep 5
    839   echo -n "WARNING: Please power device back up, waiting ... " >&2
    840   wait_for_screen -n >&2
    841   EXPECT_PROPERTY sys.boot.reason shutdown,userrequested
    842   EXPECT_PROPERTY persist.sys.boot.reason shutdown,userrequested
    843   report_bootstat_logs shutdown,userrequested
    844 }
    845 
    846 [ "USAGE: test_shell_reboot
    847 
    848 shell reboot test:
    849 - adb shell reboot
    850 - (wait until screen is up, boot has completed)
    851 - adb shell getprop sys.boot.reason
    852 - NB: should report reboot,shell" ]
    853 test_shell_reboot() {
    854   duration_test
    855   adb shell reboot
    856   wait_for_screen
    857   EXPECT_PROPERTY sys.boot.reason reboot,shell
    858   EXPECT_PROPERTY persist.sys.boot.reason reboot,shell
    859   report_bootstat_logs reboot,shell
    860 }
    861 
    862 [ "USAGE: test_adb_reboot
    863 
    864 adb reboot test:
    865 - adb reboot
    866 - (wait until screen is up, boot has completed)
    867 - adb shell getprop sys.boot.reason
    868 - NB: should report reboot,adb" ]
    869 test_adb_reboot() {
    870   duration_test
    871   adb reboot
    872   wait_for_screen
    873   EXPECT_PROPERTY sys.boot.reason reboot,adb
    874   EXPECT_PROPERTY persist.sys.boot.reason reboot,adb
    875   report_bootstat_logs reboot,adb
    876 }
    877 
    878 [ "USAGE: test_Its_Just_So_Hard_reboot
    879 
    880 Its Just So Hard reboot test:
    881 - adb shell reboot 'Its Just So Hard'
    882 - (wait until screen is up, boot has completed)
    883 - adb shell getprop sys.boot.reason
    884 - NB: should report reboot,its_just_so_hard
    885 - NB: expect log \"... I bootstat: Unknown boot reason: reboot,its_just_so_hard\"" ]
    886 test_Its_Just_So_Hard_reboot() {
    887   if isDebuggable; then       # see below
    888     duration_test
    889   else
    890     duration_test `expr ${DURATION_DEFAULT} + ${DURATION_DEFAULT}`
    891   fi
    892   adb shell 'reboot "Its Just So Hard"'
    893   wait_for_screen
    894   EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
    895   EXPECT_PROPERTY persist.sys.boot.reason "reboot,Its Just So Hard"
    896   # Do not leave this test with an illegal value in persist.sys.boot.reason
    897   save_ret=${?}           # hold on to error code from above two lines
    898   if isDebuggable; then   # can do this easy, or we can do this hard.
    899     adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
    900     ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
    901   else
    902     report_bootstat_logs reboot,its_just_so_hard  # report what we have so far
    903     # user build mitigation
    904     adb shell reboot its_just_so_hard
    905     wait_for_screen
    906     ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
    907     EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
    908   fi
    909   # Ensure persist.sys.boot.reason now valid, failure here acts as a signal
    910   # that we could choke up following tests.  For example test_properties.
    911   EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard ${flag}
    912   report_bootstat_logs reboot,its_just_so_hard
    913 }
    914 
    915 [ "USAGE: run_bootloader [value [expected]]
    916 
    917 bootloader boot reason injection tests:
    918 - setBootloaderBootReason value
    919 - adb shell reboot
    920 - (wait until screen is up, boot has completed)
    921 - adb shell getprop sys.boot.reason
    922 - NB: should report reboot,value" ]
    923 run_bootloader() {
    924   bootloader_expected="${1}"
    925   if [ -z "${bootloader_expected}" ]; then
    926     bootloader_expected="${TEST#bootloader_}"
    927   fi
    928   if ! setBootloaderBootReason ${bootloader_expected}; then
    929     echo "       Skipping FAILURE." 2>&1
    930     return
    931   fi
    932   duration_test
    933   if [ X"warm" = X"${bootloader_expected}" ]; then
    934     last_expected=cold
    935   else
    936     last_expected=warm
    937   fi
    938   adb reboot ${last_expected}
    939   wait_for_screen
    940   # Reset so that other tests do not get unexpected injection
    941   setBootloaderBootReason
    942   # Determine the expected values
    943   sys_expected="${2}"
    944   if [ -z "${sys_expected}" ]; then
    945     sys_expected="`validate_reason ${bootloader_expected}`"
    946     if [ "reboot" = "${sys_expected}" ]; then
    947       sys_expected="${last_expected}"
    948     fi
    949   else
    950     sys_expected=`validate_reason ${sys_expected}`
    951   fi
    952   case ${sys_expected} in
    953     kernel_panic | kernel_panic,* | watchdog | watchdog,* )
    954       last_expected=${sys_expected}
    955       ;;
    956   esac
    957   # Check values
    958   EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}"
    959   EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
    960   EXPECT_PROPERTY persist.sys.boot.reason "${last_expected}"
    961   report_bootstat_logs "${sys_expected}"
    962 }
    963 
    964 [ "USAGE: test_bootloader_<type>
    965 
    966 bootloader boot reasons test injection" ]
    967 test_bootloader_normal() {
    968   run_bootloader
    969 }
    970 
    971 test_bootloader_watchdog() {
    972   run_bootloader
    973 }
    974 
    975 test_bootloader_kernel_panic() {
    976   run_bootloader
    977 }
    978 
    979 test_bootloader_oem_powerkey() {
    980   run_bootloader
    981 }
    982 
    983 test_bootloader_wdog_reset() {
    984   run_bootloader
    985 }
    986 
    987 test_bootloader_cold() {
    988   run_bootloader
    989 }
    990 
    991 test_bootloader_warm() {
    992   run_bootloader
    993 }
    994 
    995 test_bootloader_hard() {
    996   run_bootloader
    997 }
    998 
    999 test_bootloader_recovery() {
   1000   run_bootloader
   1001 }
   1002 
   1003 [ "USAGE: ${0##*/} [-s SERIAL] [tests]
   1004 
   1005 Mainline executive to run the above tests" ]
   1006 
   1007 # Rudimentary argument parsing
   1008 
   1009 if [ ${#} -ge 2 -a X"-s" = X"${1}" ]; then
   1010   export ANDROID_SERIAL="${2}"
   1011   shift 2
   1012 fi
   1013 
   1014 if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
   1015   echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
   1016   echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
   1017   exit 0
   1018 fi
   1019 
   1020 # Check if all conditions for the script are sane
   1021 
   1022 if [ -z "${ANDROID_SERIAL}" ]; then
   1023   ndev=`(
   1024       adb devices | grep -v 'List of devices attached'
   1025       fastboot devices
   1026     ) |
   1027     grep -v "^[${SPACE}${TAB}]*\$" |
   1028     wc -l`
   1029   if [ ${ndev} -gt 1 ]; then
   1030     echo "ERROR: no target device specified, ${ndev} connected" >&2
   1031     echo "${RED}[  FAILED  ]${NORMAL}"
   1032     exit 1
   1033   fi
   1034   echo "WARNING: no target device specified" >&2
   1035 fi
   1036 
   1037 ret=0
   1038 
   1039 # Test Series
   1040 if [ X"all" = X"${*}" ]; then
   1041   # automagically pick up all test_<function>s.
   1042   eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
   1043   if [ X"nothing" = X"${1}" ]; then
   1044     shift 1
   1045   fi
   1046 fi
   1047 if [ -z "$*" ]; then
   1048   # automagically pick up all test_<function>, except test_optional_<function>.
   1049   eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
   1050                             grep -v '^optional_'`
   1051   if [ -z "${2}" ]; then
   1052     # Hard coded should shell fail to find them above (search/permission issues)
   1053     eval set properties ota cold factory_reset hard battery unknown \
   1054              kernel_panic warm thermal_shutdown userrequested_shutdown \
   1055              shell_reboot adb_reboot Its_Just_So_Hard_reboot \
   1056              bootloader_normal bootloader_watchdog bootloader_kernel_panic \
   1057              bootloader_oem_powerkey bootloader_wdog_reset \
   1058              bootloader_wdog_reset bootloader_wdog_reset bootloader_hard \
   1059              bootloader_recovery
   1060   fi
   1061   if [ X"nothing" = X"${1}" ]; then
   1062     shift 1
   1063   fi
   1064 fi
   1065 echo "INFO: selected test(s): ${@}" >&2
   1066 echo
   1067 # Prepare device
   1068 setBootloaderBootReason 2>/dev/null
   1069 # Start pouring through the tests.
   1070 failures=
   1071 successes=
   1072 for t in "${@}"; do
   1073   wrap_test ${t}
   1074   retval=${?}
   1075   if [ 0 = ${retval} ]; then
   1076     if [ -z "${successes}" ]; then
   1077       successes=${t}
   1078     else
   1079       successes="${successes} ${t}"
   1080     fi
   1081   else
   1082     ret=${retval}
   1083     if [ -z "${failures}" ]; then
   1084       failures=${t}
   1085     else
   1086       failures="${failures} ${t}"
   1087     fi
   1088   fi
   1089   echo
   1090 done
   1091 
   1092 if [ -n "${successes}" ]; then
   1093   echo "${GREEN}[  PASSED  ]${NORMAL} ${successes}"
   1094 fi
   1095 if [ -n "${failures}" ]; then
   1096   echo "${RED}[  FAILED  ]${NORMAL} ${failures}"
   1097 fi
   1098 exit ${ret}
   1099