Merge changes from topic '36810152'

* changes:
  fastboot: Support larger transfers during flash
  fastboot: Cap max size sent to libsparse
  fastboot: add AdbWinUsbApi as a required module
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index ea9cb37..e635e53 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -47,6 +47,7 @@
 #include <ext4_utils/wipe.h>
 #include <linux/fs.h>
 #include <linux/loop.h>
+#include <linux/magic.h>
 #include <logwrap/logwrap.h>
 #include <private/android_logger.h>  // for __android_log_is_debuggable()
 
@@ -72,17 +73,18 @@
 
 // record fs stat
 enum FsStatFlags {
-    FS_STAT_IS_EXT4           = 0x0001,
+    FS_STAT_IS_EXT4 = 0x0001,
     FS_STAT_NEW_IMAGE_VERSION = 0x0002,
-    FS_STAT_E2FSCK_F_ALWAYS   = 0x0004,
-    FS_STAT_UNCLEAN_SHUTDOWN  = 0x0008,
-    FS_STAT_QUOTA_ENABLED     = 0x0010,
-    FS_STAT_TUNE2FS_FAILED    = 0x0020,
-    FS_STAT_RO_MOUNT_FAILED   = 0x0040,
+    FS_STAT_E2FSCK_F_ALWAYS = 0x0004,
+    FS_STAT_UNCLEAN_SHUTDOWN = 0x0008,
+    FS_STAT_QUOTA_ENABLED = 0x0010,
+    FS_STAT_TUNE2FS_FAILED = 0x0020,
+    FS_STAT_RO_MOUNT_FAILED = 0x0040,
     FS_STAT_RO_UNMOUNT_FAILED = 0x0080,
     FS_STAT_FULL_MOUNT_FAILED = 0x0100,
-    FS_STAT_E2FSCK_FAILED     = 0x0200,
-    FS_STAT_E2FSCK_FS_FIXED   = 0x0400,
+    FS_STAT_E2FSCK_FAILED = 0x0200,
+    FS_STAT_E2FSCK_FS_FIXED = 0x0400,
+    FS_STAT_EXT4_INVALID_MAGIC = 0x0800,
 };
 
 /*
@@ -141,6 +143,9 @@
 
     /* Check for the types of filesystems we know how to check */
     if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+        if (*fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {  // will fail, so do not try
+            return;
+        }
         /*
          * First try to mount and unmount the filesystem.  We do this because
          * the kernel is more efficient than e2fsck in running the journal and
@@ -287,6 +292,11 @@
                     PERROR << "Can't read '" << blk_device << "' super block";
                     return force_check;
                 }
+                if (sb.s_magic != EXT4_SUPER_MAGIC) {
+                    LINFO << "Invalid ext4 magic:0x" << std::hex << sb.s_magic << "," << blk_device;
+                    *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
+                    return 0;  // not a valid fs, tune2fs, fsck, and mount  will all fail.
+                }
                 *fs_stat |= FS_STAT_IS_EXT4;
                 LINFO << "superblock s_max_mnt_count:" << sb.s_max_mnt_count << "," << blk_device;
                 if (sb.s_max_mnt_count == 0xffff) {  // -1 (int16) in ext2, but uint16 in ext4
@@ -547,7 +557,13 @@
             int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device,
                                                            fstab->recs[i].fs_type,
                                                            &fstab->recs[i], &fs_stat);
-
+            if (fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {
+                LERROR << __FUNCTION__ << "(): skipping mount, invalid ext4, mountpoint="
+                       << fstab->recs[i].mount_point << " rec[" << i
+                       << "].fs_type=" << fstab->recs[i].fs_type;
+                mount_errno = EINVAL;  // continue bootup for FDE
+                continue;
+            }
             if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
                 check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
                          fstab->recs[i].mount_point, &fs_stat);
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7c82bb1..83bf8a7 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -493,6 +493,10 @@
         return nullptr;
     }
 
+    // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
+    avb_handle->avb_version_ =
+        android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
+
     // Verifies vbmeta images against the digest passed from bootloader.
     if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
         LERROR << "VerifyVbmetaImages failed";
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h
index 526a5ce..a66ff42 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -72,7 +72,8 @@
     // Otherwise, returns false.
     bool SetUpAvb(fstab_rec* fstab_entry, bool wait_for_verity_dev);
 
-    bool AvbHashtreeDisabled() { return status_ == kFsManagerAvbHandleHashtreeDisabled; }
+    bool hashtree_disabled() const { return status_ == kFsManagerAvbHandleHashtreeDisabled; }
+    const std::string& avb_version() const { return avb_version_; }
 
     FsManagerAvbHandle(const FsManagerAvbHandle&) = delete;             // no copy
     FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete;  // no assignment
@@ -92,6 +93,7 @@
   private:
     AvbSlotVerifyData* avb_slot_data_;
     FsManagerAvbHandleStatus status_;
+    std::string avb_version_;
 };
 
 #endif /* __CORE_FS_MGR_AVB_H */
diff --git a/init/Android.mk b/init/Android.mk
index c9bf9fc..f2c0842 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -74,7 +74,7 @@
     service.cpp \
     util.cpp \
 
-LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup libnl
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
 LOCAL_WHOLE_STATIC_LIBRARIES := libcap
 LOCAL_MODULE := libinit
 LOCAL_SANITIZE := integer
@@ -124,7 +124,6 @@
     libsparse \
     libz \
     libprocessgroup \
-    libnl \
     libavb
 
 # Create symlinks.
diff --git a/init/devices.cpp b/init/devices.cpp
index 6cd3564..ad313a0 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -56,9 +56,6 @@
 #include "util.h"
 
 #define SYSFS_PREFIX    "/sys"
-static const char *firmware_dirs[] = { "/etc/firmware",
-                                       "/vendor/firmware",
-                                       "/firmware/image" };
 
 extern struct selabel_handle *sehandle;
 
@@ -79,16 +76,8 @@
     struct listnode plist;
 };
 
-struct platform_node {
-    char *name;
-    char *path;
-    int path_len;
-    struct listnode list;
-};
-
 static list_declare(sys_perms);
 static list_declare(dev_perms);
-static list_declare(platform_names);
 
 int add_dev_perms(const char *name, const char *attr,
                   mode_t perm, unsigned int uid, unsigned int gid,
@@ -153,17 +142,18 @@
     return perm_path_matches(subsys_path.c_str(), dp);
 }
 
-static void fixup_sys_perms(const char* upath, const char* subsystem) {
+static void fixup_sys_perms(const std::string& upath, const std::string& subsystem) {
     // upaths omit the "/sys" that paths in this list
     // contain, so we prepend it...
-    std::string path = std::string(SYSFS_PREFIX) + upath;
+    std::string path = SYSFS_PREFIX + upath;
 
     listnode* node;
     list_for_each(node, &sys_perms) {
         perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
-        if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
+        if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem.c_str())) {
             ; // matched
-        } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
+        } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(),
+                                   subsystem.c_str())) {
             ; // matched
         } else if (!perm_path_matches(path.c_str(), dp)) {
             continue;
@@ -209,7 +199,7 @@
     return 0600;
 }
 
