Merge "add event log range for audioserver"
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 1128993..f7be8f9 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -69,17 +69,23 @@
 }
 
 static bool secure_mkdirs(const std::string& path) {
-    uid_t uid = -1;
-    gid_t gid = -1;
-    unsigned int mode = 0775;
-    uint64_t capabilities = 0;
-
     if (path[0] != '/') return false;
 
     std::vector<std::string> path_components = android::base::Split(path, "/");
     std::string partial_path;
     for (const auto& path_component : path_components) {
-        if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
+        uid_t uid = -1;
+        gid_t gid = -1;
+        unsigned int mode = 0775;
+        uint64_t capabilities = 0;
+
+        if (path_component.empty()) {
+            continue;
+        }
+
+        if (partial_path.empty() || partial_path.back() != OS_PATH_SEPARATOR) {
+            partial_path += OS_PATH_SEPARATOR;
+        }
         partial_path += path_component;
 
         if (should_use_fs_config(partial_path)) {
diff --git a/adb/test_device.py b/adb/test_device.py
index f995be2..5aa2684 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -866,6 +866,21 @@
             self.assertTrue('Permission denied' in output or
                             'Read-only file system' in output)
 
+    @requires_non_root
+    def test_push_directory_creation(self):
+        """Regression test for directory creation.
+
+        Bug: http://b/110953234
+        """
+        with tempfile.NamedTemporaryFile() as tmp_file:
+            tmp_file.write('\0' * 1024 * 1024)
+            tmp_file.flush()
+            remote_path = self.DEVICE_TEMP_DIR + '/test_push_directory_creation'
+            self.device.shell(['rm', '-rf', remote_path])
+
+            remote_path += '/filename'
+            self.device.push(local=tmp_file.name, remote=remote_path)
+
     def _test_pull(self, remote_file, checksum):
         tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
         tmp_write.close()
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 7f0801f..aea6ce6 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -487,21 +487,14 @@
 // Note: to print the pointer, use "<< static_cast<const void*>(string_pointer)" instead.
 // Note: a not-recommended alternative is to let Clang ignore the warning by adding
 //       -Wno-user-defined-warnings to CPPFLAGS.
-#ifdef __clang__
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wgcc-compat"
 #define OSTREAM_STRING_POINTER_USAGE_WARNING \
     __attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning")))
-#else
-#define OSTREAM_STRING_POINTER_USAGE_WARNING /* empty */
-#endif
 inline std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer)
     OSTREAM_STRING_POINTER_USAGE_WARNING {
   return stream << static_cast<const void*>(string_pointer);
 }
-#ifdef __clang__
 #pragma clang diagnostic pop
-#endif
-#undef OSTREAM_STRING_POINTER_USAGE_WARNING
 
 }  // namespace std
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 0c8eac0..49cc0c9 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -170,17 +170,7 @@
 //
 //  In either case this macro has no effect on runtime behavior and performance
 //  of code.
-#if defined(__clang__) && defined(__has_warning)
-#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
 #define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
-#endif
-#endif
-
-#ifndef FALLTHROUGH_INTENDED
-#define FALLTHROUGH_INTENDED \
-  do {                       \
-  } while (0)
-#endif
 
 // Current ABI string
 #if defined(__arm__)
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 933d877..fc68d56 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -42,9 +42,7 @@
     const char* suffixes = "bkmgtpe";
     const char* suffix;
     if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false;
-#if __clang__  // TODO: win32 still builds with GCC :-(
     if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false;
-#endif
   }
   if (max < result) {
     return false;
diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h
index d56e935..5c55e63 100644
--- a/base/include/android-base/thread_annotations.h
+++ b/base/include/android-base/thread_annotations.h
@@ -16,11 +16,7 @@
 
 #pragma once
 
-#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
-#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
-#endif
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
 
 #define CAPABILITY(x) \
       THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index d334e30..6cfcd3f 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -142,10 +142,4 @@
 
 template <typename T>
 int close(const android::base::unique_fd_impl<T>&)
-#if defined(__clang__)
-  __attribute__((__unavailable__(
-#else
-  __attribute__((__error__(
-#endif
-    "close called on unique_fd"
-  )));
+    __attribute__((__unavailable__("close called on unique_fd")));
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index ddd1caf..71d3ecb 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -24,6 +24,7 @@
 NORMAL="${ESCAPE}[0m"
 # Best guess to an average device's reboot time, refined as tests return
 DURATION_DEFAULT=45
+STOP_ON_FAILURE=false
 
 # Helper functions
 
@@ -50,11 +51,18 @@
   fi
 }
 
+[ "USAGE: get_property <prop>
+
+Returns the property value" ]
+get_property() {
+  adb shell getprop ${1} 2>&1 </dev/null
+}
+
 [ "USAGE: isDebuggable
 
 Returns: true if device is (likely) a debug build" ]
 isDebuggable() {
-  if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then
+  if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
     false
   fi
 }
@@ -93,7 +101,7 @@
     return 1
   fi
   adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
-  test_reason="`adb shell getprop persist.test.boot.reason 2>/dev/null`"
+  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
     return 1
@@ -188,9 +196,9 @@
       if [ 0 != ${counter} ]; then
         adb wait-for-device </dev/null >/dev/null 2>/dev/null
       fi
-      if [ -n "`adb shell getprop sys.boot.reason </dev/null 2>/dev/null`" ]
+      if [ -n "`get_property sys.boot.reason`" ]
       then
-        vals=`adb shell getprop </dev/null 2>/dev/null |
+        vals=`get_property |
               sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
         if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
         then
@@ -223,15 +231,38 @@
   rval="${2}"
   shift 2
   if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
-    echo "ERROR: expected \"${lval}\" got \"${rval}\"" >&2
-    if [ -n "${*}" ] ; then
-      echo "       ${*}" >&2
+    if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
+*}" ]; then
+      echo "ERROR: expected \"${lval}\"" >&2
+      echo "       got \"${rval}\"" |
+        sed ': again
+             N
+             s/\(\n\)\([^ ]\)/\1             \2/
+             t again' >&2
+      if [ -n "${*}" ] ; then
+        echo "       ${*}" >&2
+      fi
+    else
+      echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
     fi
     return 1
   fi
   if [ -n "${*}" ] ; then
     if [ X"${lval}" != X"${rval}" ]; then
-      echo "INFO: ok \"${lval}\"(=\"${rval}\") ${*}" >&2
+      if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval%
+*}" ]; then
+        echo "INFO: ok \"${lval}\"" >&2
+        echo "       = \"${rval}\"" |
+          sed ': again
+               N
+               s/\(\n\)\([^ ]\)/\1          \2/
+               t again' >&2
+        if [ -n "${*}" ] ; then
+          echo "      ${*}" >&2
+        fi
+      else
+        echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+      fi
     else
       echo "INFO: ok \"${lval}\" ${*}" >&2
     fi
@@ -250,7 +281,7 @@
   property="${1}"
   value="${2}"
   shift 2
-  val=`adb shell getprop ${property} 2>&1`
+  val=`get_property ${property}`
   EXPECT_EQ "${value}" "${val}" for Android property ${property}
   local_ret=${?}
   if [ 0 != ${local_ret} -a "ro.boot.bootreason" = "${property}" ]; then
@@ -317,6 +348,7 @@
 init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
 init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
 init    : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
+init    : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc
  (/system/bin/bootstat --record_boot_complete)'...
  (/system/bin/bootstat --record_boot_complete)' (pid${SPACE}
  (/system/bin/bootstat --record_boot_reason)'...
@@ -392,6 +424,9 @@
     echo "${GREEN}[       OK ]${NORMAL} ${TEST} ${*}"
   else
     echo "${RED}[  FAILED  ]${NORMAL} ${TEST} ${*}"
+    if ${STOP_ON_FAILURE}; then
+      exit ${save_ret}
+    fi
   fi
   return ${save_ret}
 }
@@ -462,7 +497,7 @@
 
 NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
 validate_property() {
-  val="`adb shell getprop ${1} 2>&1`"
+  val=`get_property ${1}`
   ret=`validate_reason "${val}"`
   if [ "reboot" = "${ret}" ]; then
     ret=`validate_reason "reboot,${val}"`
@@ -470,6 +505,17 @@
   echo ${ret}
 }
 
+[ "USAGE: check_boilerblate_properties
+
+Check for common property values" ]
+check_boilerplate_properties() {
+  EXPECT_PROPERTY persist.sys.boot.reason ""
+  save_ret=${?}
+  reason=`validate_property sys.boot.reason`
+  ( exit ${save_ret} )  # because one can not just do ?=${save_ret}
+  EXPECT_PROPERTY persist.sys.boot.reason.history "${reason},[1-9][0-9]*\(\|[^0-9].*\)"
+}
+
 #
 # Actual test frames
 #
@@ -487,6 +533,7 @@
   duration_test 1
   wait_for_screen
   retval=0
+  # sys.boot.reason is last for a reason
   check_set="ro.boot.bootreason sys.boot.reason.last sys.boot.reason"
   bootloader=""
   # NB: this test could fail if performed _after_ optional_factory_reset test
@@ -498,12 +545,11 @@
     check_set="ro.boot.bootreason sys.boot.reason"
     bootloader="bootloader"
   fi
-  EXPECT_PROPERTY persist.sys.boot.reason ""
   for prop in ${check_set}; do
     reason=`validate_property ${prop}`
     EXPECT_PROPERTY ${prop} ${reason} || retval=${?}
   done
-  # sys.boot.reason is last for a reason
+  check_boilerplate_properties || retval=${?}
   report_bootstat_logs ${reason} ${bootloader}
   return ${retval}
 }
@@ -557,7 +603,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
   EXPECT_PROPERTY sys.boot.reason.last bootloader
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,ota bootloader
 }
 
@@ -572,7 +618,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,ota
   EXPECT_PROPERTY sys.boot.reason.last reboot,ota
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,ota
 }
 
