Merge "Increase coverage of Timers to 100%."
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 0b87b7a..05d8050 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -165,8 +165,7 @@
 
     switch (dump_type) {
       case kDebuggerdNativeBacktrace:
-      case kDebuggerdJavaBacktrace:
-        // Don't generate tombstones for backtrace requests.
+        // Don't generate tombstones for native backtrace requests.
         return {};
 
       case kDebuggerdTombstoneProto:
@@ -178,6 +177,7 @@
         result.text = create_temporary_file();
         break;
 
+      case kDebuggerdJavaBacktrace:
       case kDebuggerdTombstone:
         result.text = create_temporary_file();
         break;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 9a94d79..925d03f 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -92,7 +92,7 @@
     return false;
 }
 
-bool fs_mgr_overlayfs_mount_fstab_entry(const std::string&, const std::string&) {
+bool fs_mgr_overlayfs_mount_fstab_entry(const android::fs_mgr::FstabEntry&) {
     return false;
 }
 
@@ -1299,16 +1299,30 @@
     }
 }
 
-bool fs_mgr_overlayfs_mount_fstab_entry(const std::string& lowers,
-                                        const std::string& mount_point) {
+bool fs_mgr_overlayfs_mount_fstab_entry(const android::fs_mgr::FstabEntry& entry) {
     if (fs_mgr_overlayfs_invalid()) return false;
 
-    std::string aux = "lowerdir=" + lowers + ",override_creds=off";
-    auto rc = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, aux.c_str());
+    // Create the mount point in case it doesn't exist.
+    mkdir(entry.mount_point.c_str(), 0755);
 
-    if (rc == 0) return true;
+    auto options = kLowerdirOption + entry.lowerdir;
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
+        options += ",override_creds=off";
+    }
 
-    return false;
+    // Use .blk_device as the mount() source for debugging purposes.
+    // Overlayfs is pseudo filesystem, so the source device is a symbolic value and isn't used to
+    // back the filesystem. /proc/mounts would show the source as the device name of the mount.
+    auto report = "__mount(source=" + entry.blk_device + ",target=" + entry.mount_point +
+                  ",type=overlay," + options + ")=";
+    auto ret = mount(entry.blk_device.c_str(), entry.mount_point.c_str(), "overlay",
+                     MS_RDONLY | MS_NOATIME, options.c_str());
+    if (ret) {
+        PERROR << report << ret;
+        return false;
+    }
+    LINFO << report << ret;
+    return true;
 }
 
 bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index 830f0dd..1372511 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -92,7 +92,7 @@
     }
     auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," +
                   options + ")=";
-    auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
+    auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
                      options.c_str());
     if (ret) {
         PERROR << report << ret;
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index ac95ef5..22d12e7 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -27,7 +27,7 @@
 android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
 
 bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
-bool fs_mgr_overlayfs_mount_fstab_entry (const std::string& lowers, const std::string& mount_point);
+bool fs_mgr_overlayfs_mount_fstab_entry(const android::fs_mgr::FstabEntry& entry);
 std::vector<std::string> fs_mgr_overlayfs_required_devices(android::fs_mgr::Fstab* fstab);
 bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
                             bool* change = nullptr, bool force = true);
diff --git a/fs_mgr/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h
index 0a5ab50..212c78e 100644
--- a/fs_mgr/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd.h
@@ -99,6 +99,7 @@
     struct dm_user_header* GetHeaderPtr();
     bool ReturnData(void*, size_t) override { return true; }
     void ResetBufferOffset() { buffer_offset_ = 0; }
+    void* GetPayloadBufPtr();
 
   private:
     std::unique_ptr<uint8_t[]> buffer_;
@@ -171,7 +172,7 @@
     bool DmuserReadRequest();
     bool DmuserWriteRequest();
     bool ReadDmUserPayload(void* buffer, size_t size);
-    bool WriteDmUserPayload(size_t size);
+    bool WriteDmUserPayload(size_t size, bool header_response);
 
     bool ReadDiskExceptions(chunk_t chunk, size_t size);
     bool ZerofillDiskExceptions(size_t read_size);
diff --git a/fs_mgr/libsnapshot/snapuserd_worker.cpp b/fs_mgr/libsnapshot/snapuserd_worker.cpp
index 7e0f493..682f9da 100644
--- a/fs_mgr/libsnapshot/snapuserd_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_worker.cpp
@@ -65,6 +65,12 @@
     return header;
 }
 
