Merge "Ueventd: Fix a corner case in ReadUevent() that triggers duplicate firmware loading."

This commit is contained in:
Tom Cherry 2020-07-21 21:14:52 +00:00 committed by Gerrit Code Review
commit e122701142
2 changed files with 19 additions and 9 deletions

View file

@ -95,20 +95,18 @@ UeventListener::UeventListener(size_t uevent_socket_rcvbuf_size) {
fcntl(device_fd_, F_SETFL, O_NONBLOCK);
}
bool UeventListener::ReadUevent(Uevent* uevent) const {
ReadUeventResult UeventListener::ReadUevent(Uevent* uevent) const {
char msg[UEVENT_MSG_LEN + 2];
int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
if (n <= 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
PLOG(ERROR) << "Error reading from Uevent Fd";
}
return false;
return ReadUeventResult::kFailed;
}
if (n >= UEVENT_MSG_LEN) {
LOG(ERROR) << "Uevent overflowed buffer, discarding";
// Return true here even if we discard as we may have more uevents pending and we
// want to keep processing them.
return true;
return ReadUeventResult::kInvalid;
}
msg[n] = '\0';
@ -116,7 +114,7 @@ bool UeventListener::ReadUevent(Uevent* uevent) const {
ParseEvent(msg, uevent);
return true;
return ReadUeventResult::kSuccess;
}
// RegenerateUevents*() walks parts of the /sys tree and pokes the uevent files to cause the kernel
@ -137,7 +135,10 @@ ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
close(fd);
Uevent uevent;
while (ReadUevent(&uevent)) {
ReadUeventResult result;
while ((result = ReadUevent(&uevent)) != ReadUeventResult::kFailed) {
// Skip processing the uevent if it is invalid.
if (result == ReadUeventResult::kInvalid) continue;
if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
}
}
@ -212,7 +213,10 @@ void UeventListener::Poll(const ListenerCallback& callback,
// We're non-blocking, so if we receive a poll event keep processing until
// we have exhausted all uevent messages.
Uevent uevent;
while (ReadUevent(&uevent)) {
ReadUeventResult result;
while ((result = ReadUevent(&uevent)) != ReadUeventResult::kFailed) {
// Skip processing the uevent if it is invalid.
if (result == ReadUeventResult::kInvalid) continue;
if (callback(uevent) == ListenerAction::kStop) return;
}
}

View file

@ -37,6 +37,12 @@ enum class ListenerAction {
kContinue, // Continue regenerating uevents as we haven't seen the one(s) we're interested in.
};
enum class ReadUeventResult {
kSuccess = 0, // Uevent was successfully read.
kFailed, // Uevent reading has failed.
kInvalid, // An Invalid Uevent was read (like say, the msg received is >= UEVENT_MSG_LEN).
};
using ListenerCallback = std::function<ListenerAction(const Uevent&)>;
class UeventListener {
@ -50,7 +56,7 @@ class UeventListener {
const std::optional<std::chrono::milliseconds> relative_timeout = {}) const;
private:
bool ReadUevent(Uevent* uevent) const;
ReadUeventResult ReadUevent(Uevent* uevent) const;
ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const;
android::base::unique_fd device_fd_;