@@ -604,7 +650,7 @@
   fi
   EXPECT_PROPERTY sys.boot.reason ${reasons}
   EXPECT_PROPERTY sys.boot.reason.last ${reason}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs ${reason} ${bootloader_reason}
 }
 
@@ -638,7 +684,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
   EXPECT_PROPERTY sys.boot.reason.last "reboot,.*"
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,factory_reset reboot, reboot,adb \
     "-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \
     "-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date"
@@ -670,7 +716,7 @@
   ( 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 persist.sys.boot.reason ""
+  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" \
     "-bootstat: Failed to parse boot time record: /data/misc/bootstat/last_boot_time_utc" \
@@ -744,7 +790,7 @@
 
   EXPECT_PROPERTY sys.boot.reason shutdown,battery
   EXPECT_PROPERTY sys.boot.reason.last cold
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
   exitPstore
 }
@@ -766,7 +812,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,battery
   EXPECT_PROPERTY sys.boot.reason.last shutdown,battery
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,battery
 }
 
@@ -787,7 +833,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery
   EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal,battery
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,thermal,battery
 }
 
@@ -824,7 +870,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs kernel_panic,sysrq
   exitPstore
 }
@@ -852,7 +898,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs kernel_panic,sysrq,test \
     "-bootstat: Unknown boot reason: kernel_panic,sysrq,test"
   exitPstore
@@ -883,7 +929,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason ${panic_msg}
   EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs kernel_panic,hung
   exitPstore
 }
@@ -916,7 +962,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,thermal
   EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,thermal
 }
 
@@ -937,7 +983,7 @@
   wait_for_screen -n >&2
   EXPECT_PROPERTY sys.boot.reason shutdown,userrequested
   EXPECT_PROPERTY sys.boot.reason.last shutdown,userrequested
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs shutdown,userrequested
 }
 
@@ -954,7 +1000,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,shell
   EXPECT_PROPERTY sys.boot.reason.last reboot,shell
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,shell
 }
 
@@ -971,7 +1017,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,adb
   EXPECT_PROPERTY sys.boot.reason.last reboot,adb
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,adb
 }
 
@@ -1007,7 +1053,7 @@
   wait_for_screen
   EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
   EXPECT_PROPERTY sys.boot.reason.last reboot,its_just_so_hard
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs reboot,its_just_so_hard
 }
 
@@ -1057,7 +1103,7 @@
   EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}"
   EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
   EXPECT_PROPERTY sys.boot.reason.last "${last_expected}"
-  EXPECT_PROPERTY persist.sys.boot.reason ""
+  check_boilerplate_properties
   report_bootstat_logs "${sys_expected}"
 }
 
@@ -1111,88 +1157,98 @@
   shift 2
 fi
 
