1#! /bin/bash
2#
3# Divided into four section:
4#
5##  USAGE
6##  Helper Variables
7##  Helper Functions
8##  MAINLINE
9
10##
11##  USAGE
12##
13
14USAGE="USAGE: `basename ${0}` [--help] [--serial <SerialNumber>] [options]
15
16adb remount tests
17
18--color                     Dress output with highlighting colors
19--help                      This help
20--no-wait-screen            Do not wait for display screen to settle
21--print-time                Report the test duration
22--serial                    Specify device (must if multiple are present)
23--wait-adb <duration>       adb wait timeout
24--wait-fastboot <duration>  fastboot wait timeout
25
26Conditions:
27 - Must be a userdebug build.
28 - Must be in adb mode.
29 - Also tests overlayfs
30  - Kernel must have overlayfs enabled and patched to support override_creds.
31  - Must have either erofs, squashfs, ext4-dedupe or full partitions.
32  - Minimum expectation system and vender are overlayfs covered partitions.
33"
34
35##
36##  Helper Variables
37##
38
39EMPTY=""
40SPACE=" "
41# Line up wrap to [  XXXXXXX ] messages.
42INDENT="             "
43# A _real_ embedded tab character
44TAB="`echo | tr '\n' '\t'`"
45# A _real_ embedded escape character
46ESCAPE="`echo | tr '\n' '\033'`"
47# A _real_ embedded carriage return character
48CR="`echo | tr '\n' '\r'`"
49GREEN="${ESCAPE}[38;5;40m"
50RED="${ESCAPE}[38;5;196m"
51ORANGE="${ESCAPE}[38;5;255:165:0m"
52BLUE="${ESCAPE}[35m"
53NORMAL="${ESCAPE}[0m"
54TMPDIR=${TMPDIR:-/tmp}
55print_time=false
56start_time=`date +%s`
57ACTIVE_SLOT=
58
59ADB_WAIT=4m
60FASTBOOT_WAIT=2m
61screen_wait=true
62
63##
64##  Helper Functions
65##
66
67[ "USAGE: inFastboot
68
69Returns: true if device is in fastboot mode" ]
70inFastboot() {
71  fastboot devices |
72    if [ -n "${ANDROID_SERIAL}" ]; then
73      grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
74    else
75      wc -l | grep '^1$' >/dev/null
76    fi
77}
78
79[ "USAGE: inAdb
80
81Returns: true if device is in adb mode" ]
82inAdb() {
83  adb devices |
84    grep -v -e 'List of devices attached' -e '^$' -e "[${SPACE}${TAB}]recovery\$" |
85    if [ -n "${ANDROID_SERIAL}" ]; then
86      grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
87    else
88      wc -l | grep '^1$' >/dev/null
89    fi
90}
91
92[ "USAGE: inRecovery
93
94Returns: true if device is in recovery mode" ]
95inRecovery() {
96  local list="`adb devices |
97              grep -v -e 'List of devices attached' -e '^$'`"
98  if [ -n "${ANDROID_SERIAL}" ]; then
99    echo "${list}" |
100      grep "^${ANDROID_SERIAL}[${SPACE}${TAB}][${SPACE}${TAB}]*recovery\$" >/dev/null
101    return ${?}
102  fi
103  if echo "${list}" | wc -l | grep '^1$' >/dev/null; then
104    echo "${list}" |
105      grep "[${SPACE}${TAB}]recovery\$" >/dev/null
106    return ${?}
107  fi
108  false
109}
110
111[ "USAGE: adb_sh <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
112
113Returns: true if the command succeeded" ]
114adb_sh() {
115  local args=
116  for i in "${@}"; do
117    [ -z "${args}" ] || args="${args} "
118    if [ X"${i}" != X"${i#\'}" ]; then
119      args="${args}${i}"
120    elif [ X"${i}" != X"${i#* }" ]; then
121      args="${args}'${i}'"
122    elif [ X"${i}" != X"${i#*${TAB}}" ]; then
123      args="${args}'${i}'"
124    else
125      args="${args}${i}"
126    fi
127  done
128  adb shell "${args}"
129}
130
131[ "USAGE: adb_date >/dev/stdout
132
133Returns: report device epoch time (suitable for logcat -t)" ]
134adb_date() {
135  adb_sh date +%s.%N </dev/null
136}
137
138[ "USAGE: adb_logcat [arguments] >/dev/stdout
139
140Returns: the logcat output" ]
141adb_logcat() {
142  echo "${RED}[     INFO ]${NORMAL} logcat ${@}" >&2 &&
143  adb logcat "${@}" </dev/null |
144    tr -d '\r' |
145    grep -v 'logd    : logdr: UID=' |
146    sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
147}
148
149[ "USAGE: avc_check >/dev/stderr
150
151Returns: worrisome avc violations" ]
152avc_check() {
153  if ! ${overlayfs_supported:-false}; then
154    return
155  fi
156  local L=`adb_logcat -b all -v brief -d \
157                      -e 'context=u:object_r:unlabeled:s0' 2>/dev/null |
158             sed -n 's/.*avc: //p' |
159             sort -u`
160  if [ -z "${L}" ]; then
161    return
162  fi
163  echo "${ORANGE}[  WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2
164  echo "${L}" | sed "s/^/${INDENT}/" >&2
165}
166
167[ "USAGE: get_property <prop>
168
169Returns the property value" ]
170get_property() {
171  adb_sh getprop ${1} </dev/null
172}
173
174[ "USAGE: isDebuggable
175
176Returns: true if device is (likely) a debug build" ]
177isDebuggable() {
178  if inAdb && [ 1 != "`get_property ro.debuggable`" ]; then
179    false
180  fi
181}
182
183[ "USAGE: adb_su <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
184
185Returns: true if the command running as root succeeded" ]
186adb_su() {
187  adb_sh su root "${@}"
188}
189
190[ "USAGE: adb_cat <file> >stdout
191
192Returns: content of file to stdout with carriage returns skipped,
193         true if the file exists" ]
194adb_cat() {
195    local OUTPUT="`adb_sh cat ${1} </dev/null 2>&1`"
196    local ret=${?}
197    echo "${OUTPUT}" | tr -d '\r'
198    return ${ret}
199}
200
201[ "USAGE: adb_ls <dirfile> >stdout
202
203Returns: filename or directoru content to stdout with carriage returns skipped,
204         true if the ls had no errors" ]
205adb_ls() {
206    local OUTPUT="`adb_sh ls ${1} </dev/null 2>/dev/null`"
207    local ret=${?}
208    echo "${OUTPUT}" | tr -d '\r'
209    return ${ret}
210}
211
212[ "USAGE: adb_reboot
213
214Returns: true if the reboot command succeeded" ]
215adb_reboot() {
216  avc_check
217  adb reboot remount-test </dev/null || true
218  sleep 2
219}
220
221[ "USAGE: format_duration [<seconds>|<seconds>s|<minutes>m|<hours>h|<days>d]
222
223human readable output whole seconds, whole minutes or mm:ss" ]
224format_duration() {
225  if [ -z "${1}" ]; then
226    echo unknown
227    return
228  fi
229  local duration="${1}"
230  if [ X"${duration}" != X"${duration%s}" ]; then
231    duration=${duration%s}
232  elif [ X"${duration}" != X"${duration%m}" ]; then
233    duration=`expr ${duration%m} \* 60`
234  elif [ X"${duration}" != X"${duration%h}" ]; then
235    duration=`expr ${duration%h} \* 3600`
236  elif [ X"${duration}" != X"${duration%d}" ]; then
237    duration=`expr ${duration%d} \* 86400`
238  fi
239  local seconds=`expr ${duration} % 60`
240  local minutes=`expr \( ${duration} / 60 \) % 60`
241  local hours=`expr ${duration} / 3600`
242  if [ 0 -eq ${minutes} -a 0 -eq ${hours} ]; then
243    if [ 1 -eq ${duration} ]; then
244      echo 1 second
245      return
246    fi
247    echo ${duration} seconds
248    return
249  elif [ 60 -eq ${duration} ]; then
250    echo 1 minute
251    return
252  elif [ 0 -eq ${seconds} -a 0 -eq ${hours} ]; then
253    echo ${minutes} minutes
254    return
255  fi
256  if [ 0 -eq ${hours} ]; then
257    echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10`
258    return
259  fi
260  echo ${hours}:`expr ${minutes} / 10``expr ${minutes} % 10`:`expr ${seconds} / 10``expr ${seconds} % 10`
261}
262
263[ "USAGE: USB_DEVICE=\`usb_devnum [--next]\`
264
265USB_DEVICE contains cache. Update if system changes.
266
267Returns: the devnum for the USB_SERIAL device" ]
268usb_devnum() {
269  if [ -n "${USB_SERIAL}" ]; then
270    local usb_device=`cat ${USB_SERIAL%/serial}/devnum 2>/dev/null | tr -d ' \t\r\n'`
271    if [ -n "${usb_device}" ]; then
272      USB_DEVICE=dev${usb_device}
273    elif [ -n "${USB_DEVICE}" -a "${1}" ]; then
274      USB_DEVICE=dev`expr ${USB_DEVICE#dev} + 1`
275    fi
276    echo "${USB_DEVICE}"
277  fi
278}
279
280[ "USAGE: adb_wait [timeout]
281
282Returns: waits until the device has returned for adb or optional timeout" ]
283adb_wait() {
284  local start=`date +%s`
285  local duration=
286  local ret
287  if [ -n "${1}" ]; then
288    USB_DEVICE=`usb_devnum --next`
289    duration=`format_duration ${1}`
290    echo -n ". . . waiting ${duration}" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}"
291    timeout --preserve-status --signal=KILL ${1} adb wait-for-device 2>/dev/null
292    ret=${?}
293    echo -n "                                                                             ${CR}"
294  else
295    adb wait-for-device
296    ret=${?}
297  fi
298  USB_DEVICE=`usb_devnum`
299  if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
300    local active_slot=`get_active_slot`
301    if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
302      echo "${ORANGE}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" >&2
303    fi
304  fi
305  local end=`date +%s`
306  local diff_time=`expr ${end} - ${start}`
307  local _print_time=${print_time}
308  if [ ${diff_time} -lt 15 ]; then
309    _print_time=false
310  fi
311  diff_time=`format_duration ${diff_time}`
312  if [ "${diff_time}" = "${duration}" ]; then
313    _print_time=false
314  fi
315
316  local reason=
317  if inAdb; then
318    reason=`get_property ro.boot.bootreason`
319  fi
320  case ${reason} in
321    reboot*)
322      reason=
323      ;;
324    ${EMPTY})
325      ;;
326    *)
327      reason=" for boot reason ${reason}"
328      ;;
329  esac
330  if ${_print_time} || [ -n "${reason}" ]; then
331    echo "${BLUE}[     INFO ]${NORMAL} adb wait duration ${diff_time}${reason}"
332  fi >&2
333
334  return ${ret}
335}
336
337[ "USAGE: adb_user > /dev/stdout
338
339Returns: the adb daemon user" ]
340adb_user() {
341  adb_sh echo '${USER}' </dev/null
342}
343
344[ "USAGE: usb_status > stdout 2> stderr
345
346Assumes referenced right after adb_wait or fastboot_wait failued.
347If wait failed, check if device is in adb, recovery or fastboot mode
348and report status strings like  \"(USB stack borken?)\",
349\"(In fastboot mode)\", \"(In recovery mode)\" or \"(in adb mode)\".
350Additional diagnostics may be provided to the stderr output.
351
352Returns: USB status string" ]
353usb_status() {
354  if inFastboot; then
355    echo "(In fastboot mode)"
356  elif inRecovery; then
357    echo "(In recovery mode)"
358  elif inAdb; then
359    echo "(In adb mode `adb_user`)"
360  else
361    echo "(USB stack borken for ${USB_ADDRESS})"
362    USB_DEVICE=`usb_devnum`
363    if [ -n "${USB_DEVICE}" ]; then
364      echo "# lsusb -v -s ${USB_DEVICE#dev}"
365      local D=`lsusb -v -s ${USB_DEVICE#dev} 2>&1`
366      if [ -n "${D}" ]; then
367        echo "${D}"
368      else
369        lsusb -v
370      fi
371    else
372      echo "# lsusb -v (expected device missing)"
373      lsusb -v
374    fi >&2
375  fi
376}
377
378[ "USAGE: fastboot_wait [timeout]
379
380Returns: waits until the device has returned for fastboot or optional timeout" ]
381fastboot_wait() {
382  local ret
383  # fastboot has no wait-for-device, but it does an automatic
384  # wait and requires (even a nonsensical) command to do so.
385  if [ -n "${1}" ]; then
386    USB_DEVICE=`usb_devnum --next`
387    echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}"
388    timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device >/dev/null 2>/dev/null
389    ret=${?}
390    echo -n "                                                                             ${CR}"
391    ( exit ${ret} )
392  else
393    fastboot wait-for-device >/dev/null 2>/dev/null
394  fi ||
395    inFastboot
396  ret=${?}
397  USB_DEVICE=`usb_devnum`
398  if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
399    local active_slot=`get_active_slot`
400    if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
401      echo "${ORANGE}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
402    fi >&2
403  fi
404  return ${ret}
405}
406
407[ "USAGE: recovery_wait [timeout]
408
409Returns: waits until the device has returned for recovery or optional timeout" ]
410recovery_wait() {
411  local ret
412  if [ -n "${1}" ]; then
413    USB_DEVICE=`usb_devnum --next`
414    echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}"
415    timeout --preserve-status --signal=KILL ${1} adb wait-for-recovery 2>/dev/null
416    ret=${?}
417    echo -n "                                                                             ${CR}"
418  else
419    adb wait-for-recovery
420    ret=${?}
421  fi
422  USB_DEVICE=`usb_devnum`
423  if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
424    local active_slot=`get_active_slot`
425    if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
426      echo "${ORANGE}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
427    fi >&2
428  fi
429  return ${ret}
430}
431
432[ "any_wait [timeout]
433
434Returns: waits until a device has returned or optional timeout" ]
435any_wait() {
436  (
437    adb_wait ${1} &
438    adb_pid=${!}
439    fastboot_wait ${1} &
440    fastboot_pid=${!}
441    recovery_wait ${1} &
442    recovery_pid=${!}
443    wait -n
444    kill "${adb_pid}" "${fastboot_pid}" "${recovery_pid}"
445  ) >/dev/null 2>/dev/null
446  inFastboot || inAdb || inRecovery
447}
448
449wait_for_screen_timeout=900
450[ "USAGE: wait_for_screen [-n] [TIMEOUT]
451
452-n - echo newline at exit
453TIMEOUT - default `format_duration ${wait_for_screen_timeout}`" ]
454wait_for_screen() {
455  if ! ${screen_wait}; then
456    adb_wait
457    return
458  fi
459  exit_function=true
460  if [ X"-n" = X"${1}" ]; then
461    exit_function=echo
462    shift
463  fi
464  timeout=${wait_for_screen_timeout}
465  if [ ${#} -gt 0 ]; then
466    timeout=${1}
467    shift
468  fi
469  counter=0
470  while true; do
471    if inFastboot; then
472      fastboot reboot
473    elif inAdb; then
474      if [ 0 != ${counter} ]; then
475        adb_wait
476      fi
477      if [ -n "`get_property sys.boot.reason`" ]
478      then
479        vals=`get_property |
480              sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
481        if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
482        then
483          sleep 1
484          break
485        fi
486        if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
487        then
488          sleep 1
489          break
490        fi
491      fi
492    fi
493    counter=`expr ${counter} + 1`
494    if [ ${counter} -gt ${timeout} ]; then
495      ${exit_function}
496      echo "ERROR: wait_for_screen() timed out (`format_duration ${timeout}`)" >&2
497      return 1
498    fi
499    sleep 1
500  done
501  ${exit_function}
502}
503
504[ "USAGE: adb_root
505
506NB: This can be flakey on devices due to USB state
507
508Returns: true if device in root state" ]
509adb_root() {
510  [ root != "`adb_user`" ] || return 0
511  adb root >/dev/null </dev/null 2>/dev/null
512  sleep 2
513  adb_wait ${ADB_WAIT} &&
514    [ root = "`adb_user`" ]
515}
516
517[ "USAGE: adb_unroot
518
519NB: This can be flakey on devices due to USB state
520
521Returns: true if device in un root state" ]
522adb_unroot() {
523  [ root = "`adb_user`" ] || return 0
524  adb unroot >/dev/null </dev/null 2>/dev/null
525  sleep 2
526  adb_wait ${ADB_WAIT} &&
527    [ root != "`adb_user`" ]
528}
529
530[ "USAGE: fastboot_getvar var expected >/dev/stderr
531
532Returns: true if var output matches expected" ]
533fastboot_getvar() {
534  local O=`fastboot getvar ${1} 2>&1`
535  local ret=${?}
536  O="${O#< waiting for * >?}"
537  O="${O%%?Finished. Total time: *}"
538  if [ 0 -ne ${ret} ]; then
539    echo ${O} >&2
540    false
541    return
542  fi
543  if [ "${O}" != "${O#*FAILED}" ]; then
544    O="${1}: <empty>"
545  fi
546  if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
547    echo "${2} != ${O}"
548    false
549    return
550  fi >&2
551  echo ${O} >&2
552}
553
554[ "USAGE: get_active_slot >/dev/stdout
555
556Returns: with a or b string reporting active slot" ]
557get_active_slot() {
558  if inAdb || inRecovery; then
559    get_property ro.boot.slot_suffix | tr -d _
560  elif inFastboot; then
561    fastboot_getvar current-slot 2>&1 | sed -n 's/current-slot: //p'
562  else
563    false
564  fi
565}
566
567[ "USAGE: restore
568
569Do nothing: should be redefined when necessary.  Called after cleanup.
570
571Returns: reverses configurations" ]
572restore() {
573  true
574}
575
576[ "USAGE: cleanup
577
578Do nothing: should be redefined when necessary
579
580Returns: cleans up any latent resources" ]
581cleanup() {
582  true
583}
584
585[ "USAGE: test_duration >/dev/stderr
586
587Prints the duration of the test
588
589Returns: reports duration" ]
590test_duration() {
591  if ${print_time}; then
592    echo "${BLUE}[     INFO ]${NORMAL} end `date`"
593    [ -n "${start_time}" ] || return
594    end_time=`date +%s`
595    local diff_time=`expr ${end_time} - ${start_time}`
596    echo "${BLUE}[     INFO ]${NORMAL} duration `format_duration ${diff_time}`"
597  fi >&2
598}
599
600[ "USAGE: die [-d|-t <epoch>] [message] >/dev/stderr
601
602If -d, or -t <epoch> argument is supplied, dump logcat.
603
604Returns: exit failure, report status" ]
605die() {
606  if [ X"-d" = X"${1}" ]; then
607    adb_logcat -b all -v nsec -d
608    shift
609  elif [ X"-t" = X"${1}" ]; then
610    if [ -n "${2}" ]; then
611      adb_logcat -b all -v nsec -t ${2}
612    else
613      adb_logcat -b all -v nsec -d
614    fi
615    shift 2
616  fi >&2
617  echo "${RED}[  FAILED  ]${NORMAL} ${@}" >&2
618  cleanup
619  restore
620  test_duration
621  exit 1
622}
623
624[ "USAGE: EXPECT_EQ <lval> <rval> [--warning [message]]
625
626Returns true if (regex) lval matches rval" ]
627EXPECT_EQ() {
628  local lval="${1}"
629  local rval="${2}"
630  shift 2
631  local error=1
632  local prefix="${RED}[    ERROR ]${NORMAL}"
633  if [ X"${1}" = X"--warning" ]; then
634      prefix="${RED}[  WARNING ]${NORMAL}"
635      error=0
636      shift 1
637  fi
638  if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
639    if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
640*}" ]; then
641      echo "${prefix} expected \"${lval}\""
642      echo "${prefix} got \"${rval}\"" |
643        sed ": again
644             N
645             s/\(\n\)\([^ ]\)/\1${INDENT}\2/
646             t again"
647      if [ -n "${*}" ] ; then
648        echo "${prefix} ${*}"
649      fi
650    else
651      echo "${prefix} expected \"${lval}\" got \"${rval}\" ${*}"
652    fi >&2
653    return ${error}
654  fi
655  if [ -n "${*}" ] ; then
656    prefix="${GREEN}[     INFO ]${NORMAL}"
657    if [ X"${lval}" != X"${rval}" ]; then  # we were supplied a regex?
658      if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
659        echo "${prefix} ok \"${lval}\""
660        echo "       = \"${rval}\"" |
661          sed ": again
662               N
663               s/\(\n\)\([^ ]\)/\1${INDENT}\2/
664               t again"
665        if [ -n "${*}" ] ; then
666          echo "${prefix} ${*}"
667        fi
668      else
669        echo "${prefix} ok \"${lval}\" = \"${rval}\" ${*}"
670      fi
671    else
672      echo "${prefix} ok \"${lval}\" ${*}"
673    fi >&2
674  fi
675  return 0
676}
677
678[ "USAGE: EXPECT_NE <lval> <rval> [--warning [message]]
679
680Returns true if lval matches rval" ]
681EXPECT_NE() {
682  local lval="${1}"
683  local rval="${2}"
684  shift 2
685  local error=1
686  local prefix="${RED}[    ERROR ]${NORMAL}"
687  if [ X"${1}" = X"--warning" ]; then
688      prefix="${RED}[  WARNING ]${NORMAL}"
689      error=0
690      shift 1
691  fi
692  if [ X"${rval}" = X"${lval}" ]; then
693    echo "${prefix} did not expect \"${lval}\" ${*}" >&2
694    return ${error}
695  fi
696  if [ -n "${*}" ] ; then
697    echo "${prefix} ok \"${lval}\" not \"${rval}\" ${*}" >&2
698  fi
699  return 0
700}
701
702[ "USAGE: check_eq <lval> <rval> [--warning [message]]
703
704Exits if (regex) lval mismatches rval" ]
705check_eq() {
706  local lval="${1}"
707  local rval="${2}"
708  shift 2
709  if [ X"${1}" = X"--warning" ]; then
710      EXPECT_EQ "${lval}" "${rval}" ${*}
711      return
712  fi
713  if ! EXPECT_EQ "${lval}" "${rval}"; then
714    die "${@}"
715  fi
716}
717
718[ "USAGE: check_ne <lval> <rval> [--warning [message]]
719
720Exits if lval matches rval" ]
721check_ne() {
722  local lval="${1}"
723  local rval="${2}"
724  shift 2
725  if [ X"${1}" = X"--warning" ]; then
726      EXPECT_NE "${lval}" "${rval}" ${*}
727      return
728  fi
729  if ! EXPECT_NE "${lval}" "${rval}"; then
730    die "${@}"
731  fi
732}
733
734[ "USAGE: skip_administrative_mounts [data] < /proc/mounts
735
736Filters out all administrative (eg: sysfs) mounts uninteresting to the test" ]
737skip_administrative_mounts() {
738  if [ "data" = "${1}" ]; then
739    grep -v " /data "
740  else
741    cat -
742  fi |
743  grep -v \
744    -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
745    -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
746    -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
747    -e "^rootfs / rootfs rw," \
748    -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
749}
750
751[ "USAGE: skip_unrelated_mounts < /proc/mounts
752
753or output from df
754
755Filters out all apex and vendor override administrative overlay mounts
756uninteresting to the test" ]
757skip_unrelated_mounts() {
758    grep -v "^overlay.* /\(apex\|bionic\|system\|vendor\)/[^ ]" |
759      grep -v "[%] /\(apex\|bionic\|system\|vendor\)/[^ ][^ ]*$"
760}
761
762##
763##  MAINLINE
764##
765
766OPTIONS=`getopt --alternative --unquoted \
767                --longoptions help,serial:,colour,color,no-colour,no-color \
768                --longoptions wait-adb:,wait-fastboot: \
769                --longoptions wait-screen,wait-display \
770                --longoptions no-wait-screen,no-wait-display \
771                --longoptions gtest_print_time,print-time \
772                -- "?hs:" ${*}` ||
773  ( echo "${USAGE}" >&2 ; false ) ||
774  die "getopt failure"
775set -- ${OPTIONS}
776
777color=false
778while [ ${#} -gt 0 ]; do
779  case ${1} in
780    -h | --help | -\?)
781      echo "${USAGE}" >&2
782      exit 0
783      ;;
784    -s | --serial)
785      export ANDROID_SERIAL=${2}
786      shift
787      ;;
788    --color | --colour)
789      color=true
790      ;;
791    --no-color | --no-colour)
792      color=false
793      ;;
794    --no-wait-display | --no-wait-screen)
795      screen_wait=false
796      ;;
797    --wait-display | --wait-screen)
798      screen_wait=true
799      ;;
800    --print-time | --gtest_print_time)
801      print_time=true
802      ;;
803    --wait-adb)
804      ADB_WAIT=${2}
805      shift
806      ;;
807    --wait-fastboot)
808      FASTBOOT_WAIT=${2}
809      shift
810      ;;
811    --)
812      shift
813      break
814      ;;
815    -*)
816      echo "${USAGE}" >&2
817      die "${0}: error unknown option ${1}"
818      ;;
819    *)
820      break
821      ;;
822  esac
823  shift
824done
825if ! ${color}; then
826  GREEN=""
827  RED=""
828  ORANGE=""
829  BLUE=""
830  NORMAL=""
831fi
832
833if ${print_time}; then
834  echo "${BLUE}[     INFO ]${NORMAL}" start `date` >&2
835fi
836
837inFastboot && die "device in fastboot mode"
838inRecovery && die "device in recovery mode"
839if ! inAdb; then
840  echo "${ORANGE}[  WARNING ]${NORMAL} device not in adb mode" >&2
841  adb_wait ${ADB_WAIT}
842fi
843inAdb || die "specified device not in adb mode"
844isDebuggable || die "device not a debug build"
845enforcing=true
846if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then
847  echo "${ORANGE}[  WARNING ]${NORMAL} device does not have sepolicy in enforcing mode" >&2
848  enforcing=false
849fi
850
851# Do something.
852
853# Collect characteristics of the device and report.
854
855D=`get_property ro.serialno`
856[ -n "${D}" ] || D=`get_property ro.boot.serialno`
857[ -z "${D}" -o -n "${ANDROID_SERIAL}" ] || ANDROID_SERIAL=${D}
858USB_SERIAL=
859[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
860                                          grep usb |
861                                          xargs grep -l ${ANDROID_SERIAL}`
862USB_ADDRESS=
863if [ -n "${USB_SERIAL}" ]; then
864  USB_ADDRESS=${USB_SERIAL%/serial}
865  USB_ADDRESS=usb${USB_ADDRESS##*/}
866fi
867[ -z "${ANDROID_SERIAL}${USB_ADDRESS}" ] ||
868  USB_DEVICE=`usb_devnum`
869  echo "${BLUE}[     INFO ]${NORMAL}" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} >&2
870BUILD_DESCRIPTION=`get_property ro.build.description`
871[ -z "${BUILD_DESCRIPTION}" ] ||
872  echo "${BLUE}[     INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2
873ACTIVE_SLOT=`get_active_slot`
874[ -z "${ACTIVE_SLOT}" ] ||
875  echo "${BLUE}[     INFO ]${NORMAL} active slot is ${ACTIVE_SLOT}" >&2
876
877# Acquire list of system partitions
878
879PARTITIONS=`adb_su cat /vendor/etc/fstab* |
880              skip_administrative_mounts |
881              sed -n "s@^\([^ ${TAB}/][^ ${TAB}/]*\)[ ${TAB}].*[, ${TAB}]ro[, ${TAB}].*@\1@p" |
882              sort -u |
883              tr '\n' ' '`
884PARTITIONS="${PARTITIONS:-system vendor}"
885# KISS (we do not support sub-mounts for system partitions currently)
886MOUNTS="`for i in ${PARTITIONS}; do
887           echo /${i}
888         done |
889         tr '\n' ' '`"
890echo "${BLUE}[     INFO ]${NORMAL} System Partitions list: ${PARTITIONS}" >&2
891
892# Report existing partition sizes
893adb_sh ls -l /dev/block/by-name/ /dev/block/mapper/ </dev/null 2>/dev/null |
894  sed -n 's@.* \([^ ]*\) -> /dev/block/\([^ ]*\)$@\1 \2@p' |
895  while read name device; do
896    [ super = ${name} -o cache = ${name} ] ||
897      (
898        for i in ${PARTITIONS}; do
899          [ ${i} = ${name} -o ${i} = ${name%_[ab]} ] && exit
900        done
901        exit 1
902      ) ||
903      continue
904
905    case ${device} in
906      sd*)
907        device=${device%%[0-9]*}/${device}
908        ;;
909    esac
910    size=`adb_su cat /sys/block/${device}/size 2>/dev/null </dev/null` &&
911      size=`expr ${size} / 2` &&
912      echo "${BLUE}[     INFO ]${NORMAL} partition ${name} device ${device} size ${size}K" >&2
913  done
914
915# If reboot too soon after fresh flash, could trip device update failure logic
916wait_for_screen
917# Can we test remount -R command?
918OVERLAYFS_BACKING="cache mnt/scratch"
919overlayfs_supported=true
920if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
921     "2" != "`get_property partition.system.verified`" ]; then
922  restore() {
923    ${overlayfs_supported} || return 0
924    inFastboot &&
925      fastboot reboot &&
926      adb_wait ${ADB_WAIT} ||
927      true
928    if inAdb; then
929      reboot=false
930      for d in ${OVERLAYFS_BACKING}; do
931        if adb_su ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
932          adb_su rm -rf /${d}/overlay </dev/null
933          reboot=true
934        fi
935      done
936      if ${reboot}; then
937        adb_reboot &&
938        adb_wait ${ADB_WAIT}
939      fi
940    fi
941  }
942else
943  restore() {
944    ${overlayfs_supported} || return 0
945    inFastboot &&
946      fastboot reboot &&
947      adb_wait ${ADB_WAIT} ||
948      true
949    inAdb &&
950      adb_root &&
951      adb enable-verity >/dev/null 2>/dev/null &&
952      adb_reboot &&
953      adb_wait ${ADB_WAIT}
954  }
955
956  echo "${GREEN}[ RUN      ]${NORMAL} Testing adb shell su root remount -R command" >&2
957
958  avc_check
959  T=`adb_date`
960  adb_su remount -R system </dev/null
961  err=${?}
962  if [ "${err}" != 0 ]; then
963    echo "${ORANGE}[  WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2
964    T="-t ${T}"
965  else
966    # Rebooted, logcat will be meaningless, and last logcat will likely be clear
967    T=""
968  fi
969  sleep 2
970  adb_wait ${ADB_WAIT} ||
971    die "waiting for device after adb shell su root remount -R system `usb_status`"
972  if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
973       "2" = "`get_property partition.system.verified`" ]; then
974    die ${T} "remount -R command failed
975${INDENT}ro.boot.verifiedbootstate=\"`get_property ro.boot.verifiedbootstate`\"
976${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
977  fi
978
979  echo "${GREEN}[       OK ]${NORMAL} adb shell su root remount -R command" >&2
980fi
981
982echo "${GREEN}[ RUN      ]${NORMAL} Testing kernel support for overlayfs" >&2
983
984adb_wait || die "wait for device failed"
985adb_sh ls -d /sys/module/overlay </dev/null >/dev/null 2>/dev/null ||
986  adb_sh grep "nodev${TAB}overlay" /proc/filesystems </dev/null >/dev/null 2>/dev/null &&
987  echo "${GREEN}[       OK ]${NORMAL} overlay module present" >&2 ||
988  (
989    echo "${ORANGE}[  WARNING ]${NORMAL} overlay module not present" >&2 &&
990      false
991  ) ||
992  overlayfs_supported=false
993if ${overlayfs_supported}; then
994  adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null 2>/dev/null &&
995    echo "${GREEN}[       OK ]${NORMAL} overlay module supports override_creds" >&2 ||
996    case `adb_sh uname -r </dev/null` in
997      4.[456789].* | 4.[1-9][0-9]* | [56789].*)
998        echo "${ORANGE}[  WARNING ]${NORMAL} overlay module does not support override_creds" >&2 &&
999        overlayfs_supported=false
1000        ;;
1001      *)
1002        echo "${GREEN}[       OK ]${NORMAL} overlay module uses caller's creds" >&2
1003        ;;
1004    esac
1005fi
1006
1007adb_root ||
1008  die "initial setup"
1009
1010echo "${GREEN}[ RUN      ]${NORMAL} Checking current overlayfs status" >&2
1011
1012# We can not universally use adb enable-verity to ensure device is
1013# in a overlayfs disabled state since it can prevent reboot on
1014# devices that remount the physical content rather than overlayfs.
1015# So lets do our best to surgically wipe the overlayfs state without
1016# having to go through enable-verity transition.
1017reboot=false
1018for d in ${OVERLAYFS_BACKING}; do
1019  if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
1020    echo "${ORANGE}[  WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2
1021    adb_sh rm -rf /${d}/overlay </dev/null ||
1022      die "/${d}/overlay wipe"
1023    reboot=true
1024  fi
1025done
1026if ${reboot}; then
1027  echo "${ORANGE}[  WARNING ]${NORMAL} rebooting before test" >&2
1028  adb_reboot &&
1029    adb_wait ${ADB_WAIT} ||
1030    die "lost device after reboot after wipe `usb_status`"
1031  adb_root ||
1032    die "lost device after elevation to root after wipe `usb_status`"
1033fi
1034D=`adb_sh df -k </dev/null` &&
1035  H=`echo "${D}" | head -1` &&
1036  D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay "` &&
1037  echo "${H}" &&
1038  echo "${D}" &&
1039  echo "${ORANGE}[  WARNING ]${NORMAL} overlays present before setup" >&2 ||
1040  echo "${GREEN}[       OK ]${NORMAL} no overlay present before setup" >&2
1041overlayfs_needed=true
1042D=`adb_sh cat /proc/mounts </dev/null |
1043   skip_administrative_mounts data`
1044if echo "${D}" | grep /dev/root >/dev/null; then
1045  D=`echo / /
1046     echo "${D}" | grep -v /dev/root`
1047fi
1048D=`echo "${D}" | cut -s -d' ' -f1 | sort -u`
1049no_dedupe=true
1050for d in ${D}; do
1051  adb_sh tune2fs -l $d </dev/null 2>&1 |
1052    grep "Filesystem features:.*shared_blocks" >/dev/null &&
1053  no_dedupe=false
1054done
1055D=`adb_sh df -k ${D} </dev/null |
1056   sed 's@\([%] /\)\(apex\|bionic\|system\|vendor\)/[^ ][^ ]*$@\1@'`
1057echo "${D}"
1058if [ X"${D}" = X"${D##* 100[%] }" ] && ${no_dedupe} ; then
1059  overlayfs_needed=false
1060  # if device does not need overlays, then adb enable-verity will brick device
1061  restore() {
1062    ${overlayfs_supported} || return 0
1063    inFastboot &&
1064      fastboot reboot &&
1065      adb_wait ${ADB_WAIT}
1066    inAdb &&
1067      adb_wait ${ADB_WAIT}
1068  }
1069elif ! ${overlayfs_supported}; then
1070  die "need overlayfs, but do not have it"
1071fi
1072
1073echo "${GREEN}[ RUN      ]${NORMAL} disable verity" >&2
1074
1075T=`adb_date`
1076H=`adb disable-verity 2>&1`
1077err=${?}
1078L=
1079D="${H%?Now reboot your device for settings to take effect*}"
1080if [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ]; then
1081  echo "${GREEN}[       OK ]${NORMAL} using overlayfs" >&2
1082fi
1083if [ ${err} != 0 ]; then
1084  echo "${H}"
1085  ( [ -n "${L}" ] && echo "${L}" && false ) ||
1086  die -t "${T}" "disable-verity"
1087fi
1088rebooted=false
1089if [ X"${D}" != X"${H}" ]; then
1090  echo "${H}"
1091  if [ X"${D}" != X"${D##*setup failed}" ]; then
1092    echo "${ORANGE}[  WARNING ]${NORMAL} overlayfs setup whined" >&2
1093  fi
1094  D=`adb_sh df -k </dev/null` &&
1095    H=`echo "${D}" | head -1` &&
1096    D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay " || true` &&
1097    [ -z "${D}" ] ||
1098    ( echo "${H}" && echo "${D}" && false ) ||
1099    die -t ${T} "overlay takeover unexpected at this phase"
1100  echo "${GREEN}[     INFO ]${NORMAL} rebooting as requested" >&2
1101  L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
1102  adb_reboot &&
1103    adb_wait ${ADB_WAIT} ||
1104    die "lost device after reboot requested `usb_status`"
1105  adb_root ||
1106    die "lost device after elevation to root `usb_status`"
1107  rebooted=true
1108  # re-disable verity to see the setup remarks expected
1109  T=`adb_date`
1110  H=`adb disable-verity 2>&1`
1111  err=${?}
1112  D="${H%?Now reboot your device for settings to take effect*}"
1113  if [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ]; then
1114    echo "${GREEN}[       OK ]${NORMAL} using overlayfs" >&2
1115  fi
1116  if [ ${err} != 0 ]; then
1117    T=
1118  fi
1119fi
1120if ${overlayfs_supported} && ${overlayfs_needed} && [ X"${D}" != X"${D##*setup failed}" ]; then
1121  echo "${D}"
1122  ( [ -n "${L}" ] && echo "${L}" && false ) ||
1123  die -t "${T}" "setup for overlay"
1124fi
1125if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
1126  echo "${H}"
1127  D=`adb_sh df -k </dev/null` &&
1128    H=`echo "${D}" | head -1` &&
1129    D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay " || true` &&
1130    [ -z "${D}" ] ||
1131    ( echo "${H}" && echo "${D}" && false ) ||
1132    ( [ -n "${L}" ] && echo "${L}" && false ) ||
1133    die -t "${T}" "overlay takeover unexpected"
1134  [ -n "${L}" ] && echo "${L}"
1135  die -t "${T}" "unexpected report of verity being disabled a second time"
1136elif ${rebooted}; then
1137  echo "${GREEN}[       OK ]${NORMAL} verity already disabled" >&2
1138else
1139  echo "${ORANGE}[  WARNING ]${NORMAL} verity already disabled" >&2
1140fi
1141
1142echo "${GREEN}[ RUN      ]${NORMAL} remount" >&2
1143
1144# Feed log with selinux denials as baseline before overlays
1145adb_unroot
1146adb_sh find ${MOUNTS} </dev/null >/dev/null 2>/dev/null
1147adb_root
1148
1149D=`adb remount 2>&1`
1150ret=${?}
1151echo "${D}"
1152[ ${ret} != 0 ] ||
1153  [ X"${D}" = X"${D##*remount failed}" ] ||
1154  ( [ -n "${L}" ] && echo "${L}" && false ) ||
1155  die -t "${T}" "adb remount failed"
1156D=`adb_sh df -k </dev/null` &&
1157  H=`echo "${D}" | head -1` &&
1158  D=`echo "${D}" | skip_unrelated_mounts | grep "^overlay "` ||
1159  ( [ -n "${L}" ] && echo "${L}" && false )
1160ret=${?}
1161uses_dynamic_scratch=false
1162scratch_partition=
1163if ${overlayfs_needed}; then
1164  if [ ${ret} != 0 ]; then
1165    die -t ${T} "overlay takeover failed"
1166  fi
1167  echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
1168   echo "${ORANGE}[  WARNING ]${NORMAL} overlay takeover not complete" >&2
1169  scratch_partition=scratch
1170  if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
1171    echo "${BLUE}[     INFO ]${NORMAL} using ${scratch_partition} dynamic partition for overrides" >&2
1172  fi
1173  M=`adb_sh cat /proc/mounts </dev/null |
1174     sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
1175  [ -n "${M}" ] &&
1176    echo "${BLUE}[     INFO ]${NORMAL} scratch filesystem ${M}"
1177  uses_dynamic_scratch=true
1178  if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then
1179    uses_dynamic_scratch=false
1180    scratch_partition="${M##*/dev/block/by-name/}"
1181  fi
1182  scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null |
1183                while read device kblocks used available use mounted on; do
1184                  if [ "/mnt/scratch" = "\${mounted}" ]; then
1185                    echo \${kblocks}
1186                  fi
1187                done` &&
1188    [ -n "${scratch_size}" ] ||
1189    die "scratch size"
1190  echo "${BLUE}[     INFO ]${NORMAL} scratch size ${scratch_size}KB" >&2
1191  for d in ${OVERLAYFS_BACKING}; do
1192    if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
1193      echo "${BLUE}[     INFO ]${NORMAL} /${d}/overlay is setup" >&2
1194    fi
1195  done
1196
1197  echo "${H}" &&
1198    echo "${D}" &&
1199    echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
1200    die  "overlay takeover after remount"
1201  !(adb_sh grep "^overlay " /proc/mounts </dev/null |
1202    skip_unrelated_mounts |
1203    grep " overlay ro,") ||
1204    die "remount overlayfs missed a spot (ro)"
1205  !(adb_sh grep -v noatime /proc/mounts </dev/null |
1206    skip_administrative_mounts data |
1207    skip_unrelated_mounts |
1208    grep -v ' ro,') ||
1209    die "mounts are not noatime"
1210  D=`adb_sh grep " rw," /proc/mounts </dev/null |
1211     skip_administrative_mounts data`
1212  if echo "${D}" | grep /dev/root >/dev/null; then
1213    D=`echo / /
1214       echo "${D}" | grep -v /dev/root`
1215  fi
1216  D=`echo "${D}" | cut -s -d' ' -f1 | sort -u`
1217  bad_rw=false
1218  for d in ${D}; do
1219    if adb_sh tune2fs -l $d </dev/null 2>&1 |
1220       grep "Filesystem features:.*shared_blocks" >/dev/null; then
1221      bad_rw=true
1222    else
1223      d=`adb_sh df -k ${D} </dev/null |
1224       sed 's@\([%] /\)\(apex\|bionic\|system\|vendor\)/[^ ][^ ]*$@\1@'`
1225      [ X"${d}" = X"${d##* 100[%] }" ] ||
1226        bad_rw=true
1227    fi
1228  done
1229  [ -z "${D}" ] ||
1230    D=`adb_sh df -k ${D} </dev/null |
1231       sed -e 's@\([%] /\)\(apex\|bionic\|system\|vendor\)/[^ ][^ ]*$@\1@' \
1232           -e 's/^Filesystem      /Filesystem (rw) /'`
1233  [ -z "${D}" ] || echo "${D}"
1234  ${bad_rw} && die "remount overlayfs missed a spot (rw)"
1235else
1236  if [ ${ret} = 0 ]; then
1237    die -t ${T} "unexpected overlay takeover"
1238  fi
1239fi
1240
1241# Check something.
1242
1243echo "${GREEN}[ RUN      ]${NORMAL} push content to ${MOUNTS}" >&2
1244
1245A="Hello World! $(date)"
1246for i in ${MOUNTS}; do
1247  echo "${A}" | adb_sh cat - ">${i}/hello"
1248  B="`adb_cat ${i}/hello`" ||
1249    die "${i#/} hello"
1250  check_eq "${A}" "${B}" ${i} before reboot
1251done
1252echo "${A}" | adb_sh cat - ">/system/priv-app/hello"
1253B="`adb_cat /system/priv-app/hello`" ||
1254  die "system priv-app hello"
1255check_eq "${A}" "${B}" /system/priv-app before reboot
1256SYSTEM_DEVT=`adb_sh stat --format=%D /system/hello </dev/null`
1257VENDOR_DEVT=`adb_sh stat --format=%D /vendor/hello </dev/null`
1258SYSTEM_INO=`adb_sh stat --format=%i /system/hello </dev/null`
1259VENDOR_INO=`adb_sh stat --format=%i /vendor/hello </dev/null`
1260BASE_SYSTEM_DEVT=`adb_sh stat --format=%D /system/bin/stat </dev/null`
1261BASE_VENDOR_DEVT=`adb_sh stat --format=%D /vendor/bin/stat </dev/null`
1262check_eq "${SYSTEM_DEVT%[0-9a-fA-F][0-9a-fA-F]}" "${VENDOR_DEVT%[0-9a-fA-F][0-9a-fA-F]}" vendor and system devt
1263check_ne "${SYSTEM_INO}" "${VENDOR_INO}" vendor and system inode
1264if ${overlayfs_needed}; then
1265  check_ne "${SYSTEM_DEVT}" "${BASE_SYSTEM_DEVT}" system devt
1266  check_ne "${VENDOR_DEVT}" "${BASE_VENDOR_DEVT}" vendor devt
1267else
1268  check_eq "${SYSTEM_DEVT}" "${BASE_SYSTEM_DEVT}" system devt
1269  check_eq "${VENDOR_DEVT}" "${BASE_VENDOR_DEVT}" vendor devt
1270fi
1271check_ne "${BASE_SYSTEM_DEVT}" "${BASE_VENDOR_DEVT}" --warning system/vendor devt
1272[ -n "${SYSTEM_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
1273  die "system devt ${SYSTEM_DEVT} is major 0"
1274[ -n "${VENDOR_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
1275  die "vendor devt ${SYSTEM_DEVT} is major 0"
1276
1277# Download libc.so, append some gargage, push back, and check if the file
1278# is updated.
1279tempdir="`mktemp -d`"
1280cleanup() {
1281  rm -rf ${tempdir}
1282}
1283adb pull /system/lib/bootstrap/libc.so ${tempdir} >/dev/null ||
1284  die "pull libc.so from device"
1285garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`"
1286echo ${garbage} >> ${tempdir}/libc.so
1287adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so >/dev/null ||
1288  die "push libc.so to device"
1289adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
1290  die "pull libc.so from device"
1291diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null ||
1292  die "libc.so differ"
1293
1294echo "${GREEN}[ RUN      ]${NORMAL} reboot to confirm content persistent" >&2
1295
1296fixup_from_recovery() {
1297  inRecovery || return 1
1298  echo "${ORANGE}[    ERROR ]${NORMAL} Device in recovery" >&2
1299  adb reboot </dev/null
1300  adb_wait ${ADB_WAIT}
1301}
1302
1303adb_reboot &&
1304  adb_wait ${ADB_WAIT} ||
1305  fixup_from_recovery ||
1306  die "reboot after override content added failed `usb_status`"
1307
1308if ${overlayfs_needed}; then
1309  D=`adb_su df -k </dev/null` &&
1310    H=`echo "${D}" | head -1` &&
1311    D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay "` ||
1312    ( echo "${L}" && false ) ||
1313    die -d "overlay takeover failed after reboot"
1314
1315  adb_su sed -n '1,/overlay \/system/p' /proc/mounts </dev/null |
1316    skip_administrative_mounts |
1317    grep -v ' \(erofs\|squashfs\|ext4\|f2fs\|vfat\) ' &&
1318    echo "${ORANGE}[  WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
1319    echo "${GREEN}[       OK ]${NORMAL} overlay takeover in first stage init" >&2
1320fi
1321
1322if ${enforcing}; then
1323  adb_unroot ||
1324    die "device not in unroot'd state"
1325  B="`adb_cat /vendor/hello 2>&1`"
1326  check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
1327  echo "${GREEN}[       OK ]${NORMAL} /vendor content correct MAC after reboot" >&2
1328  # Feed unprivileged log with selinux denials as a result of overlays
1329  wait_for_screen
1330  adb_sh find ${MOUNTS} </dev/null >/dev/null 2>/dev/null
1331fi
1332# If overlayfs has a nested security problem, this will fail.
1333B="`adb_ls /system/`" ||
1334  die "adb ls /system"
1335[ X"${B}" != X"${B#*priv-app}" ] ||
1336  die "adb ls /system/priv-app"
1337B="`adb_cat /system/priv-app/hello`"
1338check_eq "${A}" "${B}" /system/priv-app after reboot
1339# Only root can read vendor if sepolicy permissions are as expected.
1340adb_root ||
1341  die "adb root"
1342for i in ${MOUNTS}; do
1343  B="`adb_cat ${i}/hello`"
1344  check_eq "${A}" "${B}" ${i#/} after reboot
1345  echo "${GREEN}[       OK ]${NORMAL} ${i} content remains after reboot" >&2
1346done
1347
1348check_eq "${SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/hello </dev/null`" system devt after reboot
1349check_eq "${VENDOR_DEVT}" "`adb_sh stat --format=%D /vendor/hello </dev/null`" vendor devt after reboot
1350check_eq "${SYSTEM_INO}" "`adb_sh stat --format=%i /system/hello </dev/null`" system inode after reboot
1351check_eq "${VENDOR_INO}" "`adb_sh stat --format=%i /vendor/hello </dev/null`" vendor inode after reboot
1352check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/bin/stat </dev/null`" base system devt after reboot
1353check_eq "${BASE_VENDOR_DEVT}" "`adb_sh stat --format=%D /vendor/bin/stat </dev/null`" base system devt after reboot
1354check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/xbin/su </dev/null`" devt for su after reboot
1355
1356# Feed log with selinux denials as a result of overlays
1357adb_sh find ${MOUNTS} </dev/null >/dev/null 2>/dev/null
1358
1359# Check if the updated libc.so is persistent after reboot.
1360adb_root &&
1361  adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
1362  die "pull libc.so from device"
1363diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
1364rm -rf ${tempdir}
1365cleanup() {
1366  true
1367}
1368echo "${GREEN}[       OK ]${NORMAL} /system/lib/bootstrap/libc.so content remains after reboot" >&2
1369
1370echo "${GREEN}[ RUN      ]${NORMAL} flash vendor, confirm its content disappears" >&2
1371
1372H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
1373is_bootloader_fastboot=false
1374# cuttlefish?
1375[ X"${H}" != X"${H#vsoc}" ] || is_bootloader_fastboot=true
1376is_userspace_fastboot=false
1377
1378if ! ${is_bootloader_fastboot}; then
1379  echo "${ORANGE}[  WARNING ]${NORMAL} does not support fastboot, skipping"
1380elif [ -z "${ANDROID_PRODUCT_OUT}" ]; then
1381  echo "${ORANGE}[  WARNING ]${NORMAL} build tree not setup, skipping"
1382elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
1383  echo "${ORANGE}[  WARNING ]${NORMAL} vendor image missing, skipping"
1384elif [ "${ANDROID_PRODUCT_OUT}" = "${ANDROID_PRODUCT_OUT%*/${H}}" ]; then
1385  echo "${ORANGE}[  WARNING ]${NORMAL} wrong vendor image, skipping"
1386elif [ -z "${ANDROID_HOST_OUT}" ]; then
1387  echo "${ORANGE}[  WARNING ]${NORMAL} please run lunch, skipping"
1388elif ! (
1389          adb_cat /vendor/build.prop |
1390          cmp -s ${ANDROID_PRODUCT_OUT}/vendor/build.prop
1391       ) >/dev/null 2>/dev/null; then
1392  echo "${ORANGE}[  WARNING ]${NORMAL} vendor image signature mismatch, skipping"
1393else
1394  wait_for_screen
1395  avc_check
1396  adb reboot fastboot </dev/null ||
1397    die "fastbootd not supported (wrong adb in path?)"
1398  any_wait ${ADB_WAIT} &&
1399    inFastboot ||
1400    die "reboot into fastboot to flash vendor `usb_status` (bad bootloader?)"
1401  fastboot flash vendor ||
1402    ( fastboot reboot && false) ||
1403    die "fastboot flash vendor"
1404  fastboot_getvar is-userspace yes &&
1405    is_userspace_fastboot=true
1406  if [ -n "${scratch_paritition}" ]; then
1407    fastboot_getvar partition-type:${scratch_partition} raw ||
1408      ( fastboot reboot && false) ||
1409      die "fastboot can not see ${scratch_partition} parameters"
1410    if ${uses_dynamic_scratch}; then
1411      # check ${scratch_partition} via fastboot
1412      fastboot_getvar has-slot:${scratch_partition} no &&
1413        fastboot_getvar is-logical:${scratch_partition} yes ||
1414        ( fastboot reboot && false) ||
1415        die "fastboot can not see ${scratch_partition} parameters"
1416    else
1417      fastboot_getvar is-logical:${scratch_partition} no ||
1418        ( fastboot reboot && false) ||
1419        die "fastboot can not see ${scratch_partition} parameters"
1420    fi
1421    if ! ${uses_dynamic_scratch}; then
1422      fastboot reboot-bootloader ||
1423        die "Reboot into fastboot"
1424    fi
1425    if ${uses_dynamic_scratch}; then
1426      echo "${BLUE}[     INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2
1427      fastboot erase ${scratch_partition} &&
1428        ( fastboot reboot || true) &&
1429        die "fastboot can erase ${scratch_partition}"
1430    fi
1431    echo "${BLUE}[     INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2
1432    fastboot format ${scratch_partition} &&
1433      ( fastboot reboot || true) &&
1434      die "fastboot can format ${scratch_partition}"
1435  fi
1436  fastboot reboot ||
1437    die "can not reboot out of fastboot"
1438  echo "${ORANGE}[  WARNING ]${NORMAL} adb after fastboot"
1439  adb_wait ${ADB_WAIT} ||
1440    fixup_from_recovery ||
1441    die "did not reboot after formatting ${scratch_partition} `usb_status`"
1442  if ${overlayfs_needed}; then
1443    adb_root &&
1444      D=`adb_sh df -k </dev/null` &&
1445      H=`echo "${D}" | head -1` &&
1446      D=`echo "${D}" | skip_unrelated_mounts | grep "^overlay "` &&
1447      echo "${H}" &&
1448      echo "${D}" &&
1449      echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
1450      die  "overlay /system takeover after flash vendor"
1451    echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
1452      if ${is_userspace_fastboot}; then
1453        die  "overlay supposed to be minus /vendor takeover after flash vendor"
1454      else
1455        echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
1456        echo "${ORANGE}[  WARNING ]${NORMAL} overlay supposed to be minus /vendor takeover after flash vendor" >&2
1457      fi
1458  fi
1459  B="`adb_cat /system/hello`"
1460  check_eq "${A}" "${B}" system after flash vendor
1461  B="`adb_ls /system/`" ||
1462    die "adb ls /system"
1463  [ X"${B}" != X"${B#*priv-app}" ] ||
1464    die "adb ls /system/priv-app"
1465  B="`adb_cat /system/priv-app/hello`"
1466  check_eq "${A}" "${B}" system/priv-app after flash vendor
1467  adb_root ||
1468    die "adb root"
1469  B="`adb_cat /vendor/hello`"
1470  if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
1471    check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
1472             vendor content after flash vendor
1473  else
1474    echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
1475    check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
1476             --warning vendor content after flash vendor
1477  fi
1478
1479  check_eq "${SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/hello </dev/null`" system devt after reboot
1480  check_eq "${SYSTEM_INO}" "`adb_sh stat --format=%i /system/hello </dev/null`" system inode after reboot
1481  check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/bin/stat </dev/null`" base system devt after reboot
1482  check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/xbin/su </dev/null`" devt for su after reboot
1483
1484fi
1485
1486wait_for_screen
1487echo "${GREEN}[ RUN      ]${NORMAL} remove test content (cleanup)" >&2
1488
1489T=`adb_date`
1490H=`adb remount 2>&1`
1491err=${?}
1492L=
1493D="${H%?Now reboot your device for settings to take effect*}"
1494if [ X"${H}" != X"${D}" ]; then
1495  echo "${ORANGE}[  WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)"
1496  L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
1497  adb_reboot &&
1498    adb_wait ${ADB_WAIT} &&
1499    adb_root ||
1500    die "failed to reboot"
1501  T=`adb_date`
1502  H=`adb remount 2>&1`
1503  err=${?}
1504fi
1505echo "${H}"
1506[ ${err} = 0 ] &&
1507  ( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
1508  adb_sh rm /system/hello /system/priv-app/hello </dev/null ||
1509  ( [ -n "${L}" ] && echo "${L}" && false ) ||
1510  die -t ${T} "cleanup hello"
1511B="`adb_cat /system/hello`"
1512check_eq "cat: /system/hello: No such file or directory" "${B}" after rm
1513B="`adb_cat /system/priv-app/hello`"
1514check_eq "cat: /system/priv-app/hello: No such file or directory" "${B}" after rm
1515B="`adb_cat /vendor/hello`"
1516check_eq "cat: /vendor/hello: No such file or directory" "${B}" after rm
1517for i in ${MOUNTS}; do
1518  adb_sh rm ${i}/hello </dev/null 2>/dev/null || true
1519done
1520
1521if ${is_bootloader_fastboot} && [ -n "${scratch_partition}" ]; then
1522
1523  echo "${GREEN}[ RUN      ]${NORMAL} test fastboot flash to ${scratch_partition} recovery" >&2
1524
1525  avc_check
1526  adb reboot fastboot </dev/null ||
1527    die "Reboot into fastbootd"
1528  img=${TMPDIR}/adb-remount-test-${$}.img
1529  cleanup() {
1530    rm ${img}
1531  }
1532  dd if=/dev/zero of=${img} bs=4096 count=16 2>/dev/null &&
1533    fastboot_wait ${FASTBOOT_WAIT} ||
1534    die "reboot into fastboot to flash scratch `usb_status`"
1535  fastboot flash --force ${scratch_partition} ${img}
1536  err=${?}
1537  cleanup
1538  cleanup() {
1539    true
1540  }
1541  fastboot reboot ||
1542    die "can not reboot out of fastboot"
1543  [ 0 -eq ${err} ] ||
1544    die "fastboot flash ${scratch_partition}"
1545  adb_wait ${ADB_WAIT} &&
1546    adb_root ||
1547    die "did not reboot after flashing empty ${scratch_partition} `usb_status`"
1548  T=`adb_date`
1549  D=`adb disable-verity 2>&1`
1550  err=${?}
1551  if [ X"${D}" != "${D%?Now reboot your device for settings to take effect*}" ]
1552  then
1553    echo "${ORANGE}[  WARNING ]${NORMAL} adb disable-verity requires a reboot after partial flash"
1554    adb_reboot &&
1555      adb_wait ${ADB_WAIT} &&
1556      adb_root ||
1557      die "failed to reboot"
1558    T=`adb_date`
1559    D="${D}
1560`adb disable-verity 2>&1`"
1561    err=${?}
1562  fi
1563
1564  echo "${D}"
1565  [ ${err} = 0 ] &&
1566    [ X"${D}" = X"${D##*setup failed}" ] &&
1567    [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ] &&
1568    echo "${GREEN}[       OK ]${NORMAL} ${scratch_partition} recreated" >&2 ||
1569    die -t ${T} "setup for overlayfs"
1570  D=`adb remount 2>&1`
1571  err=${?}
1572  echo "${D}"
1573  [ ${err} != 0 ] ||
1574    [ X"${D}" = X"${D##*remount failed}" ] ||
1575    ( echo "${D}" && false ) ||
1576    die -t ${T} "remount failed"
1577fi
1578
1579echo "${GREEN}[ RUN      ]${NORMAL} test raw remount commands" >&2
1580
1581fixup_from_fastboot() {
1582  inFastboot || return 1
1583  if [ -n "${ACTIVE_SLOT}" ]; then
1584    local active_slot=`get_active_slot`
1585    if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
1586      echo "${ORANGE}[    ERROR ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
1587    else
1588      echo "${ORANGE}[    ERROR ]${NORMAL} Active slot to be set to ${ACTIVE_SLOT}"
1589    fi >&2
1590    fastboot --set-active=${ACTIVE_SLOT}
1591  fi
1592  fastboot reboot
1593  adb_wait ${ADB_WAIT}
1594}
1595
1596# Prerequisite is a prepped device from above.
1597adb_reboot &&
1598  adb_wait ${ADB_WAIT} ||
1599  fixup_from_fastboot ||
1600  die "lost device after reboot to ro state `usb_status`"
1601adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null &&
1602  die "/vendor is not read-only"
1603adb_su mount -o rw,remount /vendor </dev/null ||
1604  die "remount command"
1605adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
1606  die "/vendor is not read-write"
1607echo "${GREEN}[       OK ]${NORMAL} mount -o rw,remount command works" >&2
1608
1609# Prerequisite is a prepped device from above.
1610adb_reboot &&
1611  adb_wait ${ADB_WAIT} ||
1612  fixup_from_fastboot ||
1613  die "lost device after reboot to ro state `usb_status`"
1614adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null &&
1615  die "/vendor is not read-only"
1616adb_su remount vendor </dev/null ||
1617  die "remount command"
1618adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
1619  die "/vendor is not read-write"
1620adb_sh grep " /system .* rw," /proc/mounts >/dev/null </dev/null &&
1621  die "/vendor is not read-only"
1622echo "${GREEN}[       OK ]${NORMAL} remount command works from setup" >&2
1623
1624# Prerequisite is an overlayfs deconstructed device but with verity disabled.
1625# This also saves a lot of 'noise' from the command doing a mkfs on backing
1626# storage and all the related tuning and adjustment.
1627for d in ${OVERLAYFS_BACKING}; do
1628  adb_su rm -rf /${d}/overlay </dev/null ||
1629    die "/${d}/overlay wipe"
1630done
1631adb_reboot &&
1632  adb_wait ${ADB_WAIT} ||
1633  fixup_from_fastboot ||
1634  die "lost device after reboot after wipe `usb_status`"
1635adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null &&
1636  die "/vendor is not read-only"
1637adb_su remount vendor </dev/null ||
1638  die "remount command"
1639adb_su df -k </dev/null | skip_unrelated_mounts
1640adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
1641  die "/vendor is not read-write"
1642adb_sh grep " \(/system\|/\) .* rw," /proc/mounts >/dev/null </dev/null &&
1643  die "/system is not read-only"
1644echo "${GREEN}[       OK ]${NORMAL} remount command works from scratch" >&2
1645
1646if ! restore; then
1647  restore() {
1648    true
1649  }
1650  die "failed to restore verity after remount from scratch test"
1651fi
1652
1653err=0
1654
1655if ${overlayfs_supported}; then
1656  echo "${GREEN}[ RUN      ]${NORMAL} test 'adb remount -R'" >&2
1657  avc_check
1658  adb_root ||
1659    die "adb root in preparation for adb remount -R"
1660  T=`adb_date`
1661  adb remount -R
1662  err=${?}
1663  if [ "${err}" != 0 ]; then
1664    die -t ${T} "adb remount -R = ${err}"
1665  fi
1666  sleep 2
1667  adb_wait ${ADB_WAIT} ||
1668    die "waiting for device after adb remount -R `usb_status`"
1669  if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
1670       "2" = "`get_property partition.system.verified`" ] &&
1671     [ -n "`get_property ro.boot.verifiedbootstate`" -o \
1672       -n "`get_property partition.system.verified`" ]; then
1673    die "remount -R command failed to disable verity
1674${INDENT}ro.boot.verifiedbootstate=\"`get_property ro.boot.verifiedbootstate`\"
1675${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
1676  fi
1677
1678  echo "${GREEN}[       OK ]${NORMAL} 'adb remount -R' command" >&2
1679
1680  restore
1681  err=${?}
1682fi
1683
1684restore() {
1685  true
1686}
1687
1688[ ${err} = 0 ] ||
1689  die "failed to restore verity"
1690
1691echo "${GREEN}[  PASSED  ]${NORMAL} adb remount" >&2
1692
1693test_duration
1694