Skip to content

NativeLooper构造

从 libutils Looper 构造追踪 eventfd、epoll、线程绑定、请求表和构造失败边界。

基于android-17.0.0_r1
AndroidNative Loopereventfdepoll文件描述符源码阅读

NativeLooper构造 ​

本文承接 NativeMessageQueue封装,只研究 libutils::Looper 从“尚未存在”到“可以等待事件”的构造过程。核心问题是:构造函数初始化了哪些不可变状态,eventfd 为什么先于 epoll,唤醒 FD 如何成为 epoll 的固定节点,线程局部绑定和 FD 请求表又怎样连接到后续 pollOnce()。

1. 字段分工 ​

源码文件:system/core/libutils/include/utils/Looper.h

相关字段:mAllowNonCallbacks、mWakeEventFd、mEpollFd、mRequests

cpp
const bool mAllowNonCallbacks;
android::base::unique_fd mWakeEventFd;
mutable std::mutex mLock;
std::atomic<bool> mPolling;
android::base::unique_fd mEpollFd;
bool mEpollRebuildRequired;
std::unordered_map<SequenceNumber, Request> mRequests;
std::unordered_map<int, SequenceNumber> mSequenceNumberByFd;
std::atomic<uint64_t> mRequestsGeneration;
SequenceNumber mNextRequestSeq;
std::vector<Response> mResponses;
size_t mResponseIndex;
nsecs_t mNextMessageUptime;

构造阶段真正要建立的是三个基础条件:有一个可写入的 wake FD,有一个把 wake FD 注册进去的 epoll FD,以及一组记录未来 FD 请求的空容器。mResponses、mNextMessageUptime 等字段服务于后续 poll,不代表构造时已经有事件或 native 消息。

2. 构造入口 ​

源码文件:system/core/libutils/Looper.cpp

相关函数:Looper::Looper()

cpp
constexpr uint64_t WAKE_EVENT_FD_SEQ = 1;
static const int EPOLL_MAX_EVENTS = 16;

Looper::Looper(bool allowNonCallbacks)
        : mAllowNonCallbacks(allowNonCallbacks),
          mSendingMessage(false), mPolling(false),
          mEpollRebuildRequired(false), mRequestsGeneration(0),
          mNextRequestSeq(WAKE_EVENT_FD_SEQ + 1),
          mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0,
            "Could not make wake event fd: %s", strerror(errno));
    std::scoped_lock _l(mLock);
    rebuildEpollLocked();
}

初始化列表先把控制状态设为“没有发送消息、没有 poll、没有待重建”;序列号从 wake FD 保留值之后开始。构造体函数再创建 wake FD,并在锁内建立 epoll 集合。allowNonCallbacks 只决定之后能否注册没有 callback 的 FD,不改变 wake FD 的注册。

3. Wake FD ​

源码文件:system/core/libutils/Looper.cpp

相关函数:构造函数、wake()

cpp
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0,
        "Could not make wake event fd: %s", strerror(errno));

eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC) 创建计数型 FD:写入表示有唤醒请求,读取消费计数;非阻塞避免 wake/awoken 卡住,CLOEXEC 避免 FD 带入后续 exec。unique_fd 接管内核 FD 的关闭责任。

4. Epoll初始集 ​

源码文件:system/core/libutils/Looper.cpp

相关函数:rebuildEpollLocked()

cpp
void Looper::rebuildEpollLocked() {
    if (mEpollFd >= 0) mEpollFd.reset();
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0,
            "Could not create epoll instance: %s", strerror(errno));

    epoll_event wakeEvent = createEpollEvent(EPOLLIN, WAKE_EVENT_FD_SEQ);
    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD,
            mWakeEventFd.get(), &wakeEvent);
    LOG_ALWAYS_FATAL_IF(result != 0,
            "Could not add wake event fd to epoll instance: %s", strerror(errno));

    for (const auto& [seq, request] : mRequests) {
        epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);
        epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
    }
}

重建先关闭旧 epoll,再创建新实例,固定加入 wake FD,最后恢复 mRequests 中的业务请求。构造第一次调用时请求表为空,所以至少得到一个只监听 wake FD 的 epoll 集。