-if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
-  echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
-  echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
-  exit 0
-fi
+# Helpful for debugging, allows us to import the functions.
+if [ X"--macros" != X"${1}" ]; then
 
-# Check if all conditions for the script are sane
+  if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
+    echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
+    echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+    exit 0
+  fi
 
-if [ -z "${ANDROID_SERIAL}" ]; then
-  ndev=`(
-      adb devices | grep -v 'List of devices attached'
-      fastboot devices
-    ) |
-    grep -v "^[${SPACE}${TAB}]*\$" |
-    wc -l`
-  if [ ${ndev} -gt 1 ]; then
-    echo "ERROR: no target device specified, ${ndev} connected" >&2
-    echo "${RED}[  FAILED  ]${NORMAL}"
-    exit 1
+  if [ X"--stop" = X"${1}" ]; then
+    STOP_ON_FAILURE=true
+    shift
   fi
-  echo "WARNING: no target device specified" >&2
-fi
 
-ret=0
+  # Check if all conditions for the script are sane
 
-# Test Series
-if [ X"all" = X"${*}" ]; then
-  # automagically pick up all test_<function>s.
-  eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
-  if [ X"nothing" = X"${1}" ]; then
-    shift 1
-  fi
-fi
-if [ -z "$*" ]; then
-  # automagically pick up all test_<function>, except test_optional_<function>.
-  eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
-                            grep -v '^optional_'`
-  if [ -z "${2}" ]; then
-    # Hard coded should shell fail to find them above (search/permission issues)
-    eval set properties ota cold factory_reset hard battery unknown \
-             kernel_panic kernel_panic_subreason kernel_panic_hung warm \
-             thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
-             Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
-             bootloader_kernel_panic bootloader_oem_powerkey \
-             bootloader_wdog_reset bootloader_wdog_reset bootloader_wdog_reset \
-             bootloader_hard bootloader_recovery
-  fi
-  if [ X"nothing" = X"${1}" ]; then
-    shift 1
-  fi
-fi
-echo "INFO: selected test(s): ${@}" >&2
-echo
-# Prepare device
-setBootloaderBootReason 2>/dev/null
-# Start pouring through the tests.
-failures=
-successes=
-for t in "${@}"; do
-  wrap_test ${t}
-  retval=${?}
-  if [ 0 = ${retval} ]; then
-    if [ -z "${successes}" ]; then
-      successes=${t}
-    else
-      successes="${successes} ${t}"
+  if [ -z "${ANDROID_SERIAL}" ]; then
+    ndev=`(
+        adb devices | grep -v 'List of devices attached'
+        fastboot devices
+      ) |
+      grep -v "^[${SPACE}${TAB}]*\$" |
+      wc -l`
+    if [ ${ndev} -gt 1 ]; then
+      echo "ERROR: no target device specified, ${ndev} connected" >&2
+      echo "${RED}[  FAILED  ]${NORMAL}"
+      exit 1
     fi
-  else
-    ret=${retval}
-    if [ -z "${failures}" ]; then
-      failures=${t}
-    else
-      failures="${failures} ${t}"
+    echo "WARNING: no target device specified" >&2
+  fi
+
+  ret=0
+
+  # Test Series
+  if [ X"all" = X"${*}" ]; then
+    # automagically pick up all test_<function>s.
+    eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+    if [ X"nothing" = X"${1}" ]; then
+      shift 1
     fi
   fi
+  if [ -z "$*" ]; then
+    # automagically pick up all test_<function>, except test_optional_<function>.
+    eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
+                              grep -v '^optional_'`
+    if [ -z "${2}" ]; then
+      # Hard coded should shell fail to find them (search/permission issues)
+      eval set properties ota cold factory_reset hard battery unknown \
+               kernel_panic kernel_panic_subreason kernel_panic_hung warm \
+               thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
+               Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
+               bootloader_kernel_panic bootloader_oem_powerkey \
+               bootloader_wdog_reset bootloader_cold bootloader_warm \
+               bootloader_hard bootloader_recovery
+    fi
+    if [ X"nothing" = X"${1}" ]; then
+      shift 1
+    fi
+  fi
+  echo "INFO: selected test(s): ${@}" >&2
   echo
-done
+  # Prepare device
+  setBootloaderBootReason 2>/dev/null
+  # Start pouring through the tests.
+  failures=
+  successes=
+  for t in "${@}"; do
+    wrap_test ${t}
+    retval=${?}
+    if [ 0 = ${retval} ]; then
+      if [ -z "${successes}" ]; then
+        successes=${t}
+      else
+        successes="${successes} ${t}"
+      fi
+    else
+      ret=${retval}
+      if [ -z "${failures}" ]; then
+        failures=${t}
+      else
+        failures="${failures} ${t}"
+      fi
+    fi
+    echo
+  done
 
-if [ -n "${successes}" ]; then
-  echo "${GREEN}[  PASSED  ]${NORMAL} ${successes}"
+  if [ -n "${successes}" ]; then
+    echo "${GREEN}[  PASSED  ]${NORMAL} ${successes}"
+  fi
+  if [ -n "${failures}" ]; then
+    echo "${RED}[  FAILED  ]${NORMAL} ${failures}"
+  fi
+  exit ${ret}
+
 fi
-if [ -n "${failures}" ]; then
-  echo "${RED}[  FAILED  ]${NORMAL} ${failures}"
-fi
-exit ${ret}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 7ec57ec..4d9f1ac 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -27,6 +27,7 @@
 #include <cstddef>
 #include <cstdio>
 #include <ctime>
+#include <iterator>
 #include <map>
 #include <memory>
 #include <regex>
@@ -123,12 +124,12 @@
   return std::string(&temp[0], len);
 }
 
