Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6890d95e authored by Corey Tabaka's avatar Corey Tabaka Committed by Alex Vakulenko
Browse files

libpdx: Add support for more event bits.

- Add generic abstraction for multiple event bits with an implementation-
  defined mechanism to deliver the bits.
- Update ServiceFS backend to pass through event bits.
- Implement EPOLLIN, EPOLLPRI, and EPOLLHUP event bit for UDS backed.

Bug: 34466748
Test: Build/flash system; observe stable operation.

Change-Id: I86afb5645b72ec69c095734c7891a690432150a3
parent 5ffa916b
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -108,8 +108,22 @@ class Client {
   */
  void DisableAutoReconnect();

  /*
   * Returns an fd that the client may use to check/wait for asynchronous
   * notifications to the channel. It is implementation dependent how the
   * transport backend handles this feature, however all implementations must
   * support at least POLLIN/EPOLLIN/readable.
   *
   * For uses that require more than one type of event, use
   * ClientChannel::GetEventMask() to distinguish between events.
   */
  int event_fd() const;

  /*
   * Returns the underlying ClientChannel object.
   */
  ClientChannel* GetChannel() const { return channel_.get(); }
  std::unique_ptr<ClientChannel>&& TakeChannel() { return std::move(channel_); }

 private:
  Client(const Client&) = delete;
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ class ClientChannel {
  virtual uint32_t GetIpcTag() const = 0;

  virtual int event_fd() const = 0;
  virtual Status<int> GetEventMask(int events) = 0;

  virtual LocalChannelHandle& GetChannelHandle() = 0;
  virtual void* AllocateTransactionState() = 0;
  virtual void FreeTransactionState(void* state) = 0;
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ class MockClientChannel : public ClientChannel {
 public:
  MOCK_CONST_METHOD0(GetIpcTag, uint32_t());
  MOCK_CONST_METHOD0(event_fd, int());
  MOCK_METHOD1(GetEventMask, Status<int>(int));
  MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&());
  MOCK_METHOD0(AllocateTransactionState, void*());
  MOCK_METHOD1(FreeTransactionState, void(void* state));
+3 −0
Original line number Diff line number Diff line
@@ -5,10 +5,13 @@ cc_library_static {
        "-Wall",
        "-Wextra",
        "-Werror",
        "-DLOG_TAG=\"libpdx_uds\"",
        "-DTRACE=0",
    ],
    export_include_dirs: ["private"],
    local_include_dirs: ["private"],
    srcs: [
        "channel_event_set.cpp",
        "channel_manager.cpp",
        "client_channel_factory.cpp",
        "client_channel.cpp",
+115 −0
Original line number Diff line number Diff line
#include "private/uds/channel_event_set.h"

#include <log/log.h>

#include <uds/ipc_helper.h>

namespace android {
namespace pdx {
namespace uds {

ChannelEventSet::ChannelEventSet() {
  const int flags = EFD_CLOEXEC | EFD_NONBLOCK;
  LocalHandle epoll_fd, event_fd;

  if (!SetupHandle(epoll_create(1), &epoll_fd, "epoll") ||
      !SetupHandle(eventfd(0, flags), &event_fd, "event")) {
    return;
  }

  epoll_event event;
  event.events = 0;
  event.data.u32 = 0;
  if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_fd.Get(), &event) < 0) {
    const int error = errno;
    ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s",
          strerror(error));
    return;
  }

  epoll_fd_ = std::move(epoll_fd);
  event_fd_ = std::move(event_fd);
}

Status<void> ChannelEventSet::AddDataFd(const LocalHandle& data_fd) {
  epoll_event event;
  event.events = EPOLLHUP | EPOLLRDHUP;
  event.data.u32 = event.events;
  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) {
    const int error = errno;
    ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s",
          strerror(error));
    return ErrorStatus{error};
  } else {
    return {};
  }
}

int ChannelEventSet::ModifyEvents(int clear_mask, int set_mask) {
  ALOGD_IF(TRACE, "ChannelEventSet::ModifyEvents: clear_mask=%x set_mask=%x",
           clear_mask, set_mask);
  const int old_bits = event_bits_;
  const int new_bits = (event_bits_ & ~clear_mask) | set_mask;
  event_bits_ = new_bits;

  // If anything changed clear the event and update the event mask.
  if (old_bits != new_bits) {
    eventfd_t value;
    eventfd_read(event_fd_.Get(), &value);

    epoll_event event;
    event.events = POLLIN;
    event.data.u32 = event_bits_;
    if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_MOD, event_fd_.Get(), &event) <
        0) {
      const int error = errno;
      ALOGE("ChannelEventSet::AddEventHandle: Failed to update event: %s",
            strerror(error));
      return -error;
    }
  }

  // If there are any bits set, re-trigger the eventfd.
  if (new_bits)
    eventfd_write(event_fd_.Get(), 1);

  return 0;
}

Status<void> ChannelEventSet::SetupHandle(int fd, LocalHandle* handle,
                                          const char* error_name) {
  const int error = errno;
  handle->Reset(fd);
  if (!*handle) {
    ALOGE("ChannelEventSet::SetupHandle: Failed to setup %s handle: %s",
          error_name, strerror(error));
    return ErrorStatus{error};
  }
  return {};
}

Status<int> ChannelEventReceiver::GetPendingEvents() const {
  constexpr long kTimeoutMs = 0;
  epoll_event event;
  const int count =
      RETRY_EINTR(epoll_wait(epoll_fd_.Get(), &event, 1, kTimeoutMs));

  Status<int> status;
  if (count < 0) {
    status.SetError(errno);
    ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s",
          status.GetErrorMessage().c_str());
    return status;
  }

  const int mask_out = event.data.u32;
  ALOGD_IF(TRACE, "ChannelEventReceiver::GetPendingEvents: mask_out=%x",
           mask_out);

  status.SetValue(mask_out);
  return status;
}

}  // namespace uds
}  // namespace pdx
}  // namespace android
Loading