5. 锁与RAII ​

构造函数在调用 rebuildEpollLocked() 前取得 mLock,函数名中的 Locked 表明它要求调用者持锁。std::scoped_lock 负责离开作用域时释放锁;unique_fd 负责构造失败或析构时关闭已取得的内核 FD。这里没有手写 close 的补偿路径。

6. 线程绑定 ​

源码文件:system/core/libutils/Looper.cpp

相关函数:getForThread()、setForThread()、prepare()

cpp
thread_local static sp<Looper> gThreadLocalLooper;

void Looper::setForThread(const sp<Looper>& looper) {
    gThreadLocalLooper = looper;
}

sp<Looper> Looper::getForThread() {
    return gThreadLocalLooper;
}

sp<Looper> Looper::prepare(int opts) {
    bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
    sp<Looper> looper = Looper::getForThread();
    if (looper == nullptr) {
        looper = sp<Looper>::make(allowNonCallbacks);
        Looper::setForThread(looper);
    }
    return looper;
}

线程绑定发生在 native gThreadLocalLooper,不是 Java Looper.sThreadLocal。NativeMessageQueue 构造时也会复用或创建同一个 native Looper。

7. 参数语义 ​

源码文件:system/core/libutils/include/utils/Looper.h

相关常量:PREPARE_ALLOW_NON_CALLBACKS

cpp
enum {
    PREPARE_ALLOW_NON_CALLBACKS = 1 << 0
};

Looper(bool allowNonCallbacks);

allowNonCallbacks 允许 addFd() 注册空 callback,调用者随后自己检查 pollOnce() 返回值;关闭时,空 callback 注册会被拒绝。它不是“是否允许 Looper 运行”,也不是 Java MessageQueue.mQuitAllowed。

8. 序列号初值 ​

源码文件:system/core/libutils/Looper.cpp

相关函数:构造函数、addFd()

cpp
constexpr uint64_t WAKE_EVENT_FD_SEQ = 1;
mNextRequestSeq(WAKE_EVENT_FD_SEQ + 1)

if (mNextRequestSeq == WAKE_EVENT_FD_SEQ) mNextRequestSeq++;
const SequenceNumber seq = mNextRequestSeq++;

wake FD 使用保留序列号,业务 FD 从后续序列号开始。epoll 返回时通过序列号区分 wake 事件和业务请求,避免直接把可复用的 FD 数值当作稳定身份。

9. 构造失败 ​

eventfd()、epoll_create1() 或把 wake FD 加入 epoll 失败,当前源码使用 LOG_ALWAYS_FATAL_IF。这表示等待器无法建立时不会返回一个空 Looper 让上层继续。普通业务 FD 的 addFd() 失败则返回 -1,是另一条运行时路径。

10. 首次状态 ​

构造完成后:mAllowNonCallbacks 固定;wake eventfd 已创建;epoll 已监听 wake FD;请求表为空;请求代数为 0;下一个业务序列号为 3;没有 response 可返回;mNextMessageUptime 为 LLONG_MAX。Looper 已具备等待和唤醒能力,但尚未注册业务 FD 或 native Message。

11. 动手验证 ​

bash
rg -n "Looper::Looper|eventfd|rebuildEpollLocked|WAKE_EVENT_FD_SEQ" \
  system/core/libutils/Looper.cpp
rg -n "gThreadLocalLooper|Looper::prepare|setForThread|getForThread" \
  system/core/libutils/Looper.cpp

按 eventfd → epoll_create1 → EPOLL_CTL_ADD(wake) → 请求表恢复的顺序阅读,再比较 Looper::prepare() 和 NativeMessageQueue 的线程绑定入口。

12. 边界说明 ​

本文不展开 pollInner() 的超时、事件分发和 wake 读取,也不展开 addFd() 的 FD 复用修复;这些行为建立在本文构造出的 wake/epoll 初始状态上。构造源码能支持资源、锁、序列号和失败策略,不能据此推断一次具体 poll 的返回结果。