-void SetProperty(const char* key, const std::string& val) {
-  property_set(key, val.c_str());
+bool SetProperty(const char* key, const std::string& val) {
+  return property_set(key, val.c_str()) == 0;
 }
 
-void SetProperty(const char* key, const char* val) {
-  property_set(key, val);
+bool SetProperty(const char* key, const char* val) {
+  return property_set(key, val) == 0;
 }
 
 constexpr int32_t kEmptyBootReason = 0;
@@ -735,8 +736,49 @@
 const char system_reboot_reason_property[] = "sys.boot.reason";
 const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
 const char last_last_reboot_reason_property[] = "sys.boot.reason.last";
+constexpr size_t history_reboot_reason_size = 4;
+const char history_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY ".history";
 const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
 
+// Land system_boot_reason into system_reboot_reason_property.
+// Shift system_boot_reason into history_reboot_reason_property.
+void BootReasonAddToHistory(const std::string& system_boot_reason) {
+  if (system_boot_reason.empty()) return;
+  LOG(INFO) << "Canonical boot reason: " << system_boot_reason;
+  auto old_system_boot_reason = GetProperty(system_reboot_reason_property);
+  if (!SetProperty(system_reboot_reason_property, system_boot_reason)) {
+    SetProperty(system_reboot_reason_property, system_boot_reason.substr(0, PROPERTY_VALUE_MAX - 1));
+  }
+  auto reason_history = android::base::Split(GetProperty(history_reboot_reason_property), "\n");
+  static auto mark = time(nullptr);
+  auto mark_str = std::string(",") + std::to_string(mark);
+  auto marked_system_boot_reason = system_boot_reason + mark_str;
+  if (!reason_history.empty()) {
+    // delete any entries that we just wrote in a previous
+    // call and leveraging duplicate line handling
+    auto last = old_system_boot_reason + mark_str;
+    // trim the list to (history_reboot_reason_size - 1)
+    ssize_t max = history_reboot_reason_size;
+    for (auto it = reason_history.begin(); it != reason_history.end();) {
+      if (it->empty() || (last == *it) || (marked_system_boot_reason == *it) || (--max <= 0)) {
+        it = reason_history.erase(it);
+      } else {
+        last = *it;
+        ++it;
+      }
+    }
+  }
+  // insert at the front, concatenating mark (<epoch time>) detail to the value.
+  reason_history.insert(reason_history.begin(), marked_system_boot_reason);
+  // If the property string is too long ( > PROPERTY_VALUE_MAX)
+  // we get an error, so trim out last entry and try again.
+  while (!(SetProperty(history_reboot_reason_property, android::base::Join(reason_history, '\n')))) {
+    auto it = std::prev(reason_history.end());
+    if (it == reason_history.end()) break;
+    reason_history.erase(it);
+  }
+}
+
 // Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
 std::string BootReasonStrToReason(const std::string& boot_reason) {
   std::string ret(GetProperty(system_reboot_reason_property));
@@ -795,6 +837,8 @@
         {"!warm", "wdt_by_pass_pwk"},  // change flavour of blunt
         {"!reboot", "^wdt$"},          // change flavour of blunt
         {"reboot,tool", "tool_by_pass_pwk"},
+        {"!reboot,longkey", "reboot_longkey"},
+        {"!reboot,longkey", "kpdpwr"},
         {"bootloader", ""},
     };
 
@@ -930,13 +974,11 @@
   if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) {
     boot_complete_prefix = "factory_reset_" + boot_complete_prefix;
     boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
-    LOG(INFO) << "Canonical boot reason: reboot,factory_reset";
-    SetProperty(system_reboot_reason_property, "reboot,factory_reset");
+    BootReasonAddToHistory("reboot,factory_reset");
   } else if (build_date != record.second) {
     boot_complete_prefix = "ota_" + boot_complete_prefix;
     boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
-    LOG(INFO) << "Canonical boot reason: reboot,ota";
-    SetProperty(system_reboot_reason_property, "reboot,ota");
+    BootReasonAddToHistory("reboot,ota");
   }
 
   return boot_complete_prefix;
@@ -1034,7 +1076,7 @@
   const std::string bootloader_boot_reason(GetProperty(bootloader_reboot_reason_property));
   const std::string system_boot_reason(BootReasonStrToReason(bootloader_boot_reason));
   // Record the scrubbed system_boot_reason to the property
-  SetProperty(system_reboot_reason_property, system_boot_reason);
+  BootReasonAddToHistory(system_boot_reason);
   // Shift last_reboot_reason_property to last_last_reboot_reason_property
   std::string last_boot_reason(GetProperty(last_reboot_reason_property));
   if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 1f6f3c8..8bdc02f 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -287,9 +287,7 @@
     case SIGFPE: return "SIGFPE";
     case SIGILL: return "SIGILL";
     case SIGSEGV: return "SIGSEGV";
-#if defined(SIGSTKFLT)
     case SIGSTKFLT: return "SIGSTKFLT";
-#endif
     case SIGSTOP: return "SIGSTOP";
     case SIGSYS: return "SIGSYS";
     case SIGTRAP: return "SIGTRAP";
@@ -311,8 +309,14 @@
         case ILL_PRVREG: return "ILL_PRVREG";
         case ILL_COPROC: return "ILL_COPROC";
         case ILL_BADSTK: return "ILL_BADSTK";
+        case ILL_BADIADDR:
+          return "ILL_BADIADDR";
+        case __ILL_BREAK:
+          return "ILL_BREAK";
+        case __ILL_BNDMOD:
+          return "ILL_BNDMOD";
       }
-      static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
+      static_assert(NSIGILL == __ILL_BNDMOD, "missing ILL_* si_code");
       break;
     case SIGBUS:
       switch (si->si_code) {
@@ -334,36 +338,44 @@
         case FPE_FLTRES: return "FPE_FLTRES";
         case FPE_FLTINV: return "FPE_FLTINV";
         case FPE_FLTSUB: return "FPE_FLTSUB";
+        case __FPE_DECOVF:
+          return "FPE_DECOVF";
+        case __FPE_DECDIV:
+          return "FPE_DECDIV";
+        case __FPE_DECERR:
+          return "FPE_DECERR";
+        case __FPE_INVASC:
+          return "FPE_INVASC";
+        case __FPE_INVDEC:
+          return "FPE_INVDEC";
+        case FPE_FLTUNK:
+          return "FPE_FLTUNK";
+        case FPE_CONDTRAP:
+          return "FPE_CONDTRAP";
       }
-      static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
+      static_assert(NSIGFPE == FPE_CONDTRAP, "missing FPE_* si_code");
       break;
     case SIGSEGV:
       switch (si->si_code) {
         case SEGV_MAPERR: return "SEGV_MAPERR";
         case SEGV_ACCERR: return "SEGV_ACCERR";
-#if defined(SEGV_BNDERR)
         case SEGV_BNDERR: return "SEGV_BNDERR";
-#endif
-#if defined(SEGV_PKUERR)
         case SEGV_PKUERR: return "SEGV_PKUERR";
-#endif
+        case SEGV_ACCADI:
+          return "SEGV_ACCADI";
+        case SEGV_ADIDERR:
+          return "SEGV_ADIDERR";
+        case SEGV_ADIPERR:
+          return "SEGV_ADIPERR";
       }
