Merge "Revert^2 "Enable APEX stubs for libnativeloader.""
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index d587589..4c5d8cb 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -356,6 +356,9 @@
     DWORD desiredAccess = 0;
     DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
 
+    // CreateFileW is inherently O_CLOEXEC by default.
+    options &= ~O_CLOEXEC;
+
     switch (options) {
         case O_RDONLY:
             desiredAccess = GENERIC_READ;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 430fc3d..14e5071 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -422,6 +422,9 @@
         with fake_adbd() as (port, _):
             serial = "localhost:{}".format(port)
             with adb_connect(self, serial):
+                # Wait a bit to give adb some time to connect.
+                time.sleep(0.25)
+
                 output = subprocess.check_output(["adb", "-s", serial,
                                                   "get-state"])
                 self.assertEqual(output.strip(), b"device")
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index f7901af..faa845d 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -16,6 +16,8 @@
 
 #include "android-base/mapped_file.h"
 
+#include <errno.h>
+
 namespace android {
 namespace base {
 
@@ -50,7 +52,14 @@
       new MappedFile{static_cast<char*>(base), length, slop, handle});
 #else
   void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd, file_offset);
-  if (base == MAP_FAILED) return nullptr;
+  if (base == MAP_FAILED) {
+    // http://b/119818070 "app crashes when reading asset of zero length".
+    // mmap fails with EINVAL for a zero length region.
+    if (errno == EINVAL && length == 0) {
+      return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0});
+    }
+    return nullptr;
+  }
   return std::unique_ptr<MappedFile>(new MappedFile{static_cast<char*>(base), length, slop});
 #endif
 }
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
index 7e89723..cfde73c 100644
--- a/base/mapped_file_test.cpp
+++ b/base/mapped_file_test.cpp
@@ -25,7 +25,6 @@
 #include <string>
 
 #include "android-base/file.h"
-#include "android-base/unique_fd.h"
 
 TEST(mapped_file, smoke) {
   TemporaryFile tf;
@@ -37,3 +36,13 @@
   ASSERT_EQ('l', m->data()[0]);
   ASSERT_EQ('o', m->data()[1]);
 }
+
+TEST(mapped_file, zero_length_mapping) {
+  // http://b/119818070 "app crashes when reading asset of zero length".
+  // mmap fails with EINVAL for a zero length region.
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
+  ASSERT_EQ(0u, m->size());
+}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 6700b6c..8528752 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -1019,6 +1019,7 @@
     auto stageTimingValues = android::base::Split(stageTiming, ":");
     DCHECK_EQ(2U, stageTimingValues.size());
 
+    if (stageTimingValues.size() < 2) continue;
     std::string stageName = stageTimingValues[0];
     int32_t time_ms;
     if (android::base::ParseInt(stageTimingValues[1], &time_ms)) {
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index 1300a27..85caf25 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -1,7 +1,9 @@
 # This file is the LOCAL_INIT_RC file for the bootstat command.
 
-# mirror bootloader boot reason to system boot reason
-on property:ro.boot.bootreason=*
+# Mirror bootloader boot reason to system boot reason
+# ro.boot.bootreason should be set by init already
+# before post-fs trigger
+on post-fs && property:ro.boot.bootreason=*
     setprop sys.boot.reason ${ro.boot.bootreason}
 
 on post-fs-data
@@ -66,11 +68,16 @@
 on property:init.svc.zygote=stopping
     setprop sys.logbootcomplete 0
 
+# Set boot reason
+on zygote-start
+    # Converts bootloader boot reason and persist.sys.boot.reason to system boot reason
+    # Need go after persist peroperties are loaded which is right before zygote-start trigger
+    exec_background - system log -- /system/bin/bootstat --set_system_boot_reason
+
 # Record boot complete metrics.
 on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
-    # Converts bootloader boot reason to system boot reason
     # Record boot_complete and related stats (decryption, etc).
     # Record the boot reason.
     # Record time since factory reset.
     # Log all boot events.
-    exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
+    exec_background - system log -- /system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index 8784c94..2aac260 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -74,7 +74,7 @@
 When *overlayfs* logic is feasible, it will use either the
 **/cache/overlay/** directory for non-A/B devices, or the
 **/mnt/scratch/overlay** directory for A/B devices that have
-access to *Logical Resizeable Android Partitions*.
+access to *Logical Resizable Android Partitions*.
 The backing store is used as soon as possible in the boot
 process and can occur at first stage init, or at the
 mount_all init rc commands.
@@ -94,12 +94,17 @@
   and thus free dynamic partition space.
 - Kernel must have CONFIG_OVERLAY_FS=y and will need to be patched
   with "*overlayfs: override_creds=off option bypass creator_cred*"
-  if higher than 4.6.
+  if kernel is higher than 4.6.
+  The patch is available on the upstream mailing list and the latest as of
+  Feb 8 2019 is https://lore.kernel.org/patchwork/patch/1009299/.
+  This patch adds an override_creds _mount_ option to overlayfs that
+  permits legacy behavior for systems that do not have overlapping
+  sepolicy rules, principals of least privilege, which is how Android behaves.
 - *adb enable-verity* will free up overlayfs and as a bonus the
   device will be reverted pristine to before any content was updated.
   Update engine does not take advantage of this, will perform a full OTA.
 - Update engine may not run if *fs_mgr_overlayfs_is_setup*() reports
-  true as adb remount overrides are incompatable with an OTA resources.
+  true as adb remount overrides are incompatible with an OTA resources.
 - For implementation simplicity on retrofit dynamic partition devices,
   take the whole alternate super (eg: if "*a*" slot, then the whole of
   "*system_b*").
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index c7d2cb9..b508b56 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -67,6 +67,13 @@
     return ret;
 }
 
