Skip to content

nativePollOnce详解

从 JNI nativePollOnce 进入 libutils pollOnce,拆解响应缓存、超时、epoll 事件和回调顺序。

基于android-17.0.0_r1
AndroidnativePollOnceNative Looperepoll源码阅读

nativePollOnce详解 ​

本文承接 NativeLooper构造。nativePollOnce() 名字像一个简单阻塞函数,实际经过三层边界:JNI 保存 Java 回调上下文,Looper::pollOnce() 先消费上轮 response,再调用 pollInner(),pollInner() 处理 epoll、native Message 和 FD callback。本文按这条控制流解释每个返回值和每次锁切换。

1. JNI入口 ​

源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp

相关函数:android_os_MessageQueue_nativePollOnce()、NativeMessageQueue::pollOnce()

cpp
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue =
            reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL;
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

Java 签名返回 void,所以 native POLL_WAKE/POLL_CALLBACK/POLL_TIMEOUT/POLL_ERROR 不会直接返回给 Java。JNI 负责的是上下文和异常;具体事件处理在 libutils::Looper 内完成。

2. 两阶段轮询 ​

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

相关函数:pollOnce()、pollInner()

cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        const uint64_t generation = mRequestsGeneration.load(
                std::memory_order_acquire);
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses[mResponseIndex++];
            int ident = response.request.ident;
            if (ident >= 0) {
                if (isResponseStale(generation, response.seq)) continue;
                if (outFd != nullptr) *outFd = response.request.fd;
                if (outEvents != nullptr) *outEvents = response.events;
                if (outData != nullptr) *outData = response.request.data;
                return ident;
            }
        }
        if (result != 0) return result;
        result = pollInner(timeoutMillis);
    }
}

pollOnce() 的第一阶段消费 mResponses 中尚未返回的非负 ident;只有没有可返回 response 时才进入 pollInner()。因此一次 epoll_wait 可能产生多个 FD response,后续调用可以不再阻塞而依次取完。

3. 超时修正 ​

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

相关函数:pollInner()

cpp
int originalTimeout = timeoutMillis;
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    int messageTimeoutMillis = toMillisecondTimeoutDelay(
            now, mNextMessageUptime);
    if (messageTimeoutMillis >= 0
            && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
        timeoutMillis = messageTimeoutMillis;
    }
}

native Looper 同时考虑调用者传入的 timeout 和 native Message 的到期时间,取更早者。originalTimeout 保留调用者是否传入 0,用于后面的“是否可以跳过 epoll_wait”优化;它不能被修正后的 timeout 替代。

4. 跳过等待 ​

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

相关函数:pollInner()

cpp
bool hasRequests;
{
    std::scoped_lock _l(mLock);
    epollFd = mEpollFd.get();
    hasRequests = !mRequests.empty();
}

if (!sSkipEpollWaitIfPossible || originalTimeout != 0 || hasRequests) {
    std::atomic_store_explicit(&mPolling, true, std::memory_order_relaxed);
    eventCount = epoll_wait(epollFd, eventItems,
            EPOLL_MAX_EVENTS, timeoutMillis);
    std::atomic_store_explicit(&mPolling, false, std::memory_order_relaxed);
}

当全局优化允许、调用者 timeout 为 0 且没有 FD request 时,可以跳过 epoll_wait(),直接处理已有 native Message。mPolling 只表示是否正在等待,注释明确它是有竞争的状态;Java isPolling() 只能作为“正在等还是卡在回调”的近似观察。

5. epoll结果 ​

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

相关函数:pollInner()

cpp
if (eventCount < 0) {
    if (errno == EINTR) goto Done;
    result = POLL_ERROR;
    goto Done;
}

if (eventCount == 0) {
    result = POLL_TIMEOUT;
    goto Done;
}

被信号打断不直接变成 POLL_ERROR,而是进入统一收尾;真正的 epoll 错误才设置 POLL_ERROR。没有事件则设置 POLL_TIMEOUT,但 pollInner() 还可能在同一轮处理已经到期的 native Message。

6. 唤醒事件 ​

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

相关函数:pollInner()、awoken()

cpp
const SequenceNumber seq = eventItems[i].data.u64;
uint32_t epollEvents = eventItems[i].events;
if (seq == WAKE_EVENT_FD_SEQ) {
    if (epollEvents & EPOLLIN) {
        awoken();
    }
}

