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