+void* BufferSink::GetPayloadBufPtr() {
+    char* buffer = reinterpret_cast<char*>(GetBufPtr());
+    struct dm_user_message* msg = reinterpret_cast<struct dm_user_message*>(&(buffer[0]));
+    return msg->payload.buf;
+}
+
 WorkerThread::WorkerThread(const std::string& cow_device, const std::string& backing_device,
                            const std::string& control_device, const std::string& misc_name,
                            std::shared_ptr<Snapuserd> snapuserd) {
@@ -241,6 +247,12 @@
         char* buffer = reinterpret_cast<char*>(bufsink_.GetBufPtr());
         struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
 
+        if (skip_sector_size == BLOCK_SZ) {
+            SNAP_LOG(ERROR) << "Invalid un-aligned IO request at sector: " << sector
+                            << " Base-sector: " << it->first;
+            return -1;
+        }
+
         memmove(msg->payload.buf, (char*)msg->payload.buf + skip_sector_size,
                 (BLOCK_SZ - skip_sector_size));
     }
@@ -315,16 +327,30 @@
     }
 
     int num_ops = DIV_ROUND_UP(size, BLOCK_SZ);
+    sector_t read_sector = sector;
     while (num_ops) {
-        if (!ProcessCowOp(it->second)) {
+        // We have to make sure that the reads are
+        // sequential; there shouldn't be a data
+        // request merged with a metadata IO.
+        if (it->first != read_sector) {
+            SNAP_LOG(ERROR) << "Invalid IO request: read_sector: " << read_sector
+                            << " cow-op sector: " << it->first;
+            return -1;
+        } else if (!ProcessCowOp(it->second)) {
             return -1;
         }
         num_ops -= 1;
+        read_sector += (BLOCK_SZ >> SECTOR_SHIFT);
+
         it++;
+
+        if (it == chunk_vec.end() && num_ops) {
+            SNAP_LOG(ERROR) << "Invalid IO request at sector " << sector
+                            << " COW ops completed; pending read-request: " << num_ops;
+            return -1;
+        }
         // Update the buffer offset
         bufsink_.UpdateBufferOffset(BLOCK_SZ);
-
-        SNAP_LOG(DEBUG) << "ReadData at sector: " << sector << " size: " << size;
     }
 
     // Reset the buffer offset
@@ -589,6 +615,7 @@
         if (errno != ENOTBLK) {
             SNAP_PLOG(ERROR) << "Control-read failed";
         }
+
         return false;
     }
 
@@ -596,10 +623,16 @@
 }
 
 // Send the payload/data back to dm-user misc device.