+// determine if a filesystem is available
+bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) {
+    std::string filesystems;
+    if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false;
+    return filesystems.find("\t" + filesystem + "\n") != std::string::npos;
+}
+
 }  // namespace
 
 #if ALLOW_ADBD_DISABLE_VERITY == 0  // If we are a user build, provide stubs
@@ -321,6 +328,7 @@
 bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point,
                                 bool* change) {
     auto ret = true;
+    if (fs_mgr_overlayfs_already_mounted(mount_point)) return ret;
     auto fsrec_mount_point = overlay + "/" + android::base::Basename(mount_point) + "/";
 
     if (setfscreatecon(kOverlayfsFileContext)) {
@@ -531,7 +539,10 @@
     std::vector<std::string> mounts;
     auto verity = fs_mgr_overlayfs_verity_enabled_list();
     for (auto& entry : *fstab) {
-        if (!fs_mgr_wants_overlayfs(&entry)) continue;
+        if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
+            !fs_mgr_wants_overlayfs(&entry)) {
+            continue;
+        }
         std::string new_mount_point(fs_mgr_mount_point(entry.mount_point.c_str()));
         if (mount_point && (new_mount_point != mount_point)) continue;
         if (std::find(verity.begin(), verity.end(), android::base::Basename(new_mount_point)) !=
@@ -625,8 +636,12 @@
 
 // Only a suggestion for _first_ try during mounting
 std::string fs_mgr_overlayfs_scratch_mount_type() {
-    if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_access("/sys/fs/f2fs")) return "f2fs";
-    if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_access("/sys/fs/ext4")) return "ext4";
+    if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("f2fs")) {
+        return "f2fs";
+    }
+    if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("ext4")) {
+        return "ext4";
+    }
     return "auto";
 }
 