wake FD 使用保留序列号。收到 EPOLLIN 后 awoken() 读取 eventfd 计数,结果仍是 POLL_WAKE 的默认值,随后继续处理 native Message 和 FD response。唤醒只表示“重新检查”,不表示“Java 队列一定有消息”。

7. FD响应 ​

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

相关函数:pollInner()

cpp
const auto& request_it = mRequests.find(seq);
if (request_it != mRequests.end()) {
    const auto& request = request_it->second;
    int events = 0;
    if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
    if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
    if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
    if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
    mResponses.push_back({.seq = seq, .events = events, .request = request});
}

epoll 原始标志先转换成 Looper 事件,再复制到 response。若序列号已不在 request 表中,事件被视为过期并忽略;这正是 FD 关闭、复用和回调修改监听集合时避免误投递的基础。

8. Native消息 ​

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

相关函数:pollInner()

cpp
mNextMessageUptime = LLONG_MAX;
while (!mMessageEnvelopes.empty()) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    const MessageEnvelope& messageEnvelope = mMessageEnvelopes.front();
    if (messageEnvelope.uptime <= now) {
        sp<MessageHandler> handler = messageEnvelope.handler;
        Message message = messageEnvelope.message;
        mMessageEnvelopes.erase(mMessageEnvelopes.begin());
        mSendingMessage = true;
        mLock.unlock();
        handler->handleMessage(message);
        mLock.lock();
        mSendingMessage = false;
        result = POLL_CALLBACK;
    } else {
        mNextMessageUptime = messageEnvelope.uptime;
        break;
    }
}

native Message 与 Java android.os.Message 是两种类型。native 先在锁内摘除 envelope,保存 Handler 强引用,再解锁调用用户 handler,完成后重新加锁。未来 envelope 的时间写入 mNextMessageUptime,供下一次 timeout 修正。

9. FD回调 ​

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

相关函数:pollInner()

cpp
const uint64_t generation = mRequestsGeneration.load(
        std::memory_order_acquire);
mLock.unlock();

for (size_t i = 0; i < mResponses.size(); i++) {
    Response& response = mResponses[i];
    if (response.request.ident == POLL_CALLBACK) {
        if (isResponseStale(generation, response.seq)) continue;
        int callbackResult = response.request.callback->handleEvent(
                response.request.fd, response.events, response.request.data);
        if (callbackResult == 0) {
            std::scoped_lock _l(mLock);
            removeSequenceNumberLocked(response.seq);
        }
        response.request.callback.clear();
        result = POLL_CALLBACK;
    }
}

FD callback 必须锁外执行;回调可能关闭或重新注册同一个 FD,所以执行前后用 request generation 和 sequence number 判断 response 是否过期。返回 0 才注销,回调引用随后立即清空,避免 response vector 延迟清空期间继续持有对象。

10. Java边界 ​

NativeMessageQueue::pollOnce() 调用 native pollOnce() 后没有读取 int 结果;它只清理 JNI 上下文并检查 mExceptionObj。因此 Java MessageQueue.next() 的控制流不会根据 POLL_TIMEOUT 或 POLL_WAKE 分支,而是返回到 Java 链表逻辑重新判断 when、屏障和退出标志。

11. 动手验证 ​

bash
rg -n "nativePollOnce|NativeMessageQueue::pollOnce|Looper::pollOnce|pollInner" \
  frameworks/base/core/jni/android_os_MessageQueue.cpp \
  system/core/libutils/Looper.cpp
rg -n "mResponses|mRequestsGeneration|POLL_WAKE|POLL_CALLBACK|POLL_TIMEOUT|POLL_ERROR" \
  system/core/libutils/Looper.cpp \
  system/core/libutils/include/utils/Looper.h

阅读一次 FD 事件时,按“旧 response → epoll → 新 response → generation 检查 → callback 返回值”顺序走;阅读一次 Java 消息等待时,重点确认 native poll 返回后仍回到 MessageQueue.next(),而不是把 native 返回值当作 Java Message。

12. 边界说明 ​

本文不展开 addFd() 的完整注册与 FD 复用修复,也不展开 pollAll() 的循环语义、eventfd 写入细节和 Java MessageQueue.next() 的同步屏障。固定源码支持的是 pollOnce/pollInner 的 response、超时、native Message 和 FD callback 控制流。