-#if defined(SEGV_PKUERR)
-      static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
-#elif defined(SEGV_BNDERR)
-      static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
-#else
-      static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
-#endif
+      static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
       break;
-#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
     case SIGSYS:
       switch (si->si_code) {
         case SYS_SECCOMP: return "SYS_SECCOMP";
       }
       static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
       break;
-#endif
     case SIGTRAP:
       switch (si->si_code) {
         case TRAP_BRKPT: return "TRAP_BRKPT";
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index f7086a8..f59fa84 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -52,6 +52,7 @@
         "libcrypto",
         "libcrypto_utils",
         "liblp",
+        "libfs_mgr",
     ],
     srcs: [
         "builder_test.cpp",
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 0e4838c..421f4e6 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -16,22 +16,47 @@
 
 #include "liblp/builder.h"
 
+#if defined(__linux__)
+#include <linux/fs.h>
+#endif
 #include <string.h>
+#include <sys/ioctl.h>
 
 #include <algorithm>
 
+#include <android-base/unique_fd.h>
 #include <uuid/uuid.h>
 
 #include "liblp/metadata_format.h"
+#include "liblp/reader.h"
 #include "utility.h"
 
 namespace android {
 namespace fs_mgr {
 
-// Align a byte count up to the nearest 512-byte sector.
-template <typename T>
-static inline T AlignToSector(T value) {
-    return (value + (LP_SECTOR_SIZE - 1)) & ~T(LP_SECTOR_SIZE - 1);
+bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
+#if defined(__linux__)
+    android::base::unique_fd fd(open(block_device.c_str(), O_RDONLY));
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
+        return false;
+    }
+    if (!GetDescriptorSize(fd, &device_info->size)) {
+        return false;
+    }
+    if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+        return false;
+    }
+    if (ioctl(fd, BLKALIGNOFF, &device_info->alignment_offset) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+        return false;
+    }
+    return true;
+#else
+    LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
+    return false;
+#endif
 }
 
 void LinearExtent::AddTo(LpMetadata* out) const {
@@ -56,7 +81,7 @@
 }
 
 void Partition::ShrinkTo(uint64_t requested_size) {
-    uint64_t aligned_size = AlignToSector(requested_size);
+    uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
     if (size_ <= aligned_size) {
         return;
     }
@@ -82,11 +107,28 @@
     DCHECK(size_ == requested_size);
 }
 
-std::unique_ptr<MetadataBuilder> MetadataBuilder::New(uint64_t blockdevice_size,
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
+                                                      uint32_t slot_number) {
+    std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number);
+    if (!metadata) {
+        return nullptr;
+    }
+    std::unique_ptr<MetadataBuilder> builder = New(*metadata.get());
+    if (!builder) {
+        return nullptr;
+    }
+    BlockDeviceInfo device_info;
+    if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) {
+        builder->set_block_device_info(device_info);
+    }
+    return builder;
+}
+
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const BlockDeviceInfo& device_info,
                                                       uint32_t metadata_max_size,
                                                       uint32_t metadata_slot_count) {
     std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
-    if (!builder->Init(blockdevice_size, metadata_max_size, metadata_slot_count)) {
+    if (!builder->Init(device_info, metadata_max_size, metadata_slot_count)) {
         return nullptr;
     }
     return builder;
@@ -135,10 +177,13 @@
             }
         }
     }
+
+    device_info_.alignment = geometry_.alignment;
+    device_info_.alignment_offset = geometry_.alignment_offset;
     return true;
 }
 
-bool MetadataBuilder::Init(uint64_t blockdevice_size, uint32_t metadata_max_size,
+bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata_max_size,
                            uint32_t metadata_slot_count) {
     if (metadata_max_size < sizeof(LpMetadataHeader)) {
         LERROR << "Invalid metadata maximum size.";
@@ -150,7 +195,22 @@
     }
 
     // Align the metadata size up to the nearest sector.
-    metadata_max_size = AlignToSector(metadata_max_size);
+    metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
+
+    // Check that device properties are sane.
+    if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) {
+        LERROR << "Alignment offset is not sector-aligned.";
+        return false;
+    }
+    if (device_info_.alignment % LP_SECTOR_SIZE != 0) {
+        LERROR << "Partition alignment is not sector-aligned.";
+        return false;
+    }
+    if (device_info_.alignment_offset > device_info_.alignment) {
+        LERROR << "Partition alignment offset is greater than its alignment.";
+        return false;
+    }
+    device_info_ = device_info;
 
     // We reserve a geometry block (4KB) plus space for each copy of the
     // maximum size of a metadata blob. Then, we double that space since
@@ -158,20 +218,36 @@
     uint64_t reserved =
             LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
     uint64_t total_reserved = reserved * 2;
-
-    if (blockdevice_size < total_reserved || blockdevice_size - total_reserved < LP_SECTOR_SIZE) {
+    if (device_info_.size < total_reserved) {
         LERROR << "Attempting to create metadata on a block device that is too small.";
         return false;
     }
 
-    // The last sector is inclusive. We subtract one to make sure that logical
-    // partitions won't overlap with the same sector as the backup metadata,
-    // which could happen if the block device was not aligned to LP_SECTOR_SIZE.
-    geometry_.first_logical_sector = reserved / LP_SECTOR_SIZE;
-    geometry_.last_logical_sector = ((blockdevice_size - reserved) / LP_SECTOR_SIZE) - 1;
+    // Compute the first free sector, factoring in alignment.
+    uint64_t free_area = AlignTo(reserved, device_info_.alignment, device_info_.alignment_offset);
+    uint64_t first_sector = free_area / LP_SECTOR_SIZE;
+
+    // Compute the last free sector, which is inclusive. We subtract 1 to make
+    // sure that logical partitions won't overlap with the same sector as the
+    // backup metadata, which could happen if the block device was not aligned
+    // to LP_SECTOR_SIZE.
+    uint64_t last_sector = ((device_info_.size - reserved) / LP_SECTOR_SIZE) - 1;
+
+    // If this check fails, it means either (1) we did not have free space to
+    // allocate a single sector, or (2) we did, but the alignment was high
+    // enough to bump the first sector out of range. Either way, we cannot
+    // continue.
+    if (first_sector > last_sector) {
+        LERROR << "Not enough space to allocate any partition tables.";
+        return false;
+    }
+
+    geometry_.first_logical_sector = first_sector;
+    geometry_.last_logical_sector = last_sector;
     geometry_.metadata_max_size = metadata_max_size;
     geometry_.metadata_slot_count = metadata_slot_count;
-    DCHECK(geometry_.last_logical_sector >= geometry_.first_logical_sector);
+    geometry_.alignment = device_info_.alignment;
+    geometry_.alignment_offset = device_info_.alignment_offset;
     return true;
 }
 
