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()
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()
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()
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()
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()
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()
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()
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()
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()
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. 动手验证
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 控制流。