-bool WorkerThread::WriteDmUserPayload(size_t size) {
-    if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
-                                   sizeof(struct dm_user_header) + size)) {
-        SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << size;
+bool WorkerThread::WriteDmUserPayload(size_t size, bool header_response) {
+    size_t payload_size = size;
+    void* buf = bufsink_.GetPayloadBufPtr();
+    if (header_response) {
+        payload_size += sizeof(struct dm_user_header);
+        buf = bufsink_.GetBufPtr();
+    }
+
+    if (!android::base::WriteFully(ctrl_fd_, buf, payload_size)) {
+        SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << payload_size;
         return false;
     }
 
@@ -634,12 +667,13 @@
     // to flush per se; hence, just respond back with a success message.
     if (header->sector == 0) {
         if (!(header->len == 0)) {
+            SNAP_LOG(ERROR) << "Invalid header length received from sector 0: " << header->len;
             header->type = DM_USER_RESP_ERROR;
         } else {
             header->type = DM_USER_RESP_SUCCESS;
         }
 
-        if (!WriteDmUserPayload(0)) {
+        if (!WriteDmUserPayload(0, true)) {
             return false;
         }
         return true;
@@ -681,7 +715,7 @@
         header->type = DM_USER_RESP_ERROR;
     }
 
-    if (!WriteDmUserPayload(0)) {
+    if (!WriteDmUserPayload(0, true)) {
         return false;
     }
 
@@ -694,6 +728,7 @@
     loff_t offset = 0;
     sector_t sector = header->sector;
     std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
+    bool header_response = true;
     do {
         size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
 
@@ -707,8 +742,13 @@
         // never see multiple IO requests. Additionally this IO
         // will always be a single 4k.
         if (header->sector == 0) {
-            ConstructKernelCowHeader();
-            SNAP_LOG(DEBUG) << "Kernel header constructed";
+            if (read_size == BLOCK_SZ) {
+                ConstructKernelCowHeader();
+                SNAP_LOG(DEBUG) << "Kernel header constructed";
+            } else {
+                SNAP_LOG(ERROR) << "Invalid read_size: " << read_size << " for sector 0";
+                header->type = DM_USER_RESP_ERROR;
+            }
         } else {
             auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
                                        std::make_pair(header->sector, nullptr), Snapuserd::compare);
@@ -724,6 +764,7 @@
                 }
             } else {
                 chunk_t num_sectors_read = (offset >> SECTOR_SHIFT);
+
                 ret = ReadData(sector + num_sectors_read, read_size);
                 if (ret < 0) {
                     SNAP_LOG(ERROR) << "ReadData failed for chunk id: " << chunk
@@ -739,12 +780,19 @@
 
         // Just return the header if it is an error
         if (header->type == DM_USER_RESP_ERROR) {
+            SNAP_LOG(ERROR) << "IO read request failed...";
             ret = 0;
         }
 
+        if (!header_response) {
+            CHECK(header->type == DM_USER_RESP_SUCCESS)
+                    << " failed for sector: " << sector << " header->len: " << header->len
+                    << " remaining_size: " << remaining_size;
+        }
+
         // Daemon will not be terminated if there is any error. We will
         // just send the error back to dm-user.
-        if (!WriteDmUserPayload(ret)) {
+        if (!WriteDmUserPayload(ret, header_response)) {
             return false;
         }
 
@@ -754,6 +802,7 @@
 
         remaining_size -= ret;
         offset += ret;
+        header_response = false;
     } while (remaining_size > 0);
 
     return true;
@@ -799,11 +848,11 @@
         return false;
     }
 
-    SNAP_LOG(DEBUG) << "msg->seq: " << std::hex << header->seq;
-    SNAP_LOG(DEBUG) << "msg->type: " << std::hex << header->type;
-    SNAP_LOG(DEBUG) << "msg->flags: " << std::hex << header->flags;
-    SNAP_LOG(DEBUG) << "msg->sector: " << std::hex << header->sector;
-    SNAP_LOG(DEBUG) << "msg->len: " << std::hex << header->len;
+    SNAP_LOG(DEBUG) << "Daemon: msg->seq: " << std::dec << header->seq;
+    SNAP_LOG(DEBUG) << "Daemon: msg->len: " << std::dec << header->len;
+    SNAP_LOG(DEBUG) << "Daemon: msg->sector: " << std::dec << header->sector;
+    SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
+    SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;
 
     switch (header->type) {
         case DM_USER_REQ_MAP_READ: {
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index d22f68f..76f5193 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -123,7 +123,10 @@
 The exact firmware file to be served can be customized by running an external program by a
 `external_firmware_handler` line in a ueventd.rc file. This line takes the format of
 
-    external_firmware_handler <devpath> <user name to run as> <path to external program>
+    external_firmware_handler <devpath> <user [group]> <path to external program>
+
+The handler will be run as the given user, or if a group is provided, as the given user and group.
+
 For example
 
     external_firmware_handler /devices/leds/red/firmware/coeffs.bin system /vendor/bin/led_coeffs.bin
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index bdc2922..30e808d 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <fnmatch.h>
 #include <glob.h>
+#include <grp.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -81,9 +82,9 @@
     return access("/dev/.booting", F_OK) == 0;
 }
 
-ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
+ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid,
                                                  std::string handler_path)
-    : devpath(std::move(devpath)), uid(uid), handler_path(std::move(handler_path)) {
+    : devpath(std::move(devpath)), uid(uid), gid(gid), handler_path(std::move(handler_path)) {
     auto wildcard_position = this->devpath.find('*');
     if (wildcard_position != std::string::npos) {
         if (wildcard_position == this->devpath.length() - 1) {
@@ -97,13 +98,17 @@
     }
 }
 
+ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
+                                                 std::string handler_path)
+    : ExternalFirmwareHandler(devpath, uid, 0, handler_path) {}
+
 FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories,
                                  std::vector<ExternalFirmwareHandler> external_firmware_handlers)
     : firmware_directories_(std::move(firmware_directories)),
       external_firmware_handlers_(std::move(external_firmware_handlers)) {}
 
 Result<std::string> FirmwareHandler::RunExternalHandler(const std::string& handler, uid_t uid,
-                                                        const Uevent& uevent) const {
+                                                        gid_t gid, const Uevent& uevent) const {
     unique_fd child_stdout;
     unique_fd parent_stdout;
     if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) {
@@ -140,6 +145,13 @@
         }
         c_args.emplace_back(nullptr);
 
+        if (gid != 0) {
+            if (setgid(gid) != 0) {
+                fprintf(stderr, "setgid() failed: %s", strerror(errno));
+                _exit(EXIT_FAILURE);
+            }
+        }
+
         if (setuid(uid) != 0) {
             fprintf(stderr, "setuid() failed: %s", strerror(errno));
             _exit(EXIT_FAILURE);
@@ -196,8 +208,8 @@
                       << "' for devpath: '" << uevent.path << "' firmware: '" << uevent.firmware
                       << "'";
 
-            auto result =
-                    RunExternalHandler(external_handler.handler_path, external_handler.uid, uevent);
+            auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid,
+                                             external_handler.gid, uevent);
             if (!result.ok()) {
                 LOG(ERROR) << "Using default firmware; External firmware handler failed: "
                            << result.error();
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index 3c35b1f..d2f7347 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <grp.h>
 #include <pwd.h>
 
 #include <functional>
@@ -31,9 +32,11 @@
 
 struct ExternalFirmwareHandler {
     ExternalFirmwareHandler(std::string devpath, uid_t uid, std::string handler_path);
+    ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid, std::string handler_path);
 
     std::string devpath;
     uid_t uid;
+    gid_t gid;
     std::string handler_path;
 
     std::function<bool(const std::string&)> match;
@@ -51,7 +54,7 @@
     friend void FirmwareTestWithExternalHandler(const std::string& test_name,
                                                 bool expect_new_firmware);
 
-    Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid,
+    Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid, gid_t gid,
                                            const Uevent& uevent) const;
     std::string GetFirmwarePath(const Uevent& uevent) const;
     void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a733839..616d285 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -331,12 +331,6 @@
     if (devices.empty()) {
         return true;
     }
-    // excluding overlays
-    for (auto iter = devices.begin(); iter != devices.end(); ) {
-        if (*iter=="overlay")  iter = devices.erase(iter);
-        else iter++;
-    }
-
     return block_dev_init_.InitDevices(std::move(devices));
 }
 
@@ -548,6 +542,7 @@
             continue;
         }
 
+        // Handle overlayfs entries later.
         if (current->fs_type == "overlay") {
             ++current;
             continue;
@@ -577,6 +572,12 @@
         current = end;
     }
 
+    for (const auto& entry : fstab_) {
+        if (entry.fs_type == "overlay") {
+            fs_mgr_overlayfs_mount_fstab_entry(entry);
+        }
+    }
+
     // If we don't see /system or / in the fstab, then we need to create an root entry for
     // overlayfs.
     if (!GetEntryForMountPoint(&fstab_, "/system") && !GetEntryForMountPoint(&fstab_, "/")) {
@@ -602,13 +603,6 @@
     };
     MapScratchPartitionIfNeeded(&fstab_, init_devices);
 
-    for (auto current = fstab_.begin(); current != fstab_.end(); ) {
-        if (current->fs_type == "overlay") {
-            fs_mgr_overlayfs_mount_fstab_entry(current->lowerdir, current->mount_point);
-        }
-        ++current;
-    }
-
     fs_mgr_overlayfs_mount_all(&fstab_);
 
     return true;
@@ -695,6 +689,10 @@
     // Includes the partition names of fstab records.
     // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
     for (const auto& fstab_entry : fstab_) {
+        // Skip pseudo filesystems.
+        if (fstab_entry.fs_type == "overlay") {
+            continue;
+        }
         if (!fstab_entry.fs_mgr_flags.logical) {
             devices->emplace(basename(fstab_entry.blk_device.c_str()));
         }
@@ -757,6 +755,10 @@
         if (fstab_entry.fs_mgr_flags.avb) {
             need_dm_verity_ = true;
         }
+        // Skip pseudo filesystems.
+        if (fstab_entry.fs_type == "overlay") {
+            continue;
+        }
         if (fstab_entry.fs_mgr_flags.logical) {
             // Don't try to find logical partitions via uevent regeneration.
             logical_partitions.emplace(basename(fstab_entry.blk_device.c_str()));
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 2221228..9a14406 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -101,8 +101,8 @@
 Result<void> ParseExternalFirmwareHandlerLine(
         std::vector<std::string>&& args,
         std::vector<ExternalFirmwareHandler>* external_firmware_handlers) {
-    if (args.size() != 4) {
-        return Error() << "external_firmware_handler lines must have exactly 3 parameters";
+    if (args.size() != 4 && args.size() != 5) {
+        return Error() << "external_firmware_handler lines must have 3 or 4 parameters";
     }
 
     if (std::find_if(external_firmware_handlers->begin(), external_firmware_handlers->end(),
@@ -117,7 +117,19 @@
         return ErrnoError() << "invalid handler uid'" << args[2] << "'";
     }
 
-    ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, std::move(args[3]));
+    gid_t gid = 0;
+    int handler_index = 3;
+    if (args.size() == 5) {
+        struct group* grp = getgrnam(args[3].c_str());
+        if (!grp) {
+            return ErrnoError() << "invalid handler gid '" << args[3] << "'";
+        }
+        gid = grp->gr_gid;
+        handler_index = 4;
+    }
+
+    ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, gid,
+                                    std::move(args[handler_index]));
     external_firmware_handlers->emplace_back(std::move(handler));
 
     return {};
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index c5aa9e3..d77cb03 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -49,6 +49,7 @@
                                  const ExternalFirmwareHandler& test) {
     EXPECT_EQ(expected.devpath, test.devpath) << expected.devpath;
     EXPECT_EQ(expected.uid, test.uid) << expected.uid;
+    EXPECT_EQ(expected.gid, test.gid) << expected.gid;
     EXPECT_EQ(expected.handler_path, test.handler_path) << expected.handler_path;
 }
 
@@ -157,39 +158,59 @@
 external_firmware_handler /devices/path/firmware/* root "/vendor/bin/firmware_handler.sh"
 external_firmware_handler /devices/path/firmware/something* system "/vendor/bin/firmware_handler.sh"
 external_firmware_handler /devices/path/*/firmware/something*.bin radio "/vendor/bin/firmware_handler.sh"
+external_firmware_handler /devices/path/firmware/something003.bin system system /vendor/bin/firmware_handler.sh
+external_firmware_handler /devices/path/firmware/something004.bin radio radio "/vendor/bin/firmware_handler.sh --has --arguments"
 )";
 
     auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
             {
                     "devpath",
                     AID_ROOT,
+                    AID_ROOT,
                     "handler_path",
             },
             {
                     "/devices/path/firmware/something001.bin",
                     AID_SYSTEM,
+                    AID_ROOT,
                     "/vendor/bin/firmware_handler.sh",
             },
             {
                     "/devices/path/firmware/something002.bin",
                     AID_RADIO,
+                    AID_ROOT,
                     "/vendor/bin/firmware_handler.sh --has --arguments",
             },
             {
                     "/devices/path/firmware/",
                     AID_ROOT,
+                    AID_ROOT,
                     "/vendor/bin/firmware_handler.sh",
             },
             {
                     "/devices/path/firmware/something",
                     AID_SYSTEM,
+                    AID_ROOT,
                     "/vendor/bin/firmware_handler.sh",
             },
             {
                     "/devices/path/*/firmware/something*.bin",
                     AID_RADIO,
+                    AID_ROOT,
                     "/vendor/bin/firmware_handler.sh",
             },
+            {
+                    "/devices/path/firmware/something003.bin",
+                    AID_SYSTEM,
+                    AID_SYSTEM,
+                    "/vendor/bin/firmware_handler.sh",
+            },
+            {
+                    "/devices/path/firmware/something004.bin",
+                    AID_RADIO,
+                    AID_RADIO,
+                    "/vendor/bin/firmware_handler.sh --has --arguments",
+            },
     };
 
     TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
@@ -205,6 +226,7 @@
             {
                     "devpath",
                     AID_ROOT,
+                    AID_ROOT,
                     "handler_path",
             },
     };
@@ -305,7 +327,7 @@
     };
 
     auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
-            {"/devices/path/firmware/firmware001.bin", AID_ROOT, "/vendor/bin/touch.sh"},
+            {"/devices/path/firmware/firmware001.bin", AID_ROOT, AID_ROOT, "/vendor/bin/touch.sh"},
     };
 
     size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;