@@ -209,7 +285,7 @@
 
 bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_size) {
     // Align the space needed up to the nearest sector.
-    uint64_t aligned_size = AlignToSector(requested_size);
+    uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
     if (partition->size() >= aligned_size) {
         return true;
     }
@@ -259,10 +335,16 @@
             continue;
         }
 
+        uint64_t aligned = AlignSector(previous.end);
+        if (aligned >= current.start) {
+            // After alignment, this extent is not usable.
+            continue;
+        }
+
         // This gap is enough to hold the remainder of the space requested, so we
         // can allocate what we need and return.
-        if (current.start - previous.end >= sectors_needed) {
-            auto extent = std::make_unique<LinearExtent>(sectors_needed, previous.end);
+        if (current.start - aligned >= sectors_needed) {
+            auto extent = std::make_unique<LinearExtent>(sectors_needed, aligned);
             sectors_needed -= extent->num_sectors();
             new_extents.push_back(std::move(extent));
             break;
@@ -270,7 +352,7 @@
 
         // This gap is not big enough to fit the remainder of the space requested,
         // so consume the whole thing and keep looking for more.
-        auto extent = std::make_unique<LinearExtent>(current.start - previous.end, previous.end);
+        auto extent = std::make_unique<LinearExtent>(current.start - aligned, aligned);
         sectors_needed -= extent->num_sectors();
         new_extents.push_back(std::move(extent));
     }
@@ -286,8 +368,12 @@
         }
         DCHECK(first_sector <= geometry_.last_logical_sector);
 
+        // Note: After alignment, |first_sector| may be > the last usable sector.
+        first_sector = AlignSector(first_sector);
+
         // Note: the last usable sector is inclusive.
-        if (geometry_.last_logical_sector + 1 - first_sector < sectors_needed) {
+        if (first_sector > geometry_.last_logical_sector ||
+            geometry_.last_logical_sector + 1 - first_sector < sectors_needed) {
             LERROR << "Not enough free space to expand partition: " << partition->name();
             return false;
         }
@@ -351,5 +437,26 @@
     return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE;
 }
 
+uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
+    // Note: when reading alignment info from the Kernel, we don't assume it
+    // is aligned to the sector size, so we round up to the nearest sector.
+    uint64_t lba = sector * LP_SECTOR_SIZE;
+    uint64_t aligned = AlignTo(lba, device_info_.alignment, device_info_.alignment_offset);
+    return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
+}
+
+void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
+    device_info_.size = device_info.size;
+
+    // The kernel does not guarantee these values are present, so we only
+    // replace existing values if the new values are non-zero.
+    if (device_info.alignment) {
+        device_info_.alignment = device_info.alignment;
+    }
+    if (device_info.alignment_offset) {
+        device_info_.alignment_offset = device_info.alignment_offset;
+    }
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 2983f0f..08440a3 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 #include <liblp/builder.h>
+#include "fs_mgr.h"
+#include "utility.h"
 
 using namespace std;
 using namespace android::fs_mgr;
@@ -127,6 +129,89 @@
     EXPECT_EQ(exported->geometry.metadata_max_size, 1024);
 }
 
+TEST(liblp, InternalAlignment) {
+    // Test the metadata fitting within alignment.
+    BlockDeviceInfo device_info(1024 * 1024, 768 * 1024, 0);
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 2);
+    ASSERT_NE(builder, nullptr);
+    unique_ptr<LpMetadata> exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
+    EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+
+    // Test a large alignment offset thrown in.
+    device_info.alignment_offset = 753664;
+    builder = MetadataBuilder::New(device_info, 1024, 2);
+    ASSERT_NE(builder, nullptr);
+    exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
+    EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+
+    // Test only an alignment offset (which should simply bump up the first
+    // logical sector).
+    device_info.alignment = 0;
+    builder = MetadataBuilder::New(device_info, 1024, 2);
+    ASSERT_NE(builder, nullptr);
+    exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    EXPECT_EQ(exported->geometry.first_logical_sector, 1484);
+    EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+
+    // Test a small alignment with an alignment offset.
+    device_info.alignment = 12 * 1024;
+    device_info.alignment_offset = 3 * 1024;
+    builder = MetadataBuilder::New(device_info, 16 * 1024, 2);
+    ASSERT_NE(builder, nullptr);
+    exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    EXPECT_EQ(exported->geometry.first_logical_sector, 78);
+    EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
+
+    // Test a small alignment with no alignment offset.
+    device_info.alignment = 11 * 1024;
+    builder = MetadataBuilder::New(device_info, 16 * 1024, 2);
+    ASSERT_NE(builder, nullptr);
+    exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    EXPECT_EQ(exported->geometry.first_logical_sector, 72);
+    EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
+}
+
+TEST(liblp, InternalPartitionAlignment) {
+    BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664);
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
+
+    Partition* a = builder->AddPartition("a", TEST_GUID, 0);
+    ASSERT_NE(a, nullptr);
+    Partition* b = builder->AddPartition("b", TEST_GUID2, 0);
+    ASSERT_NE(b, nullptr);
+
+    // Add a bunch of small extents to each, interleaving.
+    for (size_t i = 0; i < 10; i++) {
+        ASSERT_TRUE(builder->GrowPartition(a, a->size() + 4096));
+        ASSERT_TRUE(builder->GrowPartition(b, b->size() + 4096));
+    }
+    EXPECT_EQ(a->size(), 40960);
+    EXPECT_EQ(b->size(), 40960);
+
+    unique_ptr<LpMetadata> exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+
+    // Check that each starting sector is aligned.
+    for (const auto& extent : exported->extents) {
+        ASSERT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR);
+        EXPECT_EQ(extent.num_sectors, 8);
+
+        uint64_t lba = extent.target_data * LP_SECTOR_SIZE;
+        uint64_t aligned_lba = AlignTo(lba, device_info.alignment, device_info.alignment_offset);
+        EXPECT_EQ(lba, aligned_lba);
+    }
+
+    // Sanity check one extent.
+    EXPECT_EQ(exported->extents.back().target_data, 30656);
+}
+
 TEST(liblp, UseAllDiskSpace) {
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
     EXPECT_EQ(builder->AllocatableSpace(), 1036288);
@@ -312,15 +397,72 @@
     static const size_t kMetadataSize = 64 * 1024;
 
     // No space to store metadata + geometry.
-    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize, kMetadataSize, 1);
+    BlockDeviceInfo device_info(kDiskSize, 0, 0);
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
     EXPECT_EQ(builder, nullptr);
 
     // No space to store metadata + geometry + one free sector.