@@ -657,7 +672,7 @@
     if (mnt_type == "f2fs") {
         command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint);
     } else if (mnt_type == "ext4") {
-        command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
+        command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
     } else {
         errno = ESRCH;
         LERROR << mnt_type << " has no mkfs cookbook";
@@ -821,7 +836,10 @@
 
     auto scratch_can_be_mounted = true;
     for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
-        if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+        if (fs_mgr_overlayfs_already_mounted(mount_point)) {
+            ret = true;
+            continue;
+        }
         if (scratch_can_be_mounted) {
             scratch_can_be_mounted = false;
             auto scratch_device = fs_mgr_overlayfs_scratch_device();
@@ -1002,7 +1020,7 @@
     if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) {
         return OverlayfsValidResult::kOverrideCredsRequired;
     }
-    if (!fs_mgr_access("/sys/module/overlay")) {
+    if (!fs_mgr_overlayfs_filesystem_available("overlay")) {
         return OverlayfsValidResult::kNotSupported;
     }
     struct utsname uts;
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 4d9bc61..8298bf2 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1,4 +1,15 @@
 #! /bin/bash
+#
+# Divided into four section:
+#
+##  USAGE
+##  Helper Variables
+##  Helper Functions
+##  MAINLINE
+
+##
+##  USAGE
+##
 
 USAGE="USAGE: `basename ${0}` [-s <SerialNumber>]
 
@@ -17,20 +28,26 @@
   exit 0
 fi
 
-# Helper Variables
+##
+##  Helper Variables
+##
 
 SPACE=" "
 # A _real_ embedded tab character
 TAB="`echo | tr '\n' '\t'`"
 # A _real_ embedded escape character
 ESCAPE="`echo | tr '\n' '\033'`"
+# A _real_ embedded carriage return character
+CR="`echo | tr '\n' '\r'`"
 GREEN="${ESCAPE}[38;5;40m"
 RED="${ESCAPE}[38;5;196m"
 ORANGE="${ESCAPE}[38;5;255:165:0m"
 BLUE="${ESCAPE}[35m"
 NORMAL="${ESCAPE}[0m"
 
-# Helper functions
+##
+##  Helper Functions
+##
 
 [ "USAGE: inFastboot
 
@@ -68,6 +85,8 @@
       args="${args}${i}"
     elif [ X"${i}" != X"${i#* }" ]; then
       args="${args}'${i}'"
+    elif [ X"${i}" != X"${i#*${TAB}}" ]; then
+      args="${args}'${i}'"
     else
       args="${args}${i}"
     fi
@@ -130,16 +149,62 @@
 
 Returns: true if the reboot command succeeded" ]
 adb_reboot() {
-  adb reboot remount-test &&
+  adb reboot remount-test || true
   sleep 2
 }
 
+[ "USAGE: format_duration [<seconds>|<seconds>s|<minutes>m|<hours>h|<days>d]
+
+human readable output whole seconds, whole minutes or mm:ss" ]
+format_duration() {
+  if [ -z "${1}" ]; then
+    echo unknown
+    return
+  fi
+  duration="${1}"
+  if [ X"${duration}" != X"${duration%s}" ]; then
+    duration=${duration%s}
+  elif [ X"${duration}" != X"${duration%m}" ]; then
+    duration=`expr ${duration%m} \* 60`
+  elif [ X"${duration}" != X"${duration%h}" ]; then
+    duration=`expr ${duration%h} \* 3600`
+  elif [ X"${duration}" != X"${duration%d}" ]; then
+    duration=`expr ${duration%d} \* 86400`
+  fi
+  seconds=`expr ${duration} % 60`
+  minutes=`expr \( ${duration} / 60 \) % 60`
+  hours=`expr ${duration} / 3600`
+  if [ 0 -eq ${minutes} -a 0 -eq ${hours} ]; then
+    if [ 1 -eq ${duration} ]; then
+      echo 1 second
+      return
+    fi
+    echo ${duration} seconds
+    return
+  elif [ 60 -eq ${duration} ]; then
+    echo 1 minute
+    return
+  elif [ 0 -eq ${seconds} -a 0 -eq ${hours} ]; then
+    echo ${minutes} minutes
+    return
+  fi
+  if [ 0 -eq ${hours} ]; then
+    echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10`
+    return
+  fi
+  echo ${hours}:`expr ${minutes} / 10``expr ${minutes} % 10`:`expr ${seconds} / 10``expr ${seconds} % 10`
+}
+
 [ "USAGE: adb_wait [timeout]
 
 Returns: waits until the device has returned for adb or optional timeout" ]
 adb_wait() {
   if [ -n "${1}" ]; then
+    echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}"
     timeout --preserve-status --signal=KILL ${1} adb wait-for-device
+    retval=${?}
+    echo -n "                                                                             ${CR}"
+    return ${retval}
   else
     adb wait-for-device
   fi
@@ -152,10 +217,14 @@
   # fastboot has no wait-for-device, but it does an automatic
   # wait and requires (even a nonsensical) command to do so.
   if [ -n "${1}" ]; then
-    timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
+    echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}"
+    timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device >/dev/null 2>/dev/null
+    retval=${?}
+    echo -n "                                                                             ${CR}"
+    ( exit ${retval} )
   else
-    fastboot wait-for-device >/dev/null
-  fi >/dev/null 2>/dev/null ||
+    fastboot wait-for-device >/dev/null 2>/dev/null
+  fi ||
     inFastboot
 }
 
@@ -310,9 +379,14 @@
     -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
     -e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
     -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
+    -e "^rootfs / rootfs rw," \
     -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
 }
 
+##
+##  MAINLINE
+##
+
 if [ X"-s" = X"${1}" -a -n "${2}" ]; then
   export ANDROID_SERIAL="${2}"
   shift 2
@@ -320,7 +394,7 @@
 
 inFastboot && die "device in fastboot mode"
 if ! inAdb; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} device not in adb mode ... waiting 2 minutes"
+  echo "${ORANGE}[  WARNING ]${NORMAL} device not in adb mode"
   adb_wait 2m
 fi
 inAdb || die "specified device not in adb mode"
@@ -331,19 +405,38 @@
   enforcing=false
 fi
 
-# Do something
+# Do something.
 
 D=`get_property ro.serialno`
 [ -n "${D}" ] || D=`get_property ro.boot.serialno`
 [ -z "${D}" ] || ANDROID_SERIAL=${D}
+USB_SERIAL=
+[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
+                                          grep usb |
+                                          xargs grep -l ${ANDROID_SERIAL}`
+USB_ADDRESS=
+if [ -n "${USB_SERIAL}" ]; then
+  USB_ADDRESS=${USB_SERIAL%/serial}
+  USB_ADDRESS=usb${USB_ADDRESS##*/}
+fi
+[ -z "${ANDROID_SERIAL}${USB_ADDRESS}" ] ||
+  echo "${BLUE}[     INFO ]${NORMAL}" ${ANDROID_SERIAL} ${USB_ADDRESS} >&2
 BUILD_DESCRIPTION=`get_property ro.build.description`
-echo "${BLUE}[     INFO ]${NORMAL} ${ANDROID_SERIAL} ${BUILD_DESCRIPTION}" >&2
+[ -z "${BUILD_DESCRIPTION}" ] ||
+  echo "${BLUE}[     INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2
+
+VERITY_WAS_ENABLED=false
+if [ "orange" = "`get_property ro.boot.verifiedbootstate`" -a \
+     "2" = "`get_property partition.system.verified`" ]; then
+  VERITY_WAS_ENABLED=true
+fi
 
 echo "${GREEN}[ RUN      ]${NORMAL} Testing kernel support for overlayfs" >&2
 
 overlayfs_supported=true;
 adb_wait || die "wait for device failed"
-adb_sh ls -d /sys/module/overlay </dev/null >/dev/null &&
+adb_sh ls -d /sys/module/overlay </dev/null >/dev/null 2>/dev/null ||
+  adb_sh grep "nodev${TAB}overlay" /proc/filesystems </dev/null >/dev/null 2>/dev/null &&
   echo "${GREEN}[       OK ]${NORMAL} overlay module present" >&2 ||
   (
     echo "${ORANGE}[  WARNING ]${NORMAL} overlay module not present" >&2 &&
@@ -391,9 +484,9 @@
   echo "${ORANGE}[  WARNING ]${NORMAL} rebooting before test" >&2
   adb_reboot &&
     adb_wait 2m ||
-    die "lost device after reboot after wipe"
+    die "lost device after reboot after wipe (USB stack broken?)"
   adb_root ||
-    die "lost device after elevation to root after wipe"
+    die "lost device after elevation to root after wipe (USB stack broken?)"
 fi
 D=`adb_sh df -k </dev/null` &&
   H=`echo "${D}" | head -1` &&
@@ -455,9 +548,9 @@
   L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
   adb_reboot &&
     adb_wait 2m ||
-    die "lost device after reboot requested"
+    die "lost device after reboot requested (USB stack broken?)"
   adb_root ||
-    die "lost device after elevation to root"
+    die "lost device after elevation to root (USB stack broken?)"
   rebooted=true
   # re-disable verity to see the setup remarks expected
   T=`adb_date`
@@ -544,7 +637,7 @@
     echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
     die  "overlay takeover after remount"
   !(adb_sh grep "^overlay " /proc/mounts </dev/null |
-    grep -v "^overlay /\(vendor\|system\)/..* overlay ro," |
+    grep -v "^overlay /\(vendor\|system\|bionic\)/..* overlay ro," |
     grep " overlay ro,") &&
     !(adb_sh grep " rw," /proc/mounts </dev/null |
       skip_administrative_mounts data) ||
@@ -555,7 +648,7 @@
   fi
 fi
 
-# Check something
+# Check something.
 
 echo "${GREEN}[ RUN      ]${NORMAL} push content to /system and /vendor" >&2
 
@@ -569,17 +662,22 @@
   die "vendor hello"
 check_eq "${A}" "${B}" /vendor before reboot
 
-# download libc.so, append some gargage, push back, and check if the file is updated.
+# Download libc.so, append some gargage, push back, and check if the file
+# is updated.
 tempdir="`mktemp -d`"
 cleanup() {
   rm -rf ${tempdir}
 }
-adb pull /system/lib/bootstrap/libc.so ${tempdir} || die "pull libc.so from device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir} >/dev/null ||
+  die "pull libc.so from device"
 garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`"
 echo ${garbage} >> ${tempdir}/libc.so
-adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so || die "push libc.so to device"
-adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || die "pull libc.so from device"
-diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
+adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so >/dev/null ||
+  die "push libc.so to device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
+  die "pull libc.so from device"
+diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null ||
+  die "libc.so differ"
 
 echo "${GREEN}[ RUN      ]${NORMAL} reboot to confirm content persistent" >&2
 
@@ -605,7 +703,7 @@
   die "re-read /system/hello after reboot"
 check_eq "${A}" "${B}" /system after reboot
 echo "${GREEN}[       OK ]${NORMAL} /system content remains after reboot" >&2
-# Only root can read vendor if sepolicy permissions are as expected
+# Only root can read vendor if sepolicy permissions are as expected.
 if ${enforcing}; then
   adb_unroot
   B="`adb_cat /vendor/hello`" &&
@@ -619,9 +717,9 @@
 check_eq "${A}" "${B}" vendor after reboot
 echo "${GREEN}[       OK ]${NORMAL} /vendor content remains after reboot" >&2
 
-# check if the updated libc.so is persistent after reboot
+# Check if the updated libc.so is persistent after reboot.
 adb_root &&
-  adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice ||
+  adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
   die "pull libc.so from device"
 diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
 rm -r ${tempdir}
@@ -677,7 +775,7 @@
   fi
   fastboot reboot ||
     die "can not reboot out of fastboot"
-  echo "${ORANGE}[  WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
+  echo "${ORANGE}[  WARNING ]${NORMAL} adb after fastboot"
   adb_wait 2m ||
     die "did not reboot after flash"
   if ${overlayfs_needed}; then
@@ -719,9 +817,26 @@
 echo "${GREEN}[ RUN      ]${NORMAL} remove test content (cleanup)" >&2
 
 T=`adb_date`
-adb remount &&
+H=`adb remount 2>&1`
+err=${?}
+L=
+D="${H%?Now reboot your device for settings to take effect}"
+if [ X"${H}" != X"${D}" ]; then
+  echo "${ORANGE}[  WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)"
+  L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
+  adb_reboot &&
+    adb_wait 2m &&
+    adb_root ||
+    die "failed to reboot"
+  T=`adb_date`
+  H=`adb remount 2>&1`
+  err=${?}
+fi
+echo "${H}"
+[ ${err} = 0 ] &&
   ( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
   adb_sh rm /system/hello </dev/null ||
+  ( [ -n "${L}" ] && echo "${L}" && false ) ||
   die -t ${T} "cleanup hello"
 B="`adb_cat /system/hello`" &&
   die "re-read /system/hello after rm"
@@ -768,12 +883,12 @@
     die -t ${T} "setup for overlayfs"
 fi
 
-echo "${GREEN}[ RUN      ]${NORMAL} test raw remount command" >&2
+echo "${GREEN}[ RUN      ]${NORMAL} test raw remount commands" >&2
 
-# prerequisite is a prepped device from above
+# Prerequisite is a prepped device from above.
 adb_reboot &&
   adb_wait 2m ||
-  die "lost device after reboot to ro state"
+  die "lost device after reboot to ro state (USB stack broken?)"
 adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null &&
   die "/vendor is not read-only"
 adb_su mount -o rw,remount /vendor ||
@@ -782,4 +897,12 @@
   die "/vendor is not read-write"
 echo "${GREEN}[       OK ]${NORMAL} mount -o rw,remount command works" >&2
 
+if $VERITY_WAS_ENABLED && $overlayfs_supported; then
+  adb_root &&
+    adb enable-verity &&
+    adb_reboot &&
+    adb_wait 2m ||
+    die "failed to restore verity" >&2
+fi
+
 echo "${GREEN}[  PASSED  ]${NORMAL} adb remount" >&2
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index fab4b4e..17c8a13 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -60,7 +60,6 @@
     host_supported: true,
     srcs: [
         "config_utils.cpp",
-        "fs_config.cpp",
         "canned_fs_config.cpp",
         "iosched_policy.cpp",
         "load_file.cpp",
@@ -80,6 +79,7 @@
         not_windows: {
             srcs: libcutils_nonwindows_sources + [
                 "ashmem-host.cpp",
+                "fs_config.cpp",
                 "trace-host.cpp",
             ],
         },
@@ -104,6 +104,7 @@
             srcs: libcutils_nonwindows_sources + [
                 "android_reboot.cpp",
                 "ashmem-dev.cpp",
+                "fs_config.cpp",
                 "klog.cpp",
                 "partition_utils.cpp",
                 "properties.cpp",
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 59cbbc5..6184813 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -24,6 +24,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <fnmatch.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -31,6 +32,9 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <string>
+
+#include <android-base/strings.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Compat.h>
@@ -39,6 +43,9 @@
 #define O_BINARY 0
 #endif
 
+using android::base::EndsWith;
+using android::base::StartsWith;
+
 // My kingdom for <endian.h>
 static inline uint16_t get2LE(const uint8_t* src) {
     return src[0] | (src[1] << 8);
@@ -88,6 +95,9 @@
     { 00755, AID_ROOT,         AID_ROOT,         0, "system/etc/ppp" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "system/vendor" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
+    // TODO(b/123743953): eliminate the APEX name with better pattern matching
+    { 00755, AID_ROOT,         AID_SHELL,        0, "system/apex/com.android.runtime.debug/bin" },
+    { 00755, AID_ROOT,         AID_SHELL,        0, "system/apex/com.android.runtime.release/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
@@ -214,6 +224,9 @@
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
+    // TODO(b/123743953): eliminate the APEX name with better pattern matching
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/com.android.runtime.debug/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/com.android.runtime.release/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
@@ -253,46 +266,55 @@
 
 // if path is "odm/<stuff>", "oem/<stuff>", "product/<stuff>",
 // "product_services/<stuff>" or "vendor/<stuff>"
-static bool is_partition(const char* path, size_t len) {
+static bool is_partition(const std::string& path) {
     static const char* partitions[] = {"odm/", "oem/", "product/", "product_services/", "vendor/"};
     for (size_t i = 0; i < (sizeof(partitions) / sizeof(partitions[0])); ++i) {
-        size_t plen = strlen(partitions[i]);
-        if (len <= plen) continue;
-        if (!strncmp(path, partitions[i], plen)) return true;
+        if (StartsWith(path, partitions[i])) return true;
     }
     return false;
 }
 
-static inline bool prefix_cmp(bool partial, const char* prefix, size_t len, const char* path,
-                              size_t plen) {
-    return ((partial && plen >= len) || (plen == len)) && !strncmp(prefix, path, len);
-}
-
 // alias prefixes of "<partition>/<stuff>" to "system/<partition>/<stuff>" or
 // "system/<partition>/<stuff>" to "<partition>/<stuff>"
-static bool fs_config_cmp(bool partial, const char* prefix, size_t len, const char* path,
-                          size_t plen) {
-    // If name ends in * then allow partial matches.
-    if (!partial && prefix[len - 1] == '*') {
-        len--;
-        partial = true;
+static bool fs_config_cmp(bool dir, const char* prefix, size_t len, const char* path, size_t plen) {
+    std::string pattern(prefix, len);
+    std::string input(path, plen);
+
+    // Massage pattern and input so that they can be used by fnmatch where
+    // directories have to end with /.
+    if (dir) {
+        if (!EndsWith(input, "/")) {
+            input.append("/");
+        }
+
+        if (!EndsWith(pattern, "/*")) {
+            if (EndsWith(pattern, "/")) {
+                pattern.append("*");
+            } else {
+                pattern.append("/*");
+            }
+        }
     }
 
-    if (prefix_cmp(partial, prefix, len, path, plen)) return true;
+    // no FNM_PATHNAME is set in order to match a/b/c/d with a/*
+    // FNM_ESCAPE is set in order to prevent using \\? and \\* and maintenance issues.
+    const int fnm_flags = FNM_NOESCAPE;
+    if (fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0) return true;
 
-    static const char system[] = "system/";
-    if (!strncmp(path, system, strlen(system))) {
-        path += strlen(system);
-        plen -= strlen(system);
-    } else if (len <= strlen(system)) {
+    static constexpr const char* kSystem = "system/";
+    if (StartsWith(input, kSystem)) {
+        input.erase(0, strlen(kSystem));
+    } else if (input.size() <= strlen(kSystem)) {
         return false;
-    } else if (strncmp(prefix, system, strlen(system))) {
-        return false;
+    } else if (StartsWith(pattern, kSystem)) {
+        pattern.erase(0, strlen(kSystem));
     } else {
-        prefix += strlen(system);
-        len -= strlen(system);
+        return false;
     }
-    return is_partition(prefix, len) && prefix_cmp(partial, prefix, len, path, plen);
+
+    if (!is_partition(pattern)) return false;
+    if (!is_partition(input)) return false;
+    return fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0;
 }
 #ifndef __ANDROID_VNDK__
 auto __for_testing_only__fs_config_cmp = fs_config_cmp;
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index fb9bbdd..3892ce0 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -20,6 +20,7 @@
         android: {
             srcs: [
                 "AshmemTest.cpp",
+                "fs_config.cpp",
                 "MemsetTest.cpp",
                 "PropertiesTest.cpp",
                 "sched_policy_test.cpp",
@@ -28,13 +29,13 @@
                 "android_get_control_socket_test.cpp",
                 "android_get_control_file_test.cpp",
                 "multiuser_test.cpp",
-                "fs_config.cpp",
             ],
         },
 
         not_windows: {
             srcs: [
                 "test_str_parms.cpp",
+                "fs_config.cpp",
             ],
         },
     },
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp
index d5dc66a..c26315f 100644
--- a/libcutils/tests/fs_config.cpp
+++ b/libcutils/tests/fs_config.cpp
@@ -42,11 +42,15 @@
     const char* path;
     bool match;
 } fs_config_cmp_tests[] = {
-    // clang-format off
+        // clang-format off
     { true,  "system/lib",             "system/lib/hw",           true  },
     { true,  "vendor/lib",             "system/vendor/lib/hw",    true  },
     { true,  "system/vendor/lib",      "vendor/lib/hw",           true  },
     { true,  "system/vendor/lib",      "system/vendor/lib/hw",    true  },
+    { true,  "foo/*/bar/*",            "foo/1/bar/2",             true  },
+    { true,  "foo/*/bar/*",            "foo/1/bar",               true  },
+    { true,  "foo/*/bar/*",            "foo/1/bar/2/3",           true  },
+    { true,  "foo/*/bar/*",            "foo/1/bar/2/3/",          true  },
     { false, "vendor/bin/wifi",        "system/vendor/bin/w",     false },
     { false, "vendor/bin/wifi",        "system/vendor/bin/wifi",  true  },
     { false, "vendor/bin/wifi",        "system/vendor/bin/wifi2", false },
@@ -58,8 +62,14 @@
     { false, "vendor/bin/*",           "system/vendor/bin/wifi",  true  },
     { false, "system/bin/*",           "system/bin",              false },
     { false, "system/vendor/bin/*",    "vendor/bin/wifi",         true  },
+    { false, "foo/*/bar/*",            "foo/1/bar/2",             true  },
+    { false, "foo/*/bar/*",            "foo/1/bar",               false },
+    { false, "foo/*/bar/*",            "foo/1/bar/2/3",           true  },
+    { false, "foo/*/bar/*.so",         "foo/1/bar/2/3",           false },
+    { false, "foo/*/bar/*.so",         "foo/1/bar/2.so",          true  },
+    { false, "foo/*/bar/*.so",         "foo/1/bar/2/3.so",        true  },
     { false, NULL,                     NULL,                      false },
-    // clang-format on
+        // clang-format on
 };
 
 static bool check_unique(std::vector<const char*>& paths, const std::string& config_name,
diff --git a/libmeminfo/libdmabufinfo/dmabufinfo.cpp b/libmeminfo/libdmabufinfo/dmabufinfo.cpp
index b4ad667..0212cd2 100644
--- a/libmeminfo/libdmabufinfo/dmabufinfo.cpp
+++ b/libmeminfo/libdmabufinfo/dmabufinfo.cpp
@@ -130,7 +130,7 @@
             if (buf->count() == 0)
                 buf->SetCount(count);
             buf->AddFdRef(pid);
-            return true;
+            continue;
         }
 
         DmaBuffer& db =
diff --git a/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h b/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
index e3be320..a16c3fd 100644
--- a/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
+++ b/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
@@ -30,17 +30,21 @@
   public:
     DmaBuffer(ino_t inode, uint64_t size, uint64_t count, const std::string& exporter,
               const std::string& name)
-        : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) {}
+        : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) {
+        total_refs_ = 0;
+    }
     ~DmaBuffer() = default;
 
     // Adds one file descriptor reference for the given pid
     void AddFdRef(pid_t pid) {
         AddRefToPidMap(pid, &fdrefs_);
+        total_refs_++;
     }
 
     // Adds one map reference for the given pid
     void AddMapRef(pid_t pid) {
         AddRefToPidMap(pid, &maprefs_);
+        total_refs_++;
     }
 
     // Getters for each property
@@ -48,7 +52,7 @@
     const std::unordered_map<pid_t, int>& fdrefs() const { return fdrefs_; }
     const std::unordered_map<pid_t, int>& maprefs() const { return maprefs_; }
     ino_t inode() const { return inode_; }
-    uint64_t total_refs() const { return fdrefs_.size() + maprefs_.size(); }
+    uint64_t total_refs() const { return total_refs_; }
     uint64_t count() const { return count_; };
     const std::string& name() const { return name_; }
     const std::string& exporter() const { return exporter_; }
@@ -65,6 +69,7 @@
     ino_t inode_;
     uint64_t size_;
     uint64_t count_;
+    uint64_t total_refs_;
     std::string exporter_;
     std::string name_;
     std::unordered_map<pid_t, int> fdrefs_;
@@ -81,7 +86,6 @@
 // Read and return current dma buf objects from
 // DEBUGFS/dma_buf/bufinfo. The references to each dma buffer are not
 // populated here and will return an empty vector.
-//
 // Returns false if something went wrong with the function, true otherwise.
 bool ReadDmaBufInfo(std::vector<DmaBuffer>* dmabufs,
                     const std::string& path = "/sys/kernel/debug/dma_buf/bufinfo");
@@ -89,13 +93,13 @@
 
 // Read and return dmabuf objects for a given process without the help
 // of DEBUGFS
-//
 // Returns false if something went wrong with the function, true otherwise.
 bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);
 
-// Append dmabuf objects for a given process without the help
-// of DEBUGFS to an existing vector
-//
+// Append new dmabuf objects from a given process to an existing vector.
+// When the vector contains an existing element with a matching inode,
+// the reference counts will be updated.
+// Does not depend on DEBUGFS.
 // Returns false if something went wrong with the function, true otherwise.
 bool AppendDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);
 
diff --git a/libmeminfo/libdmabufinfo/tools/Android.bp b/libmeminfo/libdmabufinfo/tools/Android.bp
new file mode 100644
index 0000000..339583e
--- /dev/null
+++ b/libmeminfo/libdmabufinfo/tools/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "dmabuf_dump",
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: ["dmabuf_dump.cpp"],
+    shared_libs: [
+        "libbase",
+        "libmeminfo",
+    ],
+    static_libs: [
+        "libdmabufinfo",
+        "libc++fs",
+    ],
+}
\ No newline at end of file
diff --git a/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp
new file mode 100644
index 0000000..5ee9c3d
--- /dev/null
+++ b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+
+#include <android-base/stringprintf.h>
+#include <dmabufinfo/dmabufinfo.h>
+
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+
+[[noreturn]] static void usage(int exit_status) {
+    fprintf(stderr,
+            "Usage: %s [PID] \n"
+            "\t If PID is supplied, the dmabuf information for this process is shown.\n"
+            "\t Otherwise, shows the information for all processes.\n",
+            getprogname());
+
+    exit(exit_status);
+}
+
+static std::string GetProcessBaseName(pid_t pid) {
+    std::string pid_path = android::base::StringPrintf("/proc/%d/comm", pid);
+    std::ifstream in{pid_path};
+    if (!in) return std::string("N/A");
+    std::string line;
+    std::getline(in, line);
+    if (!in) return std::string("N/A");
+    return line;
+}
+
+static void AddPidsToSet(const std::unordered_map<pid_t, int>& map, std::set<pid_t>* set)
+{
+    for (auto it = map.begin(); it != map.end(); ++it)
+        set->insert(it->first);
+}
+
+static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) {
+    std::set<pid_t> pid_set;
+    std::map<pid_t, int> pid_column;
+
+    if (bufs.empty()) {
+        std::cout << "dmabuf info not found ¯\\_(ツ)_/¯" << std::endl;
+        return;
+    }
+
+    // Find all unique pids in the input vector, create a set
+    for (int i = 0; i < bufs.size(); i++) {
+        AddPidsToSet(bufs[i].fdrefs(), &pid_set);
+        AddPidsToSet(bufs[i].maprefs(), &pid_set);
+    }
+
+    int pid_count = 0;
+
+    std::cout << "\t\t\t\t\t\t";
+
+    // Create a map to convert each unique pid into a column number
+    for (auto it = pid_set.begin(); it != pid_set.end(); ++it, ++pid_count) {
+        pid_column.insert(std::make_pair(*it, pid_count));
+        std::cout << ::android::base::StringPrintf("[pid: % 4d]\t", *it);
+    }
+
+    std::cout << std::endl << "\t\t\t\t\t\t";
+
+    for (auto it = pid_set.begin(); it != pid_set.end(); ++it) {
+        std::cout << ::android::base::StringPrintf("%16s",
+            GetProcessBaseName(*it).c_str());
+    }
+
+    std::cout << std::endl << "\tinode\t\tsize\t\tcount\t";
+    for (int i = 0; i < pid_count; i++) {
+        std::cout << "fd\tmap\t";
+    }
+    std::cout << std::endl;
+
+    auto fds = std::make_unique<int[]>(pid_count);
+    auto maps = std::make_unique<int[]>(pid_count);
+    auto pss = std::make_unique<long[]>(pid_count);
+
+    memset(pss.get(), 0, sizeof(long) * pid_count);
+
+    for (auto buf = bufs.begin(); buf != bufs.end(); ++buf) {
+
+        std::cout << ::android::base::StringPrintf("%16lu\t%10" PRIu64 "\t%" PRIu64 "\t",
+            buf->inode(),buf->size(), buf->count());
+
+        memset(fds.get(), 0, sizeof(int) * pid_count);
+        memset(maps.get(), 0, sizeof(int) * pid_count);
+
+        for (auto it = buf->fdrefs().begin(); it != buf->fdrefs().end(); ++it) {
+            fds[pid_column[it->first]] = it->second;
+            pss[pid_column[it->first]] += buf->size() * it->second / buf->count();
+        }
+
+        for (auto it = buf->maprefs().begin(); it != buf->maprefs().end(); ++it) {
+            maps[pid_column[it->first]] = it->second;
+            pss[pid_column[it->first]] += buf->size() * it->second / buf->count();
+        }
+
+        for (int i = 0; i < pid_count; i++) {
+            std::cout << ::android::base::StringPrintf("%d\t%d\t", fds[i], maps[i]);
+        }
+        std::cout << std::endl;
+    }
+    std::cout << "-----------------------------------------" << std::endl;
+    std::cout << "PSS                                      ";
+    for (int i = 0; i < pid_count; i++) {
+        std::cout << ::android::base::StringPrintf("%15ldK", pss[i] / 1024);
+    }
+    std::cout << std::endl;
+}
+
+int main(int argc, char* argv[]) {
+    pid_t pid = -1;
+    std::vector<DmaBuffer> bufs;
+    bool show_all = true;
+
+    if (argc > 1) {
+        if (sscanf(argv[1], "%d", &pid) == 1) {
+            show_all = false;
+        }
+        else {
+            usage(EXIT_FAILURE);
+        }
+    }
+
+    if (show_all) {
+        if (!ReadDmaBufInfo(&bufs)) {
+            std::cerr << "Unable to read DEBUGFS dmabuf info" << std::endl;
+            exit(EXIT_FAILURE);
+        }
+        std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
+        if (!dir) {
+            std::cerr << "Failed to open /proc directory" << std::endl;
+            exit(EXIT_FAILURE);
+        }
+        struct dirent* dent;
+        while ((dent = readdir(dir.get()))) {
+            if (dent->d_type != DT_DIR) continue;
+
+            int matched = sscanf(dent->d_name, "%d", &pid);
+            if (matched != 1) {
+                continue;
+            }
+
+            if (!AppendDmaBufInfo(pid, &bufs)) {
+                std::cerr << "Unable to read dmabuf info for pid " << pid << std::endl;
+                exit(EXIT_FAILURE);
+            }
+        }
+    } else {
+        if (!ReadDmaBufInfo(pid, &bufs)) {
+            std::cerr << "Unable to read dmabuf info" << std::endl;
+            exit(EXIT_FAILURE);
+        }
+    }
+    PrintDmaBufInfo(bufs);
+    return 0;
+}
+
+
diff --git a/libmeminfo/vts/Android.bp b/libmeminfo/vts/Android.bp
new file mode 100644
index 0000000..5a3a23b
--- /dev/null
+++ b/libmeminfo/vts/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "vts_meminfo_test",
+    defaults: ["libmeminfo_defaults"],
+    srcs: ["vts_meminfo_test.cpp"],
+    static_libs: ["libmeminfo"],
+}
diff --git a/libmeminfo/vts/Android.mk b/libmeminfo/vts/Android.mk
new file mode 100644
index 0000000..62d68d9
--- /dev/null
+++ b/libmeminfo/vts/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsKernelMemInfoTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/libmeminfo/vts/AndroidTest.xml b/libmeminfo/vts/AndroidTest.xml
new file mode 100644
index 0000000..530d16e
--- /dev/null
+++ b/libmeminfo/vts/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS VtsKernelMemInfoTest.">
+    <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HostDrivenTest.push"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="VtsKernelMemInfoTest"/>
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_meminfo_test/vts_meminfo_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_meminfo_test/vts_meminfo_test" />
+        <option name="binary-test-type" value="gtest"/>
+        <option name="test-timeout" value="10m"/>
+    </test>
+</configuration>
diff --git a/libmeminfo/vts/vts_meminfo_test.cpp b/libmeminfo/vts/vts_meminfo_test.cpp
new file mode 100644
index 0000000..3193c31
--- /dev/null
+++ b/libmeminfo/vts/vts_meminfo_test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <meminfo/procmeminfo.h>
+
+namespace android {
+namespace meminfo {
+
+// /proc/<pid>/smaps_rollup support is required.
+TEST(SmapsRollup, IsSupported) {
+    // Use init's pid for this test since it's the only known pid.
+    ASSERT_TRUE(IsSmapsRollupSupported(1));
+}
+
+}  // namespace meminfo
+}  // namespace android
diff --git a/libsystem/OWNERS b/libsystem/OWNERS
index aeb160c..fdea804 100644
--- a/libsystem/OWNERS
+++ b/libsystem/OWNERS
@@ -1,2 +1,9 @@
-jessehall@google.com
-olv@google.com
+# graphics/composer
+adyabr@google.com
+lpy@google.com
+marissaw@google.com
+stoza@google.com
+vhau@google.com
+
+# camera
+etalvala@google.com
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 5feb2aa..1202c15 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -174,12 +174,6 @@
         return false;
     }
 #else // !defined(__MINGW32__)
-    int     prot, flags, adjust;
-    off64_t adjOffset;
-    size_t  adjLength;
-
-    void* ptr;
-
     assert(fd >= 0);
     assert(offset >= 0);
     assert(length > 0);
@@ -193,20 +187,23 @@
         }
     }
 
-    adjust = offset % mPageSize;
-    adjOffset = offset - adjust;
-    adjLength = length + adjust;
+    int adjust = offset % mPageSize;
+    off64_t adjOffset = offset - adjust;
+    size_t adjLength = length + adjust;
 
-    flags = MAP_SHARED;
-    prot = PROT_READ;
-    if (!readOnly)
-        prot |= PROT_WRITE;
+    int flags = MAP_SHARED;
+    int prot = PROT_READ;
+    if (!readOnly) prot |= PROT_WRITE;
 
-    ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
+    void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
-        ALOGE("mmap(%lld,%zu) failed: %s\n",
-            (long long)adjOffset, adjLength, strerror(errno));
-        return false;
+        if (errno == EINVAL && length == 0) {
+            ptr = nullptr;
+            adjust = 0;
+        } else {
+            ALOGE("mmap(%lld,%zu) failed: %s\n", (long long)adjOffset, adjLength, strerror(errno));
+            return false;
+        }
     }
     mBasePtr = ptr;
 #endif // !defined(__MINGW32__)
@@ -217,8 +214,6 @@
     mDataPtr = (char*) mBasePtr + adjust;
     mDataLength = length;
 
-    assert(mBasePtr != NULL);
-
     ALOGV("MAP: base %p/%zu data %p/%zu\n",
         mBasePtr, mBaseLength, mDataPtr, mDataLength);
 
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index 1390552..62f5acb 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -22,6 +22,7 @@
 
     srcs: [
         "BitSet_test.cpp",
+        "FileMap_test.cpp",
         "LruCache_test.cpp",
         "Mutex_test.cpp",
         "Singleton_test.cpp",
diff --git a/libutils/tests/FileMap_test.cpp b/libutils/tests/FileMap_test.cpp
new file mode 100644
index 0000000..576d89b
--- /dev/null
+++ b/libutils/tests/FileMap_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils/FileMap.h"
+
+#include <gtest/gtest.h>
+
+#include "android-base/file.h"
+
+TEST(FileMap, zero_length_mapping) {
+    // http://b/119818070 "app crashes when reading asset of zero length".
+    // mmap fails with EINVAL for a zero length region.
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+
+    android::FileMap m;
+    ASSERT_TRUE(m.create("test", tf.fd, 4096, 0, true));
+    ASSERT_STREQ("test", m.getFileName());
+    ASSERT_EQ(0u, m.getDataLength());
+    ASSERT_EQ(4096, m.getDataOffset());
+}