Native层总览
本文是 Java 消息机制与 native 消息循环之间的入口。前文已经追到 MessageQueue.next() 调用 nativePollOnce();现在继续向下回答:Java 的 mPtr 指向谁,JNI 如何保存 Java 回调上下文,libutils::Looper 如何用 epoll 等待,wake() 为什么能让 Java 队列重新检查。
本文只建立跨层调用主线,不把 native Looper 的每个 epoll 分支都展开。native poll 返回可能来自唤醒、超时、文件描述符事件或 native 消息,Java MessageQueue.next() 仍要重新判断自己的 Java 链表。
1. 三层对象
相关源码:
frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.javaframeworks/base/core/jni/android_os_MessageQueue.hframeworks/base/core/jni/android_os_MessageQueue.cppsystem/core/libutils/include/utils/Looper.hsystem/core/libutils/Looper.cpp
Java MessageQueue 持有 long mPtr;JNI 把它解释为 NativeMessageQueue*;NativeMessageQueue 再持有 sp<Looper> mLooper。三者不是同一个对象:Java 链表负责 Android Message,native Looper 负责等待和文件描述符事件。
2. Java入口
源码文件:frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java
相关函数:构造函数、next()、dispose()
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
mLooperThread = Thread.currentThread();
}
Message next() {
final long ptr = mPtr;
if (ptr == 0) return null;
nativePollOnce(ptr, nextPollTimeoutMillis);
// 返回后重新检查 Java 链表
}
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}Java 层只把指针和超时交给 JNI。nativePollOnce() 返回后,next() 仍在 Java 锁内检查 mMessages、屏障和 mQuitting;native 返回并不直接产生一条 Java Message。
3. JNI映射
源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp
相关函数:register_android_os_MessageQueue()
static const JNINativeMethod gMessageQueueMethods[] = {
{"nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit},
{"nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy},
{"nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce},
{"nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake},
};
int register_android_os_MessageQueue(JNIEnv* env) {
int res = RegisterMethodsOrDie(env, "android/os/MessageQueue",
gMessageQueueMethods, NELEM(gMessageQueueMethods));
jclass clazz = FindClassOrDie(env, "android/os/MessageQueue");
gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J");
gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(
env, clazz, "dispatchEvents", "(II)I");
return res;
}注册表建立两类连接:四个 native 方法的调用映射,以及 mPtr、dispatchEvents 的缓存。后者是 FD 事件回到 Java 的基础。
4. Native对象
源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp
相关函数:NativeMessageQueue::NativeMessageQueue()、nativeInit()
NativeMessageQueue::NativeMessageQueue()
: mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}native 对象按线程查找 native Looper;已有就复用,没有就创建并登记。这个线程局部存储和 Java Looper.sThreadLocal 是两套机制。
5. Poll桥接
源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp
相关函数: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;
}
}mPollEnv 和 mPollObj 只在 native poll 期间有效。FD 回调依靠它们调用 Java;poll 返回后立即清空。native 回调若产生 Java 异常,会缓存到 mExceptionObj,poll 返回后再抛回 Java。
6. Native构造
源码文件:system/core/libutils/Looper.cpp
相关函数:Looper::Looper()、setForThread()、getForThread()
thread_local static sp<Looper> gThreadLocalLooper;
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false), mPolling(false),
mEpollRebuildRequired(false) {
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();
}
void Looper::setForThread(const sp<Looper>& looper) {
gThreadLocalLooper = looper;
}
sp<Looper> Looper::getForThread() {
return gThreadLocalLooper;
}构造函数创建非阻塞 eventfd,再建立 epoll 集合;eventfd 是 native 唤醒通道,epoll 统一等待唤醒 FD 和其他已注册 FD。
7. Poll结果
源码文件:system/core/libutils/include/utils/Looper.h
相关枚举:POLL_WAKE、POLL_CALLBACK、POLL_TIMEOUT、POLL_ERROR
enum {
POLL_WAKE = -1,
POLL_CALLBACK = -2,
POLL_TIMEOUT = -3,
POLL_ERROR = -4,
};这些结果属于 native Looper::pollOnce();Java nativePollOnce() 签名返回 void,不把枚举值直接交给 MessageQueue.next()。FD 回调通过 JNI 直接调用 Java,而不是让 Java 根据枚举值自己分派。
8. 等待唤醒
源码文件:system/core/libutils/Looper.cpp
相关函数:pollInner()、wake()、awoken()
int eventCount = epoll_wait(epollFd, eventItems,
EPOLL_MAX_EVENTS, timeoutMillis);
if (eventCount == 0) {
result = POLL_TIMEOUT;
goto Done;
}
void Looper::wake() {
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(
write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
}
void Looper::awoken() {
uint64_t counter;
TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
}Java 入队或退出触发 nativeWake(),最终写入 eventfd;epoll 读到 EPOLLIN 后 awoken() 清空计数。唤醒只改变等待状态,不直接摘下 Java Message。
9. FD回调
源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp
相关函数:setFileDescriptorEvents()、handleEvent()
void NativeMessageQueue::setFileDescriptorEvents(int fd, int events) {
if (events) {
int looperEvents = 0;
if (events & CALLBACK_EVENT_INPUT) looperEvents |= Looper::EVENT_INPUT;
if (events & CALLBACK_EVENT_OUTPUT) looperEvents |= Looper::EVENT_OUTPUT;
mLooper->addFd(fd, Looper::POLL_CALLBACK, looperEvents,
sp<WeakLooperCallback>::make(this),
reinterpret_cast<void*>(events));
} else {
mLooper->removeFd(fd);
}
}
int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) {
int events = 0;
if (looperEvents & Looper::EVENT_INPUT) events |= CALLBACK_EVENT_INPUT;
if (looperEvents & Looper::EVENT_OUTPUT) events |= CALLBACK_EVENT_OUTPUT;
if (looperEvents & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP
| Looper::EVENT_INVALID)) events |= CALLBACK_EVENT_ERROR;
int newWatchedEvents = mPollEnv->CallIntMethod(
mPollObj, gMessageQueueClassInfo.dispatchEvents, fd, events);
if (!newWatchedEvents) return 0;
return 1;
}FD 事件经过 native 标志转换后进入 Java dispatchEvents()。Java 返回 0 表示取消监听,返回 1 表示保留;返回新的掩码时 native 会重新配置监听。这个回调依赖 poll 期间有效的 JNI 上下文。
10. 生命周期
源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp
相关函数:nativeDestroy()
static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue =
reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->decStrong(env);
}Java dispose() 调用 nativeDestroy() 后把 mPtr 置零。native 对象释放会结束它持有的 sp<Looper> 引用,但线程局部 Looper 是否仍被其他对象使用,不由这一行单独决定。
11. 动手验证
rg -n "nativePollOnce|nativeWake|NativeMessageQueue::pollOnce|NativeMessageQueue::wake" \
frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java \
frameworks/base/core/jni/android_os_MessageQueue.cpp
rg -n "eventfd|epoll_wait|wake\(|awoken\(|addFd|removeFd" \
system/core/libutils/Looper.cpp沿一次等待阅读 nativePollOnce() → pollOnce() → epoll_wait(),再回到 Java MessageQueue.next();沿一次唤醒则反向阅读 enqueueMessage() → nativeWake() → Looper::wake()。每次都区分“poll 被唤醒”和“Java Message 已交付”。
12. 边界说明
本文不展开 native 消息 envelope、完整 response 队列、epoll 重建异常和 ALooper NDK 适配。本文能直接支持的是 Java/JNI/native 的入口、对象关系、唤醒机制和 FD 回调边界;不能仅凭这条路线推断 Java Message 的业务顺序或设备延迟。