-    builder = MetadataBuilder::New(kDiskSize + LP_METADATA_GEOMETRY_SIZE * 2, kMetadataSize, 1);
+    device_info.size += LP_METADATA_GEOMETRY_SIZE * 2;
+    builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
     EXPECT_EQ(builder, nullptr);
 
     // Space for metadata + geometry + one free sector.
-    builder = MetadataBuilder::New(kDiskSize + LP_METADATA_GEOMETRY_SIZE * 2 + LP_SECTOR_SIZE,
-                                   kMetadataSize, 1);
+    device_info.size += LP_SECTOR_SIZE;
+    builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
     EXPECT_NE(builder, nullptr);
+
+    // Test with alignment.
+    device_info.alignment = 131072;
+    builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
+    EXPECT_EQ(builder, nullptr);
+
+    device_info.alignment = 0;
+    device_info.alignment_offset = 32768 - LP_SECTOR_SIZE;
+    builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
+    EXPECT_EQ(builder, nullptr);
+}
+
+TEST(liblp, block_device_info) {
+    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+                                                               fs_mgr_free_fstab);
+    ASSERT_NE(fstab, nullptr);
+
+    // This should read from the "super" partition once we have a well-defined
+    // way to access it.
+    struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), "/data");
+    ASSERT_NE(rec, nullptr);
+
+    BlockDeviceInfo device_info;
+    ASSERT_TRUE(GetBlockDeviceInfo(rec->blk_device, &device_info));
+
+    // Sanity check that the device doesn't give us some weird inefficient
+    // alignment.
+    ASSERT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0);
+    ASSERT_EQ(device_info.alignment_offset % LP_SECTOR_SIZE, 0);
+    ASSERT_LE(device_info.alignment_offset, INT_MAX);
+
+    // Having an alignment offset > alignment doesn't really make sense.
+    ASSERT_LT(device_info.alignment_offset, device_info.alignment);
+}
+
+TEST(liblp, UpdateBlockDeviceInfo) {
+    BlockDeviceInfo device_info(1024 * 1024, 4096, 1024);
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+    ASSERT_NE(builder, nullptr);
+
+    EXPECT_EQ(builder->block_device_info().size, device_info.size);
+    EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment);
+    EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
+
+    device_info.alignment = 0;
+    device_info.alignment_offset = 2048;
+    builder->set_block_device_info(device_info);
+    EXPECT_EQ(builder->block_device_info().alignment, 4096);
+    EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
+
+    device_info.alignment = 8192;
+    device_info.alignment_offset = 0;
+    builder->set_block_device_info(device_info);
+    EXPECT_EQ(builder->block_device_info().alignment, 8192);
+    EXPECT_EQ(builder->block_device_info().alignment_offset, 2048);
 }
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 671a3bd..3cd95ae 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -30,6 +30,24 @@
 
 class LinearExtent;
 
+// By default, partitions are aligned on a 1MiB boundary.
+static const uint32_t kDefaultPartitionAlignment = 1024 * 1024;
+
+struct BlockDeviceInfo {
+    BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0) {}
+    BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset)
+        : size(size), alignment(alignment), alignment_offset(alignment_offset) {}
+    // Size of the block device, in bytes.
+    uint64_t size;
+    // Optimal target alignment, in bytes. Partition extents will be aligned to
+    // this value by default. This value must be 0 or a multiple of 512.
+    uint32_t alignment;
+    // Alignment offset to parent device (if any), in bytes. The sector at
+    // |alignment_offset| on the target device is correctly aligned on its
+    // parent device. This value must be 0 or a multiple of 512.
+    uint32_t alignment_offset;
+};
+
 // Abstraction around dm-targets that can be encoded into logical partition tables.
 class Extent {
   public:
@@ -107,14 +125,29 @@
     // If the parameters would yield invalid metadata, nullptr is returned. This
     // could happen if the block device size is too small to store the metadata
     // and backup copies.
-    static std::unique_ptr<MetadataBuilder> New(uint64_t blockdevice_size,
+    static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
                                                 uint32_t metadata_max_size,
                                                 uint32_t metadata_slot_count);
 
+    // Import an existing table for modification. This reads metadata off the
+    // given block device and imports it. It also adjusts alignment information
+    // based on run-time values in the operating system.
+    static std::unique_ptr<MetadataBuilder> New(const std::string& block_device,
+                                                uint32_t slot_number);
+
     // Import an existing table for modification. If the table is not valid, for
     // example it contains duplicate partition names, then nullptr is returned.
+    // This method is for testing or changing off-line tables.
     static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
 
+    // Wrapper around New() with a BlockDeviceInfo that only specifies a device
+    // size. This is a convenience method for tests.
+    static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size,
+                                                uint32_t metadata_slot_count) {
+        BlockDeviceInfo device_info(blockdev_size, 0, 0);
+        return New(device_info, metadata_max_size, metadata_slot_count);
+    }
+
     // Export metadata so it can be serialized to an image, to disk, or mounted
     // via device-mapper.
     std::unique_ptr<LpMetadata> Export();
@@ -156,16 +189,28 @@
     // Amount of space that can be allocated to logical partitions.
     uint64_t AllocatableSpace() const;
 
+    // Merge new block device information into previous values. Alignment values
+    // are only overwritten if the new values are non-zero.
+    void set_block_device_info(const BlockDeviceInfo& device_info);
+    const BlockDeviceInfo& block_device_info() const { return device_info_; }
+
   private:
     MetadataBuilder();
-    bool Init(uint64_t blockdevice_size, uint32_t metadata_max_size, uint32_t metadata_slot_count);
+    bool Init(const BlockDeviceInfo& info, uint32_t metadata_max_size, uint32_t metadata_slot_count);
     bool Init(const LpMetadata& metadata);
 
