Merge "init: simplify async restorecon"
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index f25955d..552df41 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -838,26 +838,25 @@
 
 #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
 
-/*
- * The sideload-host protocol serves the data in a file (given on the
- * command line) to the client, using a simple protocol:
- *
- * - The connect message includes the total number of bytes in the
- *   file and a block size chosen by us.
- *
- * - The other side sends the desired block number as eight decimal
- *   digits (eg "00000023" for block 23).  Blocks are numbered from
- *   zero.
- *
- * - We send back the data of the requested block.  The last block is
- *   likely to be partial; when the last block is requested we only
- *   send the part of the block that exists, it's not padded up to the
- *   block size.
- *
- * - When the other side sends "DONEDONE" instead of a block number,
- *   we hang up.
- */
-static int adb_sideload_host(const char* filename) {
+// Connects to the sideload / rescue service on the device (served by minadbd) and sends over the
+// data in an OTA package.
+//
+// It uses a simple protocol as follows.
+//
+// - The connect message includes the total number of bytes in the file and a block size chosen by
+//   us.
+//
+// - The other side sends the desired block number as eight decimal digits (e.g. "00000023" for
+//   block 23). Blocks are numbered from zero.
+//
+// - We send back the data of the requested block. The last block is likely to be partial; when the
+//   last block is requested we only send the part of the block that exists, it's not padded up to
+//   the block size.
+//
+// - When the other side sends "DONEDONE" or "FAILFAIL" instead of a block number, we have done all
+//   the data transfer.
+//
+static int adb_sideload_install(const char* filename, bool rescue_mode) {
     // TODO: use a LinePrinter instead...
     struct stat sb;
     if (stat(filename, &sb) == -1) {
@@ -870,14 +869,18 @@
         return -1;
     }
 
-    std::string service =
-            android::base::StringPrintf("sideload-host:%" PRId64 ":%d",
-                                        static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
+    std::string service = android::base::StringPrintf(
+            "%s:%" PRId64 ":%d", rescue_mode ? "rescue-install" : "sideload-host",
+            static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
     std::string error;
     unique_fd device_fd(adb_connect(service, &error));
     if (device_fd < 0) {
         fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str());
 
+        if (rescue_mode) {
+            return -1;
+        }
+
         // If this is a small enough package, maybe this is an older device that doesn't
         // support sideload-host. Try falling back to the older (<= K) sideload method.
         if (sb.st_size > INT_MAX) {
@@ -901,10 +904,14 @@
         }
         buf[8] = '\0';
 
-        if (strcmp("DONEDONE", buf) == 0) {
+        if (strcmp(kSideloadServiceExitSuccess, buf) == 0 ||
+            strcmp(kSideloadServiceExitFailure, buf) == 0) {
             printf("\rTotal xfer: %.2fx%*s\n",
                    static_cast<double>(xfer) / (sb.st_size ? sb.st_size : 1),
                    static_cast<int>(strlen(filename) + 10), "");
+            if (strcmp(kSideloadServiceExitFailure, buf) == 0) {
+                return 1;
+            }
             return 0;
         }
 
@@ -1628,11 +1635,25 @@
         return adb_kill_server() ? 0 : 1;
     } else if (!strcmp(argv[0], "sideload")) {
         if (argc != 2) error_exit("sideload requires an argument");
-        if (adb_sideload_host(argv[1])) {
+        if (adb_sideload_install(argv[1], false /* rescue_mode */)) {
             return 1;
         } else {
             return 0;
         }
+    } else if (!strcmp(argv[0], "rescue")) {
+        // adb rescue getprop <prop>
+        // adb rescue install <filename>
+        if (argc != 3) error_exit("rescue requires two arguments");
+        if (!strcmp(argv[1], "getprop")) {
+            return adb_connect_command(android::base::StringPrintf("rescue-getprop:%s", argv[2]));
+        } else if (!strcmp(argv[1], "install")) {
+            if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) {
+                return 1;
+            }
+        } else {
+            error_exit("invalid rescue argument");
+        }
+        return 0;
     } else if (!strcmp(argv[0], "tcpip")) {
         if (argc != 2) error_exit("tcpip requires an argument");
         int port;
diff --git a/adb/services.h b/adb/services.h
index 0ce25ba..8f3919b 100644
--- a/adb/services.h
+++ b/adb/services.h
@@ -23,5 +23,9 @@
 constexpr char kShellServiceArgPty[] = "pty";
 constexpr char kShellServiceArgShellProtocol[] = "v2";
 
+// Special flags sent by minadbd that indicate the end of sideload transfer and install result.
+constexpr char kSideloadServiceExitSuccess[] = "DONEDONE";
+constexpr char kSideloadServiceExitFailure[] = "FAILFAIL";
+
 unique_fd create_service_thread(const char* service_name, std::function<void(unique_fd)> func);
 #endif  // SERVICES_H_
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 71d3ecb..8979b0c 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -25,6 +25,8 @@
 # Best guess to an average device's reboot time, refined as tests return
 DURATION_DEFAULT=45
 STOP_ON_FAILURE=false
+progname="${0##*/}"
+progpath="${0%${progname}}"
 
 # Helper functions
 
@@ -42,11 +44,40 @@
   adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
 }
 
+[ "USAGE: adb_sh <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
+
+Returns: true if the command succeeded" ]
+adb_sh() {
+  local args=
+  for i in "${@}"; do
+    [ -z "${args}" ] || args="${args} "
+    if [ X"${i}" != X"${i#\'}" ]; then
+      args="${args}${i}"
+    elif [ X"${i}" != X"${i#*\\}" ]; then
+      args="${args}`echo ${i} | sed 's/\\\\/\\\\\\\\/g'`"
+    elif [ X"${i}" != X"${i#* }" ]; then
+      args="${args}'${i}'"
+    elif [ X"${i}" != X"${i#*${TAB}}" ]; then
+      args="${args}'${i}'"
+    else
+      args="${args}${i}"
+    fi
+  done
+  adb shell "${args}"
+}
+
+[ "USAGE: adb_su <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
+
+Returns: true if the command running as root succeeded" ]
+adb_su() {
+  adb_sh su root "${@}"
+}
+
 [ "USAGE: hasPstore
 
 Returns: true if device (likely) has pstore data" ]
 hasPstore() {
-  if inAdb && [ 0 -eq `adb shell su root ls /sys/fs/pstore | wc -l` ]; then
+  if inAdb && [ 0 -eq `adb_su ls /sys/fs/pstore </dev/null | wc -l` ]; then
     false
   fi
 }
@@ -55,7 +86,7 @@
 
 Returns the property value" ]
 get_property() {
-  adb shell getprop ${1} 2>&1 </dev/null
+  adb_sh getprop ${1} 2>&1 </dev/null
 }
 
 [ "USAGE: isDebuggable
@@ -89,18 +120,18 @@
 Returns: true if device supports and set boot reason injection" ]
 setBootloaderBootReason() {
   inAdb || ( echo "ERROR: device not in adb mode." >&2 ; false ) || return 1
-  if [ -z "`adb shell ls /etc/init/bootstat-debug.rc 2>/dev/null`" ]; then
+  if [ -z "`adb_sh ls /etc/init/bootstat-debug.rc 2>/dev/null </dev/null`" ]; then
     echo "ERROR: '${TEST}' test requires /etc/init/bootstat-debug.rc" >&2
     return 1
   fi
   checkDebugBuild || return 1
-  if adb shell su root "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" |
+  if adb_su "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" </dev/null |
      grep '^androidboot[.]bootreason=[^ ]' >/dev/null; then
     echo "ERROR: '${TEST}' test requires a device with a bootloader that" >&2
     echo "       does not set androidboot.bootreason kernel parameter." >&2
     return 1
   fi
-  adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
+  adb_su setprop persist.test.boot.reason "'${1}'" 2>/dev/null </dev/null
   test_reason="`get_property persist.test.boot.reason`"
   if [ X"${test_reason}" != X"${1}" ]; then
     echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
@@ -299,7 +330,14 @@
   return ${save_ret}
 }
 
-[ "USAGE: report_bootstat_logs <expected> ...
+[ "USAGE: adb_date >/dev/stdout
+
+Returns: report device epoch time (suitable for logcat -t)" ]
+adb_date() {
+  adb_sh date +%s.%N </dev/null
+}
+
+[ "USAGE: report_bootstat_logs [-t<timestamp>] <expected> ...
 
 if not prefixed with a minus (-), <expected> will become a series of expected
 matches:
@@ -314,8 +352,11 @@
 report_bootstat_logs() {
   save_ret=${?}
   match=
+  timestamp=-d
   for i in "${@}"; do
-    if [ X"${i}" != X"${i#-}" ] ; then
+    if [ X"${i}" != X"${i#-t}" ]; then
+      timestamp="${i}"
+    elif [ X"${i}" != X"${i#-}" ]; then
       match="${match}
 ${i#-}"
     else
@@ -323,12 +364,13 @@
 bootstat: Canonical boot reason: ${i}"
     fi
   done
-  adb logcat -b all -d |
+  adb logcat -b all ${timestamp} |
   grep bootstat[^e] |
   grep -v -F "bootstat: Service started: /system/bin/bootstat --record_boot_complete${match}
 bootstat: Failed to read /data/misc/bootstat/post_decrypt_time_elapsed: No such file or directory
 bootstat: Failed to parse boot time record: /data/misc/bootstat/post_decrypt_time_elapsed
 bootstat: Service started: /system/bin/bootstat --record_boot_reason
+bootstat: Service started: /system/bin/bootstat --set_system_boot_reason
 bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset
 bootstat: Service started: /system/bin/bootstat -l
 bootstat: Service started: /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
@@ -341,6 +383,8 @@
 init    : processing action (post-fs-data) from (/system/etc/init/bootstat.rc
 init    : processing action (boot) from (/system/etc/init/bootstat.rc
 init    : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
+init    : processing action (ro.boot.bootreason=* && post-fs) from (/system/etc/init/bootstat.rc
+init    : processing action (zygote-start) from (/system/etc/init/bootstat.rc
 init    : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
  (/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
  (/system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
@@ -355,6 +399,8 @@
  (/system/bin/bootstat --record_boot_reason)' (pid${SPACE}
  (/system/bin/bootstat --record_time_since_factory_reset)'...
  (/system/bin/bootstat --record_time_since_factory_reset)' (pid${SPACE}
+ (/system/bin/bootstat --set_system_boot_reason)'...
+ (/system/bin/bootstat --set_system_boot_reason)' (pid${SPACE}
  (/system/bin/bootstat -l)'...
  (/system/bin/bootstat -l)' (pid " |
   grep -v 'bootstat: Unknown boot reason: $' # Hikey Special
@@ -613,7 +659,7 @@
 test_optional_ota() {
   checkDebugBuild || return
   duration_test
-  adb shell su root touch /data/misc/bootstat/build_date >&2
+  adb_su touch /data/misc/bootstat/build_date >&2 </dev/null
   adb reboot ota
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,ota
@@ -679,7 +725,7 @@
 test_factory_reset() {
   checkDebugBuild || return
   duration_test
-  adb shell su root rm /data/misc/bootstat/build_date >&2
+  adb_su rm /data/misc/bootstat/build_date >&2 </dev/null
   adb reboot >&2
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
@@ -715,7 +761,7 @@
   wait_for_screen
   ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
-  EXPECT_PROPERTY sys.boot.reason.last ""
+  EXPECT_PROPERTY sys.boot.reason.last "\(\|bootloader\)"
   check_boilerplate_properties
   report_bootstat_logs reboot,factory_reset bootloader \
     "-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \
@@ -766,12 +812,12 @@
   enterPstore
   # Send it _many_ times to combat devices with flakey pstore
   for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
-    echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
+    echo 'healthd: battery l=2 ' | adb_su tee /dev/kmsg >/dev/null
   done
   adb reboot cold >&2
   adb wait-for-device
   wait_for_screen
-  adb shell su root \
+  adb_su </dev/null \
     cat /proc/fs/pstore/console-ramoops \
         /proc/fs/pstore/console-ramoops-0 2>/dev/null |
     grep 'healthd: battery l=' |
@@ -780,7 +826,7 @@
       if ! EXPECT_PROPERTY sys.boot.reason reboot,battery >/dev/null 2>/dev/null; then
         # retry
         for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
-          echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
+          echo 'healthd: battery l=2 ' | adb_su tee /dev/kmsg >/dev/null
         done
         adb reboot cold >&2
         adb wait-for-device
@@ -806,7 +852,7 @@
 test_optional_battery() {
   duration_test ">60"
   echo "      power on request" >&2
-  adb shell setprop sys.powerctl shutdown,battery
+  adb_sh setprop sys.powerctl shutdown,battery </dev/null
   sleep 5
   echo -n "WARNING: Please power device back up, waiting ... " >&2
   wait_for_screen -n >&2
@@ -827,7 +873,7 @@
 test_optional_battery_thermal() {
   duration_test ">60"
   echo "      power on request" >&2
-  adb shell setprop sys.powerctl shutdown,thermal,battery
+  adb_sh setprop sys.powerctl shutdown,thermal,battery </dev/null
   sleep 5
   echo -n "WARNING: Please power device back up, waiting ... " >&2
   wait_for_screen -n >&2
@@ -866,7 +912,7 @@
     panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
     pstore_ok=true
   fi
-  echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
+  echo c | adb_su tee /proc/sysrq-trigger >/dev/null
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
@@ -893,8 +939,8 @@
     panic_msg="\(kernel_panic,sysrq,test\|kernel_panic\)"
     pstore_ok=true
   fi
-  echo "SysRq : Trigger a crash : 'test'" | adb shell su root tee /dev/kmsg
-  echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
+  echo "SysRq : Trigger a crash : 'test'" | adb_su tee /dev/kmsg
+  echo c | adb_su tee /proc/sysrq-trigger >/dev/null
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
@@ -924,7 +970,7 @@
     pstore_ok=true
   fi
   echo "Kernel panic - not syncing: hung_task: blocked tasks" |
-    adb shell su root tee /dev/kmsg
+    adb_su tee /dev/kmsg
   adb reboot warm
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
@@ -956,7 +1002,7 @@
 test_thermal_shutdown() {
   duration_test ">60"
   echo "      power on request" >&2
-  adb shell setprop sys.powerctl shutdown,thermal
+  adb_sh setprop sys.powerctl shutdown,thermal </dev/null
   sleep 5
   echo -n "WARNING: Please power device back up, waiting ... " >&2
   wait_for_screen -n >&2
@@ -977,7 +1023,7 @@
 test_userrequested_shutdown() {
   duration_test ">60"
   echo "      power on request" >&2
-  adb shell setprop sys.powerctl shutdown,userrequested
+  adb_sh setprop sys.powerctl shutdown,userrequested </dev/null
   sleep 5
   echo -n "WARNING: Please power device back up, waiting ... " >&2
   wait_for_screen -n >&2
@@ -996,7 +1042,7 @@
 - NB: should report reboot,shell" ]
 test_shell_reboot() {
   duration_test
-  adb shell reboot
+  adb_sh reboot </dev/null
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,shell
   EXPECT_PROPERTY sys.boot.reason.last reboot,shell
@@ -1032,7 +1078,7 @@
 test_optional_rescueparty() {
   blind_reboot_test
   echo "WARNING: legacy devices are allowed to fail following ro.boot.bootreason result" >&2
-  EXPECT_PROPERTY ro.boot.bootreason reboot,rescueparty
+  EXPECT_PROPERTY ro.boot.bootreason '\(reboot\|reboot,rescueparty\)'
 }
 
 [ "USAGE: test_Its_Just_So_Hard_reboot
@@ -1049,7 +1095,7 @@
   else
     duration_test `expr ${DURATION_DEFAULT} + ${DURATION_DEFAULT}`
   fi
-  adb shell 'reboot "Its Just So Hard"'
+  adb_sh 'reboot "Its Just So Hard"' </dev/null
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
   EXPECT_PROPERTY sys.boot.reason.last reboot,its_just_so_hard
@@ -1146,7 +1192,121 @@
   run_bootloader
 }
 
-[ "USAGE: ${0##*/} [-s SERIAL] [tests]
+[ "USAGE: run_kBootReasonMap [--boot_reason_enum] value expected
+
+bootloader boot reason injection tests:
+- if --boot_reason_enum run bootstat executable for result instead.
+- inject boot reason into sys.boot.reason
+- run bootstat --set_system_boot_reason
+- check for expected enum
+- " ]
+run_kBootReasonMap() {
+  if [ X"--boot_reason_enum" = X"${1}" ]; then
+    shift
+    local sys_expected="${1}"
+    shift
+    local enum_expected="${1}"
+    adb_su bootstat --boot_reason_enum="${sys_expected}" |
+      (
+        local retval=-1
+        while read -r id match; do
+          if [ ${retval} = -1 -a ${enum_expected} = ${id} ]; then
+            retval=0
+          fi
+          if [ ${enum_expected} != ${id} ]; then
+            echo "ERROR: ${enum_expected} ${sys_expected} got ${id} ${match}" >&2
+            retval=1
+          fi
+        done
+        exit ${retval}
+      )
+    return
+  fi
+  local sys_expected="${1}"
+  shift
+  local enum_expected="${1}"
+  adb_su setprop sys.boot.reason "${sys_expected}" </dev/null
+  adb_su bootstat --record_boot_reason </dev/null
+  # Check values
+  EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
+  local retval=${?}
+  local result=`adb_su stat -c %Y /data/misc/bootstat/system_boot_reason </dev/null 2>/dev/null`
+  [ "${enum_expected}" = "${result}" ] ||
+    (
+      [ -n "${result}" ] || result="<nothing>"
+      echo "ERROR: ${enum_expected} ${sys_expected} got ${result}" >&2
+      false
+    ) ||
+    retval=${?}
+  return ${retval}
+}
+
+[ "USAGE: filter_kBootReasonMap </dev/stdin >/dev/stdout
+
+convert any regex expressions into a series of non-regex test strings" ]
+filter_kBootReasonMap() {
+  while read -r id match; do
+    case ${match} in
+      'reboot,[empty]')
+        echo ${id}          # matches b/c of special case
+        echo ${id} reboot,y # matches b/c of regex
+        echo 1 reboot,empty # negative test (ID for unknown is 1)
+        ;;
+      reboot)
+        echo 1 reboog       # negative test (ID for unknown is 1)
+        ;;
+      'reboot,pmic_off_fault,.*')
+        echo ${id} reboot,pmic_off_fault,hello,world
+        echo ${id} reboot,pmic_off_fault,
+        echo 1 reboot,pmic_off_fault
+        ;;
+    esac
+    echo ${id} "${match}"   # matches b/c of exact
+  done
+}
+
+[ "USAGE: test_kBootReasonMap
+
+kBootReasonMap test
+- (wait until screen is up, boot has completed)
+- read bootstat for kBootReasonMap entries and test them all" ]
+test_kBootReasonMap() {
+  checkDebugBuild || return
+  duration_test 15
+  local tempfile="`mktemp`"
+  local arg=--boot_reason_enum
+  adb_su bootstat ${arg} </dev/null 2>/dev/null |
+    filter_kBootReasonMap >${tempfile}
+  if [ ! -s "${tempfile}" ]; then
+    wait_for_screen
+    arg=
+    sed -n <${progpath}bootstat.cpp \
+      '/kBootReasonMap = {/,/^};/s/.*{"\([^"]*\)", *\([0-9][0-9]*\)},.*/\2 \1/p' |
+      sed 's/\\\\/\\/g' |
+      filter_kBootReasonMap >${tempfile}
+  fi
+  T=`adb_date`
+  retval=0
+  while read -r enum string; do
+    if [ X"${string}" != X"${string#*[[].[]]}" -o X"${string}" != X"${string#*\\.}" ]; then
+      if [ 'reboot\.empty' != "${string}" ]; then
+        echo "WARNING: regex snuck through filter_kBootReasonMap ${enum} ${string}" >&2
+        enum=1
+      fi
+    fi
+    run_kBootReasonMap ${arg} "${string}" "${enum}" </dev/null || retval=${?}
+  done <${tempfile}
+  rm ${tempfile}
+  ( exit ${retval} )
+  # See filter_kBootReasonMap() for negative tests and add them here too
+  report_bootstat_logs -t${T} \
+    '-bootstat: Service started: bootstat --boot_reason_enum=' \
+    '-bootstat: Unknown boot reason: reboot,empty' \
+    '-bootstat: Unknown boot reason: reboog' \
+    '-bootstat: Unknown boot reason: reboot,pmic_off_fault'
+}
+
+[ "USAGE: ${progname} [-s SERIAL] [tests]...
 
 Mainline executive to run the above tests" ]
 
@@ -1161,7 +1321,7 @@
 if [ X"--macros" != X"${1}" ]; then
 
   if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
-    echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
+    echo "USAGE: ${progname} [-s SERIAL] [tests]..."
     echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
     exit 0
   fi
@@ -1210,7 +1370,7 @@
                Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
                bootloader_kernel_panic bootloader_oem_powerkey \
                bootloader_wdog_reset bootloader_cold bootloader_warm \
-               bootloader_hard bootloader_recovery
+               bootloader_hard bootloader_recovery kBootReasonMap
     fi
     if [ X"nothing" = X"${1}" ]; then
       shift 1
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 1ce0ec4..558e6c4 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -89,7 +89,7 @@
 }
 
 void ShowHelp(const char* cmd) {
-  fprintf(stderr, "Usage: %s [options]\n", cmd);
+  fprintf(stderr, "Usage: %s [options]...\n", cmd);
   fprintf(stderr,
           "options include:\n"
           "  -h, --help              Show this help\n"
@@ -99,7 +99,8 @@
           "  --value                 Optional value to associate with the boot event\n"
           "  --record_boot_complete  Record metrics related to the time for the device boot\n"
           "  --record_boot_reason    Record the reason why the device booted\n"
-          "  --record_time_since_factory_reset Record the time since the device was reset\n");
+          "  --record_time_since_factory_reset  Record the time since the device was reset\n"
+          "  --boot_reason_enum=<reason>  Report the match to the kBootReasonMap table\n");
 }
 
 // Constructs a readable, printable string from the givencommand line
@@ -120,9 +121,10 @@
 // A mapping from boot reason string, as read from the ro.boot.bootreason
 // system property, to a unique integer ID. Viewers of log data dashboards for
 // the boot_reason metric may refer to this mapping to discern the histogram
-// values.
+// values.  Regex matching, to manage the scale, as a minimum require either
+// [, \ or * to be present in the string to switch to checking.
 const std::map<std::string, int32_t> kBootReasonMap = {
-    {"empty", kEmptyBootReason},
+    {"reboot,[empty]", kEmptyBootReason},
     {"__BOOTSTAT_UNKNOWN__", kUnknownBootReason},
     {"normal", 2},
     {"recovery", 3},
@@ -299,6 +301,9 @@
     {"reboot,dm-verity_device_corrupted", 172},
     {"reboot,dm-verity_enforcing", 173},
     {"reboot,keys_clear", 174},
+    {"reboot,pmic_off_fault,.*", 175},
+    {"reboot,pmic_off_s3rst,.*", 176},
+    {"reboot,pmic_off_other,.*", 177},
 };
 
 // Converts a string value representing the reason the system booted to an
@@ -314,6 +319,16 @@
     return kEmptyBootReason;
   }
 
+  for (const auto& [match, id] : kBootReasonMap) {
+    // Regex matches as a minimum require either [, \ or * to be present.
+    if (match.find_first_of("[\\*") == match.npos) continue;
+    // enforce match from beginning to end
+    auto exact = match;
+    if (exact[0] != '^') exact = "^" + exact;
+    if (exact[exact.size() - 1] != '$') exact = exact + "$";
+    if (std::regex_search(boot_reason, std::regex(exact))) return id;
+  }
+
   LOG(INFO) << "Unknown boot reason: " << boot_reason;
   return kUnknownBootReason;
 }
@@ -1266,6 +1281,19 @@
   boot_event_store.AddBootEventWithValue("time_since_factory_reset", time_since_factory_reset);
 }
 
+// List the associated boot reason(s), if arg is nullptr then all.
+void PrintBootReasonEnum(const char* arg) {
+  int value = -1;
+  if (arg != nullptr) {
+    value = BootReasonStrToEnum(arg);
+  }
+  for (const auto& [match, id] : kBootReasonMap) {
+    if ((value < 0) || (value == id)) {
+      printf("%u\t%s\n", id, match.c_str());
+    }
+  }
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -1280,6 +1308,7 @@
   static const char boot_complete_str[] = "record_boot_complete";
   static const char boot_reason_str[] = "record_boot_reason";
   static const char factory_reset_str[] = "record_time_since_factory_reset";
+  static const char boot_reason_enum_str[] = "boot_reason_enum";
   static const struct option long_options[] = {
       // clang-format off
       { "help",                 no_argument,       NULL,   'h' },
@@ -1291,6 +1320,7 @@
       { boot_complete_str,      no_argument,       NULL,   0 },
       { boot_reason_str,        no_argument,       NULL,   0 },
       { factory_reset_str,      no_argument,       NULL,   0 },
+      { boot_reason_enum_str,   optional_argument, NULL,   0 },
       { NULL,                   0,                 NULL,   0 }
       // clang-format on
   };
@@ -1315,6 +1345,8 @@
           RecordBootReason();
         } else if (option_name == factory_reset_str) {
           RecordFactoryReset();
+        } else if (option_name == boot_reason_enum_str) {
+          PrintBootReasonEnum(optarg);
         } else {
           LOG(ERROR) << "Invalid option: " << option_name;
         }
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 4043fc6..da049ef 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -38,6 +38,7 @@
 
 using android::base::ParseByteCount;
 using android::base::ParseInt;
+using android::base::ReadFileToString;
 using android::base::Split;
 using android::base::StartsWith;
 
@@ -660,6 +661,8 @@
         TransformFstabForGsi(fstab);
     }
 
+    SkipMountingPartitions(fstab);
+
     return true;
 }
 
@@ -687,6 +690,36 @@
         return false;
     }
 
+    SkipMountingPartitions(fstab);
+
+    return true;
+}
+
+// For GSI to skip mounting /product and /product_services, until there are
+// well-defined interfaces between them and /system. Otherwise, the GSI flashed
+// on /system might not be able to work with /product and /product_services.
+// When they're skipped here, /system/product and /system/product_services in
+// GSI will be used.
+bool SkipMountingPartitions(Fstab* fstab) {
+    constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
+
+    std::string skip_config;
+    if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
+        return true;
+    }
+
+    for (const auto& skip_mount_point : Split(skip_config, "\n")) {
+        if (skip_mount_point.empty()) {
+            continue;
+        }
+        auto it = std::remove_if(fstab->begin(), fstab->end(),
+                                 [&skip_mount_point](const auto& entry) {
+                                     return entry.mount_point == skip_mount_point;
+                                 });
+        fstab->erase(it, fstab->end());
+        LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
+    }
+
     return true;
 }
 
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 88da41d..d7afed6 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -99,6 +99,7 @@
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
 bool ReadFstabFromDt(Fstab* fstab, bool log = true);
 bool ReadDefaultFstab(Fstab* fstab);
+bool SkipMountingPartitions(Fstab* fstab);
 
 FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
 
diff --git a/init/Android.mk b/init/Android.mk
index efa8d87..b02c926 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -65,6 +65,11 @@
 LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
 
+# Install adb_debug.prop into debug ramdisk.
+# This allows adb root on a user build, when debug ramdisk is used.
+LOCAL_REQUIRED_MODULES := \
+   adb_debug.prop \
+
 # Set up the same mount points on the ramdisk that system-as-root contains.
 LOCAL_POST_INSTALL_CMD := mkdir -p \
     $(TARGET_RAMDISK_OUT)/apex \
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 3900f72..3e76556 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -43,7 +43,6 @@
 #include "uevent_listener.h"
 #include "util.h"
 
-using android::base::ReadFileToString;
 using android::base::Split;
 using android::base::Timer;
 using android::fs_mgr::AvbHandle;
@@ -55,6 +54,7 @@
 using android::fs_mgr::FstabEntry;
 using android::fs_mgr::ReadDefaultFstab;
 using android::fs_mgr::ReadFstabFromDt;
+using android::fs_mgr::SkipMountingPartitions;
 
 using namespace std::literals;
 
@@ -524,38 +524,10 @@
     return true;
 }
 
-// For GSI to skip mounting /product and /product_services, until there are
-// well-defined interfaces between them and /system. Otherwise, the GSI flashed
-// on /system might not be able to work with /product and /product_services.
-// When they're skipped here, /system/product and /system/product_services in
-// GSI will be used.
-bool FirstStageMount::TrySkipMountingPartitions() {
-    constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
-
-    std::string skip_config;
-    if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
-        return true;
-    }
-
-    for (const auto& skip_mount_point : Split(skip_config, "\n")) {
-        if (skip_mount_point.empty()) {
-            continue;
-        }
-        auto it = std::remove_if(fstab_.begin(), fstab_.end(),
-                                 [&skip_mount_point](const auto& entry) {
-                                     return entry.mount_point == skip_mount_point;
-                                 });
-        fstab_.erase(it, fstab_.end());
-        LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
-    }
-
-    return true;
-}
-
 bool FirstStageMount::MountPartitions() {
     if (!TrySwitchSystemAsRoot()) return false;
 
-    if (!TrySkipMountingPartitions()) return false;
+    if (!SkipMountingPartitions(&fstab_)) return false;
 
     for (auto current = fstab_.begin(); current != fstab_.end();) {
         // We've already mounted /system above.
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 81adbe4..a1e9551 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -104,7 +104,24 @@
     const char* name;
 };
 
+static int PropertyAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
+    auto* d = reinterpret_cast<PropertyAuditData*>(data);
+
+    if (!d || !d->name || !d->cr) {
+        LOG(ERROR) << "AuditCallback invoked with null data arguments!";
+        return 0;
+    }
+
+    snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
+             d->cr->gid);
+    return 0;
+}
+
 void property_init() {
+    selinux_callback cb;
+    cb.func_audit = PropertyAuditCallback;
+    selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
     mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
     CreateSerializedPropertyInfo();
     if (__system_property_area_init()) {
@@ -296,18 +313,20 @@
         return result == sizeof(value);
     }
 
+    bool GetSourceContext(std::string* source_context) const {
+        char* c_source_context = nullptr;
+        if (getpeercon(socket_, &c_source_context) != 0) {
+            return false;
+        }
+        *source_context = c_source_context;
+        freecon(c_source_context);
+        return true;
+    }
+
     int socket() { return socket_; }
 
     const ucred& cred() { return cred_; }
 
-    std::string source_context() const {
-        char* source_context = nullptr;
-        getpeercon(socket_, &source_context);
-        std::string result = source_context;
-        freecon(source_context);
-        return result;
-    }
-
   private:
     bool PollIn(uint32_t* timeout_ms) {
         struct pollfd ufds[1];
@@ -526,10 +545,15 @@
         prop_name[PROP_NAME_MAX-1] = 0;
         prop_value[PROP_VALUE_MAX-1] = 0;
 
+        std::string source_context;
+        if (!socket.GetSourceContext(&source_context)) {
+            PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed";
+            return;
+        }
+
         const auto& cr = socket.cred();
         std::string error;
-        uint32_t result =
-            HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
+        uint32_t result = HandlePropertySet(prop_name, prop_value, source_context, cr, &error);
         if (result != PROP_SUCCESS) {
             LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -548,9 +572,16 @@
           return;
         }
 
+        std::string source_context;
+        if (!socket.GetSourceContext(&source_context)) {
+            PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed";
+            socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
+            return;
+        }
+
         const auto& cr = socket.cred();
         std::string error;
-        uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
+        uint32_t result = HandlePropertySet(name, value, source_context, cr, &error);
         if (result != PROP_SUCCESS) {
             LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -879,19 +910,6 @@
     update_sys_usb_config();
 }
 
-static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
-    auto* d = reinterpret_cast<PropertyAuditData*>(data);
-
-    if (!d || !d->name || !d->cr) {
-        LOG(ERROR) << "AuditCallback invoked with null data arguments!";
-        return 0;
-    }
-
-    snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
-             d->cr->gid);
-    return 0;
-}
-
 bool LoadPropertyInfoFromFile(const std::string& filename,
                               std::vector<PropertyInfoEntry>* property_infos) {
     auto file_contents = std::string();
@@ -962,10 +980,6 @@
 }
 
 void StartPropertyService(Epoll* epoll) {
-    selinux_callback cb;
-    cb.func_audit = SelinuxAuditCallback;
-    selinux_set_callback(SELINUX_CB_AUDIT, cb);
-
     property_set("ro.property_service.version", "2");
 
     property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 8d150ad..7e6bf45 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -24,18 +24,21 @@
 __BEGIN_DECLS
 
 static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
-static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
 
 bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
 bool CgroupGetAttributePath(const std::string& attr_name, std::string* path);
 bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
 
-bool UsePerAppMemcg();
-
 bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
 bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
                         bool use_fd_cache = false);
 
+#ifndef __ANDROID_VNDK__
+
+static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
+
+bool UsePerAppMemcg();
+
 // Return 0 and removes the cgroup if there are no longer any processes in it.
 // Returns -1 in the case of an error occurring or if there are processes still running
 // even after retrying for up to 200ms.
@@ -55,4 +58,6 @@
 
 void removeAllProcessGroups(void);
 
+#endif // __ANDROID_VNDK__
+
 __END_DECLS
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index c464c17..f084cd2 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -377,4 +377,13 @@
 	$(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \
 		echo $(lib).so >> $@;)
 
+#######################################
+# adb_debug.prop in debug ramdisk
+include $(CLEAR_VARS)
+LOCAL_MODULE := adb_debug.prop
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_DEBUG_RAMDISK_OUT)
+include $(BUILD_PREBUILT)
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/adb_debug.prop b/rootdir/adb_debug.prop
new file mode 100644
index 0000000..37e2f2d
--- /dev/null
+++ b/rootdir/adb_debug.prop
@@ -0,0 +1,12 @@
+# Note: This file will be loaded with highest priority to override
+# other system properties, if a special ramdisk with "/force_debuggable"
+# is used and the device is unlocked.
+
+# Disable adb authentication to allow test automation on user build GSI
+ro.adb.secure=0
+
+# Allow 'adb root' on user build GSI
+ro.debuggable=1
+
+# Introduce this property to indicate that init has loaded adb_debug.prop
+ro.force.debuggable=1