-static void make_device(const char* path, const char* /*upath*/, int block, int major, int minor,
+static void make_device(const std::string& path, int block, int major, int minor,
                         const std::vector<std::string>& links) {
     unsigned uid;
     unsigned gid;
@@ -217,7 +207,7 @@
     dev_t dev;
     char *secontext = NULL;
 
-    mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
+    mode = get_device_perm(path.c_str(), links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
 
     if (sehandle) {
         std::vector<const char*> c_links;
@@ -225,7 +215,7 @@
             c_links.emplace_back(link.c_str());
         }
         c_links.emplace_back(nullptr);
-        if (selabel_lookup_best_match(sehandle, &secontext, path, &c_links[0], mode)) {
+        if (selabel_lookup_best_match(sehandle, &secontext, path.c_str(), &c_links[0], mode)) {
             PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
             return;
         }
@@ -244,10 +234,9 @@
     }
     /* If the node already exists update its SELinux label to handle cases when
      * it was created with the wrong context during coldboot procedure. */
-    if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
-
+    if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
         char* fcon = nullptr;
-        int rc = lgetfilecon(path, &fcon);
+        int rc = lgetfilecon(path.c_str(), &fcon);
         if (rc < 0) {
             PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
             goto out;
@@ -256,13 +245,13 @@
         bool different = strcmp(fcon, secontext) != 0;
         freecon(fcon);
 
-        if (different && lsetfilecon(path, secontext)) {
+        if (different && lsetfilecon(path.c_str(), secontext)) {
             PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
         }
     }
 
 out:
-    chown(path, uid, -1);
+    chown(path.c_str(), uid, -1);
     if (setegid(AID_ROOT)) {
         PLOG(FATAL) << "setegid(AID_ROOT) failed";
     }
@@ -273,75 +262,25 @@
     }
 }
 
-void add_platform_device(const char* path) {
-    int path_len = strlen(path);
-    struct platform_node *bus;
-    const char *name = path;
+// TODO: Move this to be a member variable of a future devices class.
+std::vector<std::string> platform_devices;
 
-    if (!strncmp(path, "/devices/", 9)) {
-        name += 9;
-        if (!strncmp(name, "platform/", 9))
-            name += 9;
-    }
-
-    LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
-
-    bus = (platform_node*) calloc(1, sizeof(struct platform_node));
-    bus->path = strdup(path);
-    bus->path_len = path_len;
-    bus->name = bus->path + (name - path);
-    list_add_tail(&platform_names, &bus->list);
-}
-
-/*
- * given a path that may start with a platform device, find the length of the
- * platform device prefix.  If it doesn't start with a platform device, return
- * 0.
- */
-static struct platform_node *find_platform_device(const char *path)
-{
-    int path_len = strlen(path);
-    struct listnode *node;
-    struct platform_node *bus;
-
-    list_for_each_reverse(node, &platform_names) {
-        bus = node_to_item(node, struct platform_node, list);
-        if ((bus->path_len < path_len) &&
-                (path[bus->path_len] == '/') &&
-                !strncmp(path, bus->path, bus->path_len))
-            return bus;
-    }
-
-    return NULL;
-}
-
-void remove_platform_device(const char* path) {
-    struct listnode *node;
-    struct platform_node *bus;
-
-    list_for_each_reverse(node, &platform_names) {
-        bus = node_to_item(node, struct platform_node, list);
-        if (!strcmp(path, bus->path)) {
-            LOG(INFO) << "removing platform device " << bus->name;
-            free(bus->path);
-            list_remove(node);
-            free(bus);
-            return;
+// Given a path that may start with a platform device, find the length of the
+// platform device prefix.  If it doesn't start with a platform device, return false
+bool find_platform_device(const std::string& path, std::string* out_path) {
+    out_path->clear();
+    // platform_devices is searched backwards, since parents are added before their children,
+    // and we want to match as deep of a child as we can.
+    for (auto it = platform_devices.rbegin(); it != platform_devices.rend(); ++it) {
+        auto platform_device_path_length = it->length();
+        if (platform_device_path_length < path.length() &&
+            path[platform_device_path_length] == '/' &&
+            android::base::StartsWith(path, it->c_str())) {
+            *out_path = *it;
+            return true;
         }
     }
-}
-
-static void destroy_platform_devices() {
-    struct listnode* node;
-    struct listnode* n;
-    struct platform_node* bus;
-
-    list_for_each_safe(node, n, &platform_names) {
-        list_remove(node);
-        bus = node_to_item(node, struct platform_node, list);
-        free(bus->path);
-        free(bus);
-    }
+    return false;
 }
 
 /* Given a path that may start with a PCI device, populate the supplied buffer
@@ -398,19 +337,11 @@
     return true;
 }
 
-static void parse_event(const char *msg, struct uevent *uevent)
-{
-    uevent->action = "";
-    uevent->path = "";
-    uevent->subsystem = "";
-    uevent->firmware = "";
+void parse_event(const char* msg, uevent* uevent) {
+    uevent->partition_num = -1;
     uevent->major = -1;
     uevent->minor = -1;
-    uevent->partition_name = NULL;
-    uevent->partition_num = -1;
-    uevent->device_name = NULL;
-
-        /* currently ignoring SEQNUM */
+    // currently ignoring SEQNUM
     while(*msg) {
         if(!strncmp(msg, "ACTION=", 7)) {
             msg += 7;
@@ -441,30 +372,26 @@
             uevent->device_name = msg;
         }
 
-        /* advance to after the next \0 */
+        // advance to after the next \0
         while(*msg++)
             ;
     }
 
     if (LOG_UEVENTS) {
-        LOG(INFO) << android::base::StringPrintf("event { '%s', '%s', '%s', '%s', %d, %d }",
-                                                 uevent->action, uevent->path, uevent->subsystem,
-                                                 uevent->firmware, uevent->major, uevent->minor);
+        LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
+                  << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
+                  << ", " << uevent->minor << " }";
     }
 }
 
 std::vector<std::string> get_character_device_symlinks(uevent* uevent) {
-    platform_node* pdev = find_platform_device(uevent->path);
-    if (!pdev) return {};
+    std::string parent_device;
+    if (!find_platform_device(uevent->path, &parent_device)) return {};
 
-    /* skip "/devices/platform/<driver>" */
-    std::string parent = std::string(uevent->path);
-    auto parent_start = parent.find('/', pdev->path_len);
-    if (parent_start == std::string::npos) return {};
+    // skip path to the parent driver
+    std::string path = uevent->path.substr(parent_device.length());
 
-    parent.erase(0, parent_start);
-
-    if (!android::base::StartsWith(parent, "/usb")) return {};
+    if (!android::base::StartsWith(path, "/usb")) return {};
 
     // skip root hub name and device. use device interface
     // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
@@ -472,13 +399,13 @@
     // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
 
     std::string::size_type start = 0;
-    start = parent.find('/', start + 1);
+    start = path.find('/', start + 1);
     if (start == std::string::npos) return {};
 
-    start = parent.find('/', start + 1);
+    start = path.find('/', start + 1);
     if (start == std::string::npos) return {};
 
-    auto end = parent.find('/', start + 1);
+    auto end = path.find('/', start + 1);
     if (end == std::string::npos) return {};
 
     start++;  // Skip the first '/'
@@ -486,11 +413,10 @@
     auto length = end - start;
     if (length == 0) return {};
 
-    auto name_string = parent.substr(start, length);
+    auto name_string = path.substr(start, length);
 
-    // TODO: remove std::string() when uevent->subsystem is an std::string
     std::vector<std::string> links;
-    links.emplace_back("/dev/usb/" + std::string(uevent->subsystem) + name_string);
+    links.emplace_back("/dev/usb/" + uevent->subsystem + name_string);
 
     mkdir("/dev/usb", 0755);
 
@@ -516,12 +442,19 @@
 
 std::vector<std::string> get_block_device_symlinks(uevent* uevent) {
     std::string device;
-    struct platform_node* pdev;
     std::string type;
 
-    pdev = find_platform_device(uevent->path);
-    if (pdev) {
-        device = pdev->name;
+    if (find_platform_device(uevent->path, &device)) {
+        // Skip /devices/platform or /devices/ if present
+        static const std::string devices_platform_prefix = "/devices/platform/";
+        static const std::string devices_prefix = "/devices/";
+
+        if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
+            device = device.substr(devices_platform_prefix.length());
+        } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
+            device = device.substr(devices_prefix.length());
+        }
+
         type = "platform";
     } else if (find_pci_device_prefix(uevent->path, &device)) {
         type = "pci";
@@ -537,7 +470,7 @@
 
     auto link_path = "/dev/block/" + type + "/" + device;
 
-    if (uevent->partition_name) {
+    if (!uevent->partition_name.empty()) {
         std::string partition_name_sanitized(uevent->partition_name);
         sanitize_partition_name(&partition_name_sanitized);
         if (partition_name_sanitized != uevent->partition_name) {
@@ -551,57 +484,51 @@
         links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent->partition_num));
     }
 
-    // TODO: remove uevent_path when uevent->path is an std::string
-    std::string uevent_path = uevent->path;
-    auto last_slash = uevent_path.rfind('/');
-    links.emplace_back(link_path + "/" + uevent_path.substr(last_slash + 1));
+    auto last_slash = uevent->path.rfind('/');
+    links.emplace_back(link_path + "/" + uevent->path.substr(last_slash + 1));
 
     return links;
 }
 
-static void make_link_init(const char* oldpath, const char* newpath) {
-  const char* slash = strrchr(newpath, '/');
-  if (!slash) return;
+static void make_link_init(const std::string& oldpath, const std::string& newpath) {
+    if (mkdir_recursive(dirname(newpath.c_str()), 0755)) {
+        PLOG(ERROR) << "Failed to create directory " << dirname(newpath.c_str());
+    }
 
-  if (mkdir_recursive(dirname(newpath), 0755)) {
-    PLOG(ERROR) << "Failed to create directory " << dirname(newpath);
-  }
-
-  if (symlink(oldpath, newpath) && errno != EEXIST) {
-    PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
-  }
+    if (symlink(oldpath.c_str(), newpath.c_str()) && errno != EEXIST) {
+        PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
+    }
 }
 
-static void remove_link(const char* oldpath, const char* newpath) {
-  std::string path;
-  if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath);
+static void remove_link(const std::string& oldpath, const std::string& newpath) {
+    std::string path;
+    if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath.c_str());
 }
 
-static void handle_device(const char* action, const char* devpath, const char* path, int block,
+static void handle_device(const std::string& action, const std::string& devpath, int block,
                           int major, int minor, const std::vector<std::string>& links) {
-    if(!strcmp(action, "add")) {
-        make_device(devpath, path, block, major, minor, links);
+    if (action == "add") {
+        make_device(devpath, block, major, minor, links);
         for (const auto& link : links) {
-            make_link_init(devpath, link.c_str());
+            make_link_init(devpath, link);
         }
     }
 
-    if(!strcmp(action, "remove")) {
+    if (action == "remove") {
         for (const auto& link : links) {
-            remove_link(devpath, link.c_str());
+            remove_link(devpath, link);
         }
-        unlink(devpath);
+        unlink(devpath.c_str());
     }
 }
 
-static void handle_platform_device_event(struct uevent *uevent)
-{
-    const char *path = uevent->path;
-
-    if (!strcmp(uevent->action, "add"))
-        add_platform_device(path);
-    else if (!strcmp(uevent->action, "remove"))
-        remove_platform_device(path);
+void handle_platform_device_event(uevent* uevent) {
+    if (uevent->action == "add") {
+        platform_devices.emplace_back(uevent->path);
+    } else if (uevent->action == "remove") {
+        auto it = std::find(platform_devices.begin(), platform_devices.end(), uevent->path);
+        if (it != platform_devices.end()) platform_devices.erase(it);
+    }
 }
 
 static void handle_block_device_event(uevent* uevent) {
@@ -615,11 +542,11 @@
     std::string devpath = base + name;
 
     std::vector<std::string> links;
-    if (!strncmp(uevent->path, "/devices/", 9))
+    if (android::base::StartsWith(uevent->path, "/devices")) {
         links = get_block_device_symlinks(uevent);
+    }
 
-    handle_device(uevent->action, devpath.c_str(), uevent->path, 1, uevent->major, uevent->minor,
-                  links);
+    handle_device(uevent->action, devpath, 1, uevent->major, uevent->minor, links);
 }
 
 static void handle_generic_device_event(uevent* uevent) {
@@ -627,7 +554,7 @@
     if (uevent->major < 0 || uevent->minor < 0) return;
 
     std::string name = android::base::Basename(uevent->path);
-    ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem);
+    ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem.c_str());
 
     std::string devpath;
 
@@ -651,11 +578,10 @@
         // TODO: Remove std::string()
         devpath = std::string(subsystem->dirname) + "/" + devname;
         mkdir_recursive(android::base::Dirname(devpath), 0755);
-    } else if (!strncmp(uevent->subsystem, "usb", 3)) {
-        if (!strcmp(uevent->subsystem, "usb")) {
-            if (uevent->device_name) {
-                // TODO: Remove std::string
-                devpath = "/dev/" + std::string(uevent->device_name);
+    } else if (android::base::StartsWith(uevent->subsystem, "usb")) {
+        if (uevent->subsystem == "usb") {
+            if (!uevent->device_name.empty()) {
+                devpath = "/dev/" + uevent->device_name;
             } else {
                 // This imitates the file system that would be created
                 // if we were using devfs instead.
@@ -675,18 +601,18 @@
 
     auto links = get_character_device_symlinks(uevent);
 
-    handle_device(uevent->action, devpath.c_str(), uevent->path, 0, uevent->major, uevent->minor,
-                  links);
+    handle_device(uevent->action, devpath, 0, uevent->major, uevent->minor, links);
 }
 
 static void handle_device_event(struct uevent *uevent)
 {
-    if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
+    if (uevent->action == "add" || uevent->action == "change" || uevent->action == "online") {
         fixup_sys_perms(uevent->path, uevent->subsystem);
+    }
 
-    if (!strncmp(uevent->subsystem, "block", 5)) {
+    if (uevent->subsystem == "block") {
         handle_block_device_event(uevent);
-    } else if (!strncmp(uevent->subsystem, "platform", 8)) {
+    } else if (uevent->subsystem == "platform") {
         handle_platform_device_event(uevent);
     } else {
         handle_generic_device_event(uevent);
@@ -719,7 +645,7 @@
 
     LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
 
-    std::string root = android::base::StringPrintf("/sys%s", uevent->path);
+    std::string root = "/sys" + uevent->path;
     std::string loading = root + "/loading";
     std::string data = root + "/data";
 
@@ -735,9 +661,12 @@
         return;
     }
 
+    static const char* firmware_dirs[] = {"/etc/firmware/", "/vendor/firmware/",
+                                          "/firmware/image/"};
+
 try_loading_again:
     for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
-        std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
+        std::string file = firmware_dirs[i] + uevent->firmware;
         android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
         struct stat sb;
         if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
@@ -761,8 +690,7 @@
 }
 
 static void handle_firmware_event(uevent* uevent) {
-    if (strcmp(uevent->subsystem, "firmware")) return;
-    if (strcmp(uevent->action, "add")) return;
+    if (uevent->subsystem != "firmware" || uevent->action != "add") return;
 
     // Loading the firmware in a child means we can do that in parallel...
     // (We ignore SIGCHLD rather than wait for our children.)
@@ -796,7 +724,7 @@
         msg[n] = '\0';
         msg[n+1] = '\0';
 
-        struct uevent uevent;
+        uevent uevent;
         parse_event(msg, &uevent);
         coldboot_action_t act = handle_uevent(&uevent);
         if (should_stop_coldboot(act))
@@ -940,7 +868,7 @@
 }
 
 void device_close() {
-    destroy_platform_devices();
+    platform_devices.clear();
     device_fd.reset();
     selinux_status_close();
 }
diff --git a/init/devices.h b/init/devices.h
index f6183c9..b8b039f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -36,12 +36,12 @@
 };
 
 struct uevent {
-    const char* action;
-    const char* path;
-    const char* subsystem;
-    const char* firmware;
-    const char* partition_name;
-    const char* device_name;
+    std::string action;
+    std::string path;
+    std::string subsystem;
+    std::string firmware;
+    std::string partition_name;
+    std::string device_name;
     int partition_num;
     int major;
     int minor;
@@ -59,10 +59,11 @@
 int get_device_fd();
 
 // Exposed for testing
-void add_platform_device(const char* path);
-void remove_platform_device(const char* path);
+extern std::vector<std::string> platform_devices;
+bool find_platform_device(const std::string& path, std::string* out_path);
 std::vector<std::string> get_character_device_symlinks(uevent* uevent);
 std::vector<std::string> get_block_device_symlinks(uevent* uevent);
 void sanitize_partition_name(std::string* string);
+void handle_platform_device_event(uevent* uevent);
 
 #endif /* _INIT_DEVICES_H */
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 5be0d88..693fb54 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -22,12 +22,26 @@
 #include <android-base/scopeguard.h>
 #include <gtest/gtest.h>
 
+void add_platform_device(const std::string& path) {
+    uevent uevent = {
+        .action = "add", .subsystem = "platform", .path = path,
+    };
+    handle_platform_device_event(&uevent);
+}
+
+void remove_platform_device(const std::string& path) {
+    uevent uevent = {
+        .action = "remove", .subsystem = "platform", .path = path,
+    };
+    handle_platform_device_event(&uevent);
+}
+
 template <std::vector<std::string> (*Function)(uevent*)>
 void test_get_symlinks(const std::string& platform_device_name, uevent* uevent,
                        const std::vector<std::string> expected_links) {
-    add_platform_device(platform_device_name.c_str());
+    add_platform_device(platform_device_name);
     auto platform_device_remover = android::base::make_scope_guard(
-        [&platform_device_name]() { remove_platform_device(platform_device_name.c_str()); });
+        [&platform_device_name]() { remove_platform_device(platform_device_name); });
 
     std::vector<std::string> result = Function(uevent);
 
@@ -41,6 +55,36 @@
     }
 }
 
+TEST(devices, handle_platform_device_event) {
+    platform_devices.clear();
+    add_platform_device("/devices/platform/some_device_name");
+    ASSERT_EQ(1U, platform_devices.size());
+    remove_platform_device("/devices/platform/some_device_name");
+    ASSERT_EQ(0U, platform_devices.size());
+}
+
+TEST(devices, find_platform_device) {
+    platform_devices.clear();
+    add_platform_device("/devices/platform/some_device_name");
+    add_platform_device("/devices/platform/some_device_name/longer");
+    add_platform_device("/devices/platform/other_device_name");
+    EXPECT_EQ(3U, platform_devices.size());
+
+    std::string out_path;
+    EXPECT_FALSE(find_platform_device("/devices/platform/not_found", &out_path));
+    EXPECT_EQ("", out_path);
+
+    EXPECT_FALSE(
+        find_platform_device("/devices/platform/some_device_name_with_same_prefix", &out_path));
+
+    EXPECT_TRUE(
+        find_platform_device("/devices/platform/some_device_name/longer/longer_child", &out_path));
+    EXPECT_EQ("/devices/platform/some_device_name/longer", out_path);
+
+    EXPECT_TRUE(find_platform_device("/devices/platform/some_device_name/other_child", &out_path));
+    EXPECT_EQ("/devices/platform/some_device_name", out_path);
+}
+
 TEST(devices, get_character_device_symlinks_success) {
     const char* platform_device = "/devices/platform/some_device_name";
     uevent uevent = {
@@ -127,7 +171,7 @@
     const char* platform_device = "/devices/soc.0/f9824900.sdhci";
     uevent uevent = {
         .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0",
-        .partition_name = nullptr,
+        .partition_name = "",
         .partition_num = -1,
     };
     std::vector<std::string> expected_result{"/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0"};
@@ -156,7 +200,7 @@
     const char* platform_device = "/devices/soc.0/f9824900.sdhci";
     uevent uevent = {
         .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
-        .partition_name = nullptr,
+        .partition_name = "",
         .partition_num = 1,
     };
     std::vector<std::string> expected_result{
@@ -185,9 +229,7 @@
 TEST(devices, get_block_device_symlinks_success_pci) {
     const char* platform_device = "/devices/do/not/match";
     uevent uevent = {
-        .path = "/devices/pci0000:00/0000:00:1f.2/mmcblk0",
-        .partition_name = nullptr,
-        .partition_num = -1,
+        .path = "/devices/pci0000:00/0000:00:1f.2/mmcblk0", .partition_name = "", .partition_num = -1,
     };
     std::vector<std::string> expected_result{"/dev/block/pci/pci0000:00/0000:00:1f.2/mmcblk0"};
 
@@ -197,7 +239,7 @@
 TEST(devices, get_block_device_symlinks_pci_bad_format) {
     const char* platform_device = "/devices/do/not/match";
     uevent uevent = {
-        .path = "/devices/pci//mmcblk0", .partition_name = nullptr, .partition_num = -1,
+        .path = "/devices/pci//mmcblk0", .partition_name = "", .partition_num = -1,
     };
     std::vector<std::string> expected_result{};
 
@@ -207,7 +249,7 @@
 TEST(devices, get_block_device_symlinks_success_vbd) {
     const char* platform_device = "/devices/do/not/match";
     uevent uevent = {
-        .path = "/devices/vbd-1234/mmcblk0", .partition_name = nullptr, .partition_num = -1,
+        .path = "/devices/vbd-1234/mmcblk0", .partition_name = "", .partition_num = -1,
     };
     std::vector<std::string> expected_result{"/dev/block/vbd/1234/mmcblk0"};
 
@@ -217,7 +259,7 @@
 TEST(devices, get_block_device_symlinks_vbd_bad_format) {
     const char* platform_device = "/devices/do/not/match";
     uevent uevent = {
-        .path = "/devices/vbd-/mmcblk0", .partition_name = nullptr, .partition_num = -1,
+        .path = "/devices/vbd-/mmcblk0", .partition_name = "", .partition_num = -1,
     };
     std::vector<std::string> expected_result{};
 
@@ -228,7 +270,7 @@
     const char* platform_device = "/devices/soc.0/f9824900.sdhci";
     uevent uevent = {
         .path = "/devices/soc.0/not_the_device/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
-        .partition_name = nullptr,
+        .partition_name = "",
         .partition_num = -1,
     };
     std::vector<std::string> expected_result;
diff --git a/init/init.cpp b/init/init.cpp
index 6c09c99..181b18d 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -958,7 +958,7 @@
     const std::string syspath = "/sys/block/" + device_name;
 
     device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
-        if (uevent->device_name && device_name == uevent->device_name) {
+        if (uevent->device_name == device_name) {
             LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
             return COLDBOOT_STOP;
         }
@@ -1010,10 +1010,11 @@
         return false;
     }
 
+    setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
     for (auto rec : fstab_recs) {
         bool need_create_dm_device = false;
         if (fs_mgr_is_avb(rec)) {
-            if (avb_handle->AvbHashtreeDisabled()) {
+            if (avb_handle->hashtree_disabled()) {
                 LOG(INFO) << "avb hashtree disabled for '" << rec->mount_point << "'";
             } else if (avb_handle->SetUpAvb(rec, false /* wait_for_verity_dev */)) {
                 need_create_dm_device = true;
@@ -1055,21 +1056,17 @@
         return;
     }
     device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
-        if (!strncmp(uevent->subsystem, "firmware", 8)) {
-            return COLDBOOT_CONTINUE;
-        }
-
         // we need platform devices to create symlinks
-        if (!strncmp(uevent->subsystem, "platform", 8)) {
+        if (uevent->subsystem == "platform") {
             return COLDBOOT_CREATE;
         }
 
         // Ignore everything that is not a block device
-        if (strncmp(uevent->subsystem, "block", 5)) {
+        if (uevent->subsystem != "block") {
             return COLDBOOT_CONTINUE;
         }
 
-        if (uevent->partition_name) {
+        if (!uevent->partition_name.empty()) {
             // match partition names to create device nodes for partitions
             // both partition_names and uevent->partition_name have A/B suffix when A/B is used
             auto iter = partition_names->find(uevent->partition_name);
@@ -1366,12 +1363,14 @@
     property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
 
     // Set libavb version for Framework-only OTA match in Treble build.
-    property_set("ro.boot.init.avb_version", std::to_string(AVB_MAJOR_VERSION).c_str());
+    const char* avb_version = getenv("INIT_AVB_VERSION");
+    if (avb_version) property_set("ro.boot.avb_version", avb_version);
 
     // Clean up our environment.
     unsetenv("INIT_SECOND_STAGE");
     unsetenv("INIT_STARTED_AT");
     unsetenv("INIT_SELINUX_TOOK");
+    unsetenv("INIT_AVB_VERSION");
 
     // Now set up SELinux for second stage.
     selinux_initialize(false);
diff --git a/init/log.cpp b/init/log.cpp
index ee6489b..0615730 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -21,7 +21,6 @@
 #include <string.h>
 
 #include <android-base/logging.h>
-#include <netlink/netlink.h>
 #include <selinux/selinux.h>
 
 void InitKernelLogging(char* argv[]) {
@@ -41,24 +40,6 @@
     android::base::InitLogging(argv, &android::base::KernelLogger);
 }
 
-static void selinux_avc_log(char* buf, size_t buf_len) {
-    size_t str_len = strnlen(buf, buf_len);
-
-    // trim newline at end of string
-    buf[str_len - 1] = '\0';
-
-    struct nl_sock* sk = nl_socket_alloc();
-    if (sk == NULL) {
-        return;
-    }
-    nl_connect(sk, NETLINK_AUDIT);
-    int result;
-    do {
-        result = nl_send_simple(sk, AUDIT_USER_AVC, 0, buf, str_len);
-    } while (result == -NLE_INTR);
-    nl_socket_free(sk);
-}
-
 int selinux_klog_callback(int type, const char *fmt, ...) {
     android::base::LogSeverity severity = android::base::ERROR;
     if (type == SELINUX_WARNING) {
@@ -69,15 +50,8 @@
     char buf[1024];
     va_list ap;
     va_start(ap, fmt);
-    int res = vsnprintf(buf, sizeof(buf), fmt, ap);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
-    if (res <= 0) {
-        return 0;
-    }
-    if (type == SELINUX_AVC) {
-        selinux_avc_log(buf, sizeof(buf));
-    } else {
-        android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
-    }
+    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
     return 0;
 }
diff --git a/liblog/event.logtags b/liblog/event.logtags
index 301e885..0a3b650 100644
--- a/liblog/event.logtags
+++ b/liblog/event.logtags
@@ -29,6 +29,7 @@
 # 4: Number of allocations
 # 5: Id
 # 6: Percent
+# s: Number of seconds (monotonic time)
 # Default value for data of type int/long is 2 (bytes).
 #
 # TODO: generate ".java" and ".h" files with integer constants from this file.
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 0b977c2..73ed16f 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -229,9 +229,16 @@
   return it->second;
 }
 
+// The position after the end of a valid section of the tag string,
+// caller makes sure delimited appropriately.
+static const char* endOfTag(const char* cp) {
+  while (*cp && (isalnum(*cp) || strchr("_.-@,", *cp))) ++cp;
+  return cp;
+}
+
 // Scan one tag line.
 //
-// "*pData" should be pointing to the first digit in the tag number.  On
+// "pData" should be pointing to the first digit in the tag number.  On
 // successful return, it will be pointing to the last character in the
 // tag line (i.e. the character before the start of the next line).
 //
@@ -241,10 +248,11 @@
 // data and it will outlive the call.
 //
 // Returns 0 on success, nonzero on failure.
-static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
-  char* cp;
-  unsigned long val = strtoul(*pData, &cp, 10);
-  if (cp == *pData) {
+static int scanTagLine(EventTagMap* map, const char*& pData, int lineNum) {
+  char* ep;
+  unsigned long val = strtoul(pData, &ep, 10);
+  const char* cp = ep;
+  if (cp == pData) {
     if (lineNum) {
       fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
     }
@@ -273,14 +281,13 @@
   }
 
   const char* tag = cp;
-  // Determine whether "c" is a valid tag char.
-  while (isalnum(*++cp) || (*cp == '_')) {
-  }
+  cp = endOfTag(cp);
   size_t tagLen = cp - tag;
 
   if (!isspace(*cp)) {
     if (lineNum) {
-      fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
+      fprintf(stderr, OUT_TAG ": invalid tag char %c on line %d\n", *cp,
+              lineNum);
     }
     errno = EINVAL;
     return -1;
@@ -311,9 +318,9 @@
 
   while (*cp != '\n') ++cp;
 #ifdef DEBUG
-  fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
+  fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - pData), pData);
 #endif
-  *pData = cp;
+  pData = cp;
 
   if (lineNum) {
     if (map->emplaceUnique(tagIndex,
@@ -341,9 +348,9 @@
 
 // Parse the tags out of the file.
 static int parseMapLines(EventTagMap* map, size_t which) {
-  char* cp = static_cast<char*>(map->mapAddr[which]);
+  const char* cp = static_cast<char*>(map->mapAddr[which]);
   size_t len = map->mapLen[which];
-  char* endp = cp + len;
+  const char* endp = cp + len;
 
   // insist on EOL at EOF; simplifies parsing and null-termination
   if (!len || (*(endp - 1) != '\n')) {
@@ -370,7 +377,7 @@
         lineStart = false;
       } else if (isdigit(*cp)) {
         // looks like a tag; scan it out
-        if (scanTagLine(map, &cp, lineNum) != 0) {
+        if (scanTagLine(map, cp, lineNum) != 0) {
           if (!which || (errno != EMLINK)) {
             return -1;
           }
@@ -495,14 +502,13 @@
   int ret = asprintf(&buf, command_template, tag);
   if (ret > 0) {
     // Add some buffer margin for an estimate of the full return content.
-    char* cp;
     size_t size =
         ret - strlen(command_template) +
         strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
     if (size > (size_t)ret) {
-      cp = static_cast<char*>(realloc(buf, size));
-      if (cp) {
-        buf = cp;
+      char* np = static_cast<char*>(realloc(buf, size));
+      if (np) {
+        buf = np;
       } else {
         size = ret;
       }
@@ -512,10 +518,12 @@
     // Ask event log tag service for an existing entry
     if (__send_log_msg(buf, size) >= 0) {
       buf[size - 1] = '\0';
-      unsigned long val = strtoul(buf, &cp, 10);        // return size
+      char* ep;
+      unsigned long val = strtoul(buf, &ep, 10);  // return size
+      const char* cp = ep;
       if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
         ++cp;
-        if (!scanTagLine(map, &cp, 0)) {
+        if (!scanTagLine(map, cp, 0)) {
           free(buf);
           return map->find(tag);
         }
@@ -573,8 +581,9 @@
 LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
                                                 const char* tagname,
                                                 const char* format, int prio) {
-  size_t len = strlen(tagname);
-  if (!len) {
+  const char* ep = endOfTag(tagname);
+  size_t len = ep - tagname;
+  if (!len || *ep) {
     errno = EINVAL;
     return -1;
   }
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 2ade7b0..b62f8b4 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -326,6 +326,7 @@
   else if (!strcmp(formatString, "uid")) format = FORMAT_MODIFIER_UID;
   else if (!strcmp(formatString, "descriptive")) format = FORMAT_MODIFIER_DESCRIPT;
   /* clang-format on */
+
 #ifndef __MINGW32__
   else {
     extern char* tzname[2];
@@ -637,7 +638,8 @@
   TYPE_MILLISECONDS = '3',
   TYPE_ALLOCATIONS = '4',
   TYPE_ID = '5',
-  TYPE_PERCENT = '6'
+  TYPE_PERCENT = '6',
+  TYPE_MONOTONIC = 's'
 };
 
 static int android_log_printBinaryEvent(const unsigned char** pEventData,
@@ -651,7 +653,7 @@
   size_t outBufLen = *pOutBufLen;
   size_t outBufLenSave = outBufLen;
   unsigned char type;
-  size_t outCount;
+  size_t outCount = 0;
   int result = 0;
   const char* cp;
   size_t len;
@@ -690,6 +692,7 @@
    * 4: Number of allocations
    * 5: Id
    * 6: Percent
+   * s: Number of seconds (monotonic time)
    * Default value for data of type int/long is 2 (bytes).
    */
   if (!cp || !findChar(&cp, &len, '(')) {
@@ -921,6 +924,42 @@
             outCount = snprintf(outBuf, outBufLen, "ms");
           }
           break;
+        case TYPE_MONOTONIC: {
+          static const uint64_t minute = 60;
+          static const uint64_t hour = 60 * minute;
+          static const uint64_t day = 24 * hour;
+
+          /* Repaint as unsigned seconds, minutes, hours ... */
+          outBuf -= outCount;
+          outBufLen += outCount;
+          uint64_t val = lval;
+          if (val >= day) {
+            outCount = snprintf(outBuf, outBufLen, "%" PRIu64 "d ", val / day);
+            if (outCount >= outBufLen) break;
+            outBuf += outCount;
+            outBufLen -= outCount;
+            val = (val % day) + day;
+          }
+          if (val >= minute) {
+            if (val >= hour) {
+              outCount = snprintf(outBuf, outBufLen, "%" PRIu64 ":",
+                                  (val / hour) % (day / hour));
+              if (outCount >= outBufLen) break;
+              outBuf += outCount;
+              outBufLen -= outCount;
+            }
+            outCount =
+                snprintf(outBuf, outBufLen,
+                         (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
+                         (val / minute) % (hour / minute));
+            if (outCount >= outBufLen) break;
+            outBuf += outCount;
+            outBufLen -= outCount;
+          }
+          outCount = snprintf(outBuf, outBufLen,
+                              (val >= minute) ? "%02" PRIu64 : "%" PRIu64 "s",
+                              val % minute);
+        } break;
         case TYPE_ALLOCATIONS:
           outCount = 0;
           /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 9f05351..efcc817 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -30,6 +30,7 @@
 # 4: Number of allocations
 # 5: Id
 # 6: Percent
+# s: Number of seconds (monotonic time)
 # Default value for data of type int/long is 2 (bytes).
 #
 # TODO: generate ".java" and ".h" files with integer constants from this file.
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 21868f2..e487a97 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -17,6 +17,7 @@
 #include <ctype.h>
 #include <dirent.h>
 #include <signal.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,6 +32,7 @@
 
 #include <android-base/file.h>
 #include <gtest/gtest.h>
+#include <log/event_tag_map.h>
 #include <log/log.h>
 #include <log/log_event_list.h>
 
@@ -47,6 +49,16 @@
 
 #define BIG_BUFFER (5 * 1024)
 
+// rest(), let the logs settle.
+//
+// logd is in a background cgroup and under extreme load can take up to
+// 3 seconds to land a log entry. Under moderate load we can do with 200ms.
+static void rest() {
+    static const useconds_t restPeriod = 200000;
+
+    usleep(restPeriod);
+}
+
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
 // non-syscall libs. Since we are only using this in the emergency of
 // a signal to stuff a terminating code into the logs, we will spin rather
@@ -70,7 +82,7 @@
 #undef LOG_TAG
 #define LOG_TAG "inject"
     RLOGE(logcat_executable ".buckets");
-    sleep(1);
+    rest();
 
     ASSERT_TRUE(NULL !=
                 (fp = logcat_popen(
@@ -1412,7 +1424,7 @@
     LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
                                           logcat_regex_prefix "_aaaa"));
     // Let the logs settle
-    sleep(1);
+    rest();
 
     ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
 
@@ -1450,8 +1462,7 @@
     LOG_FAILURE_RETRY(
         __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
 
-    // Let the logs settle
-    sleep(1);
+    rest();
 
     ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
 
@@ -1476,8 +1487,7 @@
 
 static bool End_to_End(const char* tag, const char* fmt, ...) {
     logcat_define(ctx);
-    FILE* fp = logcat_popen(ctx,
-                            "logcat"
+    FILE* fp = logcat_popen(ctx, logcat_executable
                             " -v brief"
                             " -b events"
                             " -v descriptive"
@@ -1523,13 +1533,12 @@
         // Help us pinpoint where things went wrong ...
         fprintf(stderr, "Closest match for\n    %s\n  is\n    %s",
                 expect.c_str(), lastMatch.c_str());
-    } else if (count > 2) {
+    } else if (count > 3) {
         fprintf(stderr, "Too many matches (%d) for %s\n", count, expect.c_str());
     }
 
-    // Expect one the first time around as either liblogcat.descriptive or
-    // logcat.descriptive.  Expect two the second time as the other.
-    return count == 1 || count == 2;
+    // Three different known tests, we can see pollution from the others
+    return count && (count <= 3);
 }
 
 TEST(logcat, descriptive) {
@@ -1537,24 +1546,28 @@
         uint32_t tagNo;
         const char* tagStr;
     };
+    int ret;
 
     {
         static const struct tag hhgtg = { 42, "answer" };
         android_log_event_list ctx(hhgtg.tagNo);
         static const char theAnswer[] = "what is five by seven";
         ctx << theAnswer;
-        ctx.write();
+        // crafted to rest at least once after, and rest between retries.
+        for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+        EXPECT_LE(0, ret);
         EXPECT_TRUE(
             End_to_End(hhgtg.tagStr, "to life the universe etc=%s", theAnswer));
     }
 
     {
         static const struct tag sync = { 2720, "sync" };
-        static const char id[] = "logcat.decriptive";
+        static const char id[] = ___STRING(logcat) ".descriptive-sync";
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr,
                                    "[id=%s,event=42,source=-1,account=0]", id));
         }
@@ -1563,7 +1576,8 @@
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr, "[id=%s,event=43,-1,0]", id));
         }
 
@@ -1571,7 +1585,8 @@
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             fprintf(stderr, "Expect a \"Closest match\" message\n");
             EXPECT_FALSE(End_to_End(
                 sync.tagStr, "[id=%s,event=44,source=-1,account=0]", id));
@@ -1583,7 +1598,8 @@
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint64_t)30 << (int32_t)2;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(
                 End_to_End(sync.tagStr, "[aggregation time=30ms,count=2]"));
         }
@@ -1591,7 +1607,8 @@
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint64_t)31570 << (int32_t)911;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(
                 End_to_End(sync.tagStr, "[aggregation time=31.57s,count=911]"));
         }
@@ -1602,42 +1619,48 @@
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)512;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
         }
 
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)3072;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
         }
 
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)2097152;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
         }
 
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)2097153;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
         }
 
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)1073741824;
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
         }
 
         {
             android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)3221225472;  // 3MB, but on purpose overflowed
-            ctx.write();
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
         }
     }
@@ -1645,9 +1668,52 @@
     {
         static const struct tag sync = { 27501, "notification_panel_hidden" };
         android_log_event_list ctx(sync.tagNo);
-        ctx.write();
+        for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+        EXPECT_LE(0, ret);
         EXPECT_TRUE(End_to_End(sync.tagStr, ""));
     }
+
+    {
+        // Invent new entries because existing can not serve
+        EventTagMap* map = android_openEventTagMap(nullptr);
+        ASSERT_TRUE(nullptr != map);
+        static const char name[] = ___STRING(logcat) ".descriptive-monotonic";
+        int myTag = android_lookupEventTagNum(map, name, "(new|1|s)",
+                                              ANDROID_LOG_UNKNOWN);
+        android_closeEventTagMap(map);
+        ASSERT_NE(-1, myTag);
+
+        const struct tag sync = { (uint32_t)myTag, name };
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)7;
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
+            EXPECT_TRUE(End_to_End(sync.tagStr, "new=7s"));
+        }
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)62;
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
+            EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:02"));
+        }
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)3673;
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
+            EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:01:13"));
+        }
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)(86400 + 7200 + 180 + 58);
+            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
+            EXPECT_LE(0, ret);
+            EXPECT_TRUE(End_to_End(sync.tagStr, "new=1d 2:03:58"));
+        }
+    }
 }
 
 static bool reportedSecurity(const char* command) {
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index cc30f77..d3167ad 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -248,18 +248,38 @@
                       std::string(isprune ? "NUM" : ""));
 }
 
+// Helper to truncate name, if too long, and add name dressings
+static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
+                      std::string& name, std::string& size, size_t nameLen) {
+    const char* allocNameTmp = nullptr;
+    if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
+    if (nameTmp) {
+        size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
+        size_t len = EntryBaseConstants::total_len -
+                     EntryBaseConstants::pruned_len - size.length() -
+                     name.length() - lenSpace - 2;
+        size_t lenNameTmp = strlen(nameTmp);
+        while ((len < lenNameTmp) && (lenSpace > 1)) {
+            ++len;
+            --lenSpace;
+        }
+        name += android::base::StringPrintf("%*s", (int)lenSpace, "");
+        if (len < lenNameTmp) {
+            name += "...";
+            nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
+        }
+        name += nameTmp;
+        free(const_cast<char*>(allocNameTmp));
+    }
+}
+
 std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
     uid_t uid = getUid();
     std::string name = android::base::StringPrintf("%u", uid);
-    const char* nameTmp = stat.uidToName(uid);
-    if (nameTmp) {
-        name += android::base::StringPrintf(
-            "%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", nameTmp);
-        free(const_cast<char*>(nameTmp));
-    }
-
     std::string size = android::base::StringPrintf("%zu", getSizes());
 
+    formatTmp(stat, nullptr, uid, name, size, 6);
+
     std::string pruned = "";
     if (worstUidEnabledForLogid(id)) {
         size_t totalDropped = 0;
@@ -366,18 +386,10 @@
     uid_t uid = getUid();
     pid_t pid = getPid();
     std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
-    const char* nameTmp = getName();
-    if (nameTmp) {
-        name += android::base::StringPrintf(
-            "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
-    } else if ((nameTmp = stat.uidToName(uid))) {
-        name += android::base::StringPrintf(
-            "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
-        free(const_cast<char*>(nameTmp));
-    }
-
     std::string size = android::base::StringPrintf("%zu", getSizes());
 
+    formatTmp(stat, getName(), uid, name, size, 12);
+
     std::string pruned = "";
     size_t dropped = getDropped();
     if (dropped) {
@@ -398,21 +410,10 @@
                              log_id_t /* id */) const {
     uid_t uid = getUid();
     std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
-    const char* nameTmp = getName();
-    if (nameTmp) {
-        name += android::base::StringPrintf(
-            "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
-    } else if ((nameTmp = stat.uidToName(uid))) {
-        // if we do not have a PID name, lets punt to try UID name?
-        name += android::base::StringPrintf(
-            "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
-        free(const_cast<char*>(nameTmp));
-        // We tried, better to not have a name at all, we still
-        // have TID/UID by number to report in any case.
-    }
-
     std::string size = android::base::StringPrintf("%zu", getSizes());
 
+    formatTmp(stat, getName(), uid, name, size, 12);
+
     std::string pruned = "";
     size_t dropped = getDropped();
     if (dropped) {
diff --git a/logd/event.logtags b/logd/event.logtags
index 39063a9..fa13a62 100644
--- a/logd/event.logtags
+++ b/logd/event.logtags
@@ -29,6 +29,7 @@
 # 4: Number of allocations
 # 5: Id
 # 6: Percent
+# s: Number of seconds (monotonic time)
 # Default value for data of type int/long is 2 (bytes).
 #
 # TODO: generate ".java" and ".h" files with integer constants from this file.
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
new file mode 100644
index 0000000..5d10c18
--- /dev/null
+++ b/shell_and_utilities/README.md
@@ -0,0 +1,157 @@
+Android's shell and utilities
+=============================
+
+Since IceCreamSandwich Android has used
+[mksh](https://www.mirbsd.org/mksh.htm) as its shell. Before then it used
+[ash](https://en.wikipedia.org/wiki/Almquist_shell) (which actually
+remained in the tree up to and including KitKat).
+
+Initially Android had a very limited command-line provided by its
+own "toolbox" binary. These days almost everything is supplied by
+[toybox](http://landley.net/toybox/) instead.
+
+We started moving a few of the more important tools to full
+BSD implementations in JellyBean before we started in earnest in
+Lollipop. Lollipop was a major break with the past in many ways (LP64
+support and the switch to ART both having lots of knock-on effects around
+the system), so although this was the beginning of the end of toolbox it
+(a) didn't stand out given all the other systems-level changes and (b)
+in Marshmallow we changed direction and started the move to toybox.
+
+The lists below show what tools were provided and where they came from in
+each release starting with Gingerbread. This doesn't tell the full story,
+because the toolbox implementations did have bugs fixed and options added
+over the years. Gingerbread's rm, for example, supported `-r`/`-R` but not
+`-f`. But this gives you an idea of what was available in any given release,
+and how usable it was likely to be.
+
+
+Android 2.3 (Gingerbread)
+-------------------------
+
+BSD: cat dd newfs\_msdos
+
+toolbox: chmod chown cmp date df dmesg getevent getprop hd id ifconfig
+iftop insmod ioctl ionice kill ln log ls lsmod lsof mkdir mount mv
+nandread netstat notify printenv ps reboot renice rm rmdir rmmod route
+schedtop sendevent setconsole setprop sleep smd start stop sync top
+umount uptime vmstat watchprops wipe
+
+
+Android 4.0 (IceCreamSandwich)
+------------------------------
+
+BSD: cat dd newfs\_msdos
+
+toolbox: chmod chown cmp date df dmesg getevent getprop hd id ifconfig
+iftop insmod ioctl ionice kill ln log ls lsmod lsof mkdir mount mv
+nandread netstat notify printenv ps reboot renice rm rmdir rmmod route
+schedtop sendevent setconsole setprop sleep smd start stop sync top
+touch umount uptime vmstat watchprops wipe
+
+
+Android 4.1-4.3 (JellyBean)
+---------------------------
+
+BSD: cat cp dd du grep newfs\_msdos
+
+toolbox: chcon chmod chown clear cmp date df dmesg getenforce getevent
+getprop getsebool hd id ifconfig iftop insmod ioctl ionice kill ln
+load\_policy log ls lsmod lsof md5 mkdir mount mv nandread netstat notify
+printenv ps reboot renice restorecon rm rmdir rmmod route runcon schedtop
+sendevent setconsole setenforce setprop setsebool sleep smd start stop
+sync top touch umount uptime vmstat watchprops wipe
+
+
+Android 4.4 (KitKat)
+--------------------
+
+BSD: cat cp dd du grep newfs\_msdos
+
+toolbox: chcon chmod chown clear cmp date df dmesg getenforce getevent
+getprop getsebool hd id ifconfig iftop insmod ioctl ionice kill ln
+load\_policy log ls lsmod lsof md5 mkdir mkswap mount mv nandread netstat
+notify printenv ps readlink renice restorecon rm rmdir rmmod route runcon
+schedtop sendevent setconsole setenforce setprop setsebool sleep smd start
+stop swapoff swapon sync top touch umount uptime vmstat watchprops wipe
+
+
+Android 5.0 (Lollipop)
+----------------------
+
+BSD: cat chown cp dd du grep kill ln mv printenv rm rmdir sleep sync
+
+toolbox: chcon chmod clear cmp date df dmesg getenforce getevent getprop
+getsebool hd id ifconfig iftop insmod ioctl ionice load\_policy log ls
+lsmod lsof md5 mkdir mknod mkswap mount nandread netstat newfs\_msdos
+nohup notify ps readlink renice restorecon rmmod route runcon schedtop
+sendevent setenforce setprop setsebool smd start stop swapoff swapon
+top touch umount uptime vmstat watchprops wipe
+
+
+Android 6.0 (Marshmallow)
+-------------------------
+
+BSD: dd du grep
+
+toolbox: df getevent iftop ioctl ionice log ls lsof mount nandread
+newfs\_msdos ps prlimit renice sendevent start stop top uptime watchprops
+
+toybox: acpi basename blockdev bzcat cal cat chcon chgrp chmod chown
+chroot cksum clear comm cmp cp cpio cut date dirname dmesg dos2unix echo
+env expand expr fallocate false find free getenforce getprop groups
+head hostname hwclock id ifconfig inotifyd insmod kill load\_policy ln
+logname losetup lsmod lsusb md5sum mkdir mknod mkswap mktemp modinfo
+more mountpoint mv netstat nice nl nohup od paste patch pgrep pidof
+pkill pmap printenv printf pwd readlink realpath restorecon rm rmdir
+rmmod route runcon sed seq setenforce setprop setsid sha1sum sleep sort
+split stat strings swapoff swapon sync sysctl tac tail tar taskset tee
+time timeout touch tr true truncate umount uname uniq unix2dos usleep
+vmstat wc which whoami xargs yes
+
+
+Android 7.0 (Nougat)
+--------------------
+
+BSD: dd grep
+
+toolbox: getevent iftop ioctl log nandread newfs\_msdos ps prlimit
+sendevent start stop top
+
+toybox: acpi base64 basename blockdev bzcat cal cat chcon chgrp chmod
+chown chroot cksum clear comm cmp cp cpio cut date df dirname dmesg
+dos2unix du echo env expand expr fallocate false find flock free
+getenforce getprop groups head hostname hwclock id ifconfig inotifyd
+insmod ionice iorenice kill killall load\_policy ln logname losetup ls
+lsmod lsof lsusb md5sum mkdir mknod mkswap mktemp modinfo more mount
+mountpoint mv netstat nice nl nohup od paste patch pgrep pidof pkill
+pmap printenv printf pwd readlink realpath renice restorecon rm rmdir
+rmmod route runcon sed seq setenforce setprop setsid sha1sum sleep sort
+split stat strings swapoff swapon sync sysctl tac tail tar taskset tee
+time timeout touch tr true truncate tty ulimit umount uname uniq unix2dos
+uptime usleep vmstat wc which whoami xargs xxd yes
+
+
+Current AOSP
+------------
+
+BSD: dd grep
+
+bzip2: bzcat bzip2 bunzip2
+
+toolbox: getevent gzip newfs\_msdos gunzip zcat
+
+toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
+dos2unix du echo env expand expr fallocate false file find flock free
+getenforce getprop groups head hostname hwclock id ifconfig inotifyd
+insmod ionice iorenice kill killall ln load\_policy log logname losetup
+ls lsmod lsof lsusb md5sum microcom mkdir mknod mkswap mktemp modinfo
+modprobe more mount mountpoint mv netstat nice nl nohup od paste patch
+pgrep pidof pkill pmap printenv printf ps pwd readlink realpath renice
+restorecon rm rmdir rmmod runcon sed sendevent seq setenforce setprop
+setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split
+start stat stop strings swapoff swapon sync sysctl tac tail tar taskset
+tee time timeout top touch tr true truncate tty ulimit umount uname uniq
+unix2dos uptime usleep uudecode uuencode vmstat wc which whoami xargs
+xxd yes