+    uint64_t AlignSector(uint64_t sector);
+
     LpMetadataGeometry geometry_;
     LpMetadataHeader header_;
     std::vector<std::unique_ptr<Partition>> partitions_;
+    BlockDeviceInfo device_info_;
 };
 
+// Read BlockDeviceInfo for a given block device. This always returns false
+// for non-Linux operating systems.
+bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info);
+
 }  // namespace fs_mgr
 }  // namespace android
 
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 8522435..27602ac 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -107,6 +107,28 @@
      * backup geometry block at the very end.
      */
     uint64_t last_logical_sector;
+
+    /* 64: Alignment for defining partitions or partition extents. For example,
+     * an alignment of 1MiB will require that all partitions have a size evenly
+     * divisible by 1MiB, and that the smallest unit the partition can grow by
+     * is 1MiB.
+     *
+     * Alignment is normally determined at runtime when growing or adding
+     * partitions. If for some reason the alignment cannot be determined, then
+     * this predefined alignment in the geometry is used instead. By default
+     * it is set to 1MiB.
+     */
+    uint32_t alignment;
+
+    /* 68: Alignment offset for "stacked" devices. For example, if the "super"
+     * partition itself is not aligned within the parent block device's
+     * partition table, then we adjust for this in deciding where to place
+     * |first_logical_sector|.
+     *
+     * Similar to |alignment|, this will be derived from the operating system.
+     * If it cannot be determined, it is assumed to be 0.
+     */
+    uint32_t alignment_offset;
 } __attribute__((packed)) LpMetadataGeometry;
 
 /* The logical partition metadata has a number of tables; they are described
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 7938186..a0eeec9 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -41,11 +41,18 @@
         LERROR << "Logical partition metadata has invalid geometry magic signature.";
         return false;
     }
+    // Reject if the struct size is larger than what we compiled. This is so we
+    // can compute a checksum with the |struct_size| field rather than using
+    // sizeof.
+    if (geometry->struct_size > sizeof(LpMetadataGeometry)) {
+        LERROR << "Logical partition metadata has unrecognized fields.";
+        return false;
+    }
     // Recompute and check the CRC32.
     {
         LpMetadataGeometry temp = *geometry;
         memset(&temp.checksum, 0, sizeof(temp.checksum));
-        SHA256(&temp, sizeof(temp), temp.checksum);
+        SHA256(&temp, temp.struct_size, temp.checksum);
         if (memcmp(temp.checksum, geometry->checksum, sizeof(temp.checksum)) != 0) {
             LERROR << "Logical partition metadata has invalid geometry checksum.";
             return false;
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 5310cab..a590037 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -38,7 +38,8 @@
     }
 
     if (S_ISBLK(s.st_mode)) {
-        return get_block_device_size(fd);
+        *size = get_block_device_size(fd);
+        return *size != 0;
     }
 
     int64_t result = SeekFile64(fd, 0, SEEK_END);
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 09ed314..4522275 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -50,6 +50,30 @@
 // Compute a SHA256 hash.
 void SHA256(const void* data, size_t length, uint8_t out[32]);
 
+// Align |base| such that it is evenly divisible by |alignment|, which does not
+// have to be a power of two.
+constexpr uint64_t AlignTo(uint64_t base, uint32_t alignment) {
+    if (!alignment) {
+        return base;
+    }
+    uint64_t remainder = base % alignment;
+    if (remainder == 0) {
+        return base;
+    }
+    return base + (alignment - remainder);
+}
+
+// Same as the above |AlignTo|, except that |base| is only aligned when added to
+// |alignment_offset|.
+constexpr uint64_t AlignTo(uint64_t base, uint32_t alignment, uint32_t alignment_offset) {
+    uint64_t aligned = AlignTo(base, alignment) + alignment_offset;
+    if (aligned - alignment >= base) {
+        // We overaligned (base < alignment_offset).
+        return aligned - alignment;
+    }
+    return aligned;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
 
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 25e8a25..dcc569e 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -30,7 +30,7 @@
 
 TEST(liblp, GetMetadataOffset) {
     LpMetadataGeometry geometry = {
-            LP_METADATA_GEOMETRY_MAGIC, sizeof(geometry), {0}, 16384, 4, 10000, 80000};
+            LP_METADATA_GEOMETRY_MAGIC, sizeof(geometry), {0}, 16384, 4, 10000, 80000, 0, 0};
     EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
     EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
     EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);
@@ -41,3 +41,14 @@
     EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), -4096 - 16384 * 3);
     EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), -4096 - 16384 * 4);
 }
+
+TEST(liblp, AlignTo) {
+    EXPECT_EQ(AlignTo(37, 0), 37);
+    EXPECT_EQ(AlignTo(1024, 1024), 1024);
+    EXPECT_EQ(AlignTo(555, 1024), 1024);
+    EXPECT_EQ(AlignTo(555, 1000), 1000);
+    EXPECT_EQ(AlignTo(0, 1024), 0);
+    EXPECT_EQ(AlignTo(54, 32, 30), 62);
+    EXPECT_EQ(AlignTo(32, 32, 30), 62);
+    EXPECT_EQ(AlignTo(17, 32, 30), 30);
+}
diff --git a/init/init.cpp b/init/init.cpp
index 77c4fc4..686cd6e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -647,6 +647,9 @@
         // /mnt/vendor is used to mount vendor-specific partitions that can not be
         // part of the vendor partition, e.g. because they are mounted read-write.
         CHECKCALL(mkdir("/mnt/vendor", 0755));
+        // /mnt/product is used to mount product-specific partitions that can not be
+        // part of the product partition, e.g. because they are mounted read-write.
+        CHECKCALL(mkdir("/mnt/product", 0755));
 
 #undef CHECKCALL
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 625ffba..c1ae932 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -718,6 +718,9 @@
 
 on property:security.perf_harden=0
     write /proc/sys/kernel/perf_event_paranoid 1
+    write /proc/sys/kernel/perf_event_max_sample_rate ${debug.perf_event_max_sample_rate:-100000}
+    write /proc/sys/kernel/perf_cpu_time_max_percent ${debug.perf_cpu_time_max_percent:-25}
+    write /proc/sys/kernel/perf_event_mlock_kb ${debug.perf_event_mlock_kb:-516}
 
 on property:security.perf_harden=1
     write /proc/sys/kernel/perf_